xref: /NextBSD/sys/dev/iscsi_initiator/iscsi.c (revision e5d2f8730c92c4abb6de986ec4e1f39a242b9868)
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 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 
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 = 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 
409 static int
i_send(struct cdev * dev,caddr_t arg,struct thread * td)410 i_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 ...
473 out:
474      if(error)
475 	  pdu_free(sp->isc, pq);
476 
477      return error;
478 }
479 
480 static int
i_recv(struct cdev * dev,caddr_t arg,struct thread * td)481 i_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 
575 static int
i_fullfeature(struct cdev * dev,int flag)576 i_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 
600 static int
i_create_session(struct cdev * dev,int * ndev)601 i_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
644 static void
iscsi_counters(isc_session_t * sp)645 iscsi_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 
670 static void
iscsi_shutdown(void * v)671 iscsi_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 
698 static void
free_pdus(struct isc_softc * sc)699 free_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 
709 static int
iscsi_start(void)710 iscsi_start(void)
711 {
712      debug_called(8);
713 
714      isc =  malloc(sizeof(struct isc_softc), M_ISCSI, M_ZERO|M_WAITOK);
715      mtx_init(&isc->isc_mtx, "iscsi-isc", NULL, MTX_DEF);
716 
717      TAILQ_INIT(&isc->isc_sess);
718      /*
719       | now init the free pdu list
720       */
721      isc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t),
722 				 NULL, NULL, NULL, NULL,
723 				 0, 0);
724      uma_zone_set_max(isc->pdu_zone, max_pdus);
725      isc->unit = new_unrhdr(0, max_sessions-1, NULL);
726      sx_init(&isc->unit_sx, "iscsi sx");
727 
728 #ifdef DO_EVENTHANDLER
729      if((isc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown,
730 					sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL)
731 	  xdebug("shutdown event registration failed\n");
732 #endif
733      /*
734       | sysctl stuff
735       */
736      sysctl_ctx_init(&isc->clist);
737      isc->oid = SYSCTL_ADD_NODE(&isc->clist,
738 			       SYSCTL_STATIC_CHILDREN(_net),
739 			       OID_AUTO,
740 			       "iscsi_initiator",
741 			       CTLFLAG_RD,
742 			       0,
743 			       "iSCSI Subsystem");
744 
745      SYSCTL_ADD_STRING(&isc->clist,
746 		       SYSCTL_CHILDREN(isc->oid),
747 		       OID_AUTO,
748 		       "driver_version",
749 		       CTLFLAG_RD,
750 		       iscsi_driver_version,
751 		       0,
752 		       "iscsi driver version");
753 
754      SYSCTL_ADD_STRING(&isc->clist,
755 		       SYSCTL_CHILDREN(isc->oid),
756 		       OID_AUTO,
757 		       "isid",
758 		       CTLFLAG_RW,
759 		       isid,
760 		       6+1,
761 		       "initiator part of the Session Identifier");
762 
763      SYSCTL_ADD_INT(&isc->clist,
764 		    SYSCTL_CHILDREN(isc->oid),
765 		    OID_AUTO,
766 		    "sessions",
767 		    CTLFLAG_RD,
768 		    &isc->nsess,
769 		    sizeof(isc->nsess),
770 		    "number of active session");
771 
772 #ifdef ISCSI_INITIATOR_DEBUG
773      mtx_init(&iscsi_dbg_mtx, "iscsi_dbg", NULL, MTX_DEF);
774 #endif
775 
776      isc->dev = make_dev_credf(MAKEDEV_CHECKNAME, &iscsi_cdevsw, max_sessions,
777 			       NULL, UID_ROOT, GID_WHEEL, 0600, "iscsi");
778      if (isc->dev == NULL) {
779 	  xdebug("iscsi_initiator: make_dev_credf failed");
780 	  return (EEXIST);
781      }
782      isc->dev->si_drv1 = isc;
783 
784      printf("iscsi: version %s\n", iscsi_driver_version);
785      return (0);
786 }
787 
788 /*
789  | Notes:
790  |	unload SHOULD fail if there is activity
791  |	activity: there is/are active session/s
792  */
793 static void
iscsi_stop(void)794 iscsi_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 
830 static int
iscsi_modevent(module_t mod,int what,void * arg)831 iscsi_modevent(module_t mod, int what, void *arg)
832 {
833      int error = 0;
834 
835      debug_called(8);
836 
837      switch(what) {
838      case MOD_LOAD:
839 	  error = iscsi_start();
840 	  break;
841 
842      case MOD_QUIESCE:
843 	  if(isc->nsess) {
844 	       xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess);
845 	       log(LOG_ERR, "iscsi module busy, cannot unload");
846 	  }
847 	  return isc->nsess;
848 
849      case MOD_SHUTDOWN:
850 	  break;
851 
852      case MOD_UNLOAD:
853 	  iscsi_stop();
854 	  break;
855 
856      default:
857 	  break;
858      }
859      return (error);
860 }
861 
862 moduledata_t iscsi_mod = {
863          "iscsi_initiator",
864          (modeventhand_t) iscsi_modevent,
865          0
866 };
867 
868 #ifdef ISCSI_ROOT
869 static void
iscsi_rootconf(void)870 iscsi_rootconf(void)
871 {
872 #if 0
873 	nfs_setup_diskless();
874 	if (nfs_diskless_valid)
875 		rootdevnames[0] = "nfs:";
876 #endif
877 	printf("** iscsi_rootconf **\n");
878 }
879 
880 SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL)
881 #endif
882 
883 DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
884 MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1);
885