]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/iscsi_initiator/iscsi.c
Update bmake to version 20180919
[FreeBSD/FreeBSD.git] / sys / dev / iscsi_initiator / iscsi.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2005-2011 Daniel Braniss <danny@cs.huji.ac.il>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29 /*
30  | $Id: iscsi.c 752 2009-08-20 11:23:28Z danny $
31  */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35
36 #include "opt_iscsi_initiator.h"
37
38 #include <sys/param.h>
39 #include <sys/capsicum.h>
40 #include <sys/kernel.h>
41 #include <sys/module.h>
42 #include <sys/conf.h>
43 #include <sys/bus.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
46 #include <sys/ctype.h>
47 #include <sys/errno.h>
48 #include <sys/sysctl.h>
49 #include <sys/file.h>
50 #include <sys/uio.h>
51 #include <sys/socketvar.h>
52 #include <sys/socket.h>
53 #include <sys/protosw.h>
54 #include <sys/proc.h>
55 #include <sys/ioccom.h>
56 #include <sys/queue.h>
57 #include <sys/kthread.h>
58 #include <sys/mbuf.h>
59 #include <sys/syslog.h>
60 #include <vm/uma.h>
61 #include <sys/sx.h>
62
63 #include <dev/iscsi_initiator/iscsi.h>
64 #include <dev/iscsi_initiator/iscsivar.h>
65 static char *iscsi_driver_version = "2.3.1";
66
67 static struct isc_softc *isc;
68
69 MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI driver");
70 MALLOC_DEFINE(M_ISCSIBUF, "iSCbuf", "iSCSI buffers");
71 static MALLOC_DEFINE(M_TMP, "iSCtmp", "iSCSI tmp");
72
73 #ifdef ISCSI_INITIATOR_DEBUG
74 int iscsi_debug = ISCSI_INITIATOR_DEBUG;
75 SYSCTL_INT(_debug, OID_AUTO, iscsi_initiator, CTLFLAG_RW, &iscsi_debug, 0,
76         "iSCSI driver debug flag");
77
78 struct mtx iscsi_dbg_mtx;
79 #endif
80
81 static int max_sessions = MAX_SESSIONS;
82 SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_sessions, CTLFLAG_RDTUN,
83     &max_sessions, 0, "Max sessions allowed");
84 static int max_pdus = MAX_PDUS;
85 SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN,
86     &max_pdus, 0, "Max PDU pool");
87
88 static char isid[6+1] = {
89      0x80,
90      'D',
91      'I',
92      'B',
93      '0',
94      '0',
95      0
96 };
97
98 static int      i_create_session(struct cdev *dev, int *ndev);
99
100 static int      i_ping(struct cdev *dev);
101 static int      i_send(struct cdev *dev, caddr_t arg, struct thread *td);
102 static int      i_recv(struct cdev *dev, caddr_t arg, struct thread *td);
103 static int      i_setsoc(isc_session_t *sp, int fd, struct thread *td);
104 static int      i_fullfeature(struct cdev *dev, int flag);
105
106 static d_open_t iscsi_open;
107 static d_close_t iscsi_close;
108 static d_ioctl_t iscsi_ioctl;
109 #ifdef ISCSI_INITIATOR_DEBUG
110 static d_read_t iscsi_read;
111 #endif
112
113 static struct cdevsw iscsi_cdevsw = {
114      .d_version = D_VERSION,
115      .d_open    = iscsi_open,
116      .d_close   = iscsi_close,
117      .d_ioctl   = iscsi_ioctl,
118 #ifdef ISCSI_INITIATOR_DEBUG
119      .d_read    = iscsi_read,
120 #endif
121      .d_name    = "iSCSI",
122 };
123
124 static int
125 iscsi_open(struct cdev *dev, int flags, int otype, struct thread *td)
126 {
127      debug_called(8);
128
129      debug(7, "dev=%d", dev2unit(dev));
130
131      if(dev2unit(dev) > max_sessions) {
132           // should not happen
133           return ENODEV;
134      }
135      return 0;
136 }
137
138 static int
139 iscsi_close(struct cdev *dev, int flag, int otyp, struct thread *td)
140 {
141      isc_session_t      *sp;
142
143      debug_called(8);
144
145      debug(3, "session=%d flag=%x", dev2unit(dev), flag);
146
147      if(dev2unit(dev) == max_sessions) {
148           return 0;
149      }
150      sp = dev->si_drv2;
151      if(sp != NULL) {
152           sdebug(3, "sp->flags=%x", sp->flags );
153           /*
154            | if still in full phase, this probably means
155            | that something went really 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_softc   *sc;
174      isc_session_t      *sp;
175      isc_opt_t          *opt;
176      int                error;
177
178      debug_called(8);
179
180      error = 0;
181      if(dev2unit(dev) == max_sessions) {
182           /*
183            | non Session commands
184            */
185           sc = dev->si_drv1;
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                     break;
194
195           default:
196                error = ENXIO;
197           }
198           return error;
199      }
200      /*
201       | session commands
202       */
203      sp = dev->si_drv2;
204      if(sp == NULL)
205           return ENXIO;
206
207      sdebug(6, "dev=%d cmd=%d", dev2unit(dev), (int)(cmd & 0xff));
208
209      switch(cmd) {
210      case ISCSISETSOC:
211           error = i_setsoc(sp, *(u_int *)arg, td);
212           break;
213
214      case ISCSISETOPT:
215           opt = (isc_opt_t *)arg;
216           error = i_setopt(sp, opt);
217           break;
218
219      case ISCSISEND:
220           error = i_send(dev, arg, td);
221           break;
222
223      case ISCSIRECV:
224           error = i_recv(dev, arg, td);
225           break;
226
227      case ISCSIPING:
228           error = i_ping(dev);
229           break;
230
231      case ISCSISTART:
232           error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 1);
233           if(error == 0) {
234                sp->proc = td->td_proc;
235                SYSCTL_ADD_INT(&sp->clist, SYSCTL_CHILDREN(sp->oid),
236                                OID_AUTO, "pid", 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, "free npdu_alloc=%d, npdu_max=%d\n", sc->npdu_alloc, sc->npdu_max);
296           uiomove(buf, strlen(buf), uio);
297      }
298      else {
299           int   i = 0;
300           struct socket *so = sp->soc;
301 #define pukeit(i, pq) do {\
302                sprintf(buf, "%03d] %06x %02x %06x %06x %jd\n",\
303                        i, ntohl(pq->pdu.ipdu.bhs.CmdSN),\
304                        pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\
305                        ntohl(pq->pdu.ipdu.bhs.ExpStSN),\
306                        (intmax_t)pq->ts.sec);\
307                } while(0)
308
309           sprintf(buf, "%d/%d /---- hld -----/\n", sp->stats.nhld, sp->stats.max_hld);
310           uiomove(buf, strlen(buf), uio);
311           TAILQ_FOREACH(pq, &sp->hld, pq_link) {
312                if(uio->uio_resid == 0)
313                     return 0;
314                pukeit(i, pq); i++;
315                uiomove(buf, strlen(buf), uio);
316           }
317           sprintf(buf, "%d/%d /---- rsp -----/\n", sp->stats.nrsp, sp->stats.max_rsp);
318           uiomove(buf, strlen(buf), uio);
319           i = 0;
320           TAILQ_FOREACH(pq, &sp->rsp, pq_link) {
321                if(uio->uio_resid == 0)
322                     return 0;
323                pukeit(i, pq); i++;
324                uiomove(buf, strlen(buf), uio);
325           }
326           sprintf(buf, "%d/%d /---- csnd -----/\n", sp->stats.ncsnd, sp->stats.max_csnd);
327           i = 0;
328           uiomove(buf, strlen(buf), uio);
329           TAILQ_FOREACH(pq, &sp->csnd, pq_link) {
330                if(uio->uio_resid == 0)
331                     return 0;
332                pukeit(i, pq); i++;
333                uiomove(buf, strlen(buf), uio);
334           }
335           sprintf(buf, "%d/%d /---- wsnd -----/\n", sp->stats.nwsnd, sp->stats.max_wsnd);
336           i = 0;
337           uiomove(buf, strlen(buf), uio);
338           TAILQ_FOREACH(pq, &sp->wsnd, pq_link) {
339                if(uio->uio_resid == 0)
340                     return 0;
341                pukeit(i, pq); i++;
342                uiomove(buf, strlen(buf), uio);
343           }
344           sprintf(buf, "%d/%d /---- isnd -----/\n", sp->stats.nisnd, sp->stats.max_isnd);
345           i = 0;
346           uiomove(buf, strlen(buf), uio);
347           TAILQ_FOREACH(pq, &sp->isnd, pq_link) {
348                if(uio->uio_resid == 0)
349                     return 0;
350                pukeit(i, pq); i++;
351                uiomove(buf, strlen(buf), uio);
352           }
353
354           sprintf(buf, "/---- Stats ---/\n");
355           uiomove(buf, strlen(buf), uio);
356
357           sprintf(buf, "recv=%d sent=%d\n", sp->stats.nrecv, sp->stats.nsent);
358           uiomove(buf, strlen(buf), uio);
359
360           sprintf(buf, "flags=%x pdus: alloc=%d max=%d\n", 
361                   sp->flags, sc->npdu_alloc, sc->npdu_max);
362           uiomove(buf, strlen(buf), uio);
363
364           sprintf(buf, "cws=%d last cmd=%x exp=%x max=%x stat=%x itt=%x\n",
365                   sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt);
366           uiomove(buf, strlen(buf), uio);
367
368           sprintf(buf, "/---- socket -----/\nso_count=%d so_state=%x\n", so->so_count, so->so_state);
369           uiomove(buf, strlen(buf), uio);
370
371      }
372 #endif
373      return 0;
374 }
375
376 static int
377 i_ping(struct cdev *dev)
378 {
379      return 0;
380 }
381 /*
382  | low level I/O
383  */
384 static int
385 i_setsoc(isc_session_t *sp, int fd, struct thread *td)
386 {
387      cap_rights_t rights;
388      int error = 0;
389
390      if(sp->soc != NULL)
391           isc_stop_receiver(sp);
392
393      error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT),
394              &sp->fp, NULL, NULL);
395      if(error)
396           return error;
397
398      sp->soc = sp->fp->f_data;
399      sp->td = td;
400      isc_start_receiver(sp);
401
402      return error;
403 }
404
405 static int
406 i_send(struct cdev *dev, caddr_t arg, struct thread *td)
407 {
408      isc_session_t      *sp = dev->si_drv2;
409      caddr_t            bp;
410      pduq_t             *pq;
411      pdu_t              *pp;
412      int                n, error;
413
414      debug_called(8);
415
416      if(sp->soc == NULL)
417           return ENOTCONN;
418
419      if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL)
420           return EAGAIN;
421      pp = &pq->pdu;
422      pq->pdu = *(pdu_t *)arg;
423      if((error = i_prepPDU(sp, pq)) != 0)
424           goto out;
425
426      bp = NULL;
427      if((pq->len - sizeof(union ipdu_u)) > 0) {
428           pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSIBUF, M_NOWAIT);
429           if(pq->buf == NULL) {
430                error = EAGAIN;
431                goto out;
432           }
433      }
434      else
435           pq->buf = NULL; // just in case?
436
437      sdebug(2, "len=%d ahs_len=%d ds_len=%d buf=%zu@%p",
438             pq->len, pp->ahs_len, pp->ds_len, pq->len - sizeof(union ipdu_u), bp);
439
440      if(pp->ahs_len) {
441           // XXX: never tested, looks suspicious
442           n = pp->ahs_len;
443           error = copyin(pp->ahs_addr, bp, n);
444           if(error != 0) {
445                sdebug(3, "copyin ahs: error=%d", error);
446                goto out;
447           }
448           pp->ahs_addr = (ahs_t *)bp;
449           bp += n;
450      }
451      if(pp->ds_len) {
452           n = pp->ds_len;
453           error = copyin(pp->ds_addr, bp, n);
454           if(error != 0) {
455                sdebug(3, "copyin ds: error=%d", error);
456                goto out;
457           }
458           pp->ds_addr = bp;
459           bp += n;
460           while(n & 03) {
461                n++;
462                *bp++ = 0;
463           }
464      }
465
466      error = isc_qout(sp, pq);
467      if(error == 0)
468           wakeup(&sp->flags); // XXX: to 'push' proc_out ...
469 out:
470      if(error)
471           pdu_free(sp->isc, pq);
472
473      return error;
474 }
475
476 static int
477 i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
478 {
479      isc_session_t      *sp = dev->si_drv2;
480      pduq_t             *pq;
481      pdu_t              *pp, *up;
482      caddr_t            bp;
483      int                error, mustfree, cnt;
484      size_t             need, have, n;
485
486      debug_called(8);
487
488      if(sp == NULL)
489           return EIO;
490
491      if(sp->soc == NULL)
492           return ENOTCONN;
493      cnt = 6;     // XXX: maybe the user can request a time out?
494      mtx_lock(&sp->rsp_mtx);
495      while((pq = TAILQ_FIRST(&sp->rsp)) == NULL) {
496           msleep(&sp->rsp, &sp->rsp_mtx, PRIBIO, "isc_rsp", hz*10);
497           if(cnt-- == 0) break; // XXX: for now, needs work
498      }
499      if(pq != NULL) {
500           sp->stats.nrsp--;
501           TAILQ_REMOVE(&sp->rsp, pq, pq_link);
502      }
503      mtx_unlock(&sp->rsp_mtx);
504
505      sdebug(6, "cnt=%d", cnt);
506
507      if(pq == NULL) {
508           error = ENOTCONN;
509           sdebug(3, "error=%d sp->flags=%x ", error, sp->flags);
510           return error;
511      }
512      up = (pdu_t *)arg;
513      pp = &pq->pdu;
514      up->ipdu = pp->ipdu;
515      n = 0;
516      up->ds_len = 0;
517      up->ahs_len = 0;
518      error = 0;
519
520      if(pq->mp) {
521           u_int len;
522
523           // Grr...
524           len = 0;
525           if(pp->ahs_len) {
526                len += pp->ahs_len;
527           }
528           if(pp->ds_len) {
529                len += pp->ds_len;
530           }
531
532           mustfree = 0;
533           if(len > pq->mp->m_len) {
534                mustfree++;
535                bp = malloc(len, M_TMP, M_WAITOK);
536                sdebug(4, "need mbufcopy: %d", len);
537                i_mbufcopy(pq->mp, bp, len);
538           } 
539           else
540                bp = mtod(pq->mp, caddr_t);
541
542           if(pp->ahs_len) {
543                need = pp->ahs_len;
544                n = MIN(up->ahs_size, need);
545                error = copyout(bp, (caddr_t)up->ahs_addr, n);
546                up->ahs_len = n;
547                bp += need;
548           }
549           if(!error && pp->ds_len) {
550                need = pp->ds_len;
551                if((have = up->ds_size) == 0) {
552                     have = up->ahs_size - n;
553                     up->ds_addr = (caddr_t)up->ahs_addr + n;
554                }
555                n = MIN(have, need);
556                error = copyout(bp, (caddr_t)up->ds_addr, n);
557                up->ds_len = n;
558           }
559
560           if(mustfree)
561                free(bp, M_TMP);
562      }
563
564      sdebug(6, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len);
565
566      pdu_free(sp->isc, pq);
567
568      return error;
569 }
570
571 static int
572 i_fullfeature(struct cdev *dev, int flag)
573 {
574      isc_session_t      *sp = dev->si_drv2;
575      int                error;
576
577      sdebug(2, "flag=%d", flag);
578
579      error = 0;
580      switch(flag) {
581      case 0: // stop
582          sp->flags &= ~ISC_FFPHASE;
583          break;
584      case 1: // start
585          sp->flags |= ISC_FFPHASE;
586          error = ic_init(sp);
587          break;
588      case 2: // restart
589          sp->flags |= ISC_FFPHASE;
590          ism_restart(sp);
591          break;
592      }
593      return error;
594 }
595
596 static int
597 i_create_session(struct cdev *dev, int *ndev)
598
599      struct isc_softc   *sc = dev->si_drv1;
600      isc_session_t      *sp;
601      int                error, n;
602
603      debug_called(8);
604
605      sp = malloc(sizeof(isc_session_t), M_ISCSI, M_WAITOK | M_ZERO);
606      if(sp == NULL)
607           return ENOMEM;
608
609      sx_xlock(&sc->unit_sx);
610      if((n = alloc_unr(sc->unit)) < 0) {
611           sx_unlock(&sc->unit_sx);
612           free(sp, M_ISCSI);
613           xdebug("too many sessions!");
614           return EPERM;
615      }
616      sx_unlock(&sc->unit_sx);
617
618      mtx_lock(&sc->isc_mtx);
619      TAILQ_INSERT_TAIL(&sc->isc_sess, sp, sp_link);
620      isc->nsess++;
621      mtx_unlock(&sc->isc_mtx);
622
623      sp->dev = make_dev(&iscsi_cdevsw, n, UID_ROOT, GID_WHEEL, 0600, "iscsi%d", n);
624      *ndev = sp->sid = n;
625      sp->isc = sc;
626      sp->dev->si_drv1 = sc;
627      sp->dev->si_drv2 = sp;
628
629      sp->opt.maxRecvDataSegmentLength = 8192;
630      sp->opt.maxXmitDataSegmentLength = 8192;
631      sp->opt.maxBurstLength = 65536;    // 64k
632      sp->opt.maxluns = ISCSI_MAX_LUNS;
633
634      error = ism_start(sp);
635
636      return error;
637 }
638
639 #ifdef notused
640 static void
641 iscsi_counters(isc_session_t *sp)
642 {
643      int        h, r, s;
644      pduq_t     *pq;
645
646 #define _puke(i, pq) do {\
647                debug(2, "%03d] %06x %02x %x %ld %jd %x\n",\
648                        i, ntohl( pq->pdu.ipdu.bhs.CmdSN), \
649                        pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\
650                        (long)pq->ts.sec, pq->ts.frac, pq->flags);\
651                } while(0)
652
653      h = r = s = 0; 
654      TAILQ_FOREACH(pq, &sp->hld, pq_link) {
655           _puke(h, pq);
656           h++;
657      }
658      TAILQ_FOREACH(pq, &sp->rsp, pq_link) r++;
659      TAILQ_FOREACH(pq, &sp->csnd, pq_link) s++;
660      TAILQ_FOREACH(pq, &sp->wsnd, pq_link) s++;
661      TAILQ_FOREACH(pq, &sp->isnd, pq_link) s++;
662      debug(2, "hld=%d rsp=%d snd=%d", h, r, s);
663 }
664 #endif
665
666 static void
667 iscsi_shutdown(void *v)
668 {
669      struct isc_softc   *sc = v;
670      isc_session_t      *sp;
671      int        n;
672
673      debug_called(8);
674      if(sc == NULL) {
675           xdebug("sc is NULL!");
676           return;
677      }
678 #ifdef DO_EVENTHANDLER
679      if(sc->eh == NULL)
680           debug(2, "sc->eh is NULL");
681      else {
682           EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->eh);
683           debug(2, "done n=%d", sc->nsess);
684      }
685 #endif
686      n = 0;
687      TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) {
688           debug(2, "%2d] sp->flags=0x%08x", n, sp->flags);
689           n++;
690      }
691      debug(2, "done");
692 }
693
694 static void
695 free_pdus(struct isc_softc *sc)
696 {
697      debug_called(8);
698
699      if(sc->pdu_zone != NULL) {
700           uma_zdestroy(sc->pdu_zone);
701           sc->pdu_zone = NULL;
702      }
703 }
704
705 static int
706 iscsi_start(void)
707 {
708      debug_called(8);
709
710      isc =  malloc(sizeof(struct isc_softc), M_ISCSI, M_ZERO|M_WAITOK);
711      mtx_init(&isc->isc_mtx, "iscsi-isc", NULL, MTX_DEF);
712
713      TAILQ_INIT(&isc->isc_sess);
714      /*
715       | now init the free pdu list
716       */
717      isc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t),
718                                  NULL, NULL, NULL, NULL,
719                                  0, 0);
720      uma_zone_set_max(isc->pdu_zone, max_pdus);
721      isc->unit = new_unrhdr(0, max_sessions-1, NULL);
722      sx_init(&isc->unit_sx, "iscsi sx");
723
724 #ifdef DO_EVENTHANDLER
725      if((isc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown,
726                                         sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL)
727           xdebug("shutdown event registration failed\n");
728 #endif
729      /*
730       | sysctl stuff
731       */
732      sysctl_ctx_init(&isc->clist);
733      isc->oid = SYSCTL_ADD_NODE(&isc->clist,
734                                SYSCTL_STATIC_CHILDREN(_net),
735                                OID_AUTO,
736                                "iscsi_initiator",
737                                CTLFLAG_RD,
738                                0,
739                                "iSCSI Subsystem");
740
741      SYSCTL_ADD_STRING(&isc->clist,
742                        SYSCTL_CHILDREN(isc->oid),
743                        OID_AUTO,
744                        "driver_version",
745                        CTLFLAG_RD,
746                        iscsi_driver_version,
747                        0,
748                        "iscsi driver version");
749  
750      SYSCTL_ADD_STRING(&isc->clist,
751                        SYSCTL_CHILDREN(isc->oid),
752                        OID_AUTO,
753                        "isid",
754                        CTLFLAG_RW,
755                        isid,
756                        6+1,
757                        "initiator part of the Session Identifier");
758
759      SYSCTL_ADD_INT(&isc->clist,
760                     SYSCTL_CHILDREN(isc->oid),
761                     OID_AUTO,
762                     "sessions",
763                     CTLFLAG_RD,
764                     &isc->nsess,
765                     sizeof(isc->nsess),
766                     "number of active session");
767
768 #ifdef ISCSI_INITIATOR_DEBUG
769      mtx_init(&iscsi_dbg_mtx, "iscsi_dbg", NULL, MTX_DEF);
770 #endif
771
772      isc->dev = make_dev_credf(MAKEDEV_CHECKNAME, &iscsi_cdevsw, max_sessions,
773                                NULL, UID_ROOT, GID_WHEEL, 0600, "iscsi");
774      if (isc->dev == NULL) {
775           xdebug("iscsi_initiator: make_dev_credf failed");
776           return (EEXIST);
777      }
778      isc->dev->si_drv1 = isc;
779
780      printf("iscsi: version %s\n", iscsi_driver_version);
781      return (0);
782 }
783
784 /*
785  | Notes:
786  |      unload SHOULD fail if there is activity
787  |      activity: there is/are active session/s
788  */
789 static void
790 iscsi_stop(void)
791 {
792      isc_session_t      *sp, *sp_tmp;
793
794      debug_called(8);
795
796      /*
797       | go through all the sessions
798       | Note: close should have done this ...
799       */
800      TAILQ_FOREACH_SAFE(sp, &isc->isc_sess, sp_link, sp_tmp) {
801           //XXX: check for activity ...
802           ism_stop(sp);
803      }
804      mtx_destroy(&isc->isc_mtx);
805      sx_destroy(&isc->unit_sx);
806
807      free_pdus(isc);
808
809      if(isc->dev)
810           destroy_dev(isc->dev);
811
812      if(sysctl_ctx_free(&isc->clist))
813           xdebug("sysctl_ctx_free failed");
814
815      iscsi_shutdown(isc); // XXX: check EVENTHANDLER_ ...
816
817 #ifdef ISCSI_INITIATOR_DEBUG
818      mtx_destroy(&iscsi_dbg_mtx);
819 #endif
820
821      free(isc, M_ISCSI);
822 }
823
824 static int
825 iscsi_modevent(module_t mod, int what, void *arg)
826 {
827      int error = 0;
828
829      debug_called(8);
830
831      switch(what) {
832      case MOD_LOAD:
833           error = iscsi_start();
834           break;
835
836      case MOD_QUIESCE:
837           if(isc->nsess) {
838                xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess);
839                log(LOG_ERR, "iscsi module busy, cannot unload");
840           }
841           return isc->nsess;
842
843      case MOD_SHUTDOWN:
844           break;
845
846      case MOD_UNLOAD:
847           iscsi_stop();
848           break;
849
850      default:
851           break;
852      }
853      return (error);
854 }
855
856 moduledata_t iscsi_mod = {
857          "iscsi_initiator",
858          (modeventhand_t) iscsi_modevent,
859          0
860 };
861
862 #ifdef ISCSI_ROOT
863 static void
864 iscsi_rootconf(void)
865 {
866 #if 0
867         nfs_setup_diskless();
868         if (nfs_diskless_valid)
869                 rootdevnames[0] = "nfs:";
870 #endif
871         printf("** iscsi_rootconf **\n");
872 }
873
874 SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL)
875 #endif
876
877 DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
878 MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1);