xref: /freebsd-11-stable/sys/dev/iscsi_initiator/iscsi.c (revision 4ab2e064d7950be84256d671a7ae93f87cc6aa36)
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$");
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>
63 static char *iscsi_driver_version = "2.3.1";
64 
65 static struct isc_softc *isc;
66 
67 MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI driver");
68 MALLOC_DEFINE(M_ISCSIBUF, "iSCbuf", "iSCSI buffers");
69 static MALLOC_DEFINE(M_TMP, "iSCtmp", "iSCSI tmp");
70 
71 #ifdef ISCSI_INITIATOR_DEBUG
72 int iscsi_debug = ISCSI_INITIATOR_DEBUG;
73 SYSCTL_INT(_debug, OID_AUTO, iscsi_initiator, CTLFLAG_RW, &iscsi_debug, 0,
74 	"iSCSI driver debug flag");
75 
76 struct mtx iscsi_dbg_mtx;
77 #endif
78 
79 static int max_sessions = MAX_SESSIONS;
80 SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_sessions, CTLFLAG_RDTUN,
81     &max_sessions, 0, "Max sessions allowed");
82 static int max_pdus = MAX_PDUS;
83 SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN,
84     &max_pdus, 0, "Max PDU pool");
85 
86 static char isid[6+1] = {
87      0x80,
88      'D',
89      'I',
90      'B',
91      '0',
92      '0',
93      0
94 };
95 
96 static int	i_create_session(struct cdev *dev, int *ndev);
97 
98 static int	i_ping(struct cdev *dev);
99 static int	i_send(struct cdev *dev, caddr_t arg, struct thread *td);
100 static int	i_recv(struct cdev *dev, caddr_t arg, struct thread *td);
101 static int	i_setsoc(isc_session_t *sp, int fd, struct thread *td);
102 static int	i_fullfeature(struct cdev *dev, int flag);
103 
104 static d_open_t iscsi_open;
105 static d_close_t iscsi_close;
106 static d_ioctl_t iscsi_ioctl;
107 #ifdef ISCSI_INITIATOR_DEBUG
108 static d_read_t iscsi_read;
109 #endif
110 
111 static 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 
122 static int
iscsi_open(struct cdev * dev,int flags,int otype,struct thread * td)123 iscsi_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 
136 static int
iscsi_close(struct cdev * dev,int flag,int otyp,struct thread * td)137 iscsi_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 
168 static int
iscsi_ioctl(struct cdev * dev,u_long cmd,caddr_t arg,int mode,struct thread * td)169 iscsi_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 
271 static int
iscsi_read(struct cdev * dev,struct uio * uio,int ioflag)272 iscsi_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 
374 static int
i_ping(struct cdev * dev)375 i_ping(struct cdev *dev)
376 {
377      return 0;
378 }
379 /*
380  | low level I/O
381  */
382 static int
i_setsoc(isc_session_t * sp,int fd,struct thread * td)383 i_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 
403 static int
i_send(struct cdev * dev,caddr_t arg,struct thread * td)404 i_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 ...
467 out:
468      if(error)
469 	  pdu_free(sp->isc, pq);
470 
471      return error;
472 }
473 
474 static int
i_recv(struct cdev * dev,caddr_t arg,struct thread * td)475 i_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 
569 static int
i_fullfeature(struct cdev * dev,int flag)570 i_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 
594 static int
i_create_session(struct cdev * dev,int * ndev)595 i_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
638 static void
iscsi_counters(isc_session_t * sp)639 iscsi_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 
664 static void
iscsi_shutdown(void * v)665 iscsi_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 
692 static void
free_pdus(struct isc_softc * sc)693 free_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 
703 static int
iscsi_start(void)704 iscsi_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  */
787 static void
iscsi_stop(void)788 iscsi_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 
822 static int
iscsi_modevent(module_t mod,int what,void * arg)823 iscsi_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 
854 moduledata_t iscsi_mod = {
855          "iscsi_initiator",
856          (modeventhand_t) iscsi_modevent,
857          0
858 };
859 
860 #ifdef ISCSI_ROOT
861 static void
iscsi_rootconf(void)862 iscsi_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 
872 SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL)
873 #endif
874 
875 DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
876 MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1);
877