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