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