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/isc_soc.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-2010 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: isc_soc.c 998 2009-12-20 10:32:45Z danny $
   31  */
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include "opt_iscsi_initiator.h"
   36 
   37 #include <sys/param.h>
   38 #include <sys/kernel.h>
   39 #include <sys/conf.h>
   40 #include <sys/systm.h>
   41 #include <sys/malloc.h>
   42 #include <sys/ctype.h>
   43 #include <sys/errno.h>
   44 #include <sys/sysctl.h>
   45 #include <sys/file.h>
   46 #include <sys/uio.h>
   47 #include <sys/socketvar.h>
   48 #include <sys/socket.h>
   49 #include <sys/protosw.h>
   50 #include <sys/proc.h>
   51 #include <sys/ioccom.h>
   52 #include <sys/queue.h>
   53 #include <sys/kthread.h>
   54 #include <sys/syslog.h>
   55 #include <sys/mbuf.h>
   56 #include <sys/user.h>
   57 #include <vm/uma.h>
   58 
   59 #include <cam/cam.h>
   60 #include <cam/cam_ccb.h>
   61 
   62 #include <dev/iscsi_initiator/iscsi.h>
   63 #include <dev/iscsi_initiator/iscsivar.h>
   64 
   65 #ifndef NO_USE_MBUF
   66 #define USE_MBUF
   67 #endif
   68 
   69 #ifdef USE_MBUF
   70 static int ou_refcnt = 0;
   71 /*
   72  | function for freeing external storage for mbuf
   73  */
   74 static void
   75 ext_free(struct mbuf *m)
   76 {
   77      pduq_t *pq = m->m_ext.ext_arg1;
   78 
   79      if(pq->buf != NULL) {
   80           debug(3, "ou_refcnt=%d a=%p b=%p",
   81                ou_refcnt, m->m_ext.ext_buf, pq->buf);
   82           free(pq->buf, M_ISCSIBUF);
   83           pq->buf = NULL;
   84      }
   85 }
   86 
   87 int
   88 isc_sendPDU(isc_session_t *sp, pduq_t *pq)
   89 {
   90      struct mbuf *mh, **mp;
   91      pdu_t      *pp = &pq->pdu;
   92      int        len, error;
   93 
   94      debug_called(8);
   95      /* 
   96       | mbuf for the iSCSI header
   97       */
   98      MGETHDR(mh, M_WAITOK, MT_DATA);
   99      mh->m_pkthdr.rcvif = NULL;
  100      mh->m_next = NULL;
  101      mh->m_len = sizeof(union ipdu_u);
  102 
  103      if(ISOK2DIG(sp->hdrDigest, pp)) {
  104           pp->hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
  105           mh->m_len += sizeof(pp->hdr_dig);
  106           if(pp->ahs_len) {
  107                debug(2, "ahs_len=%d", pp->ahs_len);
  108                pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig);
  109           }
  110           debug(3, "pp->hdr_dig=%04x", htonl(pp->hdr_dig));
  111      }
  112      if(pp->ahs_len) {
  113           /* 
  114            | Add any AHS to the iSCSI hdr mbuf
  115            */
  116           if((mh->m_len + pp->ahs_len) < MHLEN) {
  117                M_ALIGN(mh, mh->m_len + pp->ahs_len);
  118                bcopy(&pp->ipdu, mh->m_data, mh->m_len);
  119                bcopy(pp->ahs_addr, mh->m_data + mh->m_len, pp->ahs_len);
  120                mh->m_len += pp->ahs_len;
  121           }
  122           else
  123                panic("len AHS=%d too big, not impleneted yet", pp->ahs_len);
  124      }
  125      else {
  126           M_ALIGN(mh, mh->m_len);
  127           bcopy(&pp->ipdu, mh->m_data, mh->m_len);
  128      }
  129      mh->m_pkthdr.len = mh->m_len;
  130      mp = &mh->m_next;
  131      if(pp->ds_len && pq->pdu.ds_addr) {
  132           struct mbuf *md;
  133           int   off = 0;
  134 
  135           len = pp->ds_len;
  136           while(len > 0) {
  137                int l;
  138 
  139                MGET(md, M_WAITOK, MT_DATA);
  140                md->m_ext.ext_cnt = &ou_refcnt;
  141                l = min(MCLBYTES, len);
  142                debug(4, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l);
  143                m_extadd(md, pp->ds_addr + off, l, ext_free, pq, NULL, 0,
  144                     EXT_EXTREF);
  145                md->m_len = l;
  146                md->m_next = NULL;
  147                mh->m_pkthdr.len += l;
  148                *mp = md;
  149                mp = &md->m_next;
  150                len -= l;
  151                off += l;
  152           }
  153           if(((pp->ds_len & 03) != 0) || ISOK2DIG(sp->dataDigest, pp)) {
  154                MGET(md, M_WAITOK, MT_DATA);
  155                if(pp->ds_len & 03)
  156                     len = 4 - (pp->ds_len & 03);
  157                else
  158                     len = 0;
  159                md->m_len = len;
  160                if(ISOK2DIG(sp->dataDigest, pp))
  161                     md->m_len += sizeof(pp->ds_dig);
  162                M_ALIGN(md, md->m_len);
  163                if(ISOK2DIG(sp->dataDigest, pp)) {
  164                     pp->ds_dig = sp->dataDigest(pp->ds_addr, pp->ds_len, 0);
  165                     if(len) {
  166                          bzero(md->m_data, len); // RFC says SHOULD be 0
  167                          pp->ds_dig = sp->dataDigest(md->m_data, len, pp->ds_dig);
  168                     }
  169                     bcopy(&pp->ds_dig, md->m_data+len, sizeof(pp->ds_dig));
  170                }
  171                md->m_next = NULL;
  172                mh->m_pkthdr.len += md->m_len;
  173                *mp = md;
  174           }
  175      }
  176      if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, sp->td)) != 0) {
  177           sdebug(2, "error=%d", error);
  178           return error;
  179      }
  180      sp->stats.nsent++;
  181      getbintime(&sp->stats.t_sent);
  182      return 0;
  183 }
  184 #else /* NO_USE_MBUF */
  185 int
  186 isc_sendPDU(isc_session_t *sp, pduq_t *pq)
  187 {
  188      struct uio *uio = &pq->uio;
  189      struct iovec *iv;
  190      pdu_t      *pp = &pq->pdu;
  191      int        len, error;
  192 
  193      debug_called(8);
  194 
  195      bzero(uio, sizeof(struct uio));
  196      uio->uio_rw = UIO_WRITE;
  197      uio->uio_segflg = UIO_SYSSPACE;
  198      uio->uio_td = sp->td;
  199      uio->uio_iov = iv = pq->iov;
  200 
  201      iv->iov_base = &pp->ipdu;
  202      iv->iov_len = sizeof(union ipdu_u);
  203      uio->uio_resid = iv->iov_len;
  204      iv++;
  205      if(ISOK2DIG(sp->hdrDigest, pp))
  206           pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
  207      if(pp->ahs_len) {
  208           iv->iov_base = pp->ahs_addr;
  209           iv->iov_len = pp->ahs_len;
  210           uio->uio_resid += iv->iov_len;
  211           iv++;
  212           if(ISOK2DIG(sp->hdrDigest, pp))
  213                pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig);
  214      }
  215      if(ISOK2DIG(sp->hdrDigest, pp)) {
  216           debug(3, "hdr_dig=%04x", htonl(pp->hdr_dig));
  217           iv->iov_base = &pp->hdr_dig;
  218           iv->iov_len = sizeof(int);
  219           uio->uio_resid += iv->iov_len ;
  220           iv++;
  221      }
  222      if(pq->pdu.ds_addr &&  pp->ds_len) {
  223           iv->iov_base = pp->ds_addr;
  224           iv->iov_len = pp->ds_len;
  225           while(iv->iov_len & 03) // the specs say it must be int aligned
  226                iv->iov_len++;
  227           uio->uio_resid += iv->iov_len ;
  228           iv++;
  229           if(ISOK2DIG(sp->dataDigest, pp)) {
  230                pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0);
  231                iv->iov_base = &pp->ds_dig;
  232                iv->iov_len = sizeof(pp->ds_dig);
  233                uio->uio_resid += iv->iov_len ;
  234                iv++;
  235           }
  236      }
  237      uio->uio_iovcnt = iv - pq->iov;
  238      sdebug(4, "pq->len=%d uio->uio_resid=%d  uio->uio_iovcnt=%d", pq->len,
  239             uio->uio_resid,
  240             uio->uio_iovcnt);
  241 
  242      sdebug(4, "opcode=%x iovcnt=%d uio_resid=%d itt=%x",
  243             pp->ipdu.bhs.opcode, uio->uio_iovcnt, uio->uio_resid,
  244             ntohl(pp->ipdu.bhs.itt));
  245      sdebug(5, "sp=%p sp->soc=%p uio=%p sp->td=%p",
  246             sp, sp->soc, uio, sp->td);
  247      do {
  248           len = uio->uio_resid;
  249           error = sosend(sp->soc, NULL, uio, 0, 0, 0, sp->td);
  250           if(uio->uio_resid == 0 || error || len == uio->uio_resid) {
  251                if(uio->uio_resid) {
  252                     sdebug(2, "uio->uio_resid=%d uio->uio_iovcnt=%d error=%d len=%d",
  253                            uio->uio_resid, uio->uio_iovcnt, error, len);
  254                     if(error == 0)
  255                          error = EAGAIN; // 35
  256                }
  257                break;
  258           }
  259           /*
  260            | XXX: untested code
  261            */
  262           sdebug(1, "uio->uio_resid=%d uio->uio_iovcnt=%d",
  263                  uio->uio_resid, uio->uio_iovcnt);
  264           iv = uio->uio_iov;
  265           len -= uio->uio_resid;
  266           while(uio->uio_iovcnt > 0) {
  267                if(iv->iov_len > len) {
  268                     caddr_t bp = (caddr_t)iv->iov_base;
  269 
  270                     iv->iov_len -= len;
  271                     iv->iov_base = (void *)&bp[len];
  272                     break;
  273                }
  274                len -= iv->iov_len;
  275                uio->uio_iovcnt--;
  276                uio->uio_iov++;
  277                iv++;
  278           }
  279      } while(uio->uio_resid);
  280 
  281      if(error == 0) {
  282           sp->stats.nsent++;
  283           getbintime(&sp->stats.t_sent);
  284      }
  285 
  286      return error;
  287 }
  288 #endif /* USE_MBUF */
  289 
  290 /*
  291  | wait till a PDU header is received
  292  | from the socket.
  293  */
  294 /*
  295    The format of the BHS is:
  296 
  297    Byte/     0       |       1       |       2       |       3       |
  298       /              |               |               |               |
  299      |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
  300      +---------------+---------------+---------------+---------------+
  301     0|.|I| Opcode    |F|  Opcode-specific fields                     |
  302      +---------------+---------------+---------------+---------------+
  303     4|TotalAHSLength | DataSegmentLength                             |
  304      +---------------+---------------+---------------+---------------+
  305     8| LUN or Opcode-specific fields                                 |
  306      +                                                               +
  307    12|                                                               |
  308      +---------------+---------------+---------------+---------------+
  309    16| Initiator Task Tag                                            |
  310      +---------------+---------------+---------------+---------------+
  311    20/ Opcode-specific fields                                        /
  312     +/                                                               /
  313      +---------------+---------------+---------------+---------------+
  314    48
  315  */
  316 static __inline int
  317 so_getbhs(isc_session_t *sp)
  318 {
  319      bhs_t *bhs         = &sp->bhs;
  320      struct uio         *uio = &sp->uio;
  321      struct iovec       *iov = &sp->iov;
  322      int                error, flags;
  323 
  324      debug_called(8);
  325 
  326      iov->iov_base      = bhs;
  327      iov->iov_len       = sizeof(bhs_t);
  328 
  329      uio->uio_iov       = iov;
  330      uio->uio_iovcnt    = 1;
  331      uio->uio_rw        = UIO_READ;
  332      uio->uio_segflg    = UIO_SYSSPACE;
  333      uio->uio_td        = curthread; // why ...
  334      uio->uio_resid     = sizeof(bhs_t);
  335 
  336      flags = MSG_WAITALL;
  337      error = soreceive(sp->soc, NULL, uio, 0, 0, &flags);
  338 
  339      if(error)
  340           debug(2, 
  341 #if __FreeBSD_version > 800000
  342                 "error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd",
  343 #else
  344                 "error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd",
  345 #endif
  346                 error,
  347                 sp->soc->so_error, uio->uio_resid, iov->iov_len);
  348      if(!error && (uio->uio_resid > 0)) {
  349           error = EPIPE; // was EAGAIN
  350           debug(2,
  351 #if __FreeBSD_version > 800000
  352                 "error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd so_state=%x",
  353 #else
  354                 "error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd so_state=%x",
  355 #endif
  356                 error,
  357                 sp->soc->so_error, uio->uio_resid, iov->iov_len, sp->soc->so_state);
  358      }
  359      return error;
  360 }
  361 
  362 /*
  363  | so_recv gets called when 
  364  | an iSCSI header has been received.
  365  | Note: the designers had no intentions 
  366  |       in making programmer's life easy.
  367  */
  368 static int
  369 so_recv(isc_session_t *sp, pduq_t *pq)
  370 {
  371      sn_t               *sn = &sp->sn;
  372      struct uio         *uio = &pq->uio;
  373      pdu_t              *pp = &pq->pdu;
  374      bhs_t              *bhs = &pp->ipdu.bhs;
  375      struct iovec       *iov = pq->iov;
  376      int                error;
  377      u_int              len;
  378      u_int              max, exp;
  379      int                flags = MSG_WAITALL;
  380 
  381      debug_called(8);
  382      /*
  383       | now calculate how much data should be in the buffer
  384       */
  385      uio->uio_iov       = iov;
  386      uio->uio_iovcnt    = 0;
  387      len = 0;
  388      if(bhs->AHSLength) {
  389           debug(2, "bhs->AHSLength=%d", bhs->AHSLength);
  390           pp->ahs_len = bhs->AHSLength * 4;
  391           len += pp->ahs_len;
  392           pp->ahs_addr = malloc(pp->ahs_len, M_TEMP, M_WAITOK); // XXX: could get stuck here
  393           iov->iov_base = pp->ahs_addr;
  394           iov->iov_len = pp->ahs_len;
  395           uio->uio_iovcnt++;
  396           iov++;
  397      }
  398      if(ISOK2DIG(sp->hdrDigest, pp)) {
  399           len += sizeof(pp->hdr_dig);
  400           iov->iov_base = &pp->hdr_dig;
  401           iov->iov_len = sizeof(pp->hdr_dig);
  402           uio->uio_iovcnt++;
  403      }
  404      if(len) {
  405           uio->uio_rw           = UIO_READ;
  406           uio->uio_segflg       = UIO_SYSSPACE;
  407           uio->uio_resid        = len;
  408           uio->uio_td           = sp->td; // why ...
  409           error = soreceive(sp->soc, NULL, uio, NULL, NULL, &flags);
  410           //if(error == EAGAIN)
  411           // XXX: this needs work! it hangs iscontrol
  412           if(error || uio->uio_resid) {
  413                debug(2, 
  414 #if __FreeBSD_version > 800000
  415                      "len=%d error=%d uio->uio_resid=%zd",
  416 #else
  417                      "len=%d error=%d uio->uio_resid=%d",
  418 #endif
  419                      len, error, uio->uio_resid);
  420                goto out;
  421           }
  422           if(ISOK2DIG(sp->hdrDigest, pp)) {
  423                bhs_t    *bhs;
  424                u_int    digest;
  425                
  426                bhs = (bhs_t *)&pp->ipdu;
  427                digest = sp->hdrDigest(bhs, sizeof(bhs_t), 0);
  428                if(pp->ahs_len)
  429                     digest = sp->hdrDigest(pp->ahs_addr, pp->ahs_len, digest);
  430                if(pp->hdr_dig != digest) {
  431                     debug(2, "bad header digest: received=%x calculated=%x", pp->hdr_dig, digest);
  432                     // XXX: now what?
  433                     error = EIO;
  434                     goto out;
  435                }
  436           }
  437           if(pp->ahs_len) {
  438                debug(2, "ahs len=%x type=%x spec=%x",
  439                      pp->ahs_addr->len, pp->ahs_addr->type, pp->ahs_addr->spec);
  440                // XXX: till I figure out what to do with this
  441                free(pp->ahs_addr, M_TEMP);
  442           }
  443           pq->len += len; // XXX: who needs this?
  444           bzero(uio, sizeof(struct uio));
  445           len = 0;
  446      }
  447 
  448      if(bhs->DSLength) {
  449           len = bhs->DSLength;
  450 #if BYTE_ORDER == LITTLE_ENDIAN
  451           len = ((len & 0x00ff0000) >> 16)
  452                | (len & 0x0000ff00)
  453                | ((len & 0x000000ff) << 16);
  454 #endif
  455           pp->ds_len = len;
  456           if((sp->opt.maxRecvDataSegmentLength > 0) && (len > sp->opt.maxRecvDataSegmentLength)) {
  457                xdebug("impossible PDU length(%d) opt.maxRecvDataSegmentLength=%d",
  458                       len, sp->opt.maxRecvDataSegmentLength);
  459                log(LOG_ERR,
  460                    "so_recv: impossible PDU length(%d) from iSCSI %s/%s\n",
  461                    len, sp->opt.targetAddress, sp->opt.targetName);
  462                /*
  463                 | XXX: this will really screwup the stream.
  464                 | should clear up the buffer till a valid header
  465                 | is found, or just close connection ...
  466                 | should read the RFC.
  467                 */
  468                error = E2BIG;
  469                goto out;
  470           }
  471           while(len & 03)
  472                len++;
  473           if(ISOK2DIG(sp->dataDigest, pp))
  474                len += 4;
  475           uio->uio_resid = len;
  476           uio->uio_td = sp->td; // why ...
  477           pq->len += len; // XXX: do we need this?
  478           error = soreceive(sp->soc, NULL, uio, &pq->mp, NULL, &flags);
  479           //if(error == EAGAIN)
  480           // XXX: this needs work! it hangs iscontrol
  481           if(error || uio->uio_resid)
  482                goto out;
  483           if(ISOK2DIG(sp->dataDigest, pp)) {
  484                struct mbuf *m;
  485                u_int    digest, ds_len, cnt;
  486 
  487                // get the received digest
  488                m_copydata(pq->mp,
  489                           len - sizeof(pp->ds_dig),
  490                           sizeof(pp->ds_dig),
  491                           (caddr_t)&pp->ds_dig);
  492                // calculate all mbufs 
  493                digest = 0;
  494                ds_len = len - sizeof(pp->ds_dig);
  495                for(m = pq->mp; m != NULL; m = m->m_next) {
  496                     cnt = MIN(ds_len, m->m_len);
  497                     digest = sp->dataDigest(mtod(m, char *), cnt, digest);
  498                     ds_len -= cnt;
  499                     if(ds_len == 0)
  500                          break;
  501                }
  502                if(digest != pp->ds_dig) {
  503                     sdebug(1, "bad data digest: received=%x calculated=%x", pp->ds_dig, digest);
  504                     error = EIO; // XXX: find a better error
  505                     goto out;
  506                }
  507                KASSERT(ds_len == 0, ("ds_len not zero"));
  508           }
  509      }
  510      sdebug(6, "len=%d] opcode=0x%x ahs_len=0x%x ds_len=0x%x",
  511             pq->len, bhs->opcode, pp->ahs_len, pp->ds_len);
  512 
  513      max = ntohl(bhs->MaxCmdSN);
  514      exp = ntohl(bhs->ExpStSN);
  515      if(max < exp - 1 &&
  516         max > exp - _MAXINCR) {
  517           sdebug(2,  "bad cmd window size");
  518           error = EIO; // XXX: for now;
  519           goto out; // error
  520      }
  521      if(SNA_GT(max, sn->maxCmd))
  522           sn->maxCmd = max;
  523      if(SNA_GT(exp, sn->expCmd))
  524           sn->expCmd = exp;
  525      /*
  526       | remove from the holding queue packets
  527       | that have been acked and don't need
  528       | further processing.
  529       */
  530      i_acked_hld(sp, NULL);
  531 
  532      sp->cws = sn->maxCmd - sn->expCmd + 1;
  533 
  534      return 0;
  535 
  536  out:
  537      // XXX: need some work here
  538      if(pp->ahs_len) {
  539           // XXX: till I figure out what to do with this
  540           free(pp->ahs_addr, M_TEMP);
  541      }
  542      xdebug("have a problem, error=%d", error);
  543      pdu_free(sp->isc, pq);
  544      if(!error && uio->uio_resid > 0)
  545           error = EPIPE;
  546      return error;
  547 }
  548 
  549 /*
  550  | wait for something to arrive.
  551  | and if the pdu is without errors, process it.
  552  */
  553 static int
  554 so_input(isc_session_t *sp)
  555 {
  556      pduq_t             *pq;
  557      int                error;
  558 
  559      debug_called(8);
  560      /*
  561       | first read in the iSCSI header
  562       */
  563      error = so_getbhs(sp);
  564      if(error == 0) {
  565           /*
  566            | now read the rest.
  567            */
  568           pq = pdu_alloc(sp->isc, M_NOWAIT); 
  569           if(pq == NULL) { // XXX: might cause a deadlock ...
  570                debug(2, "out of pdus, wait");
  571                pq = pdu_alloc(sp->isc, M_WAITOK);  // OK to WAIT
  572           }
  573           pq->pdu.ipdu.bhs = sp->bhs;
  574           pq->len = sizeof(bhs_t);      // so far only the header was read
  575           error = so_recv(sp, pq);
  576           if(error != 0) {
  577                error += 0x800; // XXX: just to see the error.
  578                // terminal error
  579                // XXX: close connection and exit
  580           }
  581           else {
  582                sp->stats.nrecv++;
  583                getbintime(&sp->stats.t_recv);
  584                ism_recv(sp, pq);
  585           }
  586      }
  587      return error;
  588 }
  589 
  590 /*
  591  | one per active (connected) session.
  592  | this thread is responsible for reading
  593  | in packets from the target.
  594  */
  595 static void
  596 isc_in(void *vp)
  597 {
  598      isc_session_t      *sp = (isc_session_t *)vp;
  599      struct socket      *so = sp->soc;
  600      int                error;
  601 
  602      debug_called(8);
  603 
  604      sp->flags |= ISC_CON_RUNNING;
  605      error = 0;
  606      while((sp->flags & (ISC_CON_RUN | ISC_LINK_UP)) == (ISC_CON_RUN | ISC_LINK_UP)) {
  607           // XXX: hunting ...
  608           if(sp->soc == NULL || !(so->so_state & SS_ISCONNECTED)) {
  609                debug(2, "sp->soc=%p", sp->soc);
  610                break;
  611           }
  612           error = so_input(sp);
  613           if(error == 0) {
  614                mtx_lock(&sp->io_mtx);
  615                if(sp->flags & ISC_OWAITING) {
  616                     wakeup(&sp->flags);
  617                }
  618                mtx_unlock(&sp->io_mtx);
  619           } else if(error == EPIPE) {
  620                break;
  621           }
  622           else if(error == EAGAIN) {
  623                if(so->so_state & SS_ISCONNECTED) 
  624                     // there seems to be a problem in 6.0 ...
  625                     tsleep(sp, PRIBIO, "isc_soc", 2*hz);
  626           }
  627      }
  628      sdebug(2, "terminated, flags=%x so_count=%d so_state=%x error=%d proc=%p",
  629             sp->flags, so->so_count, so->so_state, error, sp->proc);
  630      if((sp->proc != NULL) && sp->signal) {
  631           PROC_LOCK(sp->proc);
  632           kern_psignal(sp->proc, sp->signal);
  633           PROC_UNLOCK(sp->proc);
  634           sp->flags |= ISC_SIGNALED;
  635           sdebug(2, "pid=%d signaled(%d)", sp->proc->p_pid, sp->signal);
  636      }
  637      else {
  638           // we have to do something ourselves
  639           // like closing this session ...
  640      }
  641      /*
  642       | we've been terminated
  643       */
  644      // do we need this mutex ...?
  645      mtx_lock(&sp->io_mtx);
  646      sp->flags &= ~(ISC_CON_RUNNING | ISC_LINK_UP);
  647      wakeup(&sp->soc);
  648      mtx_unlock(&sp->io_mtx);
  649 
  650      sdebug(2, "dropped ISC_CON_RUNNING");
  651 #if __FreeBSD_version >= 800000
  652      kproc_exit(0);
  653 #else
  654      kthread_exit(0);
  655 #endif
  656 }
  657 
  658 void
  659 isc_stop_receiver(isc_session_t *sp)
  660 {
  661      int        n;
  662 
  663      debug_called(8);
  664      sdebug(3, "sp=%p sp->soc=%p", sp, sp? sp->soc: 0);
  665      mtx_lock(&sp->io_mtx);
  666      sp->flags &= ~ISC_LINK_UP;
  667      msleep(&sp->soc, &sp->io_mtx, PRIBIO|PDROP, "isc_stpc", 5*hz);
  668 
  669      soshutdown(sp->soc, SHUT_RD);
  670 
  671      mtx_lock(&sp->io_mtx);
  672      sdebug(3, "soshutdown");
  673      sp->flags &= ~ISC_CON_RUN;
  674      n = 2;
  675      while(n-- && (sp->flags & ISC_CON_RUNNING)) {
  676           sdebug(3, "waiting n=%d... flags=%x", n, sp->flags);
  677           msleep(&sp->soc, &sp->io_mtx, PRIBIO, "isc_stpc", 5*hz);
  678      }
  679      mtx_unlock(&sp->io_mtx);
  680 
  681      if(sp->fp != NULL)
  682           fdrop(sp->fp, sp->td);
  683      sp->soc = NULL;
  684      sp->fp = NULL;
  685 
  686      sdebug(3, "done");
  687 }
  688 
  689 void
  690 isc_start_receiver(isc_session_t *sp)
  691 {
  692      debug_called(8);
  693 
  694      sp->flags |= ISC_CON_RUN | ISC_LINK_UP;
  695 #if __FreeBSD_version >= 800000
  696      kproc_create
  697 #else
  698      kthread_create
  699 #endif
  700           (isc_in, sp, &sp->soc_proc, 0, 0, "isc_in %d", sp->sid);
  701 }

Cache object: c682ac49d8e30a2ea0385c8790c5c766


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