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