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

Cache object: c91883fdc545d3922001a1b508e03ff4


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