]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/iscsi_initiator/iscsi.c
Include eventhandler.h in more compilation units
[FreeBSD/FreeBSD.git] / sys / dev / iscsi_initiator / iscsi.c
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      '0',
97      '0',
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      }
375 #endif
376      return 0;
377 }
378
379 static int
380 i_ping(struct cdev *dev)
381 {
382      return 0;
383 }
384 /*
385  | low level I/O
386  */
387 static int
388 i_setsoc(isc_session_t *sp, int fd, struct thread *td)
389 {
390      cap_rights_t rights;
391      int error = 0;
392
393      if(sp->soc != NULL)
394           isc_stop_receiver(sp);
395
396      error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT),
397              &sp->fp, NULL, NULL);
398      if(error)
399           return error;
400
401      sp->soc = sp->fp->f_data;
402      sp->td = td;
403      isc_start_receiver(sp);
404
405      return error;
406 }
407
408 static int
409 i_send(struct cdev *dev, caddr_t arg, struct thread *td)
410 {
411      isc_session_t      *sp = dev->si_drv2;
412      caddr_t            bp;
413      pduq_t             *pq;
414      pdu_t              *pp;
415      int                n, error;
416
417      debug_called(8);
418
419      if(sp->soc == NULL)
420           return ENOTCONN;
421
422      if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL)
423           return EAGAIN;
424      pp = &pq->pdu;
425      pq->pdu = *(pdu_t *)arg;
426      if((error = i_prepPDU(sp, pq)) != 0)
427           goto out;
428
429      bp = NULL;
430      if((pq->len - sizeof(union ipdu_u)) > 0) {
431           pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSIBUF, M_NOWAIT);
432           if(pq->buf == NULL) {
433                error = EAGAIN;
434                goto out;
435           }
436      }
437      else
438           pq->buf = NULL; // just in case?
439
440      sdebug(2, "len=%d ahs_len=%d ds_len=%d buf=%zu@%p",
441             pq->len, pp->ahs_len, pp->ds_len, pq->len - sizeof(union ipdu_u), bp);
442
443      if(pp->ahs_len) {
444           // XXX: never tested, looks suspicious
445           n = pp->ahs_len;
446           error = copyin(pp->ahs_addr, bp, n);
447           if(error != 0) {
448                sdebug(3, "copyin ahs: error=%d", error);
449                goto out;
450           }
451           pp->ahs_addr = (ahs_t *)bp;
452           bp += n;
453      }
454      if(pp->ds_len) {
455           n = pp->ds_len;
456           error = copyin(pp->ds_addr, bp, n);
457           if(error != 0) {
458                sdebug(3, "copyin ds: error=%d", error);
459                goto out;
460           }
461           pp->ds_addr = bp;
462           bp += n;
463           while(n & 03) {
464                n++;
465                *bp++ = 0;
466           }
467      }
468
469      error = isc_qout(sp, pq);
470      if(error == 0)
471           wakeup(&sp->flags); // XXX: to 'push' proc_out ...
472 out:
473      if(error)
474           pdu_free(sp->isc, pq);
475
476      return error;
477 }
478
479 static int
480 i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
481 {
482      isc_session_t      *sp = dev->si_drv2;
483      pduq_t             *pq;
484      pdu_t              *pp, *up;
485      caddr_t            bp;
486      int                error, mustfree, cnt;
487      size_t             need, have, n;
488
489      debug_called(8);
490
491      if(sp == NULL)
492           return EIO;
493
494      if(sp->soc == NULL)
495           return ENOTCONN;
496      cnt = 6;     // XXX: maybe the user can request a time out?
497      mtx_lock(&sp->rsp_mtx);
498      while((pq = TAILQ_FIRST(&sp->rsp)) == NULL) {
499           msleep(&sp->rsp, &sp->rsp_mtx, PRIBIO, "isc_rsp", hz*10);
500           if(cnt-- == 0) break; // XXX: for now, needs work
501      }
502      if(pq != NULL) {
503           sp->stats.nrsp--;
504           TAILQ_REMOVE(&sp->rsp, pq, pq_link);
505      }
506      mtx_unlock(&sp->rsp_mtx);
507
508      sdebug(6, "cnt=%d", cnt);
509
510      if(pq == NULL) {
511           error = ENOTCONN;
512           sdebug(3, "error=%d sp->flags=%x ", error, sp->flags);
513           return error;
514      }
515      up = (pdu_t *)arg;
516      pp = &pq->pdu;
517      up->ipdu = pp->ipdu;
518      n = 0;
519      up->ds_len = 0;
520      up->ahs_len = 0;
521      error = 0;
522
523      if(pq->mp) {
524           u_int len;
525
526           // Grr...
527           len = 0;
528           if(pp->ahs_len) {
529                len += pp->ahs_len;
530           }
531           if(pp->ds_len) {
532                len += pp->ds_len;
533           }
534
535           mustfree = 0;
536           if(len > pq->mp->m_len) {
537                mustfree++;
538                bp = malloc(len, M_TMP, M_WAITOK);
539                sdebug(4, "need mbufcopy: %d", len);
540                i_mbufcopy(pq->mp, bp, len);
541           } 
542           else
543                bp = mtod(pq->mp, caddr_t);
544
545           if(pp->ahs_len) {
546                need = pp->ahs_len;
547                n = MIN(up->ahs_size, need);
548                error = copyout(bp, (caddr_t)up->ahs_addr, n);
549                up->ahs_len = n;
550                bp += need;
551           }
552           if(!error && pp->ds_len) {
553                need = pp->ds_len;
554                if((have = up->ds_size) == 0) {
555                     have = up->ahs_size - n;
556                     up->ds_addr = (caddr_t)up->ahs_addr + n;
557                }
558                n = MIN(have, need);
559                error = copyout(bp, (caddr_t)up->ds_addr, n);
560                up->ds_len = n;
561           }
562
563           if(mustfree)
564                free(bp, M_TMP);
565      }
566
567      sdebug(6, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len);
568
569      pdu_free(sp->isc, pq);
570
571      return error;
572 }
573
574 static int
575 i_fullfeature(struct cdev *dev, int flag)
576 {
577      isc_session_t      *sp = dev->si_drv2;
578      int                error;
579
580      sdebug(2, "flag=%d", flag);
581
582      error = 0;
583      switch(flag) {
584      case 0: // stop
585          sp->flags &= ~ISC_FFPHASE;
586          break;
587      case 1: // start
588          sp->flags |= ISC_FFPHASE;
589          error = ic_init(sp);
590          break;
591      case 2: // restart
592          sp->flags |= ISC_FFPHASE;
593          ism_restart(sp);
594          break;
595      }
596      return error;
597 }
598
599 static int
600 i_create_session(struct cdev *dev, int *ndev)
601
602      struct isc_softc   *sc = dev->si_drv1;
603      isc_session_t      *sp;
604      int                error, n;
605
606      debug_called(8);
607
608      sp = malloc(sizeof(isc_session_t), M_ISCSI, M_WAITOK | M_ZERO);
609      if(sp == NULL)
610           return ENOMEM;
611
612      sx_xlock(&sc->unit_sx);
613      if((n = alloc_unr(sc->unit)) < 0) {
614           sx_unlock(&sc->unit_sx);
615           free(sp, M_ISCSI);
616           xdebug("too many sessions!");
617           return EPERM;
618      }
619      sx_unlock(&sc->unit_sx);
620
621      mtx_lock(&sc->isc_mtx);
622      TAILQ_INSERT_TAIL(&sc->isc_sess, sp, sp_link);
623      isc->nsess++;
624      mtx_unlock(&sc->isc_mtx);
625
626      sp->dev = make_dev(&iscsi_cdevsw, n, UID_ROOT, GID_WHEEL, 0600, "iscsi%d", n);
627      *ndev = sp->sid = n;
628      sp->isc = sc;
629      sp->dev->si_drv1 = sc;
630      sp->dev->si_drv2 = sp;
631
632      sp->opt.maxRecvDataSegmentLength = 8192;
633      sp->opt.maxXmitDataSegmentLength = 8192;
634      sp->opt.maxBurstLength = 65536;    // 64k
635      sp->opt.maxluns = ISCSI_MAX_LUNS;
636
637      error = ism_start(sp);
638
639      return error;
640 }
641
642 #ifdef notused
643 static void
644 iscsi_counters(isc_session_t *sp)
645 {
646      int        h, r, s;
647      pduq_t     *pq;
648
649 #define _puke(i, pq) do {\
650                debug(2, "%03d] %06x %02x %x %ld %jd %x\n",\
651                        i, ntohl( pq->pdu.ipdu.bhs.CmdSN), \
652                        pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\
653                        (long)pq->ts.sec, pq->ts.frac, pq->flags);\
654                } while(0)
655
656      h = r = s = 0; 
657      TAILQ_FOREACH(pq, &sp->hld, pq_link) {
658           _puke(h, pq);
659           h++;
660      }
661      TAILQ_FOREACH(pq, &sp->rsp, pq_link) r++;
662      TAILQ_FOREACH(pq, &sp->csnd, pq_link) s++;
663      TAILQ_FOREACH(pq, &sp->wsnd, pq_link) s++;
664      TAILQ_FOREACH(pq, &sp->isnd, pq_link) s++;
665      debug(2, "hld=%d rsp=%d snd=%d", h, r, s);
666 }
667 #endif
668
669 static void
670 iscsi_shutdown(void *v)
671 {
672      struct isc_softc   *sc = v;
673      isc_session_t      *sp;
674      int        n;
675
676      debug_called(8);
677      if(sc == NULL) {
678           xdebug("sc is NULL!");
679           return;
680      }
681 #ifdef DO_EVENTHANDLER
682      if(sc->eh == NULL)
683           debug(2, "sc->eh is NULL");
684      else {
685           EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->eh);
686           debug(2, "done n=%d", sc->nsess);
687      }
688 #endif
689      n = 0;
690      TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) {
691           debug(2, "%2d] sp->flags=0x%08x", n, sp->flags);
692           n++;
693      }
694      debug(2, "done");
695 }
696
697 static void
698 free_pdus(struct isc_softc *sc)
699 {
700      debug_called(8);
701
702      if(sc->pdu_zone != NULL) {
703           uma_zdestroy(sc->pdu_zone);
704           sc->pdu_zone = NULL;
705      }
706 }
707
708 static int
709 iscsi_start(void)
710 {
711      debug_called(8);
712
713      isc =  malloc(sizeof(struct isc_softc), M_ISCSI, M_ZERO|M_WAITOK);
714      mtx_init(&isc->isc_mtx, "iscsi-isc", NULL, MTX_DEF);
715
716      TAILQ_INIT(&isc->isc_sess);
717      /*
718       | now init the free pdu list
719       */
720      isc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t),
721                                  NULL, NULL, NULL, NULL,
722                                  0, 0);
723      uma_zone_set_max(isc->pdu_zone, max_pdus);
724      isc->unit = new_unrhdr(0, max_sessions-1, NULL);
725      sx_init(&isc->unit_sx, "iscsi sx");
726
727 #ifdef DO_EVENTHANDLER
728      if((isc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown,
729                                         sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL)
730           xdebug("shutdown event registration failed\n");
731 #endif
732      /*
733       | sysctl stuff
734       */
735      sysctl_ctx_init(&isc->clist);
736      isc->oid = SYSCTL_ADD_NODE(&isc->clist,
737                                SYSCTL_STATIC_CHILDREN(_net),
738                                OID_AUTO,
739                                "iscsi_initiator",
740                                CTLFLAG_RD,
741                                0,
742                                "iSCSI Subsystem");
743
744      SYSCTL_ADD_STRING(&isc->clist,
745                        SYSCTL_CHILDREN(isc->oid),
746                        OID_AUTO,
747                        "driver_version",
748                        CTLFLAG_RD,
749                        iscsi_driver_version,
750                        0,
751                        "iscsi driver version");
752  
753      SYSCTL_ADD_STRING(&isc->clist,
754                        SYSCTL_CHILDREN(isc->oid),
755                        OID_AUTO,
756                        "isid",
757                        CTLFLAG_RW,
758                        isid,
759                        6+1,
760                        "initiator part of the Session Identifier");
761
762      SYSCTL_ADD_INT(&isc->clist,
763                     SYSCTL_CHILDREN(isc->oid),
764                     OID_AUTO,
765                     "sessions",
766                     CTLFLAG_RD,
767                     &isc->nsess,
768                     sizeof(isc->nsess),
769                     "number of active session");
770
771 #ifdef ISCSI_INITIATOR_DEBUG
772      mtx_init(&iscsi_dbg_mtx, "iscsi_dbg", NULL, MTX_DEF);
773 #endif
774
775      isc->dev = make_dev_credf(MAKEDEV_CHECKNAME, &iscsi_cdevsw, max_sessions,
776                                NULL, UID_ROOT, GID_WHEEL, 0600, "iscsi");
777      if (isc->dev == NULL) {
778           xdebug("iscsi_initiator: make_dev_credf failed");
779           return (EEXIST);
780      }
781      isc->dev->si_drv1 = isc;
782
783      printf("iscsi: version %s\n", iscsi_driver_version);
784      return (0);
785 }
786
787 /*
788  | Notes:
789  |      unload SHOULD fail if there is activity
790  |      activity: there is/are active session/s
791  */
792 static void
793 iscsi_stop(void)
794 {
795      isc_session_t      *sp, *sp_tmp;
796
797      debug_called(8);
798
799      /*
800       | go through all the sessions
801       | Note: close should have done this ...
802       */
803      TAILQ_FOREACH_SAFE(sp, &isc->isc_sess, sp_link, sp_tmp) {
804           //XXX: check for activity ...
805           ism_stop(sp);
806      }
807      mtx_destroy(&isc->isc_mtx);
808      sx_destroy(&isc->unit_sx);
809
810      free_pdus(isc);
811
812      if(isc->dev)
813           destroy_dev(isc->dev);
814
815      if(sysctl_ctx_free(&isc->clist))
816           xdebug("sysctl_ctx_free failed");
817
818      iscsi_shutdown(isc); // XXX: check EVENTHANDLER_ ...
819
820 #ifdef ISCSI_INITIATOR_DEBUG
821      mtx_destroy(&iscsi_dbg_mtx);
822 #endif
823
824      free(isc, M_ISCSI);
825 }
826
827 static int
828 iscsi_modevent(module_t mod, int what, void *arg)
829 {
830      int error = 0;
831
832      debug_called(8);
833
834      switch(what) {
835      case MOD_LOAD:
836           error = iscsi_start();
837           break;
838
839      case MOD_QUIESCE:
840           if(isc->nsess) {
841                xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess);
842                log(LOG_ERR, "iscsi module busy, cannot unload");
843           }
844           return isc->nsess;
845
846      case MOD_SHUTDOWN:
847           break;
848
849      case MOD_UNLOAD:
850           iscsi_stop();
851           break;
852
853      default:
854           break;
855      }
856      return (error);
857 }
858
859 moduledata_t iscsi_mod = {
860          "iscsi_initiator",
861          (modeventhand_t) iscsi_modevent,
862          0
863 };
864
865 #ifdef ISCSI_ROOT
866 static void
867 iscsi_rootconf(void)
868 {
869 #if 0
870         nfs_setup_diskless();
871         if (nfs_diskless_valid)
872                 rootdevnames[0] = "nfs:";
873 #endif
874         printf("** iscsi_rootconf **\n");
875 }
876
877 SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL)
878 #endif
879
880 DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
881 MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1);