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