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