]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/cam/ctl/ctl_frontend.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / cam / ctl / ctl_frontend.c
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  */