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