The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/iscsi_initiator/iscsi.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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: releng/10.0/sys/dev/iscsi_initiator/iscsi.c 255855 2013-09-24 17:01:29Z 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>
   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, &max_sessions, MAX_SESSIONS,
   81            "Max sessions allowed");
   82 static int max_pdus = MAX_PDUS;
   83 SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN, &max_pdus, MAX_PDUS,
   84            "Max pdu pool");
   85 
   86 static char isid[6+1] = {
   87      0x80,
   88      'D',
   89      'I',
   90      'B',
   91      '',
   92      '',
   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
  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
  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
  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
  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
  375 i_ping(struct cdev *dev)
  376 {
  377      return 0;
  378 }
  379 /*
  380  | low level I/O
  381  */
  382 static int
  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
  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
  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
  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
  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
  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
  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
  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
  710 iscsi_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      mtx_init(&isc->isc_mtx, "iscsi-isc", NULL, MTX_DEF);
  719 
  720      TAILQ_INIT(&isc->isc_sess);
  721      /*
  722       | now init the free pdu list
  723       */
  724      isc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t),
  725                                  NULL, NULL, NULL, NULL,
  726                                  0, 0);
  727      uma_zone_set_max(isc->pdu_zone, max_pdus);
  728      isc->unit = new_unrhdr(0, max_sessions-1, NULL);
  729      sx_init(&isc->unit_sx, "iscsi sx");
  730 
  731 #ifdef DO_EVENTHANDLER
  732      if((isc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown,
  733                                         sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL)
  734           xdebug("shutdown event registration failed\n");
  735 #endif
  736      /*
  737       | sysctl stuff
  738       */
  739      sysctl_ctx_init(&isc->clist);
  740      isc->oid = SYSCTL_ADD_NODE(&isc->clist,
  741                                SYSCTL_STATIC_CHILDREN(_net),
  742                                OID_AUTO,
  743                                "iscsi_initiator",
  744                                CTLFLAG_RD,
  745                                0,
  746                                "iSCSI Subsystem");
  747 
  748      SYSCTL_ADD_STRING(&isc->clist,
  749                        SYSCTL_CHILDREN(isc->oid),
  750                        OID_AUTO,
  751                        "driver_version",
  752                        CTLFLAG_RD,
  753                        iscsi_driver_version,
  754                        0,
  755                        "iscsi driver version");
  756  
  757      SYSCTL_ADD_STRING(&isc->clist,
  758                        SYSCTL_CHILDREN(isc->oid),
  759                        OID_AUTO,
  760                        "isid",
  761                        CTLFLAG_RW,
  762                        isid,
  763                        6+1,
  764                        "initiator part of the Session Identifier");
  765 
  766      SYSCTL_ADD_INT(&isc->clist,
  767                     SYSCTL_CHILDREN(isc->oid),
  768                     OID_AUTO,
  769                     "sessions",
  770                     CTLFLAG_RD,
  771                     &isc->nsess,
  772                     sizeof(isc->nsess),
  773                     "number of active session");
  774 
  775 #ifdef ISCSI_INITIATOR_DEBUG
  776      mtx_init(&iscsi_dbg_mtx, "iscsi_dbg", NULL, MTX_DEF);
  777 #endif
  778 
  779      isc->dev = make_dev_credf(MAKEDEV_CHECKNAME, &iscsi_cdevsw, max_sessions,
  780                                NULL, UID_ROOT, GID_WHEEL, 0600, "iscsi");
  781      if (isc->dev == NULL) {
  782           xdebug("iscsi_initiator: make_dev_credf failed");
  783           return (EEXIST);
  784      }
  785      isc->dev->si_drv1 = isc;
  786 
  787      printf("iscsi: version %s\n", iscsi_driver_version);
  788      return (0);
  789 }
  790 
  791 /*
  792  | Notes:
  793  |      unload SHOULD fail if there is activity
  794  |      activity: there is/are active session/s
  795  */
  796 static void
  797 iscsi_stop(void)
  798 {
  799      isc_session_t      *sp, *sp_tmp;
  800 
  801      debug_called(8);
  802 
  803      /*
  804       | go through all the sessions
  805       | Note: close should have done this ...
  806       */
  807      TAILQ_FOREACH_SAFE(sp, &isc->isc_sess, sp_link, sp_tmp) {
  808           //XXX: check for activity ...
  809           ism_stop(sp);
  810           if(sp->cam_sim != NULL)
  811                ic_destroy(sp);
  812      }
  813      mtx_destroy(&isc->isc_mtx);
  814      sx_destroy(&isc->unit_sx);
  815 
  816      free_pdus(isc);
  817 
  818      if(isc->dev)
  819           destroy_dev(isc->dev);
  820 
  821      if(sysctl_ctx_free(&isc->clist))
  822           xdebug("sysctl_ctx_free failed");
  823 
  824      iscsi_shutdown(isc); // XXX: check EVENTHANDLER_ ...
  825 
  826 #ifdef ISCSI_INITIATOR_DEBUG
  827      mtx_destroy(&iscsi_dbg_mtx);
  828 #endif
  829 
  830      free(isc, M_ISCSI);
  831 }
  832 
  833 static int
  834 iscsi_modevent(module_t mod, int what, void *arg)
  835 {
  836      int error = 0;
  837 
  838      debug_called(8);
  839 
  840      switch(what) {
  841      case MOD_LOAD:
  842           error = iscsi_start();
  843           break;
  844 
  845      case MOD_QUIESCE:
  846           if(isc->nsess) {
  847                xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess);
  848                log(LOG_ERR, "iscsi module busy, cannot unload");
  849           }
  850           return isc->nsess;
  851 
  852      case MOD_SHUTDOWN:
  853           break;
  854 
  855      case MOD_UNLOAD:
  856           iscsi_stop();
  857           break;
  858 
  859      default:
  860           break;
  861      }
  862      return (error);
  863 }
  864 
  865 moduledata_t iscsi_mod = {
  866          "iscsi_initiator",
  867          (modeventhand_t) iscsi_modevent,
  868          0
  869 };
  870 
  871 #ifdef ISCSI_ROOT
  872 static void
  873 iscsi_rootconf(void)
  874 {
  875 #if 0
  876         nfs_setup_diskless();
  877         if (nfs_diskless_valid)
  878                 rootdevnames[0] = "nfs:";
  879 #endif
  880         printf("** iscsi_rootconf **\n");
  881 }
  882 
  883 SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL)
  884 #endif
  885 
  886 DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
  887 MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1);

Cache object: f97aefd6e8123fc5370500e52c36c7e5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.