ctl_frontend.c revision 284798
190284Sobrien/*-
290284Sobrien * Copyright (c) 2003 Silicon Graphics International Corp.
3169705Skan * All rights reserved.
418334Speter *
5132743Skan * Redistribution and use in source and binary forms, with or without
618334Speter * modification, are permitted provided that the following conditions
7132743Skan * are met:
818334Speter * 1. Redistributions of source code must retain the above copyright
918334Speter *    notice, this list of conditions, and the following disclaimer,
1018334Speter *    without modification.
1118334Speter * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12132743Skan *    substantially similar to the "NO WARRANTY" disclaimer below
1318334Speter *    ("Disclaimer") and any redistribution must be conditioned upon
1418334Speter *    including a substantially similar Disclaimer requirement for further
1518334Speter *    binary redistribution.
1618334Speter *
1718334Speter * NO WARRANTY
18132743Skan * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19169705Skan * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20169705Skan * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
2118334Speter * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2251411Sobrien * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2351411Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2418334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2551411Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26132743Skan * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27132743Skan * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2818334Speter * POSSIBILITY OF SUCH DAMAGES.
2990284Sobrien *
3090284Sobrien * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_frontend.c#4 $
3118334Speter */
3218334Speter/*
3318334Speter * CAM Target Layer front end interface code
3418334Speter *
3518334Speter * Author: Ken Merry <ken@FreeBSD.org>
3618334Speter */
37169705Skan
3818334Speter#include <sys/cdefs.h>
3918334Speter__FBSDID("$FreeBSD: stable/10/sys/cam/ctl/ctl_frontend.c 284798 2015-06-25 07:11:48Z mav $");
4051411Sobrien
4118334Speter#include <sys/param.h>
4251411Sobrien#include <sys/systm.h>
4351411Sobrien#include <sys/kernel.h>
4490284Sobrien#include <sys/types.h>
4551411Sobrien#include <sys/malloc.h>
4690284Sobrien#include <sys/lock.h>
4790284Sobrien#include <sys/mutex.h>
4890284Sobrien#include <sys/condvar.h>
4990284Sobrien#include <sys/endian.h>
50117408Skan#include <sys/queue.h>
51132743Skan#include <sys/sysctl.h>
52169705Skan
53169705Skan#include <cam/scsi/scsi_all.h>
54169705Skan#include <cam/scsi/scsi_da.h>
5518334Speter#include <cam/ctl/ctl_io.h>
5651411Sobrien#include <cam/ctl/ctl.h>
5790284Sobrien#include <cam/ctl/ctl_frontend.h>
5851411Sobrien#include <cam/ctl/ctl_frontend_internal.h>
5918334Speter#include <cam/ctl/ctl_backend.h>
60132743Skan/* XXX KDM move defines from ctl_ioctl.h to somewhere else */
61132743Skan#include <cam/ctl/ctl_ioctl.h>
62132743Skan#include <cam/ctl/ctl_ha.h>
63132743Skan#include <cam/ctl/ctl_private.h>
64132743Skan#include <cam/ctl/ctl_debug.h>
65132743Skan
66132743Skanextern struct ctl_softc *control_softc;
67132743Skan
6890284Sobrienint
69169705Skanctl_frontend_register(struct ctl_frontend *fe)
70169705Skan{
71169705Skan	struct ctl_softc *softc = control_softc;
72117408Skan	struct ctl_frontend *fe_tmp;
73169705Skan
74169705Skan	KASSERT(softc != NULL, ("CTL is not initialized"));
75169705Skan
76169705Skan	/*
77169705Skan	 * Sanity check, make sure this isn't a duplicate registration.
78169705Skan	 */
79169705Skan	mtx_lock(&softc->ctl_lock);
80169705Skan	STAILQ_FOREACH(fe_tmp, &softc->fe_list, links) {
81169705Skan		if (strcmp(fe_tmp->name, fe->name) == 0) {
82169705Skan			mtx_unlock(&softc->ctl_lock);
8390284Sobrien			return (-1);
84169705Skan		}
85169705Skan	}
86169705Skan	mtx_unlock(&softc->ctl_lock);
87169705Skan	STAILQ_INIT(&fe->port_list);
88169705Skan
89169705Skan	/*
90169705Skan	 * Call the frontend's initialization routine.
9190284Sobrien	 */
9290284Sobrien	if (fe->init != NULL)
9390284Sobrien		fe->init();
9490284Sobrien
9590284Sobrien	mtx_lock(&softc->ctl_lock);
9690284Sobrien	softc->num_frontends++;
9790284Sobrien	STAILQ_INSERT_TAIL(&softc->fe_list, fe, links);
9890284Sobrien	mtx_unlock(&softc->ctl_lock);
9990284Sobrien	return (0);
10090284Sobrien}
101169705Skan
102169705Skanint
10390284Sobrienctl_frontend_deregister(struct ctl_frontend *fe)
10490284Sobrien{
10590284Sobrien	struct ctl_softc *softc = control_softc;
10690284Sobrien
10790284Sobrien	if (!STAILQ_EMPTY(&fe->port_list))
10890284Sobrien		return (-1);
10990284Sobrien
11090284Sobrien	mtx_lock(&softc->ctl_lock);
11190284Sobrien	STAILQ_REMOVE(&softc->fe_list, fe, ctl_frontend, links);
11290284Sobrien	softc->num_frontends--;
11390284Sobrien	mtx_unlock(&softc->ctl_lock);
11490284Sobrien
11590284Sobrien	/*
116169705Skan	 * Call the frontend's shutdown routine.
117169705Skan	 */
118169705Skan	if (fe->shutdown != NULL)
119169705Skan		fe->shutdown();
120169705Skan	return (0);
121169705Skan}
122169705Skan
12351411Sobrienstruct ctl_frontend *
124117408Skanctl_frontend_find(char *frontend_name)
12551411Sobrien{
126117408Skan	struct ctl_softc *softc = control_softc;
12751411Sobrien	struct ctl_frontend *fe;
128169705Skan
129169705Skan	mtx_lock(&softc->ctl_lock);
130169705Skan	STAILQ_FOREACH(fe, &softc->fe_list, links) {
131169705Skan		if (strcmp(fe->name, frontend_name) == 0) {
132169705Skan			mtx_unlock(&softc->ctl_lock);
133169705Skan			return (fe);
134169705Skan		}
135169705Skan	}
136169705Skan	mtx_unlock(&softc->ctl_lock);
137169705Skan	return (NULL);
138169705Skan}
139169705Skan
140169705Skanint
141169705Skanctl_port_register(struct ctl_port *port)
142169705Skan{
143169705Skan	struct ctl_softc *softc = control_softc;
144169705Skan	void *pool;
14590284Sobrien	int port_num;
14690284Sobrien	int retval;
14790284Sobrien
14890284Sobrien	retval = 0;
14990284Sobrien
15090284Sobrien	KASSERT(softc != NULL, ("CTL is not initialized"));
15190284Sobrien
15290284Sobrien	mtx_lock(&softc->ctl_lock);
15390284Sobrien	port_num = ctl_ffz(softc->ctl_port_mask, CTL_MAX_PORTS);
15490284Sobrien	if ((port_num == -1)
155169705Skan	 || (ctl_set_mask(softc->ctl_port_mask, port_num) == -1)) {
156169705Skan		port->targ_port = -1;
15790284Sobrien		mtx_unlock(&softc->ctl_lock);
15890284Sobrien		return (1);
15990284Sobrien	}
16090284Sobrien	softc->num_ports++;
16190284Sobrien	mtx_unlock(&softc->ctl_lock);
16290284Sobrien
16390284Sobrien	/*
16490284Sobrien	 * Initialize the initiator and portname mappings
16590284Sobrien	 */
16690284Sobrien	port->max_initiators = CTL_MAX_INIT_PER_PORT;
16790284Sobrien	port->wwpn_iid = malloc(sizeof(*port->wwpn_iid) * port->max_initiators,
16890284Sobrien	    M_CTL, M_NOWAIT | M_ZERO);
16990284Sobrien	if (port->wwpn_iid == NULL) {
170132743Skan		retval = ENOMEM;
171169705Skan		goto error;
172169705Skan	}
173169705Skan
174169705Skan	/*
175169705Skan	 * We add 20 to whatever the caller requests, so he doesn't get
176169705Skan	 * burned by queueing things back to the pending sense queue.  In
17751411Sobrien	 * theory, there should probably only be one outstanding item, at
17851411Sobrien	 * most, on the pending sense queue for a LUN.  We'll clear the
179117408Skan	 * pending sense queue on the next command, whether or not it is
18051411Sobrien	 * a REQUEST SENSE.
181169705Skan	 */
182169705Skan	retval = ctl_pool_create(softc, port->port_name,
183169705Skan				 port->num_requested_ctl_io + 20, &pool);
184169705Skan	if (retval != 0) {
185169705Skan		free(port->wwpn_iid, M_CTL);
186169705Skanerror:
187169705Skan		port->targ_port = -1;
188169705Skan		mtx_lock(&softc->ctl_lock);
189169705Skan		ctl_clear_mask(softc->ctl_port_mask, port_num);
19051411Sobrien		mtx_unlock(&softc->ctl_lock);
191169705Skan		return (retval);
192169705Skan	}
193169705Skan	port->ctl_pool_ref = pool;
194169705Skan
195169705Skan	if (port->options.stqh_first == NULL)
196169705Skan		STAILQ_INIT(&port->options);
197169705Skan
19890284Sobrien	mtx_lock(&softc->ctl_lock);
19990284Sobrien	port->targ_port = port_num + softc->port_offset;
20090284Sobrien	STAILQ_INSERT_TAIL(&port->frontend->port_list, port, fe_links);
20190284Sobrien	STAILQ_INSERT_TAIL(&softc->port_list, port, links);
20290284Sobrien	softc->ctl_ports[port_num] = port;
20390284Sobrien	mtx_unlock(&softc->ctl_lock);
20490284Sobrien
20590284Sobrien	return (retval);
20690284Sobrien}
20790284Sobrien
208169705Skanint
209169705Skanctl_port_deregister(struct ctl_port *port)
21090284Sobrien{
21190284Sobrien	struct ctl_softc *softc = control_softc;
21290284Sobrien	struct ctl_io_pool *pool;
21390284Sobrien	int port_num, retval, i;
21490284Sobrien
21590284Sobrien	retval = 0;
21690284Sobrien
21790284Sobrien	pool = (struct ctl_io_pool *)port->ctl_pool_ref;
21890284Sobrien
21990284Sobrien	if (port->targ_port == -1) {
22090284Sobrien		retval = 1;
22190284Sobrien		goto bailout;
22290284Sobrien	}
223132743Skan
224169705Skan	mtx_lock(&softc->ctl_lock);
225169705Skan	STAILQ_REMOVE(&softc->port_list, port, ctl_port, links);
226169705Skan	STAILQ_REMOVE(&port->frontend->port_list, port, ctl_port, fe_links);
227169705Skan	softc->num_ports--;
228169705Skan	port_num = (port->targ_port < CTL_MAX_PORTS) ? port->targ_port :
229169705Skan	    port->targ_port - CTL_MAX_PORTS;
23051411Sobrien	ctl_clear_mask(softc->ctl_port_mask, port_num);
23151411Sobrien	softc->ctl_ports[port_num] = NULL;
232117408Skan	mtx_unlock(&softc->ctl_lock);
23351411Sobrien
234169705Skan	ctl_pool_free(pool);
235169705Skan	ctl_free_opts(&port->options);
236169705Skan
237169705Skan	ctl_lun_map_deinit(port);
238169705Skan	free(port->port_devid, M_CTL);
239169705Skan	port->port_devid = NULL;
240169705Skan	free(port->target_devid, M_CTL);
241169705Skan	port->target_devid = NULL;
242169705Skan	free(port->init_devid, M_CTL);
24351411Sobrien	port->init_devid = NULL;
244169705Skan	for (i = 0; i < port->max_initiators; i++)
245169705Skan		free(port->wwpn_iid[i].name, M_CTL);
246169705Skan	free(port->wwpn_iid, M_CTL);
247169705Skan
248169705Skanbailout:
249169705Skan	return (retval);
250169705Skan}
25190284Sobrien
25290284Sobrienvoid
25390284Sobrienctl_port_set_wwns(struct ctl_port *port, int wwnn_valid, uint64_t wwnn,
25490284Sobrien		      int wwpn_valid, uint64_t wwpn)
25590284Sobrien{
25690284Sobrien	struct scsi_vpd_id_descriptor *desc;
25790284Sobrien	int len, proto;
25890284Sobrien
25990284Sobrien	if (port->port_type == CTL_PORT_FC)
26090284Sobrien		proto = SCSI_PROTO_FC << 4;
261169705Skan	else if (port->port_type == CTL_PORT_ISCSI)
262169705Skan		proto = SCSI_PROTO_ISCSI << 4;
26390284Sobrien	else
26490284Sobrien		proto = SCSI_PROTO_SPI << 4;
26590284Sobrien
26690284Sobrien	if (wwnn_valid) {
26790284Sobrien		port->wwnn = wwnn;
26890284Sobrien
26990284Sobrien		free(port->target_devid, M_CTL);
27090284Sobrien
27190284Sobrien		len = sizeof(struct scsi_vpd_device_id) + CTL_WWPN_LEN;
27290284Sobrien		port->target_devid = malloc(sizeof(struct ctl_devid) + len,
27390284Sobrien		    M_CTL, M_WAITOK | M_ZERO);
27490284Sobrien		port->target_devid->len = len;
27590284Sobrien		desc = (struct scsi_vpd_id_descriptor *)port->target_devid->data;
276132743Skan		desc->proto_codeset = proto | SVPD_ID_CODESET_BINARY;
277169705Skan		desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_TARGET |
278169705Skan		    SVPD_ID_TYPE_NAA;
279169705Skan		desc->length = CTL_WWPN_LEN;
280169705Skan		scsi_u64to8b(port->wwnn, desc->identifier);
281169705Skan	}
282169705Skan
28351411Sobrien	if (wwpn_valid) {
28451411Sobrien		port->wwpn = wwpn;
285117408Skan
28651411Sobrien		free(port->port_devid, M_CTL);
287169705Skan
288169705Skan		len = sizeof(struct scsi_vpd_device_id) + CTL_WWPN_LEN;
289169705Skan		port->port_devid = malloc(sizeof(struct ctl_devid) + len,
290169705Skan		    M_CTL, M_WAITOK | M_ZERO);
291169705Skan		port->port_devid->len = len;
292169705Skan		desc = (struct scsi_vpd_id_descriptor *)port->port_devid->data;
293169705Skan		desc->proto_codeset = proto | SVPD_ID_CODESET_BINARY;
294169705Skan		desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT |
295169705Skan		    SVPD_ID_TYPE_NAA;
29651411Sobrien		desc->length = CTL_WWPN_LEN;
297169705Skan		scsi_u64to8b(port->wwpn, desc->identifier);
298169705Skan	}
299169705Skan}
300169705Skan
301169705Skanvoid
302169705Skanctl_port_online(struct ctl_port *port)
303169705Skan{
30490284Sobrien	struct ctl_softc *softc = control_softc;
30590284Sobrien	struct ctl_lun *lun;
30690284Sobrien	uint32_t l;
30790284Sobrien
30890284Sobrien	if (port->lun_map) {
30990284Sobrien		for (l = 0; l < CTL_MAX_LUNS; l++) {
31090284Sobrien			if (ctl_lun_map_from_port(port, l) >= CTL_MAX_LUNS)
31190284Sobrien				continue;
31290284Sobrien			port->lun_enable(port->targ_lun_arg, l);
31390284Sobrien		}
314169705Skan	} else {
315169705Skan		STAILQ_FOREACH(lun, &softc->lun_list, links)
31690284Sobrien			port->lun_enable(port->targ_lun_arg, lun->lun);
31790284Sobrien	}
31890284Sobrien	port->port_online(port->onoff_arg);
31990284Sobrien	/* XXX KDM need a lock here? */
32090284Sobrien	port->status |= CTL_PORT_STATUS_ONLINE;
32190284Sobrien}
32290284Sobrien
32390284Sobrienvoid
32490284Sobrienctl_port_offline(struct ctl_port *port)
32590284Sobrien{
32690284Sobrien	struct ctl_softc *softc = control_softc;
32790284Sobrien	struct ctl_lun *lun;
32890284Sobrien	uint32_t l;
329132743Skan
330169705Skan	port->port_offline(port->onoff_arg);
331169705Skan	if (port->lun_map) {
332169705Skan		for (l = 0; l < CTL_MAX_LUNS; l++) {
333169705Skan			if (ctl_lun_map_from_port(port, l) >= CTL_MAX_LUNS)
334169705Skan				continue;
335169705Skan			port->lun_disable(port->targ_lun_arg, l);
33651411Sobrien		}
33751411Sobrien	} else {
338117408Skan		STAILQ_FOREACH(lun, &softc->lun_list, links)
339219374Smm			port->lun_disable(port->targ_lun_arg, lun->lun);
340219374Smm	}
341219374Smm	/* XXX KDM need a lock here? */
342219374Smm	port->status &= ~CTL_PORT_STATUS_ONLINE;
343219374Smm}
344219374Smm
345219374Smm/*
346219374Smm * vim: ts=8
347219374Smm */
348219374Smm