]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/iscsi/initiator/iscsi.c
Merge Cavium Octeon SDK 2.0 Simple Executive; this brings some fixes and new
[FreeBSD/FreeBSD.git] / sys / dev / iscsi / initiator / iscsi.c
1 /*-
2  * Copyright (c) 2005-2010 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$");
33
34 #include "opt_iscsi_initiator.h"
35
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
39 #include <sys/conf.h>
40 #include <sys/bus.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/ctype.h>
44 #include <sys/errno.h>
45 #include <sys/sysctl.h>
46 #include <sys/file.h>
47 #include <sys/uio.h>
48 #include <sys/socketvar.h>
49 #include <sys/socket.h>
50 #include <sys/protosw.h>
51 #include <sys/proc.h>
52 #include <sys/ioccom.h>
53 #include <sys/queue.h>
54 #include <sys/kthread.h>
55 #include <sys/mbuf.h>
56 #include <sys/syslog.h>
57 #include <vm/uma.h>
58 #include <sys/sx.h>
59
60 #include <dev/iscsi/initiator/iscsi.h>
61 #include <dev/iscsi/initiator/iscsivar.h>
62 static char *iscsi_driver_version = "2.2.4.2";
63
64 static struct isc_softc *isc;
65
66 MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI driver");
67 MALLOC_DEFINE(M_ISCSIBUF, "iSCbuf", "iSCSI buffers");
68 MALLOC_DEFINE(M_TMP, "iSCtmp", "iSCSI tmp");
69
70 #ifdef ISCSI_INITIATOR_DEBUG
71 int iscsi_debug = ISCSI_INITIATOR_DEBUG;
72 SYSCTL_INT(_debug, OID_AUTO, iscsi_initiator, CTLFLAG_RW, &iscsi_debug, 0,
73         "iSCSI driver debug flag");
74
75 struct mtx iscsi_dbg_mtx;
76 #endif
77
78 static int max_sessions = MAX_SESSIONS;
79 SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_sessions, CTLFLAG_RDTUN, &max_sessions, MAX_SESSIONS,
80            "Max sessions allowed");
81 static int max_pdus = MAX_PDUS;
82 SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN, &max_pdus, MAX_PDUS,
83            "Max pdu pool");
84
85 static char isid[6+1] = {
86      0x80,
87      'D',
88      'I',
89      'B',
90      '0',
91      '0',
92      0
93 };
94
95 static int      i_create_session(struct cdev *dev, int *ndev);
96
97 static int      i_ping(struct cdev *dev);
98 static int      i_send(struct cdev *dev, caddr_t arg, struct thread *td);
99 static int      i_recv(struct cdev *dev, caddr_t arg, struct thread *td);
100 static int      i_setsoc(isc_session_t *sp, int fd, struct thread *td);
101 static int      i_fullfeature(struct cdev *dev, int flag);
102
103 static d_open_t iscsi_open;
104 static d_close_t iscsi_close;
105 static d_ioctl_t iscsi_ioctl;
106 #ifdef ISCSI_INITIATOR_DEBUG
107 static d_read_t iscsi_read;
108 #endif
109
110 static struct cdevsw iscsi_cdevsw = {
111      .d_version = D_VERSION,
112      .d_open    = iscsi_open,
113      .d_close   = iscsi_close,
114      .d_ioctl   = iscsi_ioctl,
115 #ifdef ISCSI_INITIATOR_DEBUG
116      .d_read    = iscsi_read,
117 #endif
118      .d_name    = "iSCSI",
119 };
120
121 static int
122 iscsi_open(struct cdev *dev, int flags, int otype, struct thread *td)
123 {
124      debug_called(8);
125
126      debug(7, "dev=%d", dev2unit(dev));
127
128      if(dev2unit(dev) > max_sessions) {
129           // should not happen
130           return ENODEV;
131      }
132      return 0;
133 }
134
135 static int
136 iscsi_close(struct cdev *dev, int flag, int otyp, struct thread *td)
137 {
138      isc_session_t      *sp;
139
140      debug_called(8);
141
142      debug(3, "session=%d flag=%x", dev2unit(dev), flag);
143
144      if(dev2unit(dev) == max_sessions) {
145           return 0;
146      }
147      sp = dev->si_drv2;
148      if(sp != NULL) {
149           sdebug(3, "sp->flags=%x", sp->flags );
150           /*
151            | if still in full phase, this probably means
152            | that something went realy bad.
153            | it could be a result from 'shutdown', in which case
154            | we will ignore it (so buffers can be flushed).
155            | the problem is that there is no way of differentiating
156            | between a shutdown procedure and 'iscontrol' dying.
157            */
158           if(sp->flags & ISC_FFPHASE)
159                // delay in case this is a shutdown.
160                tsleep(sp, PRIBIO, "isc-cls", 60*hz);
161           ism_stop(sp);
162      }
163      debug(2, "done");
164      return 0;
165 }
166
167 static int
168 iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
169 {
170      struct isc_softc   *sc;
171      isc_session_t      *sp;
172      isc_opt_t          *opt;
173      int                error;
174
175      debug_called(8);
176
177      error = 0;
178      if(dev2unit(dev) == max_sessions) {
179           /*
180            | non Session commands
181            */
182           sc = dev->si_drv1;
183           if(sc == NULL)
184                return ENXIO;
185
186           switch(cmd) {
187           case ISCSISETSES:
188                error = i_create_session(dev, (int *)arg);
189                if(error == 0)
190                     break;
191
192           default:
193                error = ENXIO;
194           }
195           return error;
196      }
197      /*
198       | session commands
199       */
200      sp = dev->si_drv2;
201      if(sp == NULL)
202           return ENXIO;
203
204      sdebug(6, "dev=%d cmd=%d", dev2unit(dev), (int)(cmd & 0xff));
205
206      switch(cmd) {
207      case ISCSISETSOC:
208           error = i_setsoc(sp, *(u_int *)arg, td);
209           break;
210
211      case ISCSISETOPT:
212           opt = (isc_opt_t *)arg;
213           error = i_setopt(sp, opt);
214           break;
215
216      case ISCSISEND:
217           error = i_send(dev, arg, td);
218           break;
219
220      case ISCSIRECV:
221           error = i_recv(dev, arg, td);
222           break;
223
224      case ISCSIPING:
225           error = i_ping(dev);
226           break;
227
228      case ISCSISTART:
229           error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 1);
230           if(error == 0) {
231                sp->proc = td->td_proc;
232                SYSCTL_ADD_UINT(&sp->clist,
233                                SYSCTL_CHILDREN(sp->oid),
234                                OID_AUTO,
235                                "pid",
236                                CTLFLAG_RD,
237                                &sp->proc->p_pid, sizeof(pid_t), "control process id");
238           }
239           break;
240
241      case ISCSIRESTART:
242           error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 2);
243           break;
244
245      case ISCSISTOP:
246           error = i_fullfeature(dev, 0);
247           break;
248           
249      case ISCSISIGNAL: {
250           int sig = *(int *)arg;
251
252           if(sig < 0 || sig > _SIG_MAXSIG)
253                error = EINVAL;
254           else
255                 sp->signal = sig;
256           break;
257      }
258
259      case ISCSIGETCAM: {
260           iscsi_cam_t *cp = (iscsi_cam_t *)arg;
261
262           error = ic_getCamVals(sp, cp);
263           break;
264      }
265
266      default:
267           error = ENOIOCTL;
268      }
269
270      return error;
271 }
272
273 static int
274 iscsi_read(struct cdev *dev, struct uio *uio, int ioflag)
275 {
276 #ifdef  ISCSI_INITIATOR_DEBUG
277      struct isc_softc   *sc;
278      isc_session_t      *sp;
279      pduq_t             *pq;
280      char               buf[1024];
281
282      sc = dev->si_drv1;
283      sp = dev->si_drv2;
284      if(dev2unit(dev) == max_sessions) {
285           sprintf(buf, "/----- Session ------/\n");
286           uiomove(buf, strlen(buf), uio);
287           int   i = 0;
288
289           TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) {
290                if(uio->uio_resid == 0)
291                     return 0;
292                sprintf(buf, "%03d] '%s' '%s'\n", i++, sp->opt.targetAddress, sp->opt.targetName);
293                uiomove(buf, strlen(buf), uio);
294           }
295           sprintf(buf, "%d/%d /---- free -----/\n", sc->npdu_alloc, sc->npdu_max);
296           i = 0;
297           uiomove(buf, strlen(buf), uio);
298      }
299      else {
300           int   i = 0;
301           struct socket *so = sp->soc;
302 #define pukeit(i, pq) do {\
303                sprintf(buf, "%03d] %06x %02x %06x %06x %jd\n",\
304                        i, ntohl(pq->pdu.ipdu.bhs.CmdSN),\
305                        pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\
306                        ntohl(pq->pdu.ipdu.bhs.ExpStSN),\
307                        (intmax_t)pq->ts.sec);\
308                } while(0)
309
310           sprintf(buf, "%d/%d /---- hld -----/\n", sp->stats.nhld, sp->stats.max_hld);
311           uiomove(buf, strlen(buf), uio);
312           TAILQ_FOREACH(pq, &sp->hld, pq_link) {
313                if(uio->uio_resid == 0)
314                     return 0;
315                pukeit(i, pq); i++;
316                uiomove(buf, strlen(buf), uio);
317           }
318           sprintf(buf, "%d/%d /---- rsp -----/\n", sp->stats.nrsp, sp->stats.max_rsp);
319           uiomove(buf, strlen(buf), uio);
320           i = 0;
321           TAILQ_FOREACH(pq, &sp->rsp, pq_link) {
322                if(uio->uio_resid == 0)
323                     return 0;
324                pukeit(i, pq); i++;
325                uiomove(buf, strlen(buf), uio);
326           }
327           sprintf(buf, "%d/%d /---- csnd -----/\n", sp->stats.ncsnd, sp->stats.max_csnd);
328           i = 0;
329           uiomove(buf, strlen(buf), uio);
330           TAILQ_FOREACH(pq, &sp->csnd, pq_link) {
331                if(uio->uio_resid == 0)
332                     return 0;
333                pukeit(i, pq); i++;
334                uiomove(buf, strlen(buf), uio);
335           }
336           sprintf(buf, "%d/%d /---- wsnd -----/\n", sp->stats.nwsnd, sp->stats.max_wsnd);
337           i = 0;
338           uiomove(buf, strlen(buf), uio);
339           TAILQ_FOREACH(pq, &sp->wsnd, pq_link) {
340                if(uio->uio_resid == 0)
341                     return 0;
342                pukeit(i, pq); i++;
343                uiomove(buf, strlen(buf), uio);
344           }
345           sprintf(buf, "%d/%d /---- isnd -----/\n", sp->stats.nisnd, sp->stats.max_isnd);
346           i = 0;
347           uiomove(buf, strlen(buf), uio);
348           TAILQ_FOREACH(pq, &sp->isnd, pq_link) {
349                if(uio->uio_resid == 0)
350                     return 0;
351                pukeit(i, pq); i++;
352                uiomove(buf, strlen(buf), uio);
353           }
354
355           sprintf(buf, "/---- Stats ---/\n");
356           uiomove(buf, strlen(buf), uio);
357
358           sprintf(buf, "recv=%d sent=%d\n", sp->stats.nrecv, sp->stats.nsent);
359           uiomove(buf, strlen(buf), uio);
360
361           sprintf(buf, "flags=%x pdus: alloc=%d max=%d\n", 
362                   sp->flags, sc->npdu_alloc, sc->npdu_max);
363           uiomove(buf, strlen(buf), uio);
364
365           sprintf(buf, "cws=%d last cmd=%x exp=%x max=%x stat=%x itt=%x\n",
366                   sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt);
367           uiomove(buf, strlen(buf), uio);
368
369           sprintf(buf, "/---- socket -----/\nso_count=%d so_state=%x\n", so->so_count, so->so_state);
370           uiomove(buf, strlen(buf), uio);
371
372      }
373 #endif
374      return 0;
375 }
376
377 static int
378 i_ping(struct cdev *dev)
379 {
380      return 0;
381 }
382 /*
383  | low level I/O
384  */
385 static int
386 i_setsoc(isc_session_t *sp, int fd, struct thread *td)
387 {
388      int error = 0;
389
390      if(sp->soc != NULL)
391           isc_stop_receiver(sp);
392
393      error = fget(td, fd, &sp->fp);
394      if(error)
395           return error;
396
397      if((error = fgetsock(td, fd, &sp->soc, 0)) == 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
702      debug_called(8);
703
704      if(sc->pdu_zone != NULL) {
705           uma_zdestroy(sc->pdu_zone);
706           sc->pdu_zone = NULL;
707      }
708 }
709
710 static void
711 iscsi_start(void)
712 {
713      debug_called(8);
714
715      TUNABLE_INT_FETCH("net.iscsi_initiator.max_sessions", &max_sessions);
716      TUNABLE_INT_FETCH("net.iscsi_initiator.max_pdus", &max_pdus);
717
718      isc =  malloc(sizeof(struct isc_softc), M_ISCSI, M_ZERO|M_WAITOK);
719      isc->dev = make_dev(&iscsi_cdevsw, max_sessions, UID_ROOT, GID_WHEEL, 0600, "iscsi");
720      isc->dev->si_drv1 = isc;
721      mtx_init(&isc->isc_mtx, "iscsi", NULL, MTX_DEF);
722
723      TAILQ_INIT(&isc->isc_sess);
724      /*
725       | now init the free pdu list
726       */
727      isc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t),
728                                  NULL, NULL, NULL, NULL,
729                                  0, 0);
730      if(isc->pdu_zone == NULL) {
731           xdebug("iscsi_initiator: uma_zcreate failed");
732           // XXX: should fail...
733      }
734      uma_zone_set_max(isc->pdu_zone, max_pdus);
735      isc->unit = new_unrhdr(0, max_sessions-1, NULL);
736      sx_init(&isc->unit_sx, "iscsi sx");
737
738 #ifdef DO_EVENTHANDLER
739      if((isc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown,
740                                         sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL)
741           xdebug("shutdown event registration failed\n");
742 #endif
743      /*
744       | sysctl stuff
745       */
746      sysctl_ctx_init(&isc->clist);
747      isc->oid = SYSCTL_ADD_NODE(&isc->clist,
748                                SYSCTL_STATIC_CHILDREN(_net),
749                                OID_AUTO,
750                                "iscsi_initiator",
751                                CTLFLAG_RD,
752                                0,
753                                "iSCSI Subsystem");
754
755      SYSCTL_ADD_STRING(&isc->clist,
756                        SYSCTL_CHILDREN(isc->oid),
757                        OID_AUTO,
758                        "driver_version",
759                        CTLFLAG_RD,
760                        iscsi_driver_version,
761                        0,
762                        "iscsi driver version");
763  
764      SYSCTL_ADD_STRING(&isc->clist,
765                        SYSCTL_CHILDREN(isc->oid),
766                        OID_AUTO,
767                        "isid",
768                        CTLFLAG_RW,
769                        isid,
770                        6+1,
771                        "initiator part of the Session Identifier");
772
773      SYSCTL_ADD_INT(&isc->clist,
774                     SYSCTL_CHILDREN(isc->oid),
775                     OID_AUTO,
776                     "sessions",
777                     CTLFLAG_RD,
778                     &isc->nsess,
779                     sizeof(isc->nsess),
780                     "number of active session");
781
782      printf("iscsi: version %s\n", iscsi_driver_version);
783 }
784
785 /*
786  | Notes:
787  |      unload SHOULD fail if there is activity
788  |      activity: there is/are active session/s
789  */
790 static void
791 iscsi_stop(void)
792 {
793      isc_session_t      *sp, *sp_tmp;
794
795      debug_called(8);
796
797      /*
798       | go through all the sessions
799       | Note: close should have done this ...
800       */
801      TAILQ_FOREACH_SAFE(sp, &isc->isc_sess, sp_link, sp_tmp) {
802           //XXX: check for activity ...
803           ism_stop(sp);
804           if(sp->cam_sim != NULL)
805                ic_destroy(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      free(isc, M_ISCSI);
820 }
821
822 static int
823 iscsi_modevent(module_t mod, int what, void *arg)
824 {
825      debug_called(8);
826
827      switch(what) {
828      case MOD_LOAD:
829           iscsi_start();
830           break;
831
832      case MOD_QUIESCE:
833           if(isc->nsess) {
834                xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess);
835                log(LOG_ERR, "iscsi module busy, cannot unload");
836           }
837           return isc->nsess;
838
839      case MOD_SHUTDOWN:
840           break;
841
842      case MOD_UNLOAD:
843           iscsi_stop();
844           break;
845
846      default:
847           break;
848      }
849      return 0;
850 }
851
852 moduledata_t iscsi_mod = {
853          "iscsi",
854          (modeventhand_t) iscsi_modevent,
855          0
856 };
857
858 #ifdef ISCSI_ROOT
859 static void
860 iscsi_rootconf(void)
861 {
862 #if 0
863         nfs_setup_diskless();
864         if (nfs_diskless_valid)
865                 rootdevnames[0] = "nfs:";
866 #endif
867         printf("** iscsi_rootconf **\n");
868 }
869
870 SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL)
871 #endif
872
873 DECLARE_MODULE(iscsi, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
874 MODULE_DEPEND(iscsi, cam, 1, 1, 1);