iscsi.c revision 255812
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: head/sys/dev/iscsi_initiator/iscsi.c 255812 2013-09-23 10:36:03Z trasz $");
33
34#include "opt_iscsi_initiator.h"
35
36#include <sys/param.h>
37#include <sys/capability.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, &max_sessions, MAX_SESSIONS,
81	   "Max sessions allowed");
82static int max_pdus = MAX_PDUS;
83SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN, &max_pdus, MAX_PDUS,
84	   "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 realy 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 = fget(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT), &sp->fp);
392     if(error)
393	  return error;
394
395     error = fgetsock(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT),
396        &sp->soc, 0);
397     if(error == 0) {
398	  sp->td = td;
399	  isc_start_receiver(sp);
400     }
401     else {
402	  fdrop(sp->fp, td);
403	  sp->fp = NULL;
404     }
405
406     return error;
407}
408
409static int
410i_send(struct cdev *dev, caddr_t arg, struct thread *td)
411{
412     isc_session_t	*sp = dev->si_drv2;
413     caddr_t		bp;
414     pduq_t		*pq;
415     pdu_t		*pp;
416     int		n, error;
417
418     debug_called(8);
419
420     if(sp->soc == NULL)
421	  return ENOTCONN;
422
423     if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL)
424	  return EAGAIN;
425     pp = &pq->pdu;
426     pq->pdu = *(pdu_t *)arg;
427     if((error = i_prepPDU(sp, pq)) != 0)
428	  goto out;
429
430     bp = NULL;
431     if((pq->len - sizeof(union ipdu_u)) > 0) {
432	  pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSIBUF, M_NOWAIT);
433	  if(pq->buf == NULL) {
434	       error = EAGAIN;
435	       goto out;
436	  }
437     }
438     else
439	  pq->buf = NULL; // just in case?
440
441     sdebug(2, "len=%d ahs_len=%d ds_len=%d buf=%zu@%p",
442	    pq->len, pp->ahs_len, pp->ds_len, pq->len - sizeof(union ipdu_u), bp);
443
444     if(pp->ahs_len) {
445	  // XXX: never tested, looks suspicious
446	  n = pp->ahs_len;
447	  error = copyin(pp->ahs_addr, bp, n);
448	  if(error != 0) {
449	       sdebug(3, "copyin ahs: error=%d", error);
450	       goto out;
451	  }
452	  pp->ahs_addr = (ahs_t *)bp;
453	  bp += n;
454     }
455     if(pp->ds_len) {
456	  n = pp->ds_len;
457	  error = copyin(pp->ds_addr, bp, n);
458	  if(error != 0) {
459	       sdebug(3, "copyin ds: error=%d", error);
460	       goto out;
461	  }
462	  pp->ds_addr = bp;
463	  bp += n;
464	  while(n & 03) {
465	       n++;
466	       *bp++ = 0;
467	  }
468     }
469
470     error = isc_qout(sp, pq);
471     if(error == 0)
472	  wakeup(&sp->flags); // XXX: to 'push' proc_out ...
473out:
474     if(error)
475	  pdu_free(sp->isc, pq);
476
477     return error;
478}
479
480static int
481i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
482{
483     isc_session_t	*sp = dev->si_drv2;
484     pduq_t		*pq;
485     pdu_t		*pp, *up;
486     caddr_t		bp;
487     int		error, mustfree, cnt;
488     size_t		need, have, n;
489
490     debug_called(8);
491
492     if(sp == NULL)
493	  return EIO;
494
495     if(sp->soc == NULL)
496	  return ENOTCONN;
497     cnt = 6;     // XXX: maybe the user can request a time out?
498     mtx_lock(&sp->rsp_mtx);
499     while((pq = TAILQ_FIRST(&sp->rsp)) == NULL) {
500	  msleep(&sp->rsp, &sp->rsp_mtx, PRIBIO, "isc_rsp", hz*10);
501	  if(cnt-- == 0) break; // XXX: for now, needs work
502     }
503     if(pq != NULL) {
504	  sp->stats.nrsp--;
505	  TAILQ_REMOVE(&sp->rsp, pq, pq_link);
506     }
507     mtx_unlock(&sp->rsp_mtx);
508
509     sdebug(6, "cnt=%d", cnt);
510
511     if(pq == NULL) {
512	  error = ENOTCONN;
513	  sdebug(3, "error=%d sp->flags=%x ", error, sp->flags);
514	  return error;
515     }
516     up = (pdu_t *)arg;
517     pp = &pq->pdu;
518     up->ipdu = pp->ipdu;
519     n = 0;
520     up->ds_len = 0;
521     up->ahs_len = 0;
522     error = 0;
523
524     if(pq->mp) {
525	  u_int	len;
526
527	  // Grr...
528	  len = 0;
529	  if(pp->ahs_len) {
530	       len += pp->ahs_len;
531	  }
532	  if(pp->ds_len) {
533	       len += pp->ds_len;
534	  }
535
536	  mustfree = 0;
537	  if(len > pq->mp->m_len) {
538	       mustfree++;
539	       bp = malloc(len, M_TMP, M_WAITOK);
540	       sdebug(4, "need mbufcopy: %d", len);
541	       i_mbufcopy(pq->mp, bp, len);
542	  }
543	  else
544	       bp = mtod(pq->mp, caddr_t);
545
546	  if(pp->ahs_len) {
547	       need = pp->ahs_len;
548	       n = MIN(up->ahs_size, need);
549	       error = copyout(bp, (caddr_t)up->ahs_addr, n);
550	       up->ahs_len = n;
551	       bp += need;
552	  }
553	  if(!error && pp->ds_len) {
554	       need = pp->ds_len;
555	       if((have = up->ds_size) == 0) {
556		    have = up->ahs_size - n;
557		    up->ds_addr = (caddr_t)up->ahs_addr + n;
558	       }
559	       n = MIN(have, need);
560	       error = copyout(bp, (caddr_t)up->ds_addr, n);
561	       up->ds_len = n;
562	  }
563
564	  if(mustfree)
565	       free(bp, M_TMP);
566     }
567
568     sdebug(6, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len);
569
570     pdu_free(sp->isc, pq);
571
572     return error;
573}
574
575static int
576i_fullfeature(struct cdev *dev, int flag)
577{
578     isc_session_t	*sp = dev->si_drv2;
579     int		error;
580
581     sdebug(2, "flag=%d", flag);
582
583     error = 0;
584     switch(flag) {
585     case 0: // stop
586         sp->flags &= ~ISC_FFPHASE;
587         break;
588     case 1: // start
589         sp->flags |= ISC_FFPHASE;
590         error = ic_init(sp);
591         break;
592     case 2: // restart
593         sp->flags |= ISC_FFPHASE;
594         ism_restart(sp);
595         break;
596     }
597     return error;
598}
599
600static int
601i_create_session(struct cdev *dev, int *ndev)
602{
603     struct isc_softc	*sc = dev->si_drv1;
604     isc_session_t	*sp;
605     int		error, n;
606
607     debug_called(8);
608
609     sp = malloc(sizeof(isc_session_t), M_ISCSI, M_WAITOK | M_ZERO);
610     if(sp == NULL)
611	  return ENOMEM;
612
613     sx_xlock(&sc->unit_sx);
614     if((n = alloc_unr(sc->unit)) < 0) {
615	  sx_unlock(&sc->unit_sx);
616	  free(sp, M_ISCSI);
617	  xdebug("too many sessions!");
618	  return EPERM;
619     }
620     sx_unlock(&sc->unit_sx);
621
622     mtx_lock(&sc->isc_mtx);
623     TAILQ_INSERT_TAIL(&sc->isc_sess, sp, sp_link);
624     isc->nsess++;
625     mtx_unlock(&sc->isc_mtx);
626
627     sp->dev = make_dev(&iscsi_cdevsw, n, UID_ROOT, GID_WHEEL, 0600, "iscsi%d", n);
628     *ndev = sp->sid = n;
629     sp->isc = sc;
630     sp->dev->si_drv1 = sc;
631     sp->dev->si_drv2 = sp;
632
633     sp->opt.maxRecvDataSegmentLength = 8192;
634     sp->opt.maxXmitDataSegmentLength = 8192;
635     sp->opt.maxBurstLength = 65536;	// 64k
636     sp->opt.maxluns = ISCSI_MAX_LUNS;
637
638     error = ism_start(sp);
639
640     return error;
641}
642
643#ifdef notused
644static void
645iscsi_counters(isc_session_t *sp)
646{
647     int	h, r, s;
648     pduq_t	*pq;
649
650#define _puke(i, pq) do {\
651	       debug(2, "%03d] %06x %02x %x %ld %jd %x\n",\
652		       i, ntohl( pq->pdu.ipdu.bhs.CmdSN), \
653		       pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\
654		       (long)pq->ts.sec, pq->ts.frac, pq->flags);\
655	       } while(0)
656
657     h = r = s = 0;
658     TAILQ_FOREACH(pq, &sp->hld, pq_link) {
659	  _puke(h, pq);
660	  h++;
661     }
662     TAILQ_FOREACH(pq, &sp->rsp, pq_link) r++;
663     TAILQ_FOREACH(pq, &sp->csnd, pq_link) s++;
664     TAILQ_FOREACH(pq, &sp->wsnd, pq_link) s++;
665     TAILQ_FOREACH(pq, &sp->isnd, pq_link) s++;
666     debug(2, "hld=%d rsp=%d snd=%d", h, r, s);
667}
668#endif
669
670static void
671iscsi_shutdown(void *v)
672{
673     struct isc_softc	*sc = v;
674     isc_session_t	*sp;
675     int	n;
676
677     debug_called(8);
678     if(sc == NULL) {
679	  xdebug("sc is NULL!");
680	  return;
681     }
682#ifdef DO_EVENTHANDLER
683     if(sc->eh == NULL)
684	  debug(2, "sc->eh is NULL");
685     else {
686	  EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->eh);
687	  debug(2, "done n=%d", sc->nsess);
688     }
689#endif
690     n = 0;
691     TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) {
692	  debug(2, "%2d] sp->flags=0x%08x", n, sp->flags);
693	  n++;
694     }
695     debug(2, "done");
696}
697
698static void
699free_pdus(struct isc_softc *sc)
700{
701     debug_called(8);
702
703     if(sc->pdu_zone != NULL) {
704	  uma_zdestroy(sc->pdu_zone);
705	  sc->pdu_zone = NULL;
706     }
707}
708
709static void
710iscsi_start(void)
711{
712     debug_called(8);
713
714     TUNABLE_INT_FETCH("net.iscsi_initiator.max_sessions", &max_sessions);
715     TUNABLE_INT_FETCH("net.iscsi_initiator.max_pdus", &max_pdus);
716
717     isc =  malloc(sizeof(struct isc_softc), M_ISCSI, M_ZERO|M_WAITOK);
718     isc->dev = make_dev(&iscsi_cdevsw, max_sessions, UID_ROOT, GID_WHEEL, 0600, "iscsi");
719     isc->dev->si_drv1 = isc;
720     mtx_init(&isc->isc_mtx, "iscsi-isc", NULL, MTX_DEF);
721
722     TAILQ_INIT(&isc->isc_sess);
723     /*
724      | now init the free pdu list
725      */
726     isc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t),
727				 NULL, NULL, NULL, NULL,
728				 0, 0);
729     if(isc->pdu_zone == NULL) {
730	  xdebug("iscsi_initiator: uma_zcreate failed");
731	  // XXX: should fail...
732     }
733     uma_zone_set_max(isc->pdu_zone, max_pdus);
734     isc->unit = new_unrhdr(0, max_sessions-1, NULL);
735     sx_init(&isc->unit_sx, "iscsi sx");
736
737#ifdef DO_EVENTHANDLER
738     if((isc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown,
739					sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL)
740	  xdebug("shutdown event registration failed\n");
741#endif
742     /*
743      | sysctl stuff
744      */
745     sysctl_ctx_init(&isc->clist);
746     isc->oid = SYSCTL_ADD_NODE(&isc->clist,
747			       SYSCTL_STATIC_CHILDREN(_net),
748			       OID_AUTO,
749			       "iscsi_initiator",
750			       CTLFLAG_RD,
751			       0,
752			       "iSCSI Subsystem");
753
754     SYSCTL_ADD_STRING(&isc->clist,
755		       SYSCTL_CHILDREN(isc->oid),
756		       OID_AUTO,
757		       "driver_version",
758		       CTLFLAG_RD,
759		       iscsi_driver_version,
760		       0,
761		       "iscsi driver version");
762
763     SYSCTL_ADD_STRING(&isc->clist,
764		       SYSCTL_CHILDREN(isc->oid),
765		       OID_AUTO,
766		       "isid",
767		       CTLFLAG_RW,
768		       isid,
769		       6+1,
770		       "initiator part of the Session Identifier");
771
772     SYSCTL_ADD_INT(&isc->clist,
773		    SYSCTL_CHILDREN(isc->oid),
774		    OID_AUTO,
775		    "sessions",
776		    CTLFLAG_RD,
777		    &isc->nsess,
778		    sizeof(isc->nsess),
779		    "number of active session");
780
781#ifdef ISCSI_INITIATOR_DEBUG
782     mtx_init(&iscsi_dbg_mtx, "iscsi_dbg", NULL, MTX_DEF);
783#endif
784
785     printf("iscsi: version %s\n", iscsi_driver_version);
786}
787
788/*
789 | Notes:
790 |	unload SHOULD fail if there is activity
791 |	activity: there is/are active session/s
792 */
793static void
794iscsi_stop(void)
795{
796     isc_session_t	*sp, *sp_tmp;
797
798     debug_called(8);
799
800     /*
801      | go through all the sessions
802      | Note: close should have done this ...
803      */
804     TAILQ_FOREACH_SAFE(sp, &isc->isc_sess, sp_link, sp_tmp) {
805	  //XXX: check for activity ...
806	  ism_stop(sp);
807	  if(sp->cam_sim != NULL)
808	       ic_destroy(sp);
809     }
810     mtx_destroy(&isc->isc_mtx);
811     sx_destroy(&isc->unit_sx);
812
813     free_pdus(isc);
814
815     if(isc->dev)
816	  destroy_dev(isc->dev);
817
818     if(sysctl_ctx_free(&isc->clist))
819	  xdebug("sysctl_ctx_free failed");
820
821     iscsi_shutdown(isc); // XXX: check EVENTHANDLER_ ...
822
823#ifdef ISCSI_INITIATOR_DEBUG
824     mtx_destroy(&iscsi_dbg_mtx);
825#endif
826
827     free(isc, M_ISCSI);
828}
829
830static int
831iscsi_modevent(module_t mod, int what, void *arg)
832{
833     debug_called(8);
834
835     switch(what) {
836     case MOD_LOAD:
837	  iscsi_start();
838	  break;
839
840     case MOD_QUIESCE:
841	  if(isc->nsess) {
842	       xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess);
843	       log(LOG_ERR, "iscsi module busy, cannot unload");
844	  }
845	  return isc->nsess;
846
847     case MOD_SHUTDOWN:
848	  break;
849
850     case MOD_UNLOAD:
851	  iscsi_stop();
852	  break;
853
854     default:
855	  break;
856     }
857     return 0;
858}
859
860moduledata_t iscsi_mod = {
861         "iscsi_initiator",
862         (modeventhand_t) iscsi_modevent,
863         0
864};
865
866#ifdef ISCSI_ROOT
867static void
868iscsi_rootconf(void)
869{
870#if 0
871	nfs_setup_diskless();
872	if (nfs_diskless_valid)
873		rootdevnames[0] = "nfs:";
874#endif
875	printf("** iscsi_rootconf **\n");
876}
877
878SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL)
879#endif
880
881DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
882MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1);
883