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