1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2005-2011 Daniel Braniss <danny@cs.huji.ac.il>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29 /*
30 | $Id: iscsi.c 752 2009-08-20 11:23:28Z danny $
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include "opt_iscsi_initiator.h"
37
38 #include <sys/param.h>
39 #include <sys/capsicum.h>
40 #ifdef DO_EVENTHANDLER
41 #include <sys/eventhandler.h>
42 #endif
43 #include <sys/kernel.h>
44 #include <sys/module.h>
45 #include <sys/conf.h>
46 #include <sys/bus.h>
47 #include <sys/systm.h>
48 #include <sys/malloc.h>
49 #include <sys/ctype.h>
50 #include <sys/errno.h>
51 #include <sys/sysctl.h>
52 #include <sys/file.h>
53 #include <sys/uio.h>
54 #include <sys/socketvar.h>
55 #include <sys/socket.h>
56 #include <sys/protosw.h>
57 #include <sys/proc.h>
58 #include <sys/ioccom.h>
59 #include <sys/queue.h>
60 #include <sys/kthread.h>
61 #include <sys/mbuf.h>
62 #include <sys/syslog.h>
63 #include <vm/uma.h>
64 #include <sys/sx.h>
65
66 #include <dev/iscsi_initiator/iscsi.h>
67 #include <dev/iscsi_initiator/iscsivar.h>
68 static char *iscsi_driver_version = "2.3.1";
69
70 static struct isc_softc *isc;
71
72 MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI driver");
73 MALLOC_DEFINE(M_ISCSIBUF, "iSCbuf", "iSCSI buffers");
74 static MALLOC_DEFINE(M_TMP, "iSCtmp", "iSCSI tmp");
75
76 #ifdef ISCSI_INITIATOR_DEBUG
77 int iscsi_debug = ISCSI_INITIATOR_DEBUG;
78 SYSCTL_INT(_debug, OID_AUTO, iscsi_initiator, CTLFLAG_RW, &iscsi_debug, 0,
79 "iSCSI driver debug flag");
80
81 struct mtx iscsi_dbg_mtx;
82 #endif
83
84 static int max_sessions = MAX_SESSIONS;
85 SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_sessions, CTLFLAG_RDTUN,
86 &max_sessions, 0, "Max sessions allowed");
87 static int max_pdus = MAX_PDUS;
88 SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN,
89 &max_pdus, 0, "Max PDU pool");
90
91 static char isid[6+1] = {
92 0x80,
93 'D',
94 'I',
95 'B',
96 '',
97 '',
98 0
99 };
100
101 static int i_create_session(struct cdev *dev, int *ndev);
102
103 static int i_ping(struct cdev *dev);
104 static int i_send(struct cdev *dev, caddr_t arg, struct thread *td);
105 static int i_recv(struct cdev *dev, caddr_t arg, struct thread *td);
106 static int i_setsoc(isc_session_t *sp, int fd, struct thread *td);
107 static int i_fullfeature(struct cdev *dev, int flag);
108
109 static d_open_t iscsi_open;
110 static d_close_t iscsi_close;
111 static d_ioctl_t iscsi_ioctl;
112 #ifdef ISCSI_INITIATOR_DEBUG
113 static d_read_t iscsi_read;
114 #endif
115
116 static struct cdevsw iscsi_cdevsw = {
117 .d_version = D_VERSION,
118 .d_open = iscsi_open,
119 .d_close = iscsi_close,
120 .d_ioctl = iscsi_ioctl,
121 #ifdef ISCSI_INITIATOR_DEBUG
122 .d_read = iscsi_read,
123 #endif
124 .d_name = "iSCSI",
125 };
126
127 static int
128 iscsi_open(struct cdev *dev, int flags, int otype, struct thread *td)
129 {
130 debug_called(8);
131
132 debug(7, "dev=%d", dev2unit(dev));
133
134 if(dev2unit(dev) > max_sessions) {
135 // should not happen
136 return ENODEV;
137 }
138 return 0;
139 }
140
141 static int
142 iscsi_close(struct cdev *dev, int flag, int otyp, struct thread *td)
143 {
144 isc_session_t *sp;
145
146 debug_called(8);
147
148 debug(3, "session=%d flag=%x", dev2unit(dev), flag);
149
150 if(dev2unit(dev) == max_sessions) {
151 return 0;
152 }
153 sp = dev->si_drv2;
154 if(sp != NULL) {
155 sdebug(3, "sp->flags=%x", sp->flags );
156 /*
157 | if still in full phase, this probably means
158 | that something went really bad.
159 | it could be a result from 'shutdown', in which case
160 | we will ignore it (so buffers can be flushed).
161 | the problem is that there is no way of differentiating
162 | between a shutdown procedure and 'iscontrol' dying.
163 */
164 if(sp->flags & ISC_FFPHASE)
165 // delay in case this is a shutdown.
166 tsleep(sp, PRIBIO, "isc-cls", 60*hz);
167 ism_stop(sp);
168 }
169 debug(2, "done");
170 return 0;
171 }
172
173 static int
174 iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
175 {
176 struct isc_softc *sc;
177 isc_session_t *sp;
178 isc_opt_t *opt;
179 int error;
180
181 debug_called(8);
182
183 error = 0;
184 if(dev2unit(dev) == max_sessions) {
185 /*
186 | non Session commands
187 */
188 sc = dev->si_drv1;
189 if(sc == NULL)
190 return ENXIO;
191
192 switch(cmd) {
193 case ISCSISETSES:
194 error = i_create_session(dev, (int *)arg);
195 if(error == 0)
196 break;
197
198 default:
199 error = ENXIO;
200 }
201 return error;
202 }
203 /*
204 | session commands
205 */
206 sp = dev->si_drv2;
207 if(sp == NULL)
208 return ENXIO;
209
210 sdebug(6, "dev=%d cmd=%d", dev2unit(dev), (int)(cmd & 0xff));
211
212 switch(cmd) {
213 case ISCSISETSOC:
214 error = i_setsoc(sp, *(u_int *)arg, td);
215 break;
216
217 case ISCSISETOPT:
218 opt = (isc_opt_t *)arg;
219 error = i_setopt(sp, opt);
220 break;
221
222 case ISCSISEND:
223 error = i_send(dev, arg, td);
224 break;
225
226 case ISCSIRECV:
227 error = i_recv(dev, arg, td);
228 break;
229
230 case ISCSIPING:
231 error = i_ping(dev);
232 break;
233
234 case ISCSISTART:
235 error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 1);
236 if(error == 0) {
237 sp->proc = td->td_proc;
238 SYSCTL_ADD_INT(&sp->clist, SYSCTL_CHILDREN(sp->oid),
239 OID_AUTO, "pid", CTLFLAG_RD,
240 &sp->proc->p_pid, sizeof(pid_t), "control process id");
241 }
242 break;
243
244 case ISCSIRESTART:
245 error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 2);
246 break;
247
248 case ISCSISTOP:
249 error = i_fullfeature(dev, 0);
250 break;
251
252 case ISCSISIGNAL: {
253 int sig = *(int *)arg;
254
255 if(sig < 0 || sig > _SIG_MAXSIG)
256 error = EINVAL;
257 else
258 sp->signal = sig;
259 break;
260 }
261
262 case ISCSIGETCAM: {
263 iscsi_cam_t *cp = (iscsi_cam_t *)arg;
264
265 error = ic_getCamVals(sp, cp);
266 break;
267 }
268
269 default:
270 error = ENOIOCTL;
271 }
272
273 return error;
274 }
275
276 static int
277 iscsi_read(struct cdev *dev, struct uio *uio, int ioflag)
278 {
279 #ifdef ISCSI_INITIATOR_DEBUG
280 struct isc_softc *sc;
281 isc_session_t *sp;
282 pduq_t *pq;
283 char buf[1024];
284
285 sc = dev->si_drv1;
286 sp = dev->si_drv2;
287 if(dev2unit(dev) == max_sessions) {
288 sprintf(buf, "/----- Session ------/\n");
289 uiomove(buf, strlen(buf), uio);
290 int i = 0;
291
292 TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) {
293 if(uio->uio_resid == 0)
294 return 0;
295 sprintf(buf, "%03d] '%s' '%s'\n", i++, sp->opt.targetAddress, sp->opt.targetName);
296 uiomove(buf, strlen(buf), uio);
297 }
298 sprintf(buf, "free npdu_alloc=%d, npdu_max=%d\n", sc->npdu_alloc, sc->npdu_max);
299 uiomove(buf, strlen(buf), uio);
300 }
301 else {
302 int i = 0;
303 struct socket *so = sp->soc;
304 #define pukeit(i, pq) do {\
305 sprintf(buf, "%03d] %06x %02x %06x %06x %jd\n",\
306 i, ntohl(pq->pdu.ipdu.bhs.CmdSN),\
307 pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\
308 ntohl(pq->pdu.ipdu.bhs.ExpStSN),\
309 (intmax_t)pq->ts.sec);\
310 } while(0)
311
312 sprintf(buf, "%d/%d /---- hld -----/\n", sp->stats.nhld, sp->stats.max_hld);
313 uiomove(buf, strlen(buf), uio);
314 TAILQ_FOREACH(pq, &sp->hld, pq_link) {
315 if(uio->uio_resid == 0)
316 return 0;
317 pukeit(i, pq); i++;
318 uiomove(buf, strlen(buf), uio);
319 }
320 sprintf(buf, "%d/%d /---- rsp -----/\n", sp->stats.nrsp, sp->stats.max_rsp);
321 uiomove(buf, strlen(buf), uio);
322 i = 0;
323 TAILQ_FOREACH(pq, &sp->rsp, pq_link) {
324 if(uio->uio_resid == 0)
325 return 0;
326 pukeit(i, pq); i++;
327 uiomove(buf, strlen(buf), uio);
328 }
329 sprintf(buf, "%d/%d /---- csnd -----/\n", sp->stats.ncsnd, sp->stats.max_csnd);
330 i = 0;
331 uiomove(buf, strlen(buf), uio);
332 TAILQ_FOREACH(pq, &sp->csnd, pq_link) {
333 if(uio->uio_resid == 0)
334 return 0;
335 pukeit(i, pq); i++;
336 uiomove(buf, strlen(buf), uio);
337 }
338 sprintf(buf, "%d/%d /---- wsnd -----/\n", sp->stats.nwsnd, sp->stats.max_wsnd);
339 i = 0;
340 uiomove(buf, strlen(buf), uio);
341 TAILQ_FOREACH(pq, &sp->wsnd, pq_link) {
342 if(uio->uio_resid == 0)
343 return 0;
344 pukeit(i, pq); i++;
345 uiomove(buf, strlen(buf), uio);
346 }
347 sprintf(buf, "%d/%d /---- isnd -----/\n", sp->stats.nisnd, sp->stats.max_isnd);
348 i = 0;
349 uiomove(buf, strlen(buf), uio);
350 TAILQ_FOREACH(pq, &sp->isnd, pq_link) {
351 if(uio->uio_resid == 0)
352 return 0;
353 pukeit(i, pq); i++;
354 uiomove(buf, strlen(buf), uio);
355 }
356
357 sprintf(buf, "/---- Stats ---/\n");
358 uiomove(buf, strlen(buf), uio);
359
360 sprintf(buf, "recv=%d sent=%d\n", sp->stats.nrecv, sp->stats.nsent);
361 uiomove(buf, strlen(buf), uio);
362
363 sprintf(buf, "flags=%x pdus: alloc=%d max=%d\n",
364 sp->flags, sc->npdu_alloc, sc->npdu_max);
365 uiomove(buf, strlen(buf), uio);
366
367 sprintf(buf, "cws=%d last cmd=%x exp=%x max=%x stat=%x itt=%x\n",
368 sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt);
369 uiomove(buf, strlen(buf), uio);
370
371 sprintf(buf, "/---- socket -----/\nso_count=%d so_state=%x\n", so->so_count, so->so_state);
372 uiomove(buf, strlen(buf), uio);
373 }
374 #endif
375 return 0;
376 }
377
378 static int
379 i_ping(struct cdev *dev)
380 {
381 return 0;
382 }
383 /*
384 | low level I/O
385 */
386 static int
387 i_setsoc(isc_session_t *sp, int fd, struct thread *td)
388 {
389 cap_rights_t rights;
390 int error = 0;
391
392 if(sp->soc != NULL)
393 isc_stop_receiver(sp);
394
395 error = getsock_cap(td, fd, cap_rights_init_one(&rights, CAP_SOCK_CLIENT),
396 &sp->fp, NULL, NULL);
397 if(error)
398 return error;
399
400 sp->soc = sp->fp->f_data;
401 sp->td = td;
402 isc_start_receiver(sp);
403
404 return error;
405 }
406
407 static int
408 i_send(struct cdev *dev, caddr_t arg, struct thread *td)
409 {
410 isc_session_t *sp = dev->si_drv2;
411 caddr_t bp;
412 pduq_t *pq;
413 pdu_t *pp;
414 int n, error;
415
416 debug_called(8);
417
418 if(sp->soc == NULL)
419 return ENOTCONN;
420
421 if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL)
422 return EAGAIN;
423 pp = &pq->pdu;
424 pq->pdu = *(pdu_t *)arg;
425 if((error = i_prepPDU(sp, pq)) != 0)
426 goto out;
427
428 bp = NULL;
429 if((pq->len - sizeof(union ipdu_u)) > 0) {
430 pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSIBUF, M_NOWAIT);
431 if(pq->buf == NULL) {
432 error = EAGAIN;
433 goto out;
434 }
435 }
436 else
437 pq->buf = NULL; // just in case?
438
439 sdebug(2, "len=%d ahs_len=%d ds_len=%d buf=%zu@%p",
440 pq->len, pp->ahs_len, pp->ds_len, pq->len - sizeof(union ipdu_u), bp);
441
442 if(pp->ahs_len) {
443 // XXX: never tested, looks suspicious
444 n = pp->ahs_len;
445 error = copyin(pp->ahs_addr, bp, n);
446 if(error != 0) {
447 sdebug(3, "copyin ahs: error=%d", error);
448 goto out;
449 }
450 pp->ahs_addr = (ahs_t *)bp;
451 bp += n;
452 }
453 if(pp->ds_len) {
454 n = pp->ds_len;
455 error = copyin(pp->ds_addr, bp, n);
456 if(error != 0) {
457 sdebug(3, "copyin ds: error=%d", error);
458 goto out;
459 }
460 pp->ds_addr = bp;
461 bp += n;
462 while(n & 03) {
463 n++;
464 *bp++ = 0;
465 }
466 }
467
468 error = isc_qout(sp, pq);
469 if(error == 0)
470 wakeup(&sp->flags); // XXX: to 'push' proc_out ...
471 out:
472 if(error)
473 pdu_free(sp->isc, pq);
474
475 return error;
476 }
477
478 static int
479 i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
480 {
481 isc_session_t *sp = dev->si_drv2;
482 pduq_t *pq;
483 pdu_t *pp, *up;
484 caddr_t bp;
485 int error, mustfree, cnt;
486 size_t need, have, n;
487
488 debug_called(8);
489
490 if(sp == NULL)
491 return EIO;
492
493 if(sp->soc == NULL)
494 return ENOTCONN;
495 cnt = 6; // XXX: maybe the user can request a time out?
496 mtx_lock(&sp->rsp_mtx);
497 while((pq = TAILQ_FIRST(&sp->rsp)) == NULL) {
498 msleep(&sp->rsp, &sp->rsp_mtx, PRIBIO, "isc_rsp", hz*10);
499 if(cnt-- == 0) break; // XXX: for now, needs work
500 }
501 if(pq != NULL) {
502 sp->stats.nrsp--;
503 TAILQ_REMOVE(&sp->rsp, pq, pq_link);
504 }
505 mtx_unlock(&sp->rsp_mtx);
506
507 sdebug(6, "cnt=%d", cnt);
508
509 if(pq == NULL) {
510 error = ENOTCONN;
511 sdebug(3, "error=%d sp->flags=%x ", error, sp->flags);
512 return error;
513 }
514 up = (pdu_t *)arg;
515 pp = &pq->pdu;
516 up->ipdu = pp->ipdu;
517 n = 0;
518 up->ds_len = 0;
519 up->ahs_len = 0;
520 error = 0;
521
522 if(pq->mp) {
523 u_int len;
524
525 // Grr...
526 len = 0;
527 if(pp->ahs_len) {
528 len += pp->ahs_len;
529 }
530 if(pp->ds_len) {
531 len += pp->ds_len;
532 }
533
534 mustfree = 0;
535 if(len > pq->mp->m_len) {
536 mustfree++;
537 bp = malloc(len, M_TMP, M_WAITOK);
538 sdebug(4, "need mbufcopy: %d", len);
539 i_mbufcopy(pq->mp, bp, len);
540 }
541 else
542 bp = mtod(pq->mp, caddr_t);
543
544 if(pp->ahs_len) {
545 need = pp->ahs_len;
546 n = MIN(up->ahs_size, need);
547 error = copyout(bp, (caddr_t)up->ahs_addr, n);
548 up->ahs_len = n;
549 bp += need;
550 }
551 if(!error && pp->ds_len) {
552 need = pp->ds_len;
553 if((have = up->ds_size) == 0) {
554 have = up->ahs_size - n;
555 up->ds_addr = (caddr_t)up->ahs_addr + n;
556 }
557 n = MIN(have, need);
558 error = copyout(bp, (caddr_t)up->ds_addr, n);
559 up->ds_len = n;
560 }
561
562 if(mustfree)
563 free(bp, M_TMP);
564 }
565
566 sdebug(6, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len);
567
568 pdu_free(sp->isc, pq);
569
570 return error;
571 }
572
573 static int
574 i_fullfeature(struct cdev *dev, int flag)
575 {
576 isc_session_t *sp = dev->si_drv2;
577 int error;
578
579 sdebug(2, "flag=%d", flag);
580
581 error = 0;
582 switch(flag) {
583 case 0: // stop
584 sp->flags &= ~ISC_FFPHASE;
585 break;
586 case 1: // start
587 sp->flags |= ISC_FFPHASE;
588 error = ic_init(sp);
589 break;
590 case 2: // restart
591 sp->flags |= ISC_FFPHASE;
592 ism_restart(sp);
593 break;
594 }
595 return error;
596 }
597
598 static int
599 i_create_session(struct cdev *dev, int *ndev)
600 {
601 struct isc_softc *sc = dev->si_drv1;
602 isc_session_t *sp;
603 int error, n;
604
605 debug_called(8);
606
607 sp = malloc(sizeof(isc_session_t), M_ISCSI, M_WAITOK | M_ZERO);
608 if(sp == NULL)
609 return ENOMEM;
610
611 sx_xlock(&sc->unit_sx);
612 if((n = alloc_unr(sc->unit)) < 0) {
613 sx_unlock(&sc->unit_sx);
614 free(sp, M_ISCSI);
615 xdebug("too many sessions!");
616 return EPERM;
617 }
618 sx_unlock(&sc->unit_sx);
619
620 mtx_lock(&sc->isc_mtx);
621 TAILQ_INSERT_TAIL(&sc->isc_sess, sp, sp_link);
622 isc->nsess++;
623 mtx_unlock(&sc->isc_mtx);
624
625 sp->dev = make_dev(&iscsi_cdevsw, n, UID_ROOT, GID_WHEEL, 0600, "iscsi%d", n);
626 *ndev = sp->sid = n;
627 sp->isc = sc;
628 sp->dev->si_drv1 = sc;
629 sp->dev->si_drv2 = sp;
630
631 sp->opt.maxRecvDataSegmentLength = 8192;
632 sp->opt.maxXmitDataSegmentLength = 8192;
633 sp->opt.maxBurstLength = 65536; // 64k
634 sp->opt.maxluns = ISCSI_MAX_LUNS;
635
636 error = ism_start(sp);
637
638 return error;
639 }
640
641 #ifdef notused
642 static void
643 iscsi_counters(isc_session_t *sp)
644 {
645 int h, r, s;
646 pduq_t *pq;
647
648 #define _puke(i, pq) do {\
649 debug(2, "%03d] %06x %02x %x %ld %jd %x\n",\
650 i, ntohl( pq->pdu.ipdu.bhs.CmdSN), \
651 pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\
652 (long)pq->ts.sec, pq->ts.frac, pq->flags);\
653 } while(0)
654
655 h = r = s = 0;
656 TAILQ_FOREACH(pq, &sp->hld, pq_link) {
657 _puke(h, pq);
658 h++;
659 }
660 TAILQ_FOREACH(pq, &sp->rsp, pq_link) r++;
661 TAILQ_FOREACH(pq, &sp->csnd, pq_link) s++;
662 TAILQ_FOREACH(pq, &sp->wsnd, pq_link) s++;
663 TAILQ_FOREACH(pq, &sp->isnd, pq_link) s++;
664 debug(2, "hld=%d rsp=%d snd=%d", h, r, s);
665 }
666 #endif
667
668 static void
669 iscsi_shutdown(void *v)
670 {
671 struct isc_softc *sc = v;
672 isc_session_t *sp;
673 int n;
674
675 debug_called(8);
676 if(sc == NULL) {
677 xdebug("sc is NULL!");
678 return;
679 }
680 #ifdef DO_EVENTHANDLER
681 if(sc->eh == NULL)
682 debug(2, "sc->eh is NULL");
683 else {
684 EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->eh);
685 debug(2, "done n=%d", sc->nsess);
686 }
687 #endif
688 n = 0;
689 TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) {
690 debug(2, "%2d] sp->flags=0x%08x", n, sp->flags);
691 n++;
692 }
693 debug(2, "done");
694 }
695
696 static void
697 free_pdus(struct isc_softc *sc)
698 {
699 debug_called(8);
700
701 if(sc->pdu_zone != NULL) {
702 uma_zdestroy(sc->pdu_zone);
703 sc->pdu_zone = NULL;
704 }
705 }
706
707 static int
708 iscsi_start(void)
709 {
710 debug_called(8);
711
712 isc = malloc(sizeof(struct isc_softc), M_ISCSI, M_ZERO|M_WAITOK);
713 mtx_init(&isc->isc_mtx, "iscsi-isc", NULL, MTX_DEF);
714
715 TAILQ_INIT(&isc->isc_sess);
716 /*
717 | now init the free pdu list
718 */
719 isc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t),
720 NULL, NULL, NULL, NULL,
721 0, 0);
722 uma_zone_set_max(isc->pdu_zone, max_pdus);
723 isc->unit = new_unrhdr(0, max_sessions-1, NULL);
724 sx_init(&isc->unit_sx, "iscsi sx");
725
726 #ifdef DO_EVENTHANDLER
727 if((isc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown,
728 sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL)
729 xdebug("shutdown event registration failed\n");
730 #endif
731 /*
732 | sysctl stuff
733 */
734 sysctl_ctx_init(&isc->clist);
735 isc->oid = SYSCTL_ADD_NODE(&isc->clist,
736 SYSCTL_STATIC_CHILDREN(_net),
737 OID_AUTO,
738 "iscsi_initiator",
739 CTLFLAG_RD | CTLFLAG_MPSAFE,
740 0,
741 "iSCSI Subsystem");
742
743 SYSCTL_ADD_STRING(&isc->clist,
744 SYSCTL_CHILDREN(isc->oid),
745 OID_AUTO,
746 "driver_version",
747 CTLFLAG_RD,
748 iscsi_driver_version,
749 0,
750 "iscsi driver version");
751
752 SYSCTL_ADD_STRING(&isc->clist,
753 SYSCTL_CHILDREN(isc->oid),
754 OID_AUTO,
755 "isid",
756 CTLFLAG_RW,
757 isid,
758 6+1,
759 "initiator part of the Session Identifier");
760
761 SYSCTL_ADD_INT(&isc->clist,
762 SYSCTL_CHILDREN(isc->oid),
763 OID_AUTO,
764 "sessions",
765 CTLFLAG_RD,
766 &isc->nsess,
767 sizeof(isc->nsess),
768 "number of active session");
769
770 #ifdef ISCSI_INITIATOR_DEBUG
771 mtx_init(&iscsi_dbg_mtx, "iscsi_dbg", NULL, MTX_DEF);
772 #endif
773
774 isc->dev = make_dev_credf(MAKEDEV_CHECKNAME, &iscsi_cdevsw, max_sessions,
775 NULL, UID_ROOT, GID_WHEEL, 0600, "iscsi");
776 if (isc->dev == NULL) {
777 xdebug("iscsi_initiator: make_dev_credf failed");
778 return (EEXIST);
779 }
780 isc->dev->si_drv1 = isc;
781
782 printf("iscsi: version %s\n", iscsi_driver_version);
783 return (0);
784 }
785
786 /*
787 | Notes:
788 | unload SHOULD fail if there is activity
789 | activity: there is/are active session/s
790 */
791 static void
792 iscsi_stop(void)
793 {
794 isc_session_t *sp, *sp_tmp;
795
796 debug_called(8);
797
798 /*
799 | go through all the sessions
800 | Note: close should have done this ...
801 */
802 TAILQ_FOREACH_SAFE(sp, &isc->isc_sess, sp_link, sp_tmp) {
803 //XXX: check for activity ...
804 ism_stop(sp);
805 }
806 mtx_destroy(&isc->isc_mtx);
807 sx_destroy(&isc->unit_sx);
808
809 free_pdus(isc);
810
811 if(isc->dev)
812 destroy_dev(isc->dev);
813
814 if(sysctl_ctx_free(&isc->clist))
815 xdebug("sysctl_ctx_free failed");
816
817 iscsi_shutdown(isc); // XXX: check EVENTHANDLER_ ...
818
819 #ifdef ISCSI_INITIATOR_DEBUG
820 mtx_destroy(&iscsi_dbg_mtx);
821 #endif
822
823 free(isc, M_ISCSI);
824 }
825
826 static int
827 iscsi_modevent(module_t mod, int what, void *arg)
828 {
829 int error = 0;
830
831 debug_called(8);
832
833 switch(what) {
834 case MOD_LOAD:
835 error = iscsi_start();
836 break;
837
838 case MOD_QUIESCE:
839 if(isc->nsess) {
840 xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess);
841 log(LOG_ERR, "iscsi module busy, cannot unload");
842 }
843 return isc->nsess;
844
845 case MOD_SHUTDOWN:
846 break;
847
848 case MOD_UNLOAD:
849 iscsi_stop();
850 break;
851
852 default:
853 break;
854 }
855 return (error);
856 }
857
858 moduledata_t iscsi_mod = {
859 "iscsi_initiator",
860 (modeventhand_t) iscsi_modevent,
861 0
862 };
863
864 #ifdef ISCSI_ROOT
865 static void
866 iscsi_rootconf(void)
867 {
868 #if 0
869 nfs_setup_diskless();
870 if (nfs_diskless_valid)
871 rootdevnames[0] = "nfs:";
872 #endif
873 printf("** iscsi_rootconf **\n");
874 }
875
876 SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL)
877 #endif
878
879 DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
880 MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1);
Cache object: c91883fdc545d3922001a1b508e03ff4
|