iscsi.c revision 330897
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: stable/11/sys/dev/iscsi_initiator/iscsi.c 330897 2018-03-14 03:19:51Z eadler $");
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>
65static char *iscsi_driver_version = "2.3.1";
66
67static struct isc_softc *isc;
68
69MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI driver");
70MALLOC_DEFINE(M_ISCSIBUF, "iSCbuf", "iSCSI buffers");
71static MALLOC_DEFINE(M_TMP, "iSCtmp", "iSCSI tmp");
72
73#ifdef ISCSI_INITIATOR_DEBUG
74int iscsi_debug = ISCSI_INITIATOR_DEBUG;
75SYSCTL_INT(_debug, OID_AUTO, iscsi_initiator, CTLFLAG_RW, &iscsi_debug, 0,
76	"iSCSI driver debug flag");
77
78struct mtx iscsi_dbg_mtx;
79#endif
80
81static int max_sessions = MAX_SESSIONS;
82SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_sessions, CTLFLAG_RDTUN,
83    &max_sessions, 0, "Max sessions allowed");
84static int max_pdus = MAX_PDUS;
85SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN,
86    &max_pdus, 0, "Max PDU pool");
87
88static char isid[6+1] = {
89     0x80,
90     'D',
91     'I',
92     'B',
93     '0',
94     '0',
95     0
96};
97
98static int	i_create_session(struct cdev *dev, int *ndev);
99
100static int	i_ping(struct cdev *dev);
101static int	i_send(struct cdev *dev, caddr_t arg, struct thread *td);
102static int	i_recv(struct cdev *dev, caddr_t arg, struct thread *td);
103static int	i_setsoc(isc_session_t *sp, int fd, struct thread *td);
104static int	i_fullfeature(struct cdev *dev, int flag);
105
106static d_open_t iscsi_open;
107static d_close_t iscsi_close;
108static d_ioctl_t iscsi_ioctl;
109#ifdef ISCSI_INITIATOR_DEBUG
110static d_read_t iscsi_read;
111#endif
112
113static 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
124static int
125iscsi_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
138static int
139iscsi_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
170static int
171iscsi_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
273static int
274iscsi_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
376static int
377i_ping(struct cdev *dev)
378{
379     return 0;
380}
381/*
382 | low level I/O
383 */
384static int
385i_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
405static int
406i_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 ...
469out:
470     if(error)
471	  pdu_free(sp->isc, pq);
472
473     return error;
474}
475
476static int
477i_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
571static int
572i_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
596static int
597i_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
640static void
641iscsi_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
666static void
667iscsi_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
694static void
695free_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
705static int
706iscsi_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 */
789static void
790iscsi_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
824static int
825iscsi_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
856moduledata_t iscsi_mod = {
857         "iscsi_initiator",
858         (modeventhand_t) iscsi_modevent,
859         0
860};
861
862#ifdef ISCSI_ROOT
863static void
864iscsi_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
874SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL)
875#endif
876
877DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
878MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1);
879