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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2005-2011 Daniel Braniss <danny@cs.huji.ac.il>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  */
   29 /*
   30  | $Id: iscsi.c 752 2009-08-20 11:23:28Z danny $
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include "opt_iscsi_initiator.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/capsicum.h>
   40 #include <sys/kernel.h>
   41 #include <sys/module.h>
   42 #include <sys/conf.h>
   43 #include <sys/bus.h>
   44 #include <sys/systm.h>
   45 #include <sys/malloc.h>
   46 #include <sys/ctype.h>
   47 #include <sys/errno.h>
   48 #include <sys/sysctl.h>
   49 #include <sys/file.h>
   50 #include <sys/uio.h>
   51 #include <sys/socketvar.h>
   52 #include <sys/socket.h>
   53 #include <sys/protosw.h>
   54 #include <sys/proc.h>
   55 #include <sys/ioccom.h>
   56 #include <sys/queue.h>
   57 #include <sys/kthread.h>
   58 #include <sys/mbuf.h>
   59 #include <sys/syslog.h>
   60 #include <vm/uma.h>
   61 #include <sys/sx.h>
   62 
   63 #include <dev/iscsi_initiator/iscsi.h>
   64 #include <dev/iscsi_initiator/iscsivar.h>
   65 static char *iscsi_driver_version = "2.3.1";
   66 
   67 static struct isc_softc *isc;
   68 
   69 MALLOC_DEFINE(M_ISCSI, "iSCSI", "iSCSI driver");
   70 MALLOC_DEFINE(M_ISCSIBUF, "iSCbuf", "iSCSI buffers");
   71 static MALLOC_DEFINE(M_TMP, "iSCtmp", "iSCSI tmp");
   72 
   73 #ifdef ISCSI_INITIATOR_DEBUG
   74 int iscsi_debug = ISCSI_INITIATOR_DEBUG;
   75 SYSCTL_INT(_debug, OID_AUTO, iscsi_initiator, CTLFLAG_RW, &iscsi_debug, 0,
   76         "iSCSI driver debug flag");
   77 
   78 struct mtx iscsi_dbg_mtx;
   79 #endif
   80 
   81 static int max_sessions = MAX_SESSIONS;
   82 SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_sessions, CTLFLAG_RDTUN,
   83     &max_sessions, 0, "Max sessions allowed");
   84 static int max_pdus = MAX_PDUS;
   85 SYSCTL_INT(_net, OID_AUTO, iscsi_initiator_max_pdus, CTLFLAG_RDTUN,
   86     &max_pdus, 0, "Max PDU pool");
   87 
   88 static char isid[6+1] = {
   89      0x80,
   90      'D',
   91      'I',
   92      'B',
   93      '',
   94      '',
   95      0
   96 };
   97 
   98 static int      i_create_session(struct cdev *dev, int *ndev);
   99 
  100 static int      i_ping(struct cdev *dev);
  101 static int      i_send(struct cdev *dev, caddr_t arg, struct thread *td);
  102 static int      i_recv(struct cdev *dev, caddr_t arg, struct thread *td);
  103 static int      i_setsoc(isc_session_t *sp, int fd, struct thread *td);
  104 static int      i_fullfeature(struct cdev *dev, int flag);
  105 
  106 static d_open_t iscsi_open;
  107 static d_close_t iscsi_close;
  108 static d_ioctl_t iscsi_ioctl;
  109 #ifdef ISCSI_INITIATOR_DEBUG
  110 static d_read_t iscsi_read;
  111 #endif
  112 
  113 static struct cdevsw iscsi_cdevsw = {
  114      .d_version = D_VERSION,
  115      .d_open    = iscsi_open,
  116      .d_close   = iscsi_close,
  117      .d_ioctl   = iscsi_ioctl,
  118 #ifdef ISCSI_INITIATOR_DEBUG
  119      .d_read    = iscsi_read,
  120 #endif
  121      .d_name    = "iSCSI",
  122 };
  123 
  124 static int
  125 iscsi_open(struct cdev *dev, int flags, int otype, struct thread *td)
  126 {
  127      debug_called(8);
  128 
  129      debug(7, "dev=%d", dev2unit(dev));
  130 
  131      if(dev2unit(dev) > max_sessions) {
  132           // should not happen
  133           return ENODEV;
  134      }
  135      return 0;
  136 }
  137 
  138 static int
  139 iscsi_close(struct cdev *dev, int flag, int otyp, struct thread *td)
  140 {
  141      isc_session_t      *sp;
  142 
  143      debug_called(8);
  144 
  145      debug(3, "session=%d flag=%x", dev2unit(dev), flag);
  146 
  147      if(dev2unit(dev) == max_sessions) {
  148           return 0;
  149      }
  150      sp = dev->si_drv2;
  151      if(sp != NULL) {
  152           sdebug(3, "sp->flags=%x", sp->flags );
  153           /*
  154            | if still in full phase, this probably means
  155            | that something went really bad.
  156            | it could be a result from 'shutdown', in which case
  157            | we will ignore it (so buffers can be flushed).
  158            | the problem is that there is no way of differentiating
  159            | between a shutdown procedure and 'iscontrol' dying.
  160            */
  161           if(sp->flags & ISC_FFPHASE)
  162                // delay in case this is a shutdown.
  163                tsleep(sp, PRIBIO, "isc-cls", 60*hz);
  164           ism_stop(sp);
  165      }
  166      debug(2, "done");
  167      return 0;
  168 }
  169 
  170 static int
  171 iscsi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
  172 {
  173      struct isc_softc   *sc;
  174      isc_session_t      *sp;
  175      isc_opt_t          *opt;
  176      int                error;
  177 
  178      debug_called(8);
  179 
  180      error = 0;
  181      if(dev2unit(dev) == max_sessions) {
  182           /*
  183            | non Session commands
  184            */
  185           sc = dev->si_drv1;
  186           if(sc == NULL)
  187                return ENXIO;
  188 
  189           switch(cmd) {
  190           case ISCSISETSES:
  191                error = i_create_session(dev, (int *)arg);
  192                if(error == 0)
  193                     break;
  194 
  195           default:
  196                error = ENXIO;
  197           }
  198           return error;
  199      }
  200      /*
  201       | session commands
  202       */
  203      sp = dev->si_drv2;
  204      if(sp == NULL)
  205           return ENXIO;
  206 
  207      sdebug(6, "dev=%d cmd=%d", dev2unit(dev), (int)(cmd & 0xff));
  208 
  209      switch(cmd) {
  210      case ISCSISETSOC:
  211           error = i_setsoc(sp, *(u_int *)arg, td);
  212           break;
  213 
  214      case ISCSISETOPT:
  215           opt = (isc_opt_t *)arg;
  216           error = i_setopt(sp, opt);
  217           break;
  218 
  219      case ISCSISEND:
  220           error = i_send(dev, arg, td);
  221           break;
  222 
  223      case ISCSIRECV:
  224           error = i_recv(dev, arg, td);
  225           break;
  226 
  227      case ISCSIPING:
  228           error = i_ping(dev);
  229           break;
  230 
  231      case ISCSISTART:
  232           error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 1);
  233           if(error == 0) {
  234                sp->proc = td->td_proc;
  235                SYSCTL_ADD_INT(&sp->clist, SYSCTL_CHILDREN(sp->oid),
  236                                OID_AUTO, "pid", CTLFLAG_RD,
  237                                &sp->proc->p_pid, sizeof(pid_t), "control process id");
  238           }
  239           break;
  240 
  241      case ISCSIRESTART:
  242           error = sp->soc == NULL? ENOTCONN: i_fullfeature(dev, 2);
  243           break;
  244 
  245      case ISCSISTOP:
  246           error = i_fullfeature(dev, 0);
  247           break;
  248           
  249      case ISCSISIGNAL: {
  250           int sig = *(int *)arg;
  251 
  252           if(sig < 0 || sig > _SIG_MAXSIG)
  253                error = EINVAL;
  254           else
  255                 sp->signal = sig;
  256           break;
  257      }
  258 
  259      case ISCSIGETCAM: {
  260           iscsi_cam_t *cp = (iscsi_cam_t *)arg;
  261 
  262           error = ic_getCamVals(sp, cp);
  263           break;
  264      }
  265 
  266      default:
  267           error = ENOIOCTL;
  268      }
  269 
  270      return error;
  271 }
  272 
  273 static int
  274 iscsi_read(struct cdev *dev, struct uio *uio, int ioflag)
  275 {
  276 #ifdef  ISCSI_INITIATOR_DEBUG
  277      struct isc_softc   *sc;
  278      isc_session_t      *sp;
  279      pduq_t             *pq;
  280      char               buf[1024];
  281 
  282      sc = dev->si_drv1;
  283      sp = dev->si_drv2;
  284      if(dev2unit(dev) == max_sessions) {
  285           sprintf(buf, "/----- Session ------/\n");
  286           uiomove(buf, strlen(buf), uio);
  287           int   i = 0;
  288 
  289           TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) {
  290                if(uio->uio_resid == 0)
  291                     return 0;
  292                sprintf(buf, "%03d] '%s' '%s'\n", i++, sp->opt.targetAddress, sp->opt.targetName);
  293                uiomove(buf, strlen(buf), uio);
  294           }
  295           sprintf(buf, "free npdu_alloc=%d, npdu_max=%d\n", sc->npdu_alloc, sc->npdu_max);
  296           uiomove(buf, strlen(buf), uio);
  297      }
  298      else {
  299           int   i = 0;
  300           struct socket *so = sp->soc;
  301 #define pukeit(i, pq) do {\
  302                sprintf(buf, "%03d] %06x %02x %06x %06x %jd\n",\
  303                        i, ntohl(pq->pdu.ipdu.bhs.CmdSN),\
  304                        pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\
  305                        ntohl(pq->pdu.ipdu.bhs.ExpStSN),\
  306                        (intmax_t)pq->ts.sec);\
  307                } while(0)
  308 
  309           sprintf(buf, "%d/%d /---- hld -----/\n", sp->stats.nhld, sp->stats.max_hld);
  310           uiomove(buf, strlen(buf), uio);
  311           TAILQ_FOREACH(pq, &sp->hld, pq_link) {
  312                if(uio->uio_resid == 0)
  313                     return 0;
  314                pukeit(i, pq); i++;
  315                uiomove(buf, strlen(buf), uio);
  316           }
  317           sprintf(buf, "%d/%d /---- rsp -----/\n", sp->stats.nrsp, sp->stats.max_rsp);
  318           uiomove(buf, strlen(buf), uio);
  319           i = 0;
  320           TAILQ_FOREACH(pq, &sp->rsp, pq_link) {
  321                if(uio->uio_resid == 0)
  322                     return 0;
  323                pukeit(i, pq); i++;
  324                uiomove(buf, strlen(buf), uio);
  325           }
  326           sprintf(buf, "%d/%d /---- csnd -----/\n", sp->stats.ncsnd, sp->stats.max_csnd);
  327           i = 0;
  328           uiomove(buf, strlen(buf), uio);
  329           TAILQ_FOREACH(pq, &sp->csnd, pq_link) {
  330                if(uio->uio_resid == 0)
  331                     return 0;
  332                pukeit(i, pq); i++;
  333                uiomove(buf, strlen(buf), uio);
  334           }
  335           sprintf(buf, "%d/%d /---- wsnd -----/\n", sp->stats.nwsnd, sp->stats.max_wsnd);
  336           i = 0;
  337           uiomove(buf, strlen(buf), uio);
  338           TAILQ_FOREACH(pq, &sp->wsnd, pq_link) {
  339                if(uio->uio_resid == 0)
  340                     return 0;
  341                pukeit(i, pq); i++;
  342                uiomove(buf, strlen(buf), uio);
  343           }
  344           sprintf(buf, "%d/%d /---- isnd -----/\n", sp->stats.nisnd, sp->stats.max_isnd);
  345           i = 0;
  346           uiomove(buf, strlen(buf), uio);
  347           TAILQ_FOREACH(pq, &sp->isnd, pq_link) {
  348                if(uio->uio_resid == 0)
  349                     return 0;
  350                pukeit(i, pq); i++;
  351                uiomove(buf, strlen(buf), uio);
  352           }
  353 
  354           sprintf(buf, "/---- Stats ---/\n");
  355           uiomove(buf, strlen(buf), uio);
  356 
  357           sprintf(buf, "recv=%d sent=%d\n", sp->stats.nrecv, sp->stats.nsent);
  358           uiomove(buf, strlen(buf), uio);
  359 
  360           sprintf(buf, "flags=%x pdus: alloc=%d max=%d\n", 
  361                   sp->flags, sc->npdu_alloc, sc->npdu_max);
  362           uiomove(buf, strlen(buf), uio);
  363 
  364           sprintf(buf, "cws=%d last cmd=%x exp=%x max=%x stat=%x itt=%x\n",
  365                   sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt);
  366           uiomove(buf, strlen(buf), uio);
  367 
  368           sprintf(buf, "/---- socket -----/\nso_count=%d so_state=%x\n", so->so_count, so->so_state);
  369           uiomove(buf, strlen(buf), uio);
  370 
  371      }
  372 #endif
  373      return 0;
  374 }
  375 
  376 static int
  377 i_ping(struct cdev *dev)
  378 {
  379      return 0;
  380 }
  381 /*
  382  | low level I/O
  383  */
  384 static int
  385 i_setsoc(isc_session_t *sp, int fd, struct thread *td)
  386 {
  387      cap_rights_t rights;
  388      int error = 0;
  389 
  390      if(sp->soc != NULL)
  391           isc_stop_receiver(sp);
  392 
  393      error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_SOCK_CLIENT),
  394              &sp->fp, NULL, NULL);
  395      if(error)
  396           return error;
  397 
  398      sp->soc = sp->fp->f_data;
  399      sp->td = td;
  400      isc_start_receiver(sp);
  401 
  402      return error;
  403 }
  404 
  405 static int
  406 i_send(struct cdev *dev, caddr_t arg, struct thread *td)
  407 {
  408      isc_session_t      *sp = dev->si_drv2;
  409      caddr_t            bp;
  410      pduq_t             *pq;
  411      pdu_t              *pp;
  412      int                n, error;
  413 
  414      debug_called(8);
  415 
  416      if(sp->soc == NULL)
  417           return ENOTCONN;
  418 
  419      if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL)
  420           return EAGAIN;
  421      pp = &pq->pdu;
  422      pq->pdu = *(pdu_t *)arg;
  423      if((error = i_prepPDU(sp, pq)) != 0)
  424           goto out;
  425 
  426      bp = NULL;
  427      if((pq->len - sizeof(union ipdu_u)) > 0) {
  428           pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSIBUF, M_NOWAIT);
  429           if(pq->buf == NULL) {
  430                error = EAGAIN;
  431                goto out;
  432           }
  433      }
  434      else
  435           pq->buf = NULL; // just in case?
  436 
  437      sdebug(2, "len=%d ahs_len=%d ds_len=%d buf=%zu@%p",
  438             pq->len, pp->ahs_len, pp->ds_len, pq->len - sizeof(union ipdu_u), bp);
  439 
  440      if(pp->ahs_len) {
  441           // XXX: never tested, looks suspicious
  442           n = pp->ahs_len;
  443           error = copyin(pp->ahs_addr, bp, n);
  444           if(error != 0) {
  445                sdebug(3, "copyin ahs: error=%d", error);
  446                goto out;
  447           }
  448           pp->ahs_addr = (ahs_t *)bp;
  449           bp += n;
  450      }
  451      if(pp->ds_len) {
  452           n = pp->ds_len;
  453           error = copyin(pp->ds_addr, bp, n);
  454           if(error != 0) {
  455                sdebug(3, "copyin ds: error=%d", error);
  456                goto out;
  457           }
  458           pp->ds_addr = bp;
  459           bp += n;
  460           while(n & 03) {
  461                n++;
  462                *bp++ = 0;
  463           }
  464      }
  465 
  466      error = isc_qout(sp, pq);
  467      if(error == 0)
  468           wakeup(&sp->flags); // XXX: to 'push' proc_out ...
  469 out:
  470      if(error)
  471           pdu_free(sp->isc, pq);
  472 
  473      return error;
  474 }
  475 
  476 static int
  477 i_recv(struct cdev *dev, caddr_t arg, struct thread *td)
  478 {
  479      isc_session_t      *sp = dev->si_drv2;
  480      pduq_t             *pq;
  481      pdu_t              *pp, *up;
  482      caddr_t            bp;
  483      int                error, mustfree, cnt;
  484      size_t             need, have, n;
  485 
  486      debug_called(8);
  487 
  488      if(sp == NULL)
  489           return EIO;
  490 
  491      if(sp->soc == NULL)
  492           return ENOTCONN;
  493      cnt = 6;     // XXX: maybe the user can request a time out?
  494      mtx_lock(&sp->rsp_mtx);
  495      while((pq = TAILQ_FIRST(&sp->rsp)) == NULL) {
  496           msleep(&sp->rsp, &sp->rsp_mtx, PRIBIO, "isc_rsp", hz*10);
  497           if(cnt-- == 0) break; // XXX: for now, needs work
  498      }
  499      if(pq != NULL) {
  500           sp->stats.nrsp--;
  501           TAILQ_REMOVE(&sp->rsp, pq, pq_link);
  502      }
  503      mtx_unlock(&sp->rsp_mtx);
  504 
  505      sdebug(6, "cnt=%d", cnt);
  506 
  507      if(pq == NULL) {
  508           error = ENOTCONN;
  509           sdebug(3, "error=%d sp->flags=%x ", error, sp->flags);
  510           return error;
  511      }
  512      up = (pdu_t *)arg;
  513      pp = &pq->pdu;
  514      up->ipdu = pp->ipdu;
  515      n = 0;
  516      up->ds_len = 0;
  517      up->ahs_len = 0;
  518      error = 0;
  519 
  520      if(pq->mp) {
  521           u_int len;
  522 
  523           // Grr...
  524           len = 0;
  525           if(pp->ahs_len) {
  526                len += pp->ahs_len;
  527           }
  528           if(pp->ds_len) {
  529                len += pp->ds_len;
  530           }
  531 
  532           mustfree = 0;
  533           if(len > pq->mp->m_len) {
  534                mustfree++;
  535                bp = malloc(len, M_TMP, M_WAITOK);
  536                sdebug(4, "need mbufcopy: %d", len);
  537                i_mbufcopy(pq->mp, bp, len);
  538           } 
  539           else
  540                bp = mtod(pq->mp, caddr_t);
  541 
  542           if(pp->ahs_len) {
  543                need = pp->ahs_len;
  544                n = MIN(up->ahs_size, need);
  545                error = copyout(bp, (caddr_t)up->ahs_addr, n);
  546                up->ahs_len = n;
  547                bp += need;
  548           }
  549           if(!error && pp->ds_len) {
  550                need = pp->ds_len;
  551                if((have = up->ds_size) == 0) {
  552                     have = up->ahs_size - n;
  553                     up->ds_addr = (caddr_t)up->ahs_addr + n;
  554                }
  555                n = MIN(have, need);
  556                error = copyout(bp, (caddr_t)up->ds_addr, n);
  557                up->ds_len = n;
  558           }
  559 
  560           if(mustfree)
  561                free(bp, M_TMP);
  562      }
  563 
  564      sdebug(6, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len);
  565 
  566      pdu_free(sp->isc, pq);
  567 
  568      return error;
  569 }
  570 
  571 static int
  572 i_fullfeature(struct cdev *dev, int flag)
  573 {
  574      isc_session_t      *sp = dev->si_drv2;
  575      int                error;
  576 
  577      sdebug(2, "flag=%d", flag);
  578 
  579      error = 0;
  580      switch(flag) {
  581      case 0: // stop
  582          sp->flags &= ~ISC_FFPHASE;
  583          break;
  584      case 1: // start
  585          sp->flags |= ISC_FFPHASE;
  586          error = ic_init(sp);
  587          break;
  588      case 2: // restart
  589          sp->flags |= ISC_FFPHASE;
  590          ism_restart(sp);
  591          break;
  592      }
  593      return error;
  594 }
  595 
  596 static int
  597 i_create_session(struct cdev *dev, int *ndev)
  598 { 
  599      struct isc_softc   *sc = dev->si_drv1;
  600      isc_session_t      *sp;
  601      int                error, n;
  602 
  603      debug_called(8);
  604 
  605      sp = malloc(sizeof(isc_session_t), M_ISCSI, M_WAITOK | M_ZERO);
  606      if(sp == NULL)
  607           return ENOMEM;
  608 
  609      sx_xlock(&sc->unit_sx);
  610      if((n = alloc_unr(sc->unit)) < 0) {
  611           sx_unlock(&sc->unit_sx);
  612           free(sp, M_ISCSI);
  613           xdebug("too many sessions!");
  614           return EPERM;
  615      }
  616      sx_unlock(&sc->unit_sx);
  617 
  618      mtx_lock(&sc->isc_mtx);
  619      TAILQ_INSERT_TAIL(&sc->isc_sess, sp, sp_link);
  620      isc->nsess++;
  621      mtx_unlock(&sc->isc_mtx);
  622 
  623      sp->dev = make_dev(&iscsi_cdevsw, n, UID_ROOT, GID_WHEEL, 0600, "iscsi%d", n);
  624      *ndev = sp->sid = n;
  625      sp->isc = sc;
  626      sp->dev->si_drv1 = sc;
  627      sp->dev->si_drv2 = sp;
  628 
  629      sp->opt.maxRecvDataSegmentLength = 8192;
  630      sp->opt.maxXmitDataSegmentLength = 8192;
  631      sp->opt.maxBurstLength = 65536;    // 64k
  632      sp->opt.maxluns = ISCSI_MAX_LUNS;
  633 
  634      error = ism_start(sp);
  635 
  636      return error;
  637 }
  638 
  639 #ifdef notused
  640 static void
  641 iscsi_counters(isc_session_t *sp)
  642 {
  643      int        h, r, s;
  644      pduq_t     *pq;
  645 
  646 #define _puke(i, pq) do {\
  647                debug(2, "%03d] %06x %02x %x %ld %jd %x\n",\
  648                        i, ntohl( pq->pdu.ipdu.bhs.CmdSN), \
  649                        pq->pdu.ipdu.bhs.opcode, ntohl(pq->pdu.ipdu.bhs.itt),\
  650                        (long)pq->ts.sec, pq->ts.frac, pq->flags);\
  651                } while(0)
  652 
  653      h = r = s = 0; 
  654      TAILQ_FOREACH(pq, &sp->hld, pq_link) {
  655           _puke(h, pq);
  656           h++;
  657      }
  658      TAILQ_FOREACH(pq, &sp->rsp, pq_link) r++;
  659      TAILQ_FOREACH(pq, &sp->csnd, pq_link) s++;
  660      TAILQ_FOREACH(pq, &sp->wsnd, pq_link) s++;
  661      TAILQ_FOREACH(pq, &sp->isnd, pq_link) s++;
  662      debug(2, "hld=%d rsp=%d snd=%d", h, r, s);
  663 }
  664 #endif
  665 
  666 static void
  667 iscsi_shutdown(void *v)
  668 {
  669      struct isc_softc   *sc = v;
  670      isc_session_t      *sp;
  671      int        n;
  672 
  673      debug_called(8);
  674      if(sc == NULL) {
  675           xdebug("sc is NULL!");
  676           return;
  677      }
  678 #ifdef DO_EVENTHANDLER
  679      if(sc->eh == NULL)
  680           debug(2, "sc->eh is NULL");
  681      else {
  682           EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->eh);
  683           debug(2, "done n=%d", sc->nsess);
  684      }
  685 #endif
  686      n = 0;
  687      TAILQ_FOREACH(sp, &sc->isc_sess, sp_link) {
  688           debug(2, "%2d] sp->flags=0x%08x", n, sp->flags);
  689           n++;
  690      }
  691      debug(2, "done");
  692 }
  693 
  694 static void
  695 free_pdus(struct isc_softc *sc)
  696 {
  697      debug_called(8);
  698 
  699      if(sc->pdu_zone != NULL) {
  700           uma_zdestroy(sc->pdu_zone);
  701           sc->pdu_zone = NULL;
  702      }
  703 }
  704 
  705 static int
  706 iscsi_start(void)
  707 {
  708      debug_called(8);
  709 
  710      isc =  malloc(sizeof(struct isc_softc), M_ISCSI, M_ZERO|M_WAITOK);
  711      mtx_init(&isc->isc_mtx, "iscsi-isc", NULL, MTX_DEF);
  712 
  713      TAILQ_INIT(&isc->isc_sess);
  714      /*
  715       | now init the free pdu list
  716       */
  717      isc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t),
  718                                  NULL, NULL, NULL, NULL,
  719                                  0, 0);
  720      uma_zone_set_max(isc->pdu_zone, max_pdus);
  721      isc->unit = new_unrhdr(0, max_sessions-1, NULL);
  722      sx_init(&isc->unit_sx, "iscsi sx");
  723 
  724 #ifdef DO_EVENTHANDLER
  725      if((isc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown,
  726                                         sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL)
  727           xdebug("shutdown event registration failed\n");
  728 #endif
  729      /*
  730       | sysctl stuff
  731       */
  732      sysctl_ctx_init(&isc->clist);
  733      isc->oid = SYSCTL_ADD_NODE(&isc->clist,
  734                                SYSCTL_STATIC_CHILDREN(_net),
  735                                OID_AUTO,
  736                                "iscsi_initiator",
  737                                CTLFLAG_RD,
  738                                0,
  739                                "iSCSI Subsystem");
  740 
  741      SYSCTL_ADD_STRING(&isc->clist,
  742                        SYSCTL_CHILDREN(isc->oid),
  743                        OID_AUTO,
  744                        "driver_version",
  745                        CTLFLAG_RD,
  746                        iscsi_driver_version,
  747                        0,
  748                        "iscsi driver version");
  749  
  750      SYSCTL_ADD_STRING(&isc->clist,
  751                        SYSCTL_CHILDREN(isc->oid),
  752                        OID_AUTO,
  753                        "isid",
  754                        CTLFLAG_RW,
  755                        isid,
  756                        6+1,
  757                        "initiator part of the Session Identifier");
  758 
  759      SYSCTL_ADD_INT(&isc->clist,
  760                     SYSCTL_CHILDREN(isc->oid),
  761                     OID_AUTO,
  762                     "sessions",
  763                     CTLFLAG_RD,
  764                     &isc->nsess,
  765                     sizeof(isc->nsess),
  766                     "number of active session");
  767 
  768 #ifdef ISCSI_INITIATOR_DEBUG
  769      mtx_init(&iscsi_dbg_mtx, "iscsi_dbg", NULL, MTX_DEF);
  770 #endif
  771 
  772      isc->dev = make_dev_credf(MAKEDEV_CHECKNAME, &iscsi_cdevsw, max_sessions,
  773                                NULL, UID_ROOT, GID_WHEEL, 0600, "iscsi");
  774      if (isc->dev == NULL) {
  775           xdebug("iscsi_initiator: make_dev_credf failed");
  776           return (EEXIST);
  777      }
  778      isc->dev->si_drv1 = isc;
  779 
  780      printf("iscsi: version %s\n", iscsi_driver_version);
  781      return (0);
  782 }
  783 
  784 /*
  785  | Notes:
  786  |      unload SHOULD fail if there is activity
  787  |      activity: there is/are active session/s
  788  */
  789 static void
  790 iscsi_stop(void)
  791 {
  792      isc_session_t      *sp, *sp_tmp;
  793 
  794      debug_called(8);
  795 
  796      /*
  797       | go through all the sessions
  798       | Note: close should have done this ...
  799       */
  800      TAILQ_FOREACH_SAFE(sp, &isc->isc_sess, sp_link, sp_tmp) {
  801           //XXX: check for activity ...
  802           ism_stop(sp);
  803      }
  804      mtx_destroy(&isc->isc_mtx);
  805      sx_destroy(&isc->unit_sx);
  806 
  807      free_pdus(isc);
  808 
  809      if(isc->dev)
  810           destroy_dev(isc->dev);
  811 
  812      if(sysctl_ctx_free(&isc->clist))
  813           xdebug("sysctl_ctx_free failed");
  814 
  815      iscsi_shutdown(isc); // XXX: check EVENTHANDLER_ ...
  816 
  817 #ifdef ISCSI_INITIATOR_DEBUG
  818      mtx_destroy(&iscsi_dbg_mtx);
  819 #endif
  820 
  821      free(isc, M_ISCSI);
  822 }
  823 
  824 static int
  825 iscsi_modevent(module_t mod, int what, void *arg)
  826 {
  827      int error = 0;
  828 
  829      debug_called(8);
  830 
  831      switch(what) {
  832      case MOD_LOAD:
  833           error = iscsi_start();
  834           break;
  835 
  836      case MOD_QUIESCE:
  837           if(isc->nsess) {
  838                xdebug("iscsi module busy(nsess=%d), cannot unload", isc->nsess);
  839                log(LOG_ERR, "iscsi module busy, cannot unload");
  840           }
  841           return isc->nsess;
  842 
  843      case MOD_SHUTDOWN:
  844           break;
  845 
  846      case MOD_UNLOAD:
  847           iscsi_stop();
  848           break;
  849 
  850      default:
  851           break;
  852      }
  853      return (error);
  854 }
  855 
  856 moduledata_t iscsi_mod = {
  857          "iscsi_initiator",
  858          (modeventhand_t) iscsi_modevent,
  859          0
  860 };
  861 
  862 #ifdef ISCSI_ROOT
  863 static void
  864 iscsi_rootconf(void)
  865 {
  866 #if 0
  867         nfs_setup_diskless();
  868         if (nfs_diskless_valid)
  869                 rootdevnames[0] = "nfs:";
  870 #endif
  871         printf("** iscsi_rootconf **\n");
  872 }
  873 
  874 SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL)
  875 #endif
  876 
  877 DECLARE_MODULE(iscsi_initiator, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
  878 MODULE_DEPEND(iscsi_initiator, cam, 1, 1, 1);

Cache object: efbe749d3f5c4f4c73b42c61d320c2b4


[ 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.