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