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