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/* 28171568Sscottl | iSCSI - Session Manager 29211095Sdes | $Id: isc_sm.c 743 2009-08-08 10:54:53Z danny $ 30171568Sscottl */ 31171568Sscottl 32171568Sscottl#include <sys/cdefs.h> 33171568Sscottl__FBSDID("$FreeBSD$"); 34171568Sscottl 35171568Sscottl#include "opt_iscsi_initiator.h" 36171568Sscottl 37171568Sscottl#include <sys/param.h> 38171568Sscottl#include <sys/kernel.h> 39171568Sscottl#include <sys/conf.h> 40171568Sscottl#include <sys/systm.h> 41171568Sscottl#include <sys/malloc.h> 42171568Sscottl#include <sys/ctype.h> 43171568Sscottl#include <sys/errno.h> 44171568Sscottl#include <sys/sysctl.h> 45171568Sscottl#include <sys/file.h> 46171568Sscottl#include <sys/uio.h> 47171568Sscottl#include <sys/socketvar.h> 48171568Sscottl#include <sys/socket.h> 49171568Sscottl#include <sys/protosw.h> 50171568Sscottl#include <sys/proc.h> 51171568Sscottl#include <sys/ioccom.h> 52171568Sscottl#include <sys/queue.h> 53171568Sscottl#include <sys/kthread.h> 54171568Sscottl#include <sys/syslog.h> 55171568Sscottl#include <sys/mbuf.h> 56171568Sscottl#include <sys/bus.h> 57211095Sdes#include <sys/sx.h> 58171568Sscottl 59171568Sscottl#include <cam/cam.h> 60171568Sscottl#include <cam/cam_ccb.h> 61171568Sscottl#include <cam/cam_sim.h> 62171568Sscottl#include <cam/cam_xpt_sim.h> 63171568Sscottl#include <cam/cam_periph.h> 64171568Sscottl 65254657Strasz#include <dev/iscsi_initiator/iscsi.h> 66254657Strasz#include <dev/iscsi_initiator/iscsivar.h> 67171568Sscottl 68171568Sscottlstatic void 69171568Sscottl_async(isc_session_t *sp, pduq_t *pq) 70171568Sscottl{ 71171568Sscottl debug_called(8); 72171568Sscottl 73171568Sscottl iscsi_async(sp, pq); 74171568Sscottl 75171568Sscottl pdu_free(sp->isc, pq); 76171568Sscottl} 77171568Sscottl 78171568Sscottlstatic void 79171568Sscottl_reject(isc_session_t *sp, pduq_t *pq) 80171568Sscottl{ 81171568Sscottl pduq_t *opq; 82171568Sscottl pdu_t *pdu; 83171568Sscottl reject_t *reject; 84171568Sscottl int itt; 85171568Sscottl 86171568Sscottl debug_called(8); 87171568Sscottl pdu = mtod(pq->mp, pdu_t *); 88171568Sscottl itt = pdu->ipdu.bhs.itt; 89171568Sscottl reject = &pq->pdu.ipdu.reject; 90171568Sscottl sdebug(2, "itt=%x reason=0x%x", ntohl(itt), reject->reason); 91171568Sscottl opq = i_search_hld(sp, itt, 0); 92171568Sscottl if(opq != NULL) 93171568Sscottl iscsi_reject(sp, opq, pq); 94171568Sscottl else { 95171568Sscottl switch(pq->pdu.ipdu.bhs.opcode) { 96171568Sscottl case ISCSI_LOGOUT_CMD: // XXX: wasabi does this - can't figure out why 97171568Sscottl sdebug(2, "ISCSI_LOGOUT_CMD ..."); 98171568Sscottl break; 99171568Sscottl default: 100171568Sscottl xdebug("%d] we lost something itt=%x", 101171568Sscottl sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); 102171568Sscottl } 103171568Sscottl } 104171568Sscottl pdu_free(sp->isc, pq); 105171568Sscottl} 106171568Sscottl 107171568Sscottlstatic void 108171568Sscottl_r2t(isc_session_t *sp, pduq_t *pq) 109171568Sscottl{ 110171568Sscottl pduq_t *opq; 111171568Sscottl 112171568Sscottl debug_called(8); 113171568Sscottl opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1); 114171568Sscottl if(opq != NULL) { 115171568Sscottl iscsi_r2t(sp, opq, pq); 116171568Sscottl } 117171568Sscottl else { 118171568Sscottl r2t_t *r2t = &pq->pdu.ipdu.r2t; 119171568Sscottl 120171568Sscottl xdebug("%d] we lost something itt=%x r2tSN=%d bo=%x ddtl=%x", 121171568Sscottl sp->sid, ntohl(pq->pdu.ipdu.bhs.itt), 122171568Sscottl ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl)); 123171568Sscottl } 124171568Sscottl pdu_free(sp->isc, pq); 125171568Sscottl} 126171568Sscottl 127171568Sscottlstatic void 128171568Sscottl_scsi_rsp(isc_session_t *sp, pduq_t *pq) 129171568Sscottl{ 130171568Sscottl pduq_t *opq; 131171568Sscottl 132171568Sscottl debug_called(8); 133171568Sscottl opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 0); 134171568Sscottl debug(5, "itt=%x pq=%p opq=%p", ntohl(pq->pdu.ipdu.bhs.itt), pq, opq); 135211095Sdes if(opq != NULL) { 136171568Sscottl iscsi_done(sp, opq, pq); 137211095Sdes i_acked_hld(sp, &pq->pdu); 138211095Sdes } 139171568Sscottl else 140171568Sscottl xdebug("%d] we lost something itt=%x", 141171568Sscottl sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); 142171568Sscottl pdu_free(sp->isc, pq); 143171568Sscottl} 144171568Sscottl 145171568Sscottlstatic void 146171568Sscottl_read_data(isc_session_t *sp, pduq_t *pq) 147171568Sscottl{ 148171568Sscottl pduq_t *opq; 149171568Sscottl 150171568Sscottl debug_called(8); 151171568Sscottl opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1); 152171568Sscottl if(opq != NULL) { 153171568Sscottl if(scsi_decap(sp, opq, pq) != 1) { 154171568Sscottl i_remove_hld(sp, opq); // done 155171568Sscottl pdu_free(sp->isc, opq); 156171568Sscottl } 157171568Sscottl } 158171568Sscottl else 159171568Sscottl xdebug("%d] we lost something itt=%x", 160171568Sscottl sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); 161171568Sscottl pdu_free(sp->isc, pq); 162171568Sscottl} 163171568Sscottl/* 164171568Sscottl | this is a kludge, 165171568Sscottl | the jury is not back with a veredict, user or kernel 166171568Sscottl */ 167171568Sscottlstatic void 168171568Sscottl_nop_out(isc_session_t *sp) 169171568Sscottl{ 170171568Sscottl pduq_t *pq; 171171568Sscottl nop_out_t *nop_out; 172171568Sscottl 173171568Sscottl debug_called(8); 174171568Sscottl 175171568Sscottl sdebug(4, "cws=%d", sp->cws); 176171568Sscottl if(sp->cws == 0) { 177171568Sscottl /* 178171568Sscottl | only send a nop if window is closed. 179171568Sscottl */ 180185289Sscottl if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) 181171568Sscottl // I guess we ran out of resources 182171568Sscottl return; 183171568Sscottl nop_out = &pq->pdu.ipdu.nop_out; 184171568Sscottl nop_out->opcode = ISCSI_NOP_OUT; 185171568Sscottl nop_out->itt = htonl(sp->sn.itt); 186171568Sscottl nop_out->ttt = -1; 187171568Sscottl nop_out->I = 1; 188171568Sscottl nop_out->F = 1; 189171568Sscottl if(isc_qout(sp, pq) != 0) { 190171568Sscottl sdebug(1, "failed"); 191171568Sscottl pdu_free(sp->isc, pq); 192171568Sscottl } 193171568Sscottl } 194171568Sscottl} 195171568Sscottl 196171568Sscottlstatic void 197171568Sscottl_nop_in(isc_session_t *sp, pduq_t *pq) 198171568Sscottl{ 199171568Sscottl pdu_t *pp = &pq->pdu; 200171568Sscottl nop_in_t *nop_in = &pp->ipdu.nop_in; 201171568Sscottl bhs_t *bhs = &pp->ipdu.bhs; 202171568Sscottl 203171568Sscottl debug_called(8); 204171568Sscottl 205171568Sscottl sdebug(5, "itt=%x ttt=%x", htonl(nop_in->itt), htonl(nop_in->ttt)); 206171568Sscottl if(nop_in->itt == -1) { 207171568Sscottl if(pp->ds_len != 0) { 208171568Sscottl /* 209171568Sscottl | according to RFC 3720 this should be zero 210171568Sscottl | what to do if not? 211171568Sscottl */ 212171568Sscottl xdebug("%d] dslen not zero", sp->sid); 213171568Sscottl } 214171568Sscottl if(nop_in->ttt != -1) { 215171568Sscottl nop_out_t *nop_out; 216171568Sscottl /* 217171568Sscottl | target wants a nop_out 218171568Sscottl */ 219171568Sscottl bhs->opcode = ISCSI_NOP_OUT; 220171568Sscottl bhs->I = 1; 221171568Sscottl bhs->F = 1; 222171568Sscottl /* 223171568Sscottl | we are reusing the pdu, so bhs->ttt == nop_in->ttt; 224171568Sscottl | and need to zero out 'Reserved' 225171568Sscottl | small cludge here. 226171568Sscottl */ 227171568Sscottl nop_out = &pp->ipdu.nop_out; 228171568Sscottl nop_out->sn.maxcmd = 0; 229171568Sscottl memset(nop_out->mbz, 0, sizeof(nop_out->mbz)); 230171568Sscottl (void)isc_qout(sp, pq); //XXX: should check return? 231171568Sscottl return; 232171568Sscottl } 233171568Sscottl //else { 234171568Sscottl // just making noise? 235171568Sscottl // see 10.9.1: target does not want and answer. 236171568Sscottl //} 237171568Sscottl 238171568Sscottl } else 239171568Sscottl if(nop_in->ttt == -1) { 240171568Sscottl /* 241171568Sscottl | it is an answer to a nop_in from us 242171568Sscottl */ 243171568Sscottl if(nop_in->itt != -1) { 244171568Sscottl#ifdef ISC_WAIT4PING 245171568Sscottl // XXX: MUTEX please 246171568Sscottl if(sp->flags & ISC_WAIT4PING) { 247171568Sscottl i_nqueue_rsp(sp, pq); 248171568Sscottl wakeup(&sp->rsp); 249171568Sscottl return; 250171568Sscottl } 251171568Sscottl#endif 252171568Sscottl } 253171568Sscottl } 254171568Sscottl /* 255171568Sscottl | drop it 256171568Sscottl */ 257171568Sscottl pdu_free(sp->isc, pq); 258171568Sscottl return; 259171568Sscottl} 260171568Sscottl 261171568Sscottlint 262171568Sscottli_prepPDU(isc_session_t *sp, pduq_t *pq) 263171568Sscottl{ 264171568Sscottl size_t len, n; 265171568Sscottl pdu_t *pp = &pq->pdu; 266171568Sscottl bhs_t *bhp = &pp->ipdu.bhs; 267171568Sscottl 268171568Sscottl len = sizeof(bhs_t); 269171568Sscottl if(pp->ahs_len) { 270171568Sscottl len += pp->ahs_len; 271171568Sscottl bhp->AHSLength = pp->ahs_len / 4; 272171568Sscottl } 273211095Sdes if(ISOK2DIG(sp->hdrDigest, pp)) 274171568Sscottl len += 4; 275171568Sscottl if(pp->ds_len) { 276171568Sscottl n = pp->ds_len; 277171568Sscottl len += n; 278171568Sscottl#if BYTE_ORDER == LITTLE_ENDIAN 279171568Sscottl bhp->DSLength = ((n & 0x00ff0000) >> 16) 280171568Sscottl | (n & 0x0000ff00) 281171568Sscottl | ((n & 0x000000ff) << 16); 282171568Sscottl#else 283171568Sscottl bhp->DSLength = n; 284171568Sscottl#endif 285171568Sscottl if(len & 03) { 286171568Sscottl n = 4 - (len & 03); 287171568Sscottl len += n; 288171568Sscottl } 289211095Sdes if(ISOK2DIG(sp->dataDigest, pp)) 290171568Sscottl len += 4; 291171568Sscottl } 292171568Sscottl 293171568Sscottl pq->len = len; 294171568Sscottl len -= sizeof(bhs_t); 295171568Sscottl if(sp->opt.maxBurstLength && (len > sp->opt.maxBurstLength)) { 296171568Sscottl xdebug("%d] pdu len=%zd > %d", 297171568Sscottl sp->sid, len, sp->opt.maxBurstLength); 298171568Sscottl // XXX: when this happens it used to hang ... 299171568Sscottl return E2BIG; 300171568Sscottl } 301171568Sscottl return 0; 302171568Sscottl} 303171568Sscottl 304171568Sscottlint 305171568Sscottlisc_qout(isc_session_t *sp, pduq_t *pq) 306171568Sscottl{ 307171568Sscottl int error = 0; 308171568Sscottl 309171568Sscottl debug_called(8); 310171568Sscottl 311171568Sscottl if(pq->len == 0 && (error = i_prepPDU(sp, pq))) 312171568Sscottl return error; 313171568Sscottl 314171568Sscottl if(pq->pdu.ipdu.bhs.I) 315171568Sscottl i_nqueue_isnd(sp, pq); 316171568Sscottl else 317171568Sscottl if(pq->pdu.ipdu.data_out.opcode == ISCSI_WRITE_DATA) 318171568Sscottl i_nqueue_wsnd(sp, pq); 319171568Sscottl else 320171568Sscottl i_nqueue_csnd(sp, pq); 321171568Sscottl 322171568Sscottl sdebug(5, "enqued: pq=%p", pq); 323185289Sscottl 324185289Sscottl mtx_lock(&sp->io_mtx); 325185289Sscottl sp->flags |= ISC_OQNOTEMPTY; 326185289Sscottl if(sp->flags & ISC_OWAITING) 327211095Sdes wakeup(&sp->flags); 328185289Sscottl mtx_unlock(&sp->io_mtx); 329185289Sscottl 330171568Sscottl return error; 331171568Sscottl} 332171568Sscottl/* 333171568Sscottl | called when a fullPhase is restarted 334171568Sscottl */ 335211095Sdesvoid 336171568Sscottlism_restart(isc_session_t *sp) 337171568Sscottl{ 338171568Sscottl int lastcmd; 339171568Sscottl 340171568Sscottl sdebug(2, "restart ..."); 341171568Sscottl lastcmd = iscsi_requeue(sp); 342171568Sscottl#if 0 343171568Sscottl if(lastcmd != sp->sn.cmd) { 344171568Sscottl sdebug(1, "resetting CmdSN to=%d (from %d)", lastcmd, sp->sn.cmd); 345171568Sscottl sp->sn.cmd = lastcmd; 346171568Sscottl } 347171568Sscottl#endif 348185289Sscottl mtx_lock(&sp->io_mtx); 349185289Sscottl if(sp->flags & ISC_OWAITING) { 350185289Sscottl wakeup(&sp->flags); 351185289Sscottl } 352185289Sscottl mtx_unlock(&sp->io_mtx); 353185289Sscottl 354211095Sdes sdebug(2, "restarted sn.cmd=0x%x lastcmd=0x%x", sp->sn.cmd, lastcmd); 355171568Sscottl} 356171568Sscottl 357171568Sscottlvoid 358171568Sscottlism_recv(isc_session_t *sp, pduq_t *pq) 359171568Sscottl{ 360171568Sscottl bhs_t *bhs; 361171568Sscottl int statSN; 362171568Sscottl 363171568Sscottl debug_called(8); 364171568Sscottl 365171568Sscottl bhs = &pq->pdu.ipdu.bhs; 366171568Sscottl statSN = ntohl(bhs->OpcodeSpecificFields[1]); 367171568Sscottl 368171568Sscottl#ifdef notyet 369171568Sscottl if(sp->sn.expCmd != sn->cmd) { 370171568Sscottl sdebug(1, "we lost something ... exp=0x%x cmd=0x%x", 371171568Sscottl sn->expCmd, sn->cmd); 372171568Sscottl } 373171568Sscottl#endif 374171568Sscottl sdebug(5, "opcode=0x%x itt=0x%x stat#0x%x maxcmd=0x%0x", 375171568Sscottl bhs->opcode, ntohl(bhs->itt), statSN, sp->sn.maxCmd); 376171568Sscottl 377171568Sscottl switch(bhs->opcode) { 378171568Sscottl case ISCSI_READ_DATA: { 379171568Sscottl data_in_t *cmd = &pq->pdu.ipdu.data_in; 380171568Sscottl 381171568Sscottl if(cmd->S == 0) 382171568Sscottl break; 383171568Sscottl } 384171568Sscottl 385171568Sscottl default: 386171568Sscottl if(statSN > (sp->sn.stat + 1)) { 387171568Sscottl sdebug(1, "we lost some rec=0x%x exp=0x%x", 388171568Sscottl statSN, sp->sn.stat); 389171568Sscottl // XXX: must do some error recovery here. 390171568Sscottl } 391171568Sscottl sp->sn.stat = statSN; 392171568Sscottl } 393171568Sscottl 394171568Sscottl switch(bhs->opcode) { 395171568Sscottl case ISCSI_LOGIN_RSP: 396171568Sscottl case ISCSI_TEXT_RSP: 397171568Sscottl case ISCSI_LOGOUT_RSP: 398171568Sscottl i_nqueue_rsp(sp, pq); 399171568Sscottl wakeup(&sp->rsp); 400171568Sscottl sdebug(3, "wakeup rsp"); 401171568Sscottl break; 402171568Sscottl 403171568Sscottl case ISCSI_NOP_IN: _nop_in(sp, pq); break; 404171568Sscottl case ISCSI_SCSI_RSP: _scsi_rsp(sp, pq); break; 405171568Sscottl case ISCSI_READ_DATA: _read_data(sp, pq); break; 406171568Sscottl case ISCSI_R2T: _r2t(sp, pq); break; 407171568Sscottl case ISCSI_REJECT: _reject(sp, pq); break; 408171568Sscottl case ISCSI_ASYNC: _async(sp, pq); break; 409171568Sscottl 410171568Sscottl case ISCSI_TASK_RSP: 411171568Sscottl default: 412171568Sscottl sdebug(1, "opcode=0x%x itt=0x%x not implemented yet", 413171568Sscottl bhs->opcode, ntohl(bhs->itt)); 414171568Sscottl break; 415171568Sscottl } 416171568Sscottl} 417211095Sdes 418185289Sscottl/* 419185289Sscottl | go through the out queues looking for work 420185289Sscottl | if either nothing to do, or window is closed 421185289Sscottl | return. 422185289Sscottl */ 423171568Sscottlstatic int 424171568Sscottlproc_out(isc_session_t *sp) 425171568Sscottl{ 426171568Sscottl sn_t *sn = &sp->sn; 427171568Sscottl pduq_t *pq; 428211095Sdes int error, which; 429171568Sscottl 430171568Sscottl debug_called(8); 431211095Sdes error = 0; 432171568Sscottl 433185289Sscottl while(sp->flags & ISC_LINK_UP) { 434171568Sscottl pdu_t *pp; 435171568Sscottl bhs_t *bhs; 436171568Sscottl /* 437171568Sscottl | check if there is outstanding work in: 438185289Sscottl | 1- the Immediate queue 439171568Sscottl | 2- the R2T queue 440171568Sscottl | 3- the cmd queue, only if the command window allows it. 441171568Sscottl */ 442171568Sscottl which = BIT(0) | BIT(1); 443185289Sscottl if(SNA_GT(sn->cmd, sn->maxCmd) == 0) // if(sn->maxCmd - sn->smc + 1) > 0 444171568Sscottl which |= BIT(2); 445171568Sscottl 446185289Sscottl sdebug(4, "which=%d sn->maxCmd=%d sn->cmd=%d", which, sn->maxCmd, sn->cmd); 447185289Sscottl 448171568Sscottl if((pq = i_dqueue_snd(sp, which)) == NULL) 449171568Sscottl break; 450185289Sscottl sdebug(4, "pq=%p", pq); 451171568Sscottl 452171568Sscottl pp = &pq->pdu; 453171568Sscottl bhs = &pp->ipdu.bhs; 454171568Sscottl switch(bhs->opcode) { 455171568Sscottl case ISCSI_SCSI_CMD: 456171568Sscottl sn->itt++; 457171568Sscottl bhs->itt = htonl(sn->itt); 458171568Sscottl 459171568Sscottl case ISCSI_LOGIN_CMD: 460171568Sscottl case ISCSI_TEXT_CMD: 461171568Sscottl case ISCSI_LOGOUT_CMD: 462171568Sscottl case ISCSI_SNACK: 463171568Sscottl case ISCSI_NOP_OUT: 464171568Sscottl case ISCSI_TASK_CMD: 465171568Sscottl bhs->CmdSN = htonl(sn->cmd); 466171568Sscottl if(bhs->I == 0) 467171568Sscottl sn->cmd++; 468171568Sscottl 469171568Sscottl case ISCSI_WRITE_DATA: 470211095Sdes bhs->ExpStSN = htonl(sn->stat + 1); 471171568Sscottl break; 472171568Sscottl 473171568Sscottl default: 474171568Sscottl // XXX: can this happen? 475171568Sscottl xdebug("bad opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", 476171568Sscottl bhs->opcode, 477171568Sscottl sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt); 478171568Sscottl // XXX: and now? 479171568Sscottl } 480171568Sscottl 481185289Sscottl sdebug(4, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", 482171568Sscottl bhs->opcode, 483171568Sscottl sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt); 484171568Sscottl 485211095Sdes if(bhs->opcode != ISCSI_NOP_OUT) 486211095Sdes /* 487211095Sdes | enqued till ack is received 488211095Sdes | note: sosend(...) does not mean the packet left 489211095Sdes | the host so that freeing resources has to wait 490211095Sdes */ 491171568Sscottl i_nqueue_hld(sp, pq); 492171568Sscottl 493211095Sdes error = isc_sendPDU(sp, pq); 494211095Sdes if(bhs->opcode == ISCSI_NOP_OUT) 495211095Sdes pdu_free(sp->isc, pq); 496211095Sdes if(error) { 497211095Sdes xdebug("error=%d opcode=0x%x ccb=%p itt=%x", 498211095Sdes error, bhs->opcode, pq->ccb, ntohl(bhs->itt)); 499211095Sdes i_remove_hld(sp, pq); 500185289Sscottl switch(error) { 501185289Sscottl case EPIPE: 502185289Sscottl sp->flags &= ~ISC_LINK_UP; 503185289Sscottl 504185289Sscottl case EAGAIN: 505185289Sscottl xdebug("requed"); 506185289Sscottl i_rqueue_pdu(sp, pq); 507171568Sscottl break; 508185289Sscottl 509185289Sscottl default: 510211095Sdes if(pq->ccb) { 511185289Sscottl xdebug("back to cam"); 512185289Sscottl pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error? 513211095Sdes XPT_DONE(sp, pq->ccb); 514185289Sscottl pdu_free(sp->isc, pq); 515211095Sdes } 516185289Sscottl else 517185289Sscottl xdebug("we lost it!"); 518171568Sscottl } 519171568Sscottl } 520171568Sscottl } 521185289Sscottl return error; 522171568Sscottl} 523211095Sdes 524171568Sscottl/* 525171568Sscottl | survives link breakdowns. 526171568Sscottl */ 527171568Sscottlstatic void 528211095Sdesism_out(void *vp) 529171568Sscottl{ 530171568Sscottl isc_session_t *sp = (isc_session_t *)vp; 531185289Sscottl int error; 532171568Sscottl 533171568Sscottl debug_called(8); 534171568Sscottl 535171568Sscottl sp->flags |= ISC_SM_RUNNING; 536185289Sscottl sdebug(3, "started sp->flags=%x", sp->flags); 537171568Sscottl do { 538185289Sscottl if((sp->flags & ISC_HOLD) == 0) { 539185289Sscottl error = proc_out(sp); 540185289Sscottl if(error) { 541185289Sscottl sdebug(3, "error=%d", error); 542185289Sscottl } 543185289Sscottl } 544211095Sdes mtx_lock(&sp->io_mtx); 545185289Sscottl if((sp->flags & ISC_LINK_UP) == 0) { 546211095Sdes sdebug(3, "ISC_LINK_UP==0, sp->flags=%x ", sp->flags); 547211095Sdes if(sp->soc != NULL) 548211095Sdes sdebug(3, "so_state=%x", sp->soc->so_state); 549185289Sscottl wakeup(&sp->soc); 550185289Sscottl } 551185289Sscottl 552185289Sscottl if(!(sp->flags & ISC_OQNOTEMPTY)) { 553171568Sscottl sp->flags |= ISC_OWAITING; 554185289Sscottl if(msleep(&sp->flags, &sp->io_mtx, PRIBIO, "isc_proc", hz*30) == EWOULDBLOCK) { 555185289Sscottl if(sp->flags & ISC_CON_RUNNING) 556211095Sdes _nop_out(sp); 557185289Sscottl } 558171568Sscottl sp->flags &= ~ISC_OWAITING; 559171568Sscottl } 560185289Sscottl sp->flags &= ~ISC_OQNOTEMPTY; 561185289Sscottl mtx_unlock(&sp->io_mtx); 562171568Sscottl } while(sp->flags & ISC_SM_RUN); 563171568Sscottl 564171568Sscottl sp->flags &= ~ISC_SM_RUNNING; 565185289Sscottl sdebug(3, "dropped ISC_SM_RUNNING"); 566171568Sscottl 567211095Sdes wakeup(&sp->soc); 568211095Sdes wakeup(sp); // XXX: do we need this one? 569211095Sdes 570171568Sscottl#if __FreeBSD_version >= 700000 571171568Sscottl destroy_dev(sp->dev); 572171568Sscottl#endif 573171568Sscottl 574185289Sscottl debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid); 575171568Sscottl 576211095Sdes#if __FreeBSD_version >= 800000 577172836Sjulian kproc_exit(0); 578211095Sdes#else 579211095Sdes kthread_exit(0); 580211095Sdes#endif 581171568Sscottl} 582171568Sscottl 583171568Sscottl#if 0 584171568Sscottlstatic int 585171568Sscottlisc_dump_options(SYSCTL_HANDLER_ARGS) 586171568Sscottl{ 587171568Sscottl int error; 588171568Sscottl isc_session_t *sp; 589171568Sscottl char buf[1024], *bp; 590171568Sscottl 591171568Sscottl sp = (isc_session_t *)arg1; 592171568Sscottl bp = buf; 593171568Sscottl sprintf(bp, "targetname='%s'", sp->opt.targetName); 594171568Sscottl bp += strlen(bp); 595171568Sscottl sprintf(bp, " targetname='%s'", sp->opt.targetAddress); 596171568Sscottl error = SYSCTL_OUT(req, buf, strlen(buf)); 597171568Sscottl return error; 598171568Sscottl} 599171568Sscottl#endif 600171568Sscottl 601171568Sscottlstatic int 602171568Sscottlisc_dump_stats(SYSCTL_HANDLER_ARGS) 603171568Sscottl{ 604171568Sscottl isc_session_t *sp; 605171568Sscottl struct isc_softc *sc; 606171568Sscottl char buf[1024], *bp; 607171568Sscottl int error, n; 608171568Sscottl 609171568Sscottl sp = (isc_session_t *)arg1; 610171568Sscottl sc = sp->isc; 611171568Sscottl 612171568Sscottl bp = buf; 613171568Sscottl n = sizeof(buf); 614171568Sscottl snprintf(bp, n, "recv=%d sent=%d", sp->stats.nrecv, sp->stats.nsent); 615171568Sscottl bp += strlen(bp); 616171568Sscottl n -= strlen(bp); 617171568Sscottl snprintf(bp, n, " flags=0x%08x pdus-alloc=%d pdus-max=%d", 618171568Sscottl sp->flags, sc->npdu_alloc, sc->npdu_max); 619171568Sscottl bp += strlen(bp); 620171568Sscottl n -= strlen(bp); 621171568Sscottl snprintf(bp, n, " cws=%d cmd=%x exp=%x max=%x stat=%x itt=%x", 622171568Sscottl sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt); 623171568Sscottl error = SYSCTL_OUT(req, buf, strlen(buf)); 624171568Sscottl return error; 625171568Sscottl} 626171568Sscottl 627171568Sscottlstatic int 628171568Sscottlisc_sysctl_targetName(SYSCTL_HANDLER_ARGS) 629171568Sscottl{ 630171568Sscottl char buf[128], **cp; 631171568Sscottl int error; 632171568Sscottl 633171568Sscottl cp = (char **)arg1; 634171568Sscottl snprintf(buf, sizeof(buf), "%s", *cp); 635171568Sscottl error = SYSCTL_OUT(req, buf, strlen(buf)); 636171568Sscottl return error; 637171568Sscottl} 638171568Sscottl 639171568Sscottlstatic int 640171568Sscottlisc_sysctl_targetAddress(SYSCTL_HANDLER_ARGS) 641171568Sscottl{ 642171568Sscottl char buf[128], **cp; 643171568Sscottl int error; 644171568Sscottl 645171568Sscottl cp = (char **)arg1; 646171568Sscottl snprintf(buf, sizeof(buf), "%s", *cp); 647171568Sscottl error = SYSCTL_OUT(req, buf, strlen(buf)); 648171568Sscottl return error; 649171568Sscottl} 650171568Sscottl 651171568Sscottlstatic void 652171568Sscottlisc_add_sysctls(isc_session_t *sp) 653171568Sscottl{ 654171568Sscottl debug_called(8); 655231378Sed sdebug(6, "sid=%d %s", sp->sid, devtoname(sp->dev)); 656171568Sscottl 657171568Sscottl sysctl_ctx_init(&sp->clist); 658171568Sscottl sp->oid = SYSCTL_ADD_NODE(&sp->clist, 659171568Sscottl SYSCTL_CHILDREN(sp->isc->oid), 660171568Sscottl OID_AUTO, 661231378Sed devtoname(sp->dev) + 5, // iscsi0 662171568Sscottl CTLFLAG_RD, 663171568Sscottl 0, 664171568Sscottl "initiator"); 665171568Sscottl SYSCTL_ADD_PROC(&sp->clist, 666171568Sscottl SYSCTL_CHILDREN(sp->oid), 667171568Sscottl OID_AUTO, 668171568Sscottl "targetname", 669217556Smdf CTLTYPE_STRING | CTLFLAG_RD, 670171568Sscottl (void *)&sp->opt.targetName, 0, 671171568Sscottl isc_sysctl_targetName, "A", "target name"); 672171568Sscottl 673171568Sscottl SYSCTL_ADD_PROC(&sp->clist, 674171568Sscottl SYSCTL_CHILDREN(sp->oid), 675171568Sscottl OID_AUTO, 676171568Sscottl "targeaddress", 677217556Smdf CTLTYPE_STRING | CTLFLAG_RD, 678171568Sscottl (void *)&sp->opt.targetAddress, 0, 679171568Sscottl isc_sysctl_targetAddress, "A", "target address"); 680171568Sscottl 681171568Sscottl SYSCTL_ADD_PROC(&sp->clist, 682171568Sscottl SYSCTL_CHILDREN(sp->oid), 683171568Sscottl OID_AUTO, 684171568Sscottl "stats", 685217556Smdf CTLTYPE_STRING | CTLFLAG_RD, 686171568Sscottl (void *)sp, 0, 687171568Sscottl isc_dump_stats, "A", "statistics"); 688185289Sscottl 689185289Sscottl SYSCTL_ADD_INT(&sp->clist, 690185289Sscottl SYSCTL_CHILDREN(sp->oid), 691185289Sscottl OID_AUTO, 692185289Sscottl "douio", 693185289Sscottl CTLFLAG_RW, 694185289Sscottl &sp->douio, 0, "enable uio on read"); 695171568Sscottl} 696171568Sscottl 697171568Sscottlvoid 698171568Sscottlism_stop(isc_session_t *sp) 699171568Sscottl{ 700171568Sscottl struct isc_softc *sc = sp->isc; 701171568Sscottl int n; 702171568Sscottl 703171568Sscottl debug_called(8); 704171568Sscottl sdebug(2, "terminating"); 705171568Sscottl /* 706171568Sscottl | first stop the receiver 707171568Sscottl */ 708171568Sscottl isc_stop_receiver(sp); 709171568Sscottl /* 710171568Sscottl | now stop the xmitter 711171568Sscottl */ 712171568Sscottl n = 5; 713171568Sscottl sp->flags &= ~ISC_SM_RUN; 714171568Sscottl while(n-- && (sp->flags & ISC_SM_RUNNING)) { 715171568Sscottl sdebug(2, "n=%d", n); 716171568Sscottl wakeup(&sp->flags); 717171568Sscottl tsleep(sp, PRIBIO, "-", 5*hz); 718171568Sscottl } 719171568Sscottl sdebug(2, "final n=%d", n); 720171568Sscottl sp->flags &= ~ISC_FFPHASE; 721171568Sscottl 722171568Sscottl iscsi_cleanup(sp); 723171568Sscottl 724171568Sscottl (void)i_pdu_flush(sp); 725171568Sscottl 726211095Sdes ic_destroy(sp); 727171568Sscottl 728211095Sdes sx_xlock(&sc->unit_sx); 729211095Sdes free_unr(sc->unit, sp->sid); 730211095Sdes sx_xunlock(&sc->unit_sx); 731211095Sdes 732211095Sdes mtx_lock(&sc->isc_mtx); 733171568Sscottl TAILQ_REMOVE(&sc->isc_sess, sp, sp_link); 734171568Sscottl sc->nsess--; 735211095Sdes mtx_unlock(&sc->isc_mtx); 736171568Sscottl 737171568Sscottl#if __FreeBSD_version < 700000 738171568Sscottl destroy_dev(sp->dev); 739171568Sscottl#endif 740171568Sscottl 741171568Sscottl mtx_destroy(&sp->rsp_mtx); 742171568Sscottl mtx_destroy(&sp->rsv_mtx); 743171568Sscottl mtx_destroy(&sp->hld_mtx); 744171568Sscottl mtx_destroy(&sp->snd_mtx); 745171568Sscottl mtx_destroy(&sp->io_mtx); 746171568Sscottl 747171568Sscottl i_freeopt(&sp->opt); 748171568Sscottl 749171568Sscottl if(sysctl_ctx_free(&sp->clist)) 750171568Sscottl xdebug("sysctl_ctx_free failed"); 751171568Sscottl 752171568Sscottl free(sp, M_ISCSI); 753171568Sscottl} 754171568Sscottl 755171568Sscottlint 756171568Sscottlism_start(isc_session_t *sp) 757171568Sscottl{ 758171568Sscottl debug_called(8); 759171568Sscottl /* 760171568Sscottl | now is a good time to do some initialization 761171568Sscottl */ 762171568Sscottl TAILQ_INIT(&sp->rsp); 763171568Sscottl TAILQ_INIT(&sp->rsv); 764171568Sscottl TAILQ_INIT(&sp->csnd); 765171568Sscottl TAILQ_INIT(&sp->isnd); 766171568Sscottl TAILQ_INIT(&sp->wsnd); 767171568Sscottl TAILQ_INIT(&sp->hld); 768211095Sdes 769171568Sscottl mtx_init(&sp->rsv_mtx, "iscsi-rsv", NULL, MTX_DEF); 770171568Sscottl mtx_init(&sp->rsp_mtx, "iscsi-rsp", NULL, MTX_DEF); 771171568Sscottl mtx_init(&sp->snd_mtx, "iscsi-snd", NULL, MTX_DEF); 772171568Sscottl mtx_init(&sp->hld_mtx, "iscsi-hld", NULL, MTX_DEF); 773171568Sscottl mtx_init(&sp->io_mtx, "iscsi-io", NULL, MTX_DEF); 774171568Sscottl 775171568Sscottl isc_add_sysctls(sp); 776171568Sscottl 777171568Sscottl sp->flags |= ISC_SM_RUN; 778171568Sscottl 779185289Sscottl debug(4, "starting ism_proc: sp->sid=%d", sp->sid); 780211095Sdes 781211095Sdes#if __FreeBSD_version >= 800000 782211095Sdes return kproc_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid); 783211095Sdes#else 784211095Sdes return kthread_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid); 785211095Sdes#endif 786171568Sscottl} 787