1171568Sscottl/*-
2211095Sdes * Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
3171568Sscottl * All rights reserved.
4171568Sscottl *
5171568Sscottl * Redistribution and use in source and binary forms, with or without
6171568Sscottl * modification, are permitted provided that the following conditions
7171568Sscottl * are met:
8171568Sscottl * 1. Redistributions of source code must retain the above copyright
9171568Sscottl *    notice, this list of conditions and the following disclaimer.
10171568Sscottl * 2. Redistributions in binary form must reproduce the above copyright
11171568Sscottl *    notice, this list of conditions and the following disclaimer in the
12171568Sscottl *    documentation and/or other materials provided with the distribution.
13171568Sscottl *
14171568Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15171568Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16171568Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17171568Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18171568Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19171568Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20171568Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21171568Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22171568Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23171568Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24171568Sscottl * SUCH DAMAGE.
25171568Sscottl *
26171568Sscottl */
27171568Sscottl/*
28211095Sdes | $Id: isc_soc.c 998 2009-12-20 10:32:45Z danny $
29171568Sscottl */
30171568Sscottl#include <sys/cdefs.h>
31171568Sscottl__FBSDID("$FreeBSD$");
32171568Sscottl
33171568Sscottl#include "opt_iscsi_initiator.h"
34171568Sscottl
35171568Sscottl#include <sys/param.h>
36171568Sscottl#include <sys/kernel.h>
37171568Sscottl#include <sys/conf.h>
38171568Sscottl#include <sys/systm.h>
39171568Sscottl#include <sys/malloc.h>
40171568Sscottl#include <sys/ctype.h>
41171568Sscottl#include <sys/errno.h>
42171568Sscottl#include <sys/sysctl.h>
43171568Sscottl#include <sys/file.h>
44171568Sscottl#include <sys/uio.h>
45171568Sscottl#include <sys/socketvar.h>
46171568Sscottl#include <sys/socket.h>
47171568Sscottl#include <sys/protosw.h>
48171568Sscottl#include <sys/proc.h>
49171568Sscottl#include <sys/ioccom.h>
50171568Sscottl#include <sys/queue.h>
51171568Sscottl#include <sys/kthread.h>
52171568Sscottl#include <sys/syslog.h>
53171568Sscottl#include <sys/mbuf.h>
54171568Sscottl#include <sys/user.h>
55171568Sscottl
56185289Sscottl#include <cam/cam.h>
57185289Sscottl#include <cam/cam_ccb.h>
58185289Sscottl
59171568Sscottl#include <dev/iscsi/initiator/iscsi.h>
60171568Sscottl#include <dev/iscsi/initiator/iscsivar.h>
61171568Sscottl
62185289Sscottl#ifndef NO_USE_MBUF
63171568Sscottl#define USE_MBUF
64171568Sscottl#endif
65171568Sscottl
66171568Sscottl#ifdef USE_MBUF
67185289Sscottlstatic int ou_refcnt = 0;
68171568Sscottl/*
69185289Sscottl | function for freeing external storage for mbuf
70171568Sscottl */
71171568Sscottlstatic void
72185289Sscottlext_free(void *a, void *b)
73171568Sscottl{
74185289Sscottl     pduq_t *pq = b;
75185289Sscottl
76185289Sscottl     if(pq->buf != NULL) {
77185289Sscottl	  debug(3, "ou_refcnt=%d a=%p b=%p", ou_refcnt, a, pq->buf);
78211095Sdes	  free(pq->buf, M_ISCSIBUF);
79185289Sscottl	  pq->buf = NULL;
80185289Sscottl     }
81171568Sscottl}
82171568Sscottl
83171568Sscottlint
84171568Sscottlisc_sendPDU(isc_session_t *sp, pduq_t *pq)
85171568Sscottl{
86185289Sscottl     struct mbuf *mh, **mp;
87211095Sdes     pdu_t	*pp = &pq->pdu;
88211095Sdes     int	len, error;
89171568Sscottl
90171568Sscottl     debug_called(8);
91185289Sscottl     /*
92185289Sscottl      | mbuf for the iSCSI header
93185289Sscottl      */
94185289Sscottl     MGETHDR(mh, M_TRYWAIT, MT_DATA);
95171568Sscottl     mh->m_pkthdr.rcvif = NULL;
96171568Sscottl     mh->m_next = NULL;
97211095Sdes     mh->m_len = sizeof(union ipdu_u);
98171568Sscottl
99211095Sdes     if(ISOK2DIG(sp->hdrDigest, pp)) {
100211095Sdes	  pp->hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
101211095Sdes	  mh->m_len += sizeof(pp->hdr_dig);
102211095Sdes	  if(pp->ahs_len) {
103211095Sdes	       debug(2, "ahs_len=%d", pp->ahs_len);
104211095Sdes	       pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig);
105211095Sdes	  }
106211095Sdes	  debug(3, "pp->hdr_dig=%04x", htonl(pp->hdr_dig));
107211095Sdes     }
108171568Sscottl     if(pp->ahs_len) {
109185289Sscottl          /*
110185289Sscottl	   | Add any AHS to the iSCSI hdr mbuf
111185289Sscottl	   */
112211095Sdes	  if((mh->m_len + pp->ahs_len) < MHLEN) {
113211095Sdes	       MH_ALIGN(mh, mh->m_len + pp->ahs_len);
114211095Sdes	       bcopy(&pp->ipdu, mh->m_data, mh->m_len);
115211095Sdes	       bcopy(pp->ahs_addr, mh->m_data + mh->m_len, pp->ahs_len);
116211095Sdes	       mh->m_len += pp->ahs_len;
117211095Sdes	  }
118211095Sdes	  else
119211095Sdes	       panic("len AHS=%d too big, not impleneted yet", pp->ahs_len);
120171568Sscottl     }
121211095Sdes     else {
122211095Sdes	  MH_ALIGN(mh, mh->m_len);
123211095Sdes	  bcopy(&pp->ipdu, mh->m_data, mh->m_len);
124171568Sscottl     }
125211095Sdes     mh->m_pkthdr.len = mh->m_len;
126171568Sscottl     mp = &mh->m_next;
127211095Sdes     if(pp->ds_len && pq->pdu.ds_addr) {
128211095Sdes          struct mbuf *md;
129211095Sdes          int	off = 0;
130171568Sscottl
131171568Sscottl          len = pp->ds_len;
132185289Sscottl          while(len > 0) {
133211095Sdes	       int l;
134211095Sdes
135185289Sscottl	       MGET(md, M_TRYWAIT, MT_DATA);
136185289Sscottl	       md->m_ext.ref_cnt = &ou_refcnt;
137211095Sdes	       l = min(MCLBYTES, len);
138211095Sdes	       debug(4, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l);
139211095Sdes	       MEXTADD(md, pp->ds_addr + off, l, ext_free,
140211095Sdes#if __FreeBSD_version >= 800000
141211095Sdes		       pp->ds_addr + off,
142211095Sdes#endif
143211095Sdes		       pq, 0, EXT_EXTREF);
144211095Sdes	       md->m_len = l;
145211095Sdes	       md->m_next = NULL;
146211095Sdes	       mh->m_pkthdr.len += l;
147211095Sdes	       *mp = md;
148211095Sdes	       mp = &md->m_next;
149211095Sdes	       len -= l;
150211095Sdes	       off += l;
151211095Sdes          }
152211095Sdes	  if(((pp->ds_len & 03) != 0) || ISOK2DIG(sp->dataDigest, pp)) {
153211095Sdes	       MGET(md, M_TRYWAIT, MT_DATA);
154211095Sdes	       if(pp->ds_len & 03)
155211095Sdes		    len = 4 - (pp->ds_len & 03);
156211095Sdes	       else
157211095Sdes		    len = 0;
158211095Sdes	       md->m_len = len;
159211095Sdes	       if(ISOK2DIG(sp->dataDigest, pp))
160211095Sdes		    md->m_len += sizeof(pp->ds_dig);
161211095Sdes	       M_ALIGN(md, md->m_len);
162211095Sdes	       if(ISOK2DIG(sp->dataDigest, pp)) {
163211095Sdes		    pp->ds_dig = sp->dataDigest(pp->ds_addr, pp->ds_len, 0);
164211095Sdes		    if(len) {
165211095Sdes			 bzero(md->m_data, len); // RFC says SHOULD be 0
166211095Sdes			 pp->ds_dig = sp->dataDigest(md->m_data, len, pp->ds_dig);
167211095Sdes		    }
168211095Sdes		    bcopy(&pp->ds_dig, md->m_data+len, sizeof(pp->ds_dig));
169211095Sdes	       }
170211095Sdes	       md->m_next = NULL;
171211095Sdes	       mh->m_pkthdr.len += md->m_len;
172211095Sdes	       *mp = md;
173211095Sdes	  }
174171568Sscottl     }
175185289Sscottl     if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, sp->td)) != 0) {
176211095Sdes	  sdebug(2, "error=%d", error);
177185289Sscottl	  return error;
178185289Sscottl     }
179185289Sscottl     sp->stats.nsent++;
180185289Sscottl     getbintime(&sp->stats.t_sent);
181185289Sscottl     return 0;
182185289Sscottl}
183185289Sscottl#else /* NO_USE_MBUF */
184185289Sscottlint
185185289Sscottlisc_sendPDU(isc_session_t *sp, pduq_t *pq)
186185289Sscottl{
187185289Sscottl     struct uio *uio = &pq->uio;
188185289Sscottl     struct iovec *iv;
189185289Sscottl     pdu_t	*pp = &pq->pdu;
190185289Sscottl     int	len, error;
191171568Sscottl
192185289Sscottl     debug_called(8);
193185289Sscottl
194185289Sscottl     bzero(uio, sizeof(struct uio));
195185289Sscottl     uio->uio_rw = UIO_WRITE;
196185289Sscottl     uio->uio_segflg = UIO_SYSSPACE;
197185289Sscottl     uio->uio_td = sp->td;
198185289Sscottl     uio->uio_iov = iv = pq->iov;
199185289Sscottl
200185289Sscottl     iv->iov_base = &pp->ipdu;
201185289Sscottl     iv->iov_len = sizeof(union ipdu_u);
202211095Sdes     uio->uio_resid = iv->iov_len;
203185289Sscottl     iv++;
204211095Sdes     if(ISOK2DIG(sp->hdrDigest, pp))
205185289Sscottl	  pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
206185289Sscottl     if(pp->ahs_len) {
207211095Sdes	  iv->iov_base = pp->ahs_addr;
208185289Sscottl	  iv->iov_len = pp->ahs_len;
209211095Sdes	  uio->uio_resid += iv->iov_len;
210185289Sscottl	  iv++;
211211095Sdes	  if(ISOK2DIG(sp->hdrDigest, pp))
212211095Sdes	       pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig);
213185289Sscottl     }
214211095Sdes     if(ISOK2DIG(sp->hdrDigest, pp)) {
215211095Sdes	  debug(3, "hdr_dig=%04x", htonl(pp->hdr_dig));
216185289Sscottl	  iv->iov_base = &pp->hdr_dig;
217185289Sscottl	  iv->iov_len = sizeof(int);
218211095Sdes	  uio->uio_resid += iv->iov_len ;
219185289Sscottl	  iv++;
220185289Sscottl     }
221211095Sdes     if(pq->pdu.ds_addr &&  pp->ds_len) {
222211095Sdes	  iv->iov_base = pp->ds_addr;
223185289Sscottl	  iv->iov_len = pp->ds_len;
224185289Sscottl	  while(iv->iov_len & 03) // the specs say it must be int alligned
225185289Sscottl	       iv->iov_len++;
226211095Sdes	  uio->uio_resid += iv->iov_len ;
227185289Sscottl	  iv++;
228211095Sdes	  if(ISOK2DIG(sp->dataDigest, pp)) {
229211095Sdes	       pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0);
230211095Sdes	       iv->iov_base = &pp->ds_dig;
231211095Sdes	       iv->iov_len = sizeof(pp->ds_dig);
232211095Sdes	       uio->uio_resid += iv->iov_len ;
233211095Sdes	       iv++;
234211095Sdes	  }
235185289Sscottl     }
236211095Sdes     uio->uio_iovcnt = iv - pq->iov;
237211095Sdes     sdebug(4, "pq->len=%d uio->uio_resid=%d  uio->uio_iovcnt=%d", pq->len,
238211095Sdes	    uio->uio_resid,
239211095Sdes	    uio->uio_iovcnt);
240211095Sdes
241211095Sdes     sdebug(4, "opcode=%x iovcnt=%d uio_resid=%d itt=%x",
242171568Sscottl	    pp->ipdu.bhs.opcode, uio->uio_iovcnt, uio->uio_resid,
243171568Sscottl	    ntohl(pp->ipdu.bhs.itt));
244171568Sscottl     sdebug(5, "sp=%p sp->soc=%p uio=%p sp->td=%p",
245171568Sscottl	    sp, sp->soc, uio, sp->td);
246171568Sscottl     do {
247171568Sscottl	  len = uio->uio_resid;
248171568Sscottl	  error = sosend(sp->soc, NULL, uio, 0, 0, 0, sp->td);
249171568Sscottl	  if(uio->uio_resid == 0 || error || len == uio->uio_resid) {
250171568Sscottl	       if(uio->uio_resid) {
251171568Sscottl		    sdebug(2, "uio->uio_resid=%d uio->uio_iovcnt=%d error=%d len=%d",
252171568Sscottl			   uio->uio_resid, uio->uio_iovcnt, error, len);
253171568Sscottl		    if(error == 0)
254171568Sscottl			 error = EAGAIN; // 35
255171568Sscottl	       }
256171568Sscottl	       break;
257171568Sscottl	  }
258171568Sscottl	  /*
259171568Sscottl	   | XXX: untested code
260171568Sscottl	   */
261171568Sscottl	  sdebug(1, "uio->uio_resid=%d uio->uio_iovcnt=%d",
262211095Sdes		 uio->uio_resid, uio->uio_iovcnt);
263171568Sscottl	  iv = uio->uio_iov;
264171568Sscottl	  len -= uio->uio_resid;
265171568Sscottl	  while(uio->uio_iovcnt > 0) {
266171568Sscottl	       if(iv->iov_len > len) {
267211095Sdes		    caddr_t bp = (caddr_t)iv->iov_base;
268171568Sscottl
269171568Sscottl		    iv->iov_len -= len;
270171568Sscottl		    iv->iov_base = (void *)&bp[len];
271171568Sscottl		    break;
272171568Sscottl	       }
273171568Sscottl	       len -= iv->iov_len;
274171568Sscottl	       uio->uio_iovcnt--;
275171568Sscottl	       uio->uio_iov++;
276171568Sscottl	       iv++;
277171568Sscottl	  }
278171568Sscottl     } while(uio->uio_resid);
279171568Sscottl
280171568Sscottl     if(error == 0) {
281171568Sscottl	  sp->stats.nsent++;
282171568Sscottl	  getbintime(&sp->stats.t_sent);
283171568Sscottl     }
284185289Sscottl
285171568Sscottl     return error;
286185289Sscottl}
287171568Sscottl#endif /* USE_MBUF */
288171568Sscottl
289171568Sscottl/*
290171568Sscottl | wait till a PDU header is received
291171568Sscottl | from the socket.
292171568Sscottl */
293171568Sscottl/*
294171568Sscottl   The format of the BHS is:
295171568Sscottl
296171568Sscottl   Byte/     0       |       1       |       2       |       3       |
297171568Sscottl      /              |               |               |               |
298171568Sscottl     |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|
299171568Sscottl     +---------------+---------------+---------------+---------------+
300171568Sscottl    0|.|I| Opcode    |F|  Opcode-specific fields                     |
301171568Sscottl     +---------------+---------------+---------------+---------------+
302171568Sscottl    4|TotalAHSLength | DataSegmentLength                             |
303171568Sscottl     +---------------+---------------+---------------+---------------+
304171568Sscottl    8| LUN or Opcode-specific fields                                 |
305171568Sscottl     +                                                               +
306171568Sscottl   12|                                                               |
307171568Sscottl     +---------------+---------------+---------------+---------------+
308171568Sscottl   16| Initiator Task Tag                                            |
309171568Sscottl     +---------------+---------------+---------------+---------------+
310171568Sscottl   20/ Opcode-specific fields                                        /
311171568Sscottl    +/                                                               /
312171568Sscottl     +---------------+---------------+---------------+---------------+
313171568Sscottl   48
314171568Sscottl */
315171568Sscottlstatic __inline int
316171568Sscottlso_getbhs(isc_session_t *sp)
317171568Sscottl{
318171568Sscottl     bhs_t *bhs		= &sp->bhs;
319171568Sscottl     struct uio		*uio = &sp->uio;
320171568Sscottl     struct iovec	*iov = &sp->iov;
321171568Sscottl     int		error, flags;
322171568Sscottl
323171568Sscottl     debug_called(8);
324171568Sscottl
325171568Sscottl     iov->iov_base	= bhs;
326171568Sscottl     iov->iov_len	= sizeof(bhs_t);
327171568Sscottl
328171568Sscottl     uio->uio_iov	= iov;
329171568Sscottl     uio->uio_iovcnt	= 1;
330171568Sscottl     uio->uio_rw	= UIO_READ;
331171568Sscottl     uio->uio_segflg	= UIO_SYSSPACE;
332171568Sscottl     uio->uio_td	= curthread; // why ...
333171568Sscottl     uio->uio_resid	= sizeof(bhs_t);
334171568Sscottl
335171568Sscottl     flags = MSG_WAITALL;
336171568Sscottl     error = soreceive(sp->soc, NULL, uio, 0, 0, &flags);
337171568Sscottl
338171568Sscottl     if(error)
339211095Sdes	  debug(2,
340211095Sdes#if __FreeBSD_version > 800000
341211095Sdes		"error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd",
342211095Sdes#else
343211095Sdes		"error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd",
344211095Sdes#endif
345171568Sscottl		error,
346171568Sscottl		sp->soc->so_error, uio->uio_resid, iov->iov_len);
347171568Sscottl     if(!error && (uio->uio_resid > 0)) {
348185289Sscottl	  error = EPIPE; // was EAGAIN
349211095Sdes	  debug(2,
350211095Sdes#if __FreeBSD_version > 800000
351211095Sdes		"error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd so_state=%x",
352211095Sdes#else
353211095Sdes		"error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd so_state=%x",
354211095Sdes#endif
355171568Sscottl		error,
356171568Sscottl		sp->soc->so_error, uio->uio_resid, iov->iov_len, sp->soc->so_state);
357171568Sscottl     }
358171568Sscottl     return error;
359171568Sscottl}
360171568Sscottl
361171568Sscottl/*
362211095Sdes | so_recv gets called when
363211095Sdes | an iSCSI header has been received.
364211095Sdes | Note: the designers had no intentions
365211095Sdes |       in making programmer's life easy.
366171568Sscottl */
367171568Sscottlstatic int
368171568Sscottlso_recv(isc_session_t *sp, pduq_t *pq)
369171568Sscottl{
370171568Sscottl     sn_t		*sn = &sp->sn;
371171568Sscottl     struct uio		*uio = &pq->uio;
372211095Sdes     pdu_t		*pp = &pq->pdu;
373211095Sdes     bhs_t		*bhs = &pp->ipdu.bhs;
374211095Sdes     struct iovec	*iov = pq->iov;
375171568Sscottl     int		error;
376211095Sdes     u_int		len;
377171568Sscottl     u_int		max, exp;
378211095Sdes     int		flags = MSG_WAITALL;
379171568Sscottl
380171568Sscottl     debug_called(8);
381171568Sscottl     /*
382171568Sscottl      | now calculate how much data should be in the buffer
383171568Sscottl      */
384211095Sdes     uio->uio_iov	= iov;
385211095Sdes     uio->uio_iovcnt	= 0;
386171568Sscottl     len = 0;
387171568Sscottl     if(bhs->AHSLength) {
388211095Sdes	  debug(2, "bhs->AHSLength=%d", bhs->AHSLength);
389171568Sscottl	  pp->ahs_len = bhs->AHSLength * 4;
390171568Sscottl	  len += pp->ahs_len;
391211095Sdes	  pp->ahs_addr = malloc(pp->ahs_len, M_TEMP, M_WAITOK); // XXX: could get stuck here
392211095Sdes	  iov->iov_base = pp->ahs_addr;
393211095Sdes	  iov->iov_len = pp->ahs_len;
394211095Sdes	  uio->uio_iovcnt++;
395211095Sdes	  iov++;
396171568Sscottl     }
397211095Sdes     if(ISOK2DIG(sp->hdrDigest, pp)) {
398211095Sdes	  len += sizeof(pp->hdr_dig);
399211095Sdes	  iov->iov_base = &pp->hdr_dig;
400211095Sdes	  iov->iov_len = sizeof(pp->hdr_dig);
401211095Sdes	  uio->uio_iovcnt++;
402211095Sdes     }
403211095Sdes     if(len) {
404211095Sdes	  uio->uio_rw		= UIO_READ;
405211095Sdes	  uio->uio_segflg	= UIO_SYSSPACE;
406211095Sdes	  uio->uio_resid	= len;
407211095Sdes	  uio->uio_td		= sp->td; // why ...
408211095Sdes	  error = soreceive(sp->soc, NULL, uio, NULL, NULL, &flags);
409211095Sdes	  //if(error == EAGAIN)
410211095Sdes	  // XXX: this needs work! it hangs iscontrol
411211095Sdes	  if(error || uio->uio_resid) {
412211095Sdes	       debug(2,
413211095Sdes#if __FreeBSD_version > 800000
414211095Sdes		     "len=%d error=%d uio->uio_resid=%zd",
415211095Sdes#else
416211095Sdes		     "len=%d error=%d uio->uio_resid=%d",
417211095Sdes#endif
418211095Sdes		     len, error, uio->uio_resid);
419211095Sdes	       goto out;
420211095Sdes	  }
421211095Sdes	  if(ISOK2DIG(sp->hdrDigest, pp)) {
422211095Sdes	       bhs_t	*bhs;
423211095Sdes	       u_int	digest;
424211095Sdes
425211095Sdes	       bhs = (bhs_t *)&pp->ipdu;
426211095Sdes	       digest = sp->hdrDigest(bhs, sizeof(bhs_t), 0);
427211095Sdes	       if(pp->ahs_len)
428211095Sdes		    digest = sp->hdrDigest(pp->ahs_addr, pp->ahs_len, digest);
429211095Sdes	       if(pp->hdr_dig != digest) {
430211095Sdes		    debug(2, "bad header digest: received=%x calculated=%x", pp->hdr_dig, digest);
431211095Sdes		    // XXX: now what?
432211095Sdes		    error = EIO;
433211095Sdes		    goto out;
434211095Sdes	       }
435211095Sdes	  }
436211095Sdes	  if(pp->ahs_len) {
437211095Sdes	       debug(2, "ahs len=%x type=%x spec=%x",
438211095Sdes		     pp->ahs_addr->len, pp->ahs_addr->type, pp->ahs_addr->spec);
439211095Sdes	       // XXX: till I figure out what to do with this
440211095Sdes	       free(pp->ahs_addr, M_TEMP);
441211095Sdes	  }
442211095Sdes	  pq->len += len; // XXX: who needs this?
443211095Sdes	  bzero(uio, sizeof(struct uio));
444211095Sdes	  len = 0;
445211095Sdes     }
446211095Sdes
447171568Sscottl     if(bhs->DSLength) {
448211095Sdes	  len = bhs->DSLength;
449171568Sscottl#if BYTE_ORDER == LITTLE_ENDIAN
450211095Sdes	  len = ((len & 0x00ff0000) >> 16)
451211095Sdes	       | (len & 0x0000ff00)
452211095Sdes	       | ((len & 0x000000ff) << 16);
453171568Sscottl#endif
454211095Sdes	  pp->ds_len = len;
455211095Sdes	  if((sp->opt.maxRecvDataSegmentLength > 0) && (len > sp->opt.maxRecvDataSegmentLength)) {
456211095Sdes	       xdebug("impossible PDU length(%d) opt.maxRecvDataSegmentLength=%d",
457211095Sdes		      len, sp->opt.maxRecvDataSegmentLength);
458211095Sdes	       log(LOG_ERR,
459211095Sdes		   "so_recv: impossible PDU length(%d) from iSCSI %s/%s\n",
460211095Sdes		   len, sp->opt.targetAddress, sp->opt.targetName);
461211095Sdes	       /*
462211095Sdes		| XXX: this will really screwup the stream.
463211095Sdes		| should clear up the buffer till a valid header
464211095Sdes		| is found, or just close connection ...
465211095Sdes		| should read the RFC.
466211095Sdes	        */
467211095Sdes	       error = E2BIG;
468211095Sdes	       goto out;
469211095Sdes	  }
470171568Sscottl	  while(len & 03)
471171568Sscottl	       len++;
472211095Sdes	  if(ISOK2DIG(sp->dataDigest, pp))
473171568Sscottl	       len += 4;
474171568Sscottl	  uio->uio_resid = len;
475211095Sdes	  uio->uio_td = sp->td; // why ...
476211095Sdes	  pq->len += len; // XXX: do we need this?
477211095Sdes	  error = soreceive(sp->soc, NULL, uio, &pq->mp, NULL, &flags);
478171568Sscottl	  //if(error == EAGAIN)
479171568Sscottl	  // XXX: this needs work! it hangs iscontrol
480171568Sscottl	  if(error || uio->uio_resid)
481171568Sscottl	       goto out;
482211095Sdes          if(ISOK2DIG(sp->dataDigest, pp)) {
483211095Sdes	       struct mbuf *m;
484211095Sdes	       u_int    digest, ds_len, cnt;
485211095Sdes
486211095Sdes	       // get the received digest
487211095Sdes	       m_copydata(pq->mp,
488211095Sdes			  len - sizeof(pp->ds_dig),
489211095Sdes			  sizeof(pp->ds_dig),
490211095Sdes			  (caddr_t)&pp->ds_dig);
491211095Sdes	       // calculate all mbufs
492211095Sdes	       digest = 0;
493211095Sdes	       ds_len = len - sizeof(pp->ds_dig);
494211095Sdes	       for(m = pq->mp; m != NULL; m = m->m_next) {
495211095Sdes		    cnt = MIN(ds_len, m->m_len);
496211095Sdes		    digest = sp->dataDigest(mtod(m, char *), cnt, digest);
497211095Sdes		    ds_len -= cnt;
498211095Sdes		    if(ds_len == 0)
499211095Sdes			 break;
500211095Sdes	       }
501211095Sdes	       if(digest != pp->ds_dig) {
502211095Sdes		    sdebug(1, "bad data digest: received=%x calculated=%x", pp->ds_dig, digest);
503211095Sdes		    error = EIO; // XXX: find a better error
504211095Sdes		    goto out;
505211095Sdes	       }
506211095Sdes	       KASSERT(ds_len == 0, ("ds_len not zero"));
507211095Sdes	  }
508171568Sscottl     }
509171568Sscottl     sdebug(6, "len=%d] opcode=0x%x ahs_len=0x%x ds_len=0x%x",
510171568Sscottl	    pq->len, bhs->opcode, pp->ahs_len, pp->ds_len);
511171568Sscottl
512171568Sscottl     max = ntohl(bhs->MaxCmdSN);
513171568Sscottl     exp = ntohl(bhs->ExpStSN);
514171568Sscottl     if(max < exp - 1 &&
515171568Sscottl	max > exp - _MAXINCR) {
516171568Sscottl	  sdebug(2,  "bad cmd window size");
517171568Sscottl	  error = EIO; // XXX: for now;
518171568Sscottl	  goto out; // error
519171568Sscottl     }
520171568Sscottl     if(SNA_GT(max, sn->maxCmd))
521171568Sscottl	  sn->maxCmd = max;
522171568Sscottl     if(SNA_GT(exp, sn->expCmd))
523171568Sscottl	  sn->expCmd = exp;
524211095Sdes     /*
525211095Sdes      | remove from the holding queue packets
526211095Sdes      | that have been acked and don't need
527211095Sdes      | further processing.
528211095Sdes      */
529211095Sdes     i_acked_hld(sp, NULL);
530171568Sscottl
531171568Sscottl     sp->cws = sn->maxCmd - sn->expCmd + 1;
532171568Sscottl
533171568Sscottl     return 0;
534171568Sscottl
535171568Sscottl out:
536171568Sscottl     // XXX: need some work here
537211095Sdes     if(pp->ahs_len) {
538211095Sdes	  // XXX: till I figure out what to do with this
539211095Sdes	  free(pp->ahs_addr, M_TEMP);
540211095Sdes     }
541171568Sscottl     xdebug("have a problem, error=%d", error);
542171568Sscottl     pdu_free(sp->isc, pq);
543171568Sscottl     if(!error && uio->uio_resid > 0)
544171568Sscottl	  error = EPIPE;
545171568Sscottl     return error;
546171568Sscottl}
547185289Sscottl
548171568Sscottl/*
549171568Sscottl | wait for something to arrive.
550171568Sscottl | and if the pdu is without errors, process it.
551171568Sscottl */
552171568Sscottlstatic int
553171568Sscottlso_input(isc_session_t *sp)
554171568Sscottl{
555171568Sscottl     pduq_t		*pq;
556171568Sscottl     int		error;
557171568Sscottl
558171568Sscottl     debug_called(8);
559171568Sscottl     /*
560171568Sscottl      | first read in the iSCSI header
561171568Sscottl      */
562171568Sscottl     error = so_getbhs(sp);
563171568Sscottl     if(error == 0) {
564171568Sscottl	  /*
565171568Sscottl	   | now read the rest.
566171568Sscottl	   */
567185289Sscottl	  pq = pdu_alloc(sp->isc, M_NOWAIT);
568185289Sscottl	  if(pq == NULL) { // XXX: might cause a deadlock ...
569211095Sdes	       debug(2, "out of pdus, wait");
570211095Sdes	       pq = pdu_alloc(sp->isc, M_WAITOK);  // OK to WAIT
571185289Sscottl	  }
572171568Sscottl	  pq->pdu.ipdu.bhs = sp->bhs;
573171568Sscottl	  pq->len = sizeof(bhs_t);	// so far only the header was read
574171568Sscottl	  error = so_recv(sp, pq);
575171568Sscottl	  if(error != 0) {
576171568Sscottl	       error += 0x800; // XXX: just to see the error.
577171568Sscottl	       // terminal error
578171568Sscottl	       // XXX: close connection and exit
579171568Sscottl	  }
580171568Sscottl	  else {
581171568Sscottl	       sp->stats.nrecv++;
582171568Sscottl	       getbintime(&sp->stats.t_recv);
583171568Sscottl	       ism_recv(sp, pq);
584171568Sscottl	  }
585171568Sscottl     }
586171568Sscottl     return error;
587171568Sscottl}
588171568Sscottl
589171568Sscottl/*
590171568Sscottl | one per active (connected) session.
591171568Sscottl | this thread is responsible for reading
592171568Sscottl | in packets from the target.
593171568Sscottl */
594171568Sscottlstatic void
595211095Sdesisc_in(void *vp)
596171568Sscottl{
597171568Sscottl     isc_session_t	*sp = (isc_session_t *)vp;
598171568Sscottl     struct socket	*so = sp->soc;
599171568Sscottl     int		error;
600171568Sscottl
601171568Sscottl     debug_called(8);
602171568Sscottl
603171568Sscottl     sp->flags |= ISC_CON_RUNNING;
604171568Sscottl     error = 0;
605185289Sscottl     while((sp->flags & (ISC_CON_RUN | ISC_LINK_UP)) == (ISC_CON_RUN | ISC_LINK_UP)) {
606171568Sscottl	  // XXX: hunting ...
607171568Sscottl	  if(sp->soc == NULL || !(so->so_state & SS_ISCONNECTED)) {
608171568Sscottl	       debug(2, "sp->soc=%p", sp->soc);
609171568Sscottl	       break;
610171568Sscottl	  }
611171568Sscottl	  error = so_input(sp);
612171568Sscottl	  if(error == 0) {
613171568Sscottl	       mtx_lock(&sp->io_mtx);
614171568Sscottl	       if(sp->flags & ISC_OWAITING) {
615211095Sdes		    wakeup(&sp->flags);
616171568Sscottl	       }
617171568Sscottl	       mtx_unlock(&sp->io_mtx);
618185289Sscottl	  } else if(error == EPIPE) {
619171568Sscottl	       break;
620185289Sscottl	  }
621171568Sscottl	  else if(error == EAGAIN) {
622171568Sscottl	       if(so->so_state & SS_ISCONNECTED)
623171568Sscottl		    // there seems to be a problem in 6.0 ...
624171568Sscottl		    tsleep(sp, PRIBIO, "isc_soc", 2*hz);
625171568Sscottl	  }
626171568Sscottl     }
627185289Sscottl     sdebug(2, "terminated, flags=%x so_count=%d so_state=%x error=%d proc=%p",
628185289Sscottl	    sp->flags, so->so_count, so->so_state, error, sp->proc);
629171568Sscottl     if((sp->proc != NULL) && sp->signal) {
630171568Sscottl	  PROC_LOCK(sp->proc);
631225617Skmacy	  kern_psignal(sp->proc, sp->signal);
632171568Sscottl	  PROC_UNLOCK(sp->proc);
633171568Sscottl	  sp->flags |= ISC_SIGNALED;
634171568Sscottl	  sdebug(2, "pid=%d signaled(%d)", sp->proc->p_pid, sp->signal);
635171568Sscottl     }
636171568Sscottl     else {
637171568Sscottl	  // we have to do something ourselves
638171568Sscottl	  // like closing this session ...
639171568Sscottl     }
640171568Sscottl     /*
641171568Sscottl      | we've been terminated
642171568Sscottl      */
643171568Sscottl     // do we need this mutex ...?
644171568Sscottl     mtx_lock(&sp->io_mtx);
645185289Sscottl     sp->flags &= ~(ISC_CON_RUNNING | ISC_LINK_UP);
646171568Sscottl     wakeup(&sp->soc);
647171568Sscottl     mtx_unlock(&sp->io_mtx);
648171568Sscottl
649185289Sscottl     sdebug(2, "dropped ISC_CON_RUNNING");
650211095Sdes#if __FreeBSD_version >= 800000
651172836Sjulian     kproc_exit(0);
652211095Sdes#else
653211095Sdes     kthread_exit(0);
654211095Sdes#endif
655171568Sscottl}
656171568Sscottl
657171568Sscottlvoid
658171568Sscottlisc_stop_receiver(isc_session_t *sp)
659171568Sscottl{
660185289Sscottl     int	n;
661185289Sscottl
662171568Sscottl     debug_called(8);
663185289Sscottl     sdebug(3, "sp=%p sp->soc=%p", sp, sp? sp->soc: 0);
664185289Sscottl     mtx_lock(&sp->io_mtx);
665185289Sscottl     sp->flags &= ~ISC_LINK_UP;
666185289Sscottl     msleep(&sp->soc, &sp->io_mtx, PRIBIO|PDROP, "isc_stpc", 5*hz);
667171568Sscottl
668171568Sscottl     soshutdown(sp->soc, SHUT_RD);
669171568Sscottl
670171568Sscottl     mtx_lock(&sp->io_mtx);
671185289Sscottl     sdebug(3, "soshutdown");
672171568Sscottl     sp->flags &= ~ISC_CON_RUN;
673185289Sscottl     n = 2;
674171568Sscottl     while(n-- && (sp->flags & ISC_CON_RUNNING)) {
675171568Sscottl	  sdebug(3, "waiting n=%d... flags=%x", n, sp->flags);
676171568Sscottl	  msleep(&sp->soc, &sp->io_mtx, PRIBIO, "isc_stpc", 5*hz);
677171568Sscottl     }
678171568Sscottl     mtx_unlock(&sp->io_mtx);
679171568Sscottl
680171568Sscottl     if(sp->fp != NULL)
681171568Sscottl	  fdrop(sp->fp, sp->td);
682171568Sscottl     fputsock(sp->soc);
683171568Sscottl     sp->soc = NULL;
684171568Sscottl     sp->fp = NULL;
685185289Sscottl
686185289Sscottl     sdebug(3, "done");
687171568Sscottl}
688171568Sscottl
689171568Sscottlvoid
690171568Sscottlisc_start_receiver(isc_session_t *sp)
691171568Sscottl{
692171568Sscottl     debug_called(8);
693171568Sscottl
694185289Sscottl     sp->flags |= ISC_CON_RUN | ISC_LINK_UP;
695211095Sdes#if __FreeBSD_version >= 800000
696211095Sdes     kproc_create
697211095Sdes#else
698211095Sdes     kthread_create
699211095Sdes#endif
700211095Sdes	  (isc_in, sp, &sp->soc_proc, 0, 0, "isc_in %d", sp->sid);
701171568Sscottl}
702