xref: /freebsd/sys/cam/ctl/ctl_frontend.c (revision c36e54bb328697af1e6113812caecbd3bac89fe0)
1 /*-
2  * Copyright (c) 2003 Silicon Graphics International Corp.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions, and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    substantially similar to the "NO WARRANTY" disclaimer below
13  *    ("Disclaimer") and any redistribution must be conditioned upon
14  *    including a substantially similar Disclaimer requirement for further
15  *    binary redistribution.
16  *
17  * NO WARRANTY
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGES.
29  *
30  * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_frontend.c#4 $
31  */
32 /*
33  * CAM Target Layer front end interface code
34  *
35  * Author: Ken Merry <ken@FreeBSD.org>
36  */
37 
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/types.h>
45 #include <sys/malloc.h>
46 #include <sys/lock.h>
47 #include <sys/mutex.h>
48 #include <sys/condvar.h>
49 #include <sys/endian.h>
50 #include <sys/queue.h>
51 #include <sys/sysctl.h>
52 
53 #include <cam/scsi/scsi_all.h>
54 #include <cam/scsi/scsi_da.h>
55 #include <cam/ctl/ctl_io.h>
56 #include <cam/ctl/ctl.h>
57 #include <cam/ctl/ctl_frontend.h>
58 #include <cam/ctl/ctl_frontend_internal.h>
59 #include <cam/ctl/ctl_backend.h>
60 /* XXX KDM move defines from ctl_ioctl.h to somewhere else */
61 #include <cam/ctl/ctl_ioctl.h>
62 #include <cam/ctl/ctl_ha.h>
63 #include <cam/ctl/ctl_private.h>
64 #include <cam/ctl/ctl_debug.h>
65 
66 extern struct ctl_softc *control_softc;
67 
68 int
69 ctl_frontend_register(struct ctl_frontend *fe)
70 {
71 	struct ctl_softc *softc = control_softc;
72 	struct ctl_frontend *fe_tmp;
73 
74 	KASSERT(softc != NULL, ("CTL is not initialized"));
75 
76 	/*
77 	 * Sanity check, make sure this isn't a duplicate registration.
78 	 */
79 	mtx_lock(&softc->ctl_lock);
80 	STAILQ_FOREACH(fe_tmp, &softc->fe_list, links) {
81 		if (strcmp(fe_tmp->name, fe->name) == 0) {
82 			mtx_unlock(&softc->ctl_lock);
83 			return (-1);
84 		}
85 	}
86 	mtx_unlock(&softc->ctl_lock);
87 	STAILQ_INIT(&fe->port_list);
88 
89 	/*
90 	 * Call the frontend's initialization routine.
91 	 */
92 	if (fe->init != NULL)
93 		fe->init();
94 
95 	mtx_lock(&softc->ctl_lock);
96 	softc->num_frontends++;
97 	STAILQ_INSERT_TAIL(&softc->fe_list, fe, links);
98 	mtx_unlock(&softc->ctl_lock);
99 	return (0);
100 }
101 
102 int
103 ctl_frontend_deregister(struct ctl_frontend *fe)
104 {
105 	struct ctl_softc *softc = control_softc;
106 
107 	if (!STAILQ_EMPTY(&fe->port_list))
108 		return (-1);
109 
110 	mtx_lock(&softc->ctl_lock);
111 	STAILQ_REMOVE(&softc->fe_list, fe, ctl_frontend, links);
112 	softc->num_frontends--;
113 	mtx_unlock(&softc->ctl_lock);
114 
115 	/*
116 	 * Call the frontend's shutdown routine.
117 	 */
118 	if (fe->shutdown != NULL)
119 		fe->shutdown();
120 	return (0);
121 }
122 
123 struct ctl_frontend *
124 ctl_frontend_find(char *frontend_name)
125 {
126 	struct ctl_softc *softc = control_softc;
127 	struct ctl_frontend *fe;
128 
129 	mtx_lock(&softc->ctl_lock);
130 	STAILQ_FOREACH(fe, &softc->fe_list, links) {
131 		if (strcmp(fe->name, frontend_name) == 0) {
132 			mtx_unlock(&softc->ctl_lock);
133 			return (fe);
134 		}
135 	}
136 	mtx_unlock(&softc->ctl_lock);
137 	return (NULL);
138 }
139 
140 int
141 ctl_port_register(struct ctl_port *port)
142 {
143 	struct ctl_softc *softc = control_softc;
144 	void *pool;
145 	int port_num;
146 	int retval;
147 
148 	retval = 0;
149 
150 	KASSERT(softc != NULL, ("CTL is not initialized"));
151 
152 	mtx_lock(&softc->ctl_lock);
153 	port_num = ctl_ffz(softc->ctl_port_mask, CTL_MAX_PORTS);
154 	if ((port_num == -1)
155 	 || (ctl_set_mask(softc->ctl_port_mask, port_num) == -1)) {
156 		port->targ_port = -1;
157 		mtx_unlock(&softc->ctl_lock);
158 		return (1);
159 	}
160 	softc->num_ports++;
161 	mtx_unlock(&softc->ctl_lock);
162 
163 	/*
164 	 * Initialize the initiator and portname mappings
165 	 */
166 	port->max_initiators = CTL_MAX_INIT_PER_PORT;
167 	port->wwpn_iid = malloc(sizeof(*port->wwpn_iid) * port->max_initiators,
168 	    M_CTL, M_NOWAIT | M_ZERO);
169 	if (port->wwpn_iid == NULL) {
170 		retval = ENOMEM;
171 		goto error;
172 	}
173 
174 	/*
175 	 * We add 20 to whatever the caller requests, so he doesn't get
176 	 * burned by queueing things back to the pending sense queue.  In
177 	 * theory, there should probably only be one outstanding item, at
178 	 * most, on the pending sense queue for a LUN.  We'll clear the
179 	 * pending sense queue on the next command, whether or not it is
180 	 * a REQUEST SENSE.
181 	 */
182 	retval = ctl_pool_create(softc, port->port_name,
183 				 port->num_requested_ctl_io + 20, &pool);
184 	if (retval != 0) {
185 		free(port->wwpn_iid, M_CTL);
186 error:
187 		port->targ_port = -1;
188 		mtx_lock(&softc->ctl_lock);
189 		ctl_clear_mask(softc->ctl_port_mask, port_num);
190 		mtx_unlock(&softc->ctl_lock);
191 		return (retval);
192 	}
193 	port->ctl_pool_ref = pool;
194 
195 	if (port->options.stqh_first == NULL)
196 		STAILQ_INIT(&port->options);
197 
198 	mtx_lock(&softc->ctl_lock);
199 	port->targ_port = port_num + softc->port_offset;
200 	STAILQ_INSERT_TAIL(&port->frontend->port_list, port, fe_links);
201 	STAILQ_INSERT_TAIL(&softc->port_list, port, links);
202 	softc->ctl_ports[port_num] = port;
203 	mtx_unlock(&softc->ctl_lock);
204 
205 	return (retval);
206 }
207 
208 int
209 ctl_port_deregister(struct ctl_port *port)
210 {
211 	struct ctl_softc *softc = control_softc;
212 	struct ctl_io_pool *pool;
213 	int port_num, retval, i;
214 
215 	retval = 0;
216 
217 	pool = (struct ctl_io_pool *)port->ctl_pool_ref;
218 
219 	if (port->targ_port == -1) {
220 		retval = 1;
221 		goto bailout;
222 	}
223 
224 	mtx_lock(&softc->ctl_lock);
225 	STAILQ_REMOVE(&softc->port_list, port, ctl_port, links);
226 	STAILQ_REMOVE(&port->frontend->port_list, port, ctl_port, fe_links);
227 	softc->num_ports--;
228 	port_num = (port->targ_port < CTL_MAX_PORTS) ? port->targ_port :
229 	    port->targ_port - CTL_MAX_PORTS;
230 	ctl_clear_mask(softc->ctl_port_mask, port_num);
231 	softc->ctl_ports[port_num] = NULL;
232 	mtx_unlock(&softc->ctl_lock);
233 
234 	ctl_pool_free(pool);
235 	ctl_free_opts(&port->options);
236 
237 	ctl_lun_map_deinit(port);
238 	free(port->port_devid, M_CTL);
239 	port->port_devid = NULL;
240 	free(port->target_devid, M_CTL);
241 	port->target_devid = NULL;
242 	free(port->init_devid, M_CTL);
243 	port->init_devid = NULL;
244 	for (i = 0; i < port->max_initiators; i++)
245 		free(port->wwpn_iid[i].name, M_CTL);
246 	free(port->wwpn_iid, M_CTL);
247 
248 bailout:
249 	return (retval);
250 }
251 
252 void
253 ctl_port_set_wwns(struct ctl_port *port, int wwnn_valid, uint64_t wwnn,
254 		      int wwpn_valid, uint64_t wwpn)
255 {
256 	struct scsi_vpd_id_descriptor *desc;
257 	int len, proto;
258 
259 	if (port->port_type == CTL_PORT_FC)
260 		proto = SCSI_PROTO_FC << 4;
261 	else if (port->port_type == CTL_PORT_ISCSI)
262 		proto = SCSI_PROTO_ISCSI << 4;
263 	else
264 		proto = SCSI_PROTO_SPI << 4;
265 
266 	if (wwnn_valid) {
267 		port->wwnn = wwnn;
268 
269 		free(port->target_devid, M_CTL);
270 
271 		len = sizeof(struct scsi_vpd_device_id) + CTL_WWPN_LEN;
272 		port->target_devid = malloc(sizeof(struct ctl_devid) + len,
273 		    M_CTL, M_WAITOK | M_ZERO);
274 		port->target_devid->len = len;
275 		desc = (struct scsi_vpd_id_descriptor *)port->target_devid->data;
276 		desc->proto_codeset = proto | SVPD_ID_CODESET_BINARY;
277 		desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_TARGET |
278 		    SVPD_ID_TYPE_NAA;
279 		desc->length = CTL_WWPN_LEN;
280 		scsi_u64to8b(port->wwnn, desc->identifier);
281 	}
282 
283 	if (wwpn_valid) {
284 		port->wwpn = wwpn;
285 
286 		free(port->port_devid, M_CTL);
287 
288 		len = sizeof(struct scsi_vpd_device_id) + CTL_WWPN_LEN;
289 		port->port_devid = malloc(sizeof(struct ctl_devid) + len,
290 		    M_CTL, M_WAITOK | M_ZERO);
291 		port->port_devid->len = len;
292 		desc = (struct scsi_vpd_id_descriptor *)port->port_devid->data;
293 		desc->proto_codeset = proto | SVPD_ID_CODESET_BINARY;
294 		desc->id_type = SVPD_ID_PIV | SVPD_ID_ASSOC_PORT |
295 		    SVPD_ID_TYPE_NAA;
296 		desc->length = CTL_WWPN_LEN;
297 		scsi_u64to8b(port->wwpn, desc->identifier);
298 	}
299 }
300 
301 void
302 ctl_port_online(struct ctl_port *port)
303 {
304 	struct ctl_softc *softc = control_softc;
305 	struct ctl_lun *lun;
306 	uint32_t l;
307 
308 	if (port->lun_map) {
309 		for (l = 0; l < CTL_MAX_LUNS; l++) {
310 			if (ctl_lun_map_from_port(port, l) >= CTL_MAX_LUNS)
311 				continue;
312 			port->lun_enable(port->targ_lun_arg, l);
313 		}
314 	} else {
315 		STAILQ_FOREACH(lun, &softc->lun_list, links)
316 			port->lun_enable(port->targ_lun_arg, lun->lun);
317 	}
318 	port->port_online(port->onoff_arg);
319 	/* XXX KDM need a lock here? */
320 	port->status |= CTL_PORT_STATUS_ONLINE;
321 }
322 
323 void
324 ctl_port_offline(struct ctl_port *port)
325 {
326 	struct ctl_softc *softc = control_softc;
327 	struct ctl_lun *lun;
328 	uint32_t l;
329 
330 	port->port_offline(port->onoff_arg);
331 	if (port->lun_map) {
332 		for (l = 0; l < CTL_MAX_LUNS; l++) {
333 			if (ctl_lun_map_from_port(port, l) >= CTL_MAX_LUNS)
334 				continue;
335 			port->lun_disable(port->targ_lun_arg, l);
336 		}
337 	} else {
338 		STAILQ_FOREACH(lun, &softc->lun_list, links)
339 			port->lun_disable(port->targ_lun_arg, lun->lun);
340 	}
341 	/* XXX KDM need a lock here? */
342 	port->status &= ~CTL_PORT_STATUS_ONLINE;
343 }
344 
345 /*
346  * vim: ts=8
347  */
348