Index: head/sys/dev/iscsi_initiator/isc_cam.c =================================================================== --- head/sys/dev/iscsi_initiator/isc_cam.c (revision 358492) +++ head/sys/dev/iscsi_initiator/isc_cam.c (revision 358493) @@ -1,382 +1,352 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2010 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* | $Id: isc_cam.c 998 2009-12-20 10:32:45Z danny $ */ #include __FBSDID("$FreeBSD$"); #include "opt_iscsi_initiator.h" #include #include #include -#if __FreeBSD_version >= 700000 #include #include -#endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void _inq(struct cam_sim *sim, union ccb *ccb) { struct ccb_pathinq *cpi = &ccb->cpi; isc_session_t *sp = cam_sim_softc(sim); debug_called(8); debug(3, "sid=%d target=%d lun=%jx", sp->sid, ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun); cpi->version_num = 1; /* XXX??? */ cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE | PI_WIDE_32; cpi->target_sprt = 0; cpi->hba_misc = 0; cpi->hba_eng_cnt = 0; cpi->max_target = 0; //ISCSI_MAX_TARGETS - 1; cpi->initiator_id = ISCSI_MAX_TARGETS; cpi->max_lun = sp->opt.maxluns - 1; cpi->bus_id = cam_sim_bus(sim); cpi->base_transfer_speed = 3300; // 40000; // XXX: strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strlcpy(cpi->hba_vid, "iSCSI", HBA_IDLEN); strlcpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); cpi->unit_number = cam_sim_unit(sim); cpi->ccb_h.status = CAM_REQ_CMP; #if defined(KNOB_VALID_ADDRESS) cpi->transport = XPORT_ISCSI; cpi->transport_version = 0; #endif } static __inline int _scsi_encap(struct cam_sim *sim, union ccb *ccb) { int ret; - -#if __FreeBSD_version < 700000 - ret = scsi_encap(sim, ccb); -#else isc_session_t *sp = cam_sim_softc(sim); mtx_unlock(&sp->cam_mtx); ret = scsi_encap(sim, ccb); mtx_lock(&sp->cam_mtx); -#endif + return ret; } void ic_lost_target(isc_session_t *sp, int target) { debug_called(8); sdebug(2, "lost target=%d", target); if(sp->cam_path != NULL) { mtx_lock(&sp->cam_mtx); xpt_async(AC_LOST_DEVICE, sp->cam_path, NULL); xpt_free_path(sp->cam_path); mtx_unlock(&sp->cam_mtx); sp->cam_path = 0; // XXX } } static void scan_callback(struct cam_periph *periph, union ccb *ccb) { isc_session_t *sp = (isc_session_t *)ccb->ccb_h.spriv_ptr0; debug_called(8); xpt_free_ccb(ccb); if(sp->flags & ISC_SCANWAIT) { sp->flags &= ~ISC_SCANWAIT; wakeup(sp); } } static int ic_scan(isc_session_t *sp) { union ccb *ccb; debug_called(8); sdebug(2, "scanning sid=%d", sp->sid); sp->flags &= ~ISC_CAMDEVS; sp->flags |= ISC_SCANWAIT; ccb = xpt_alloc_ccb(); ccb->ccb_h.path = sp->cam_path; ccb->ccb_h.cbfcnp = scan_callback; ccb->ccb_h.spriv_ptr0 = sp; xpt_rescan(ccb); while(sp->flags & ISC_SCANWAIT) tsleep(sp, PRIBIO, "ffp", 5*hz); // the timeout time should // be configurable sdebug(2, "# of luns=%d", sp->target_nluns); if(sp->target_nluns > 0) { sp->flags |= ISC_CAMDEVS; return 0; } return ENODEV; } static void ic_action(struct cam_sim *sim, union ccb *ccb) { isc_session_t *sp = cam_sim_softc(sim); struct ccb_hdr *ccb_h = &ccb->ccb_h; debug_called(8); ccb_h->spriv_ptr0 = sp; sdebug(4, "func_code=0x%x flags=0x%x status=0x%x target=%d lun=%jx retry_count=%d timeout=%d", ccb_h->func_code, ccb->ccb_h.flags, ccb->ccb_h.status, ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun, ccb->ccb_h.retry_count, ccb_h->timeout); if(sp == NULL) { xdebug("sp == NULL! cannot happen"); return; } switch(ccb_h->func_code) { case XPT_PATH_INQ: _inq(sim, ccb); break; case XPT_RESET_BUS: // (can just be a stub that does nothing and completes) { struct ccb_pathinq *cpi = &ccb->cpi; debug(3, "XPT_RESET_BUS"); cpi->ccb_h.status = CAM_REQ_CMP; break; } case XPT_SCSI_IO: { struct ccb_scsiio* csio = &ccb->csio; debug(4, "XPT_SCSI_IO cmd=0x%x", csio->cdb_io.cdb_bytes[0]); if(sp == NULL) { ccb_h->status = CAM_REQ_INVALID; //CAM_NO_NEXUS; debug(4, "xpt_done.status=%d", ccb_h->status); break; } if(ccb_h->target_lun == CAM_LUN_WILDCARD) { debug(3, "target=%d: bad lun (-1)", ccb_h->target_id); ccb_h->status = CAM_LUN_INVALID; break; } if(_scsi_encap(sim, ccb) != 0) return; break; } case XPT_CALC_GEOMETRY: { struct ccb_calc_geometry *ccg; ccg = &ccb->ccg; debug(4, "sid=%d target=%d lun=%jx XPT_CALC_GEOMETRY vsize=%jd bsize=%d", sp->sid, ccb->ccb_h.target_id, (uintmax_t)ccb->ccb_h.target_lun, ccg->volume_size, ccg->block_size); if(ccg->block_size == 0 || (ccg->volume_size < ccg->block_size)) { // print error message ... /* XXX: what error is appropriate? */ break; } else { int lun, *off, boff; lun = ccb->ccb_h.target_lun; if(lun > ISCSI_MAX_LUNS) { // XXX: xdebug("lun %d > ISCSI_MAX_LUNS!\n", lun); lun %= ISCSI_MAX_LUNS; } off = &sp->target_lun[lun / (sizeof(int)*8)]; boff = BIT(lun % (sizeof(int)*8)); debug(4, "sp->target_nluns=%d *off=%x boff=%x", sp->target_nluns, *off, boff); if((*off & boff) == 0) { sp->target_nluns++; *off |= boff; } cam_calc_geometry(ccg, /*extended*/1); } break; } case XPT_GET_TRAN_SETTINGS: default: ccb_h->status = CAM_REQ_INVALID; break; } -#if __FreeBSD_version < 700000 - XPT_DONE(sp, ccb); -#else xpt_done(ccb); -#endif return; } static void ic_poll(struct cam_sim *sim) { debug_called(4); } int ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp) { debug_called(8); if(sp && sp->cam_sim) { cp->path_id = cam_sim_path(sp->cam_sim); cp->target_id = 0; cp->target_nluns = ISCSI_MAX_LUNS; // XXX: -1? return 0; } return ENXIO; } void ic_destroy(isc_session_t *sp ) { debug_called(8); if(sp->cam_path != NULL) { sdebug(2, "name=%s unit=%d", cam_sim_name(sp->cam_sim), cam_sim_unit(sp->cam_sim)); - CAM_LOCK(sp); #if 0 xpt_async(AC_LOST_DEVICE, sp->cam_path, NULL); #else xpt_async(XPT_RESET_BUS, sp->cam_path, NULL); #endif xpt_free_path(sp->cam_path); xpt_bus_deregister(cam_sim_path(sp->cam_sim)); cam_sim_free(sp->cam_sim, TRUE /*free_devq*/); - CAM_UNLOCK(sp); sdebug(2, "done"); } } int ic_init(isc_session_t *sp) { struct cam_sim *sim; struct cam_devq *devq; debug_called(8); if((devq = cam_simq_alloc(256)) == NULL) return ENOMEM; -#if __FreeBSD_version >= 700000 mtx_init(&sp->cam_mtx, "isc-cam", NULL, MTX_DEF); -#else - isp->cam_mtx = Giant; -#endif sim = cam_sim_alloc(ic_action, ic_poll, "iscsi", sp, sp->sid, // unit -#if __FreeBSD_version >= 700000 &sp->cam_mtx, -#endif 1, // max_dev_transactions 0, // max_tagged_dev_transactions devq); if(sim == NULL) { cam_simq_free(devq); -#if __FreeBSD_version >= 700000 mtx_destroy(&sp->cam_mtx); -#endif return ENXIO; } - CAM_LOCK(sp); if(xpt_bus_register(sim, -#if __FreeBSD_version >= 700000 NULL, -#endif 0/*bus_number*/) != CAM_SUCCESS) { cam_sim_free(sim, /*free_devq*/TRUE); - CAM_UNLOCK(sp); -#if __FreeBSD_version >= 700000 mtx_destroy(&sp->cam_mtx); -#endif return ENXIO; } sp->cam_sim = sim; if(xpt_create_path(&sp->cam_path, NULL, cam_sim_path(sp->cam_sim), CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP) { xpt_bus_deregister(cam_sim_path(sp->cam_sim)); cam_sim_free(sim, /*free_devq*/TRUE); - CAM_UNLOCK(sp); -#if __FreeBSD_version >= 700000 mtx_destroy(&sp->cam_mtx); -#endif return ENXIO; } - CAM_UNLOCK(sp); sdebug(1, "cam subsystem initialized"); ic_scan(sp); return 0; } Index: head/sys/dev/iscsi_initiator/isc_sm.c =================================================================== --- head/sys/dev/iscsi_initiator/isc_sm.c (revision 358492) +++ head/sys/dev/iscsi_initiator/isc_sm.c (revision 358493) @@ -1,764 +1,750 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2010 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* | iSCSI - Session Manager | $Id: isc_sm.c 743 2009-08-08 10:54:53Z danny $ */ #include __FBSDID("$FreeBSD$"); #include "opt_iscsi_initiator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void _async(isc_session_t *sp, pduq_t *pq) { debug_called(8); iscsi_async(sp, pq); pdu_free(sp->isc, pq); } static void _reject(isc_session_t *sp, pduq_t *pq) { pduq_t *opq; pdu_t *pdu; reject_t *reject; int itt; debug_called(8); pdu = mtod(pq->mp, pdu_t *); itt = pdu->ipdu.bhs.itt; reject = &pq->pdu.ipdu.reject; sdebug(2, "itt=%x reason=0x%x", ntohl(itt), reject->reason); opq = i_search_hld(sp, itt, 0); if(opq != NULL) iscsi_reject(sp, opq, pq); else { switch(pq->pdu.ipdu.bhs.opcode) { case ISCSI_LOGOUT_CMD: // XXX: wasabi does this - can't figure out why sdebug(2, "ISCSI_LOGOUT_CMD ..."); break; default: xdebug("%d] we lost something itt=%x", sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); } } pdu_free(sp->isc, pq); } static void _r2t(isc_session_t *sp, pduq_t *pq) { pduq_t *opq; debug_called(8); opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1); if(opq != NULL) { iscsi_r2t(sp, opq, pq); } else { r2t_t *r2t = &pq->pdu.ipdu.r2t; xdebug("%d] we lost something itt=%x r2tSN=%d bo=%x ddtl=%x", sp->sid, ntohl(pq->pdu.ipdu.bhs.itt), ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl)); } pdu_free(sp->isc, pq); } static void _scsi_rsp(isc_session_t *sp, pduq_t *pq) { pduq_t *opq; debug_called(8); opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 0); debug(5, "itt=%x pq=%p opq=%p", ntohl(pq->pdu.ipdu.bhs.itt), pq, opq); if(opq != NULL) { iscsi_done(sp, opq, pq); i_acked_hld(sp, &pq->pdu); } else xdebug("%d] we lost something itt=%x", sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); pdu_free(sp->isc, pq); } static void _read_data(isc_session_t *sp, pduq_t *pq) { pduq_t *opq; debug_called(8); opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1); if(opq != NULL) { if(scsi_decap(sp, opq, pq) != 1) { i_remove_hld(sp, opq); // done pdu_free(sp->isc, opq); } } else xdebug("%d] we lost something itt=%x", sp->sid, ntohl(pq->pdu.ipdu.bhs.itt)); pdu_free(sp->isc, pq); } /* | this is a kludge, | the jury is not back with a veredict, user or kernel */ static void _nop_out(isc_session_t *sp) { pduq_t *pq; nop_out_t *nop_out; debug_called(8); sdebug(4, "cws=%d", sp->cws); if(sp->cws == 0) { /* | only send a nop if window is closed. */ if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) // I guess we ran out of resources return; nop_out = &pq->pdu.ipdu.nop_out; nop_out->opcode = ISCSI_NOP_OUT; nop_out->itt = htonl(sp->sn.itt); nop_out->ttt = -1; nop_out->I = 1; nop_out->F = 1; if(isc_qout(sp, pq) != 0) { sdebug(1, "failed"); pdu_free(sp->isc, pq); } } } static void _nop_in(isc_session_t *sp, pduq_t *pq) { pdu_t *pp = &pq->pdu; nop_in_t *nop_in = &pp->ipdu.nop_in; bhs_t *bhs = &pp->ipdu.bhs; debug_called(8); sdebug(5, "itt=%x ttt=%x", htonl(nop_in->itt), htonl(nop_in->ttt)); if(nop_in->itt == -1) { if(pp->ds_len != 0) { /* | according to RFC 3720 this should be zero | what to do if not? */ xdebug("%d] dslen not zero", sp->sid); } if(nop_in->ttt != -1) { nop_out_t *nop_out; /* | target wants a nop_out */ bhs->opcode = ISCSI_NOP_OUT; bhs->I = 1; bhs->F = 1; /* | we are reusing the pdu, so bhs->ttt == nop_in->ttt; | and need to zero out 'Reserved' | small cludge here. */ nop_out = &pp->ipdu.nop_out; nop_out->sn.maxcmd = 0; memset(nop_out->mbz, 0, sizeof(nop_out->mbz)); (void)isc_qout(sp, pq); //XXX: should check return? return; } //else { // just making noise? // see 10.9.1: target does not want and answer. //} } else if(nop_in->ttt == -1) { /* | it is an answer to a nop_in from us */ if(nop_in->itt != -1) { #ifdef ISC_WAIT4PING // XXX: MUTEX please if(sp->flags & ISC_WAIT4PING) { i_nqueue_rsp(sp, pq); wakeup(&sp->rsp); return; } #endif } } /* | drop it */ pdu_free(sp->isc, pq); return; } int i_prepPDU(isc_session_t *sp, pduq_t *pq) { size_t len, n; pdu_t *pp = &pq->pdu; bhs_t *bhp = &pp->ipdu.bhs; len = sizeof(bhs_t); if(pp->ahs_len) { len += pp->ahs_len; bhp->AHSLength = pp->ahs_len / 4; } if(ISOK2DIG(sp->hdrDigest, pp)) len += 4; if(pp->ds_len) { n = pp->ds_len; len += n; #if BYTE_ORDER == LITTLE_ENDIAN bhp->DSLength = ((n & 0x00ff0000) >> 16) | (n & 0x0000ff00) | ((n & 0x000000ff) << 16); #else bhp->DSLength = n; #endif if(len & 03) { n = 4 - (len & 03); len += n; } if(ISOK2DIG(sp->dataDigest, pp)) len += 4; } pq->len = len; len -= sizeof(bhs_t); if(sp->opt.maxBurstLength && (len > sp->opt.maxBurstLength)) { xdebug("%d] pdu len=%zd > %d", sp->sid, len, sp->opt.maxBurstLength); // XXX: when this happens it used to hang ... return E2BIG; } return 0; } int isc_qout(isc_session_t *sp, pduq_t *pq) { int error = 0; debug_called(8); if(pq->len == 0 && (error = i_prepPDU(sp, pq))) return error; if(pq->pdu.ipdu.bhs.I) i_nqueue_isnd(sp, pq); else if(pq->pdu.ipdu.data_out.opcode == ISCSI_WRITE_DATA) i_nqueue_wsnd(sp, pq); else i_nqueue_csnd(sp, pq); sdebug(5, "enqued: pq=%p", pq); mtx_lock(&sp->io_mtx); sp->flags |= ISC_OQNOTEMPTY; if(sp->flags & ISC_OWAITING) wakeup(&sp->flags); mtx_unlock(&sp->io_mtx); return error; } /* | called when a fullPhase is restarted */ void ism_restart(isc_session_t *sp) { int lastcmd; sdebug(2, "restart ..."); lastcmd = iscsi_requeue(sp); #if 0 if(lastcmd != sp->sn.cmd) { sdebug(1, "resetting CmdSN to=%d (from %d)", lastcmd, sp->sn.cmd); sp->sn.cmd = lastcmd; } #endif mtx_lock(&sp->io_mtx); if(sp->flags & ISC_OWAITING) { wakeup(&sp->flags); } mtx_unlock(&sp->io_mtx); sdebug(2, "restarted sn.cmd=0x%x lastcmd=0x%x", sp->sn.cmd, lastcmd); } void ism_recv(isc_session_t *sp, pduq_t *pq) { bhs_t *bhs; int statSN; debug_called(8); bhs = &pq->pdu.ipdu.bhs; statSN = ntohl(bhs->OpcodeSpecificFields[1]); #ifdef notyet if(sp->sn.expCmd != sn->cmd) { sdebug(1, "we lost something ... exp=0x%x cmd=0x%x", sn->expCmd, sn->cmd); } #endif sdebug(5, "opcode=0x%x itt=0x%x stat#0x%x maxcmd=0x%0x", bhs->opcode, ntohl(bhs->itt), statSN, sp->sn.maxCmd); switch(bhs->opcode) { case ISCSI_READ_DATA: { data_in_t *cmd = &pq->pdu.ipdu.data_in; if(cmd->S == 0) break; } default: if(statSN > (sp->sn.stat + 1)) { sdebug(1, "we lost some rec=0x%x exp=0x%x", statSN, sp->sn.stat); // XXX: must do some error recovery here. } sp->sn.stat = statSN; } switch(bhs->opcode) { case ISCSI_LOGIN_RSP: case ISCSI_TEXT_RSP: case ISCSI_LOGOUT_RSP: i_nqueue_rsp(sp, pq); wakeup(&sp->rsp); sdebug(3, "wakeup rsp"); break; case ISCSI_NOP_IN: _nop_in(sp, pq); break; case ISCSI_SCSI_RSP: _scsi_rsp(sp, pq); break; case ISCSI_READ_DATA: _read_data(sp, pq); break; case ISCSI_R2T: _r2t(sp, pq); break; case ISCSI_REJECT: _reject(sp, pq); break; case ISCSI_ASYNC: _async(sp, pq); break; case ISCSI_TASK_RSP: default: sdebug(1, "opcode=0x%x itt=0x%x not implemented yet", bhs->opcode, ntohl(bhs->itt)); break; } } /* | go through the out queues looking for work | if either nothing to do, or window is closed | return. */ static int proc_out(isc_session_t *sp) { sn_t *sn = &sp->sn; pduq_t *pq; int error, which; debug_called(8); error = 0; while(sp->flags & ISC_LINK_UP) { pdu_t *pp; bhs_t *bhs; /* | check if there is outstanding work in: | 1- the Immediate queue | 2- the R2T queue | 3- the cmd queue, only if the command window allows it. */ which = BIT(0) | BIT(1); if(SNA_GT(sn->cmd, sn->maxCmd) == 0) // if(sn->maxCmd - sn->smc + 1) > 0 which |= BIT(2); sdebug(4, "which=%d sn->maxCmd=%d sn->cmd=%d", which, sn->maxCmd, sn->cmd); if((pq = i_dqueue_snd(sp, which)) == NULL) break; sdebug(4, "pq=%p", pq); pp = &pq->pdu; bhs = &pp->ipdu.bhs; switch(bhs->opcode) { case ISCSI_SCSI_CMD: sn->itt++; bhs->itt = htonl(sn->itt); case ISCSI_LOGIN_CMD: case ISCSI_TEXT_CMD: case ISCSI_LOGOUT_CMD: case ISCSI_SNACK: case ISCSI_NOP_OUT: case ISCSI_TASK_CMD: bhs->CmdSN = htonl(sn->cmd); if(bhs->I == 0) sn->cmd++; case ISCSI_WRITE_DATA: bhs->ExpStSN = htonl(sn->stat + 1); break; default: // XXX: can this happen? xdebug("bad opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", bhs->opcode, sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt); // XXX: and now? } sdebug(4, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", bhs->opcode, sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt); if(bhs->opcode != ISCSI_NOP_OUT) /* | enqued till ack is received | note: sosend(...) does not mean the packet left | the host so that freeing resources has to wait */ i_nqueue_hld(sp, pq); error = isc_sendPDU(sp, pq); if(bhs->opcode == ISCSI_NOP_OUT) pdu_free(sp->isc, pq); if(error) { xdebug("error=%d opcode=0x%x ccb=%p itt=%x", error, bhs->opcode, pq->ccb, ntohl(bhs->itt)); i_remove_hld(sp, pq); switch(error) { case EPIPE: sp->flags &= ~ISC_LINK_UP; case EAGAIN: xdebug("requed"); i_rqueue_pdu(sp, pq); break; default: if(pq->ccb) { xdebug("back to cam"); pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error? - XPT_DONE(sp, pq->ccb); + xpt_done(sp, pq->ccb); pdu_free(sp->isc, pq); } else xdebug("we lost it!"); } } } return error; } /* | survives link breakdowns. */ static void ism_out(void *vp) { isc_session_t *sp = (isc_session_t *)vp; int error; debug_called(8); sp->flags |= ISC_SM_RUNNING; sdebug(3, "started sp->flags=%x", sp->flags); do { if((sp->flags & ISC_HOLD) == 0) { error = proc_out(sp); if(error) { sdebug(3, "error=%d", error); } } mtx_lock(&sp->io_mtx); if((sp->flags & ISC_LINK_UP) == 0) { sdebug(3, "ISC_LINK_UP==0, sp->flags=%x ", sp->flags); if(sp->soc != NULL) sdebug(3, "so_state=%x", sp->soc->so_state); wakeup(&sp->soc); } if(!(sp->flags & ISC_OQNOTEMPTY)) { sp->flags |= ISC_OWAITING; if(msleep(&sp->flags, &sp->io_mtx, PRIBIO, "isc_proc", hz*30) == EWOULDBLOCK) { if(sp->flags & ISC_CON_RUNNING) _nop_out(sp); } sp->flags &= ~ISC_OWAITING; } sp->flags &= ~ISC_OQNOTEMPTY; mtx_unlock(&sp->io_mtx); } while(sp->flags & ISC_SM_RUN); sp->flags &= ~ISC_SM_RUNNING; sdebug(3, "dropped ISC_SM_RUNNING"); wakeup(&sp->soc); wakeup(sp); // XXX: do we need this one? -#if __FreeBSD_version >= 700000 destroy_dev(sp->dev); -#endif debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid); -#if __FreeBSD_version >= 800000 kproc_exit(0); -#else - kthread_exit(0); -#endif } #if 0 static int isc_dump_options(SYSCTL_HANDLER_ARGS) { int error; isc_session_t *sp; struct sbuf sb; sbuf_new_for_sysctl(&sb, NULL, 128, req); sp = (isc_session_t *)arg1; sbuf_printf(&sb, "targetname='%s'", sp->opt.targetName); sbuf_printf(&sb, " targetaddress='%s'", sp->opt.targetAddress); error = sbuf_finish(&sb); sbuf_delete(&sb); return error; } #endif static int isc_dump_stats(SYSCTL_HANDLER_ARGS) { isc_session_t *sp; struct isc_softc *sc; int error; struct sbuf sb; sp = (isc_session_t *)arg1; sc = sp->isc; sbuf_new_for_sysctl(&sb, NULL, 128, req); sbuf_printf(&sb, "recv=%d sent=%d", sp->stats.nrecv, sp->stats.nsent); sbuf_printf(&sb, " flags=0x%08x pdus-alloc=%d pdus-max=%d", sp->flags, sc->npdu_alloc, sc->npdu_max); sbuf_printf(&sb, " cws=%d cmd=%x exp=%x max=%x stat=%x itt=%x", sp->cws, sp->sn.cmd, sp->sn.expCmd, sp->sn.maxCmd, sp->sn.stat, sp->sn.itt); error = sbuf_finish(&sb); sbuf_delete(&sb); return error; } static void isc_add_sysctls(isc_session_t *sp) { debug_called(8); sdebug(6, "sid=%d %s", sp->sid, devtoname(sp->dev)); sysctl_ctx_init(&sp->clist); sp->oid = SYSCTL_ADD_NODE(&sp->clist, SYSCTL_CHILDREN(sp->isc->oid), OID_AUTO, devtoname(sp->dev) + 5, // iscsi0 CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "initiator"); SYSCTL_ADD_PROC(&sp->clist, SYSCTL_CHILDREN(sp->oid), OID_AUTO, "targetname", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, (void *)&sp->opt.targetName, 0, sysctl_handle_string, "A", "target name"); SYSCTL_ADD_PROC(&sp->clist, SYSCTL_CHILDREN(sp->oid), OID_AUTO, "targeaddress", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, (void *)&sp->opt.targetAddress, 0, sysctl_handle_string, "A", "target address"); SYSCTL_ADD_PROC(&sp->clist, SYSCTL_CHILDREN(sp->oid), OID_AUTO, "stats", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, (void *)sp, 0, isc_dump_stats, "A", "statistics"); SYSCTL_ADD_INT(&sp->clist, SYSCTL_CHILDREN(sp->oid), OID_AUTO, "douio", CTLFLAG_RW, &sp->douio, 0, "enable uio on read"); } void ism_stop(isc_session_t *sp) { struct isc_softc *sc = sp->isc; int n; debug_called(8); sdebug(2, "terminating"); /* | first stop the receiver */ isc_stop_receiver(sp); /* | now stop the xmitter */ n = 5; sp->flags &= ~ISC_SM_RUN; while(n-- && (sp->flags & ISC_SM_RUNNING)) { sdebug(2, "n=%d", n); wakeup(&sp->flags); tsleep(sp, PRIBIO, "-", 5*hz); } sdebug(2, "final n=%d", n); sp->flags &= ~ISC_FFPHASE; iscsi_cleanup(sp); (void)i_pdu_flush(sp); ic_destroy(sp); sx_xlock(&sc->unit_sx); free_unr(sc->unit, sp->sid); sx_xunlock(&sc->unit_sx); mtx_lock(&sc->isc_mtx); TAILQ_REMOVE(&sc->isc_sess, sp, sp_link); sc->nsess--; mtx_unlock(&sc->isc_mtx); -#if __FreeBSD_version < 700000 - destroy_dev(sp->dev); -#endif - mtx_destroy(&sp->rsp_mtx); mtx_destroy(&sp->rsv_mtx); mtx_destroy(&sp->hld_mtx); mtx_destroy(&sp->snd_mtx); mtx_destroy(&sp->io_mtx); i_freeopt(&sp->opt); if(sysctl_ctx_free(&sp->clist)) xdebug("sysctl_ctx_free failed"); free(sp, M_ISCSI); } int ism_start(isc_session_t *sp) { debug_called(8); /* | now is a good time to do some initialization */ TAILQ_INIT(&sp->rsp); TAILQ_INIT(&sp->rsv); TAILQ_INIT(&sp->csnd); TAILQ_INIT(&sp->isnd); TAILQ_INIT(&sp->wsnd); TAILQ_INIT(&sp->hld); mtx_init(&sp->rsv_mtx, "iscsi-rsv", NULL, MTX_DEF); mtx_init(&sp->rsp_mtx, "iscsi-rsp", NULL, MTX_DEF); mtx_init(&sp->snd_mtx, "iscsi-snd", NULL, MTX_DEF); mtx_init(&sp->hld_mtx, "iscsi-hld", NULL, MTX_DEF); mtx_init(&sp->io_mtx, "iscsi-io", NULL, MTX_DEF); isc_add_sysctls(sp); sp->flags |= ISC_SM_RUN; debug(4, "starting ism_proc: sp->sid=%d", sp->sid); -#if __FreeBSD_version >= 800000 return kproc_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid); -#else - return kthread_create(ism_out, sp, &sp->stp, 0, 0, "isc_out %d", sp->sid); -#endif -} +a} Index: head/sys/dev/iscsi_initiator/isc_soc.c =================================================================== --- head/sys/dev/iscsi_initiator/isc_soc.c (revision 358492) +++ head/sys/dev/iscsi_initiator/isc_soc.c (revision 358493) @@ -1,701 +1,680 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2010 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* | $Id: isc_soc.c 998 2009-12-20 10:32:45Z danny $ */ #include __FBSDID("$FreeBSD$"); #include "opt_iscsi_initiator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef NO_USE_MBUF #define USE_MBUF #endif #ifdef USE_MBUF static int ou_refcnt = 0; /* | function for freeing external storage for mbuf */ static void ext_free(struct mbuf *m) { pduq_t *pq = m->m_ext.ext_arg1; if(pq->buf != NULL) { debug(3, "ou_refcnt=%d a=%p b=%p", ou_refcnt, m->m_ext.ext_buf, pq->buf); free(pq->buf, M_ISCSIBUF); pq->buf = NULL; } } int isc_sendPDU(isc_session_t *sp, pduq_t *pq) { struct mbuf *mh, **mp; pdu_t *pp = &pq->pdu; int len, error; debug_called(8); /* | mbuf for the iSCSI header */ MGETHDR(mh, M_WAITOK, MT_DATA); mh->m_pkthdr.rcvif = NULL; mh->m_next = NULL; mh->m_len = sizeof(union ipdu_u); if(ISOK2DIG(sp->hdrDigest, pp)) { pp->hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0); mh->m_len += sizeof(pp->hdr_dig); if(pp->ahs_len) { debug(2, "ahs_len=%d", pp->ahs_len); pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig); } debug(3, "pp->hdr_dig=%04x", htonl(pp->hdr_dig)); } if(pp->ahs_len) { /* | Add any AHS to the iSCSI hdr mbuf */ if((mh->m_len + pp->ahs_len) < MHLEN) { M_ALIGN(mh, mh->m_len + pp->ahs_len); bcopy(&pp->ipdu, mh->m_data, mh->m_len); bcopy(pp->ahs_addr, mh->m_data + mh->m_len, pp->ahs_len); mh->m_len += pp->ahs_len; } else panic("len AHS=%d too big, not impleneted yet", pp->ahs_len); } else { M_ALIGN(mh, mh->m_len); bcopy(&pp->ipdu, mh->m_data, mh->m_len); } mh->m_pkthdr.len = mh->m_len; mp = &mh->m_next; if(pp->ds_len && pq->pdu.ds_addr) { struct mbuf *md; int off = 0; len = pp->ds_len; while(len > 0) { int l; MGET(md, M_WAITOK, MT_DATA); md->m_ext.ext_cnt = &ou_refcnt; l = min(MCLBYTES, len); debug(4, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l); m_extadd(md, pp->ds_addr + off, l, ext_free, pq, NULL, 0, EXT_EXTREF); md->m_len = l; md->m_next = NULL; mh->m_pkthdr.len += l; *mp = md; mp = &md->m_next; len -= l; off += l; } if(((pp->ds_len & 03) != 0) || ISOK2DIG(sp->dataDigest, pp)) { MGET(md, M_WAITOK, MT_DATA); if(pp->ds_len & 03) len = 4 - (pp->ds_len & 03); else len = 0; md->m_len = len; if(ISOK2DIG(sp->dataDigest, pp)) md->m_len += sizeof(pp->ds_dig); M_ALIGN(md, md->m_len); if(ISOK2DIG(sp->dataDigest, pp)) { pp->ds_dig = sp->dataDigest(pp->ds_addr, pp->ds_len, 0); if(len) { bzero(md->m_data, len); // RFC says SHOULD be 0 pp->ds_dig = sp->dataDigest(md->m_data, len, pp->ds_dig); } bcopy(&pp->ds_dig, md->m_data+len, sizeof(pp->ds_dig)); } md->m_next = NULL; mh->m_pkthdr.len += md->m_len; *mp = md; } } if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, sp->td)) != 0) { sdebug(2, "error=%d", error); return error; } sp->stats.nsent++; getbintime(&sp->stats.t_sent); return 0; } #else /* NO_USE_MBUF */ int isc_sendPDU(isc_session_t *sp, pduq_t *pq) { struct uio *uio = &pq->uio; struct iovec *iv; pdu_t *pp = &pq->pdu; int len, error; debug_called(8); bzero(uio, sizeof(struct uio)); uio->uio_rw = UIO_WRITE; uio->uio_segflg = UIO_SYSSPACE; uio->uio_td = sp->td; uio->uio_iov = iv = pq->iov; iv->iov_base = &pp->ipdu; iv->iov_len = sizeof(union ipdu_u); uio->uio_resid = iv->iov_len; iv++; if(ISOK2DIG(sp->hdrDigest, pp)) pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0); if(pp->ahs_len) { iv->iov_base = pp->ahs_addr; iv->iov_len = pp->ahs_len; uio->uio_resid += iv->iov_len; iv++; if(ISOK2DIG(sp->hdrDigest, pp)) pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig); } if(ISOK2DIG(sp->hdrDigest, pp)) { debug(3, "hdr_dig=%04x", htonl(pp->hdr_dig)); iv->iov_base = &pp->hdr_dig; iv->iov_len = sizeof(int); uio->uio_resid += iv->iov_len ; iv++; } if(pq->pdu.ds_addr && pp->ds_len) { iv->iov_base = pp->ds_addr; iv->iov_len = pp->ds_len; while(iv->iov_len & 03) // the specs say it must be int aligned iv->iov_len++; uio->uio_resid += iv->iov_len ; iv++; if(ISOK2DIG(sp->dataDigest, pp)) { pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0); iv->iov_base = &pp->ds_dig; iv->iov_len = sizeof(pp->ds_dig); uio->uio_resid += iv->iov_len ; iv++; } } uio->uio_iovcnt = iv - pq->iov; sdebug(4, "pq->len=%d uio->uio_resid=%d uio->uio_iovcnt=%d", pq->len, uio->uio_resid, uio->uio_iovcnt); sdebug(4, "opcode=%x iovcnt=%d uio_resid=%d itt=%x", pp->ipdu.bhs.opcode, uio->uio_iovcnt, uio->uio_resid, ntohl(pp->ipdu.bhs.itt)); sdebug(5, "sp=%p sp->soc=%p uio=%p sp->td=%p", sp, sp->soc, uio, sp->td); do { len = uio->uio_resid; error = sosend(sp->soc, NULL, uio, 0, 0, 0, sp->td); if(uio->uio_resid == 0 || error || len == uio->uio_resid) { if(uio->uio_resid) { sdebug(2, "uio->uio_resid=%d uio->uio_iovcnt=%d error=%d len=%d", uio->uio_resid, uio->uio_iovcnt, error, len); if(error == 0) error = EAGAIN; // 35 } break; } /* | XXX: untested code */ sdebug(1, "uio->uio_resid=%d uio->uio_iovcnt=%d", uio->uio_resid, uio->uio_iovcnt); iv = uio->uio_iov; len -= uio->uio_resid; while(uio->uio_iovcnt > 0) { if(iv->iov_len > len) { caddr_t bp = (caddr_t)iv->iov_base; iv->iov_len -= len; iv->iov_base = (void *)&bp[len]; break; } len -= iv->iov_len; uio->uio_iovcnt--; uio->uio_iov++; iv++; } } while(uio->uio_resid); if(error == 0) { sp->stats.nsent++; getbintime(&sp->stats.t_sent); } return error; } #endif /* USE_MBUF */ /* | wait till a PDU header is received | from the socket. */ /* The format of the BHS is: Byte/ 0 | 1 | 2 | 3 | / | | | | |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| +---------------+---------------+---------------+---------------+ 0|.|I| Opcode |F| Opcode-specific fields | +---------------+---------------+---------------+---------------+ 4|TotalAHSLength | DataSegmentLength | +---------------+---------------+---------------+---------------+ 8| LUN or Opcode-specific fields | + + 12| | +---------------+---------------+---------------+---------------+ 16| Initiator Task Tag | +---------------+---------------+---------------+---------------+ 20/ Opcode-specific fields / +/ / +---------------+---------------+---------------+---------------+ 48 */ static __inline int so_getbhs(isc_session_t *sp) { bhs_t *bhs = &sp->bhs; struct uio *uio = &sp->uio; struct iovec *iov = &sp->iov; int error, flags; debug_called(8); iov->iov_base = bhs; iov->iov_len = sizeof(bhs_t); uio->uio_iov = iov; uio->uio_iovcnt = 1; uio->uio_rw = UIO_READ; uio->uio_segflg = UIO_SYSSPACE; uio->uio_td = curthread; // why ... uio->uio_resid = sizeof(bhs_t); flags = MSG_WAITALL; error = soreceive(sp->soc, NULL, uio, 0, 0, &flags); if(error) debug(2, -#if __FreeBSD_version > 800000 "error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd", -#else - "error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd", -#endif error, sp->soc->so_error, uio->uio_resid, iov->iov_len); if(!error && (uio->uio_resid > 0)) { error = EPIPE; // was EAGAIN debug(2, -#if __FreeBSD_version > 800000 "error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd so_state=%x", -#else - "error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd so_state=%x", -#endif error, sp->soc->so_error, uio->uio_resid, iov->iov_len, sp->soc->so_state); } return error; } /* | so_recv gets called when | an iSCSI header has been received. | Note: the designers had no intentions | in making programmer's life easy. */ static int so_recv(isc_session_t *sp, pduq_t *pq) { sn_t *sn = &sp->sn; struct uio *uio = &pq->uio; pdu_t *pp = &pq->pdu; bhs_t *bhs = &pp->ipdu.bhs; struct iovec *iov = pq->iov; int error; u_int len; u_int max, exp; int flags = MSG_WAITALL; debug_called(8); /* | now calculate how much data should be in the buffer */ uio->uio_iov = iov; uio->uio_iovcnt = 0; len = 0; if(bhs->AHSLength) { debug(2, "bhs->AHSLength=%d", bhs->AHSLength); pp->ahs_len = bhs->AHSLength * 4; len += pp->ahs_len; pp->ahs_addr = malloc(pp->ahs_len, M_TEMP, M_WAITOK); // XXX: could get stuck here iov->iov_base = pp->ahs_addr; iov->iov_len = pp->ahs_len; uio->uio_iovcnt++; iov++; } if(ISOK2DIG(sp->hdrDigest, pp)) { len += sizeof(pp->hdr_dig); iov->iov_base = &pp->hdr_dig; iov->iov_len = sizeof(pp->hdr_dig); uio->uio_iovcnt++; } if(len) { uio->uio_rw = UIO_READ; uio->uio_segflg = UIO_SYSSPACE; uio->uio_resid = len; uio->uio_td = sp->td; // why ... error = soreceive(sp->soc, NULL, uio, NULL, NULL, &flags); //if(error == EAGAIN) // XXX: this needs work! it hangs iscontrol if(error || uio->uio_resid) { debug(2, -#if __FreeBSD_version > 800000 "len=%d error=%d uio->uio_resid=%zd", -#else - "len=%d error=%d uio->uio_resid=%d", -#endif len, error, uio->uio_resid); goto out; } if(ISOK2DIG(sp->hdrDigest, pp)) { bhs_t *bhs; u_int digest; bhs = (bhs_t *)&pp->ipdu; digest = sp->hdrDigest(bhs, sizeof(bhs_t), 0); if(pp->ahs_len) digest = sp->hdrDigest(pp->ahs_addr, pp->ahs_len, digest); if(pp->hdr_dig != digest) { debug(2, "bad header digest: received=%x calculated=%x", pp->hdr_dig, digest); // XXX: now what? error = EIO; goto out; } } if(pp->ahs_len) { debug(2, "ahs len=%x type=%x spec=%x", pp->ahs_addr->len, pp->ahs_addr->type, pp->ahs_addr->spec); // XXX: till I figure out what to do with this free(pp->ahs_addr, M_TEMP); } pq->len += len; // XXX: who needs this? bzero(uio, sizeof(struct uio)); len = 0; } if(bhs->DSLength) { len = bhs->DSLength; #if BYTE_ORDER == LITTLE_ENDIAN len = ((len & 0x00ff0000) >> 16) | (len & 0x0000ff00) | ((len & 0x000000ff) << 16); #endif pp->ds_len = len; if((sp->opt.maxRecvDataSegmentLength > 0) && (len > sp->opt.maxRecvDataSegmentLength)) { xdebug("impossible PDU length(%d) opt.maxRecvDataSegmentLength=%d", len, sp->opt.maxRecvDataSegmentLength); log(LOG_ERR, "so_recv: impossible PDU length(%d) from iSCSI %s/%s\n", len, sp->opt.targetAddress, sp->opt.targetName); /* | XXX: this will really screwup the stream. | should clear up the buffer till a valid header | is found, or just close connection ... | should read the RFC. */ error = E2BIG; goto out; } while(len & 03) len++; if(ISOK2DIG(sp->dataDigest, pp)) len += 4; uio->uio_resid = len; uio->uio_td = sp->td; // why ... pq->len += len; // XXX: do we need this? error = soreceive(sp->soc, NULL, uio, &pq->mp, NULL, &flags); //if(error == EAGAIN) // XXX: this needs work! it hangs iscontrol if(error || uio->uio_resid) goto out; if(ISOK2DIG(sp->dataDigest, pp)) { struct mbuf *m; u_int digest, ds_len, cnt; // get the received digest m_copydata(pq->mp, len - sizeof(pp->ds_dig), sizeof(pp->ds_dig), (caddr_t)&pp->ds_dig); // calculate all mbufs digest = 0; ds_len = len - sizeof(pp->ds_dig); for(m = pq->mp; m != NULL; m = m->m_next) { cnt = MIN(ds_len, m->m_len); digest = sp->dataDigest(mtod(m, char *), cnt, digest); ds_len -= cnt; if(ds_len == 0) break; } if(digest != pp->ds_dig) { sdebug(1, "bad data digest: received=%x calculated=%x", pp->ds_dig, digest); error = EIO; // XXX: find a better error goto out; } KASSERT(ds_len == 0, ("ds_len not zero")); } } sdebug(6, "len=%d] opcode=0x%x ahs_len=0x%x ds_len=0x%x", pq->len, bhs->opcode, pp->ahs_len, pp->ds_len); max = ntohl(bhs->MaxCmdSN); exp = ntohl(bhs->ExpStSN); if(max < exp - 1 && max > exp - _MAXINCR) { sdebug(2, "bad cmd window size"); error = EIO; // XXX: for now; goto out; // error } if(SNA_GT(max, sn->maxCmd)) sn->maxCmd = max; if(SNA_GT(exp, sn->expCmd)) sn->expCmd = exp; /* | remove from the holding queue packets | that have been acked and don't need | further processing. */ i_acked_hld(sp, NULL); sp->cws = sn->maxCmd - sn->expCmd + 1; return 0; out: // XXX: need some work here if(pp->ahs_len) { // XXX: till I figure out what to do with this free(pp->ahs_addr, M_TEMP); } xdebug("have a problem, error=%d", error); pdu_free(sp->isc, pq); if(!error && uio->uio_resid > 0) error = EPIPE; return error; } /* | wait for something to arrive. | and if the pdu is without errors, process it. */ static int so_input(isc_session_t *sp) { pduq_t *pq; int error; debug_called(8); /* | first read in the iSCSI header */ error = so_getbhs(sp); if(error == 0) { /* | now read the rest. */ pq = pdu_alloc(sp->isc, M_NOWAIT); if(pq == NULL) { // XXX: might cause a deadlock ... debug(2, "out of pdus, wait"); pq = pdu_alloc(sp->isc, M_WAITOK); // OK to WAIT } pq->pdu.ipdu.bhs = sp->bhs; pq->len = sizeof(bhs_t); // so far only the header was read error = so_recv(sp, pq); if(error != 0) { error += 0x800; // XXX: just to see the error. // terminal error // XXX: close connection and exit } else { sp->stats.nrecv++; getbintime(&sp->stats.t_recv); ism_recv(sp, pq); } } return error; } /* | one per active (connected) session. | this thread is responsible for reading | in packets from the target. */ static void isc_in(void *vp) { isc_session_t *sp = (isc_session_t *)vp; struct socket *so = sp->soc; int error; debug_called(8); sp->flags |= ISC_CON_RUNNING; error = 0; while((sp->flags & (ISC_CON_RUN | ISC_LINK_UP)) == (ISC_CON_RUN | ISC_LINK_UP)) { // XXX: hunting ... if(sp->soc == NULL || !(so->so_state & SS_ISCONNECTED)) { debug(2, "sp->soc=%p", sp->soc); break; } error = so_input(sp); if(error == 0) { mtx_lock(&sp->io_mtx); if(sp->flags & ISC_OWAITING) { wakeup(&sp->flags); } mtx_unlock(&sp->io_mtx); } else if(error == EPIPE) { break; } else if(error == EAGAIN) { if(so->so_state & SS_ISCONNECTED) // there seems to be a problem in 6.0 ... tsleep(sp, PRIBIO, "isc_soc", 2*hz); } } sdebug(2, "terminated, flags=%x so_count=%d so_state=%x error=%d proc=%p", sp->flags, so->so_count, so->so_state, error, sp->proc); if((sp->proc != NULL) && sp->signal) { PROC_LOCK(sp->proc); kern_psignal(sp->proc, sp->signal); PROC_UNLOCK(sp->proc); sp->flags |= ISC_SIGNALED; sdebug(2, "pid=%d signaled(%d)", sp->proc->p_pid, sp->signal); } else { // we have to do something ourselves // like closing this session ... } /* | we've been terminated */ // do we need this mutex ...? mtx_lock(&sp->io_mtx); sp->flags &= ~(ISC_CON_RUNNING | ISC_LINK_UP); wakeup(&sp->soc); mtx_unlock(&sp->io_mtx); sdebug(2, "dropped ISC_CON_RUNNING"); -#if __FreeBSD_version >= 800000 kproc_exit(0); -#else - kthread_exit(0); -#endif } void isc_stop_receiver(isc_session_t *sp) { int n; debug_called(8); sdebug(3, "sp=%p sp->soc=%p", sp, sp? sp->soc: 0); mtx_lock(&sp->io_mtx); sp->flags &= ~ISC_LINK_UP; msleep(&sp->soc, &sp->io_mtx, PRIBIO|PDROP, "isc_stpc", 5*hz); soshutdown(sp->soc, SHUT_RD); mtx_lock(&sp->io_mtx); sdebug(3, "soshutdown"); sp->flags &= ~ISC_CON_RUN; n = 2; while(n-- && (sp->flags & ISC_CON_RUNNING)) { sdebug(3, "waiting n=%d... flags=%x", n, sp->flags); msleep(&sp->soc, &sp->io_mtx, PRIBIO, "isc_stpc", 5*hz); } mtx_unlock(&sp->io_mtx); if(sp->fp != NULL) fdrop(sp->fp, sp->td); sp->soc = NULL; sp->fp = NULL; sdebug(3, "done"); } void isc_start_receiver(isc_session_t *sp) { debug_called(8); sp->flags |= ISC_CON_RUN | ISC_LINK_UP; -#if __FreeBSD_version >= 800000 - kproc_create -#else - kthread_create -#endif - (isc_in, sp, &sp->soc_proc, 0, 0, "isc_in %d", sp->sid); + kproc_create(isc_in, sp, &sp->soc_proc, 0, 0, "isc_in %d", sp->sid); } Index: head/sys/dev/iscsi_initiator/isc_subr.c =================================================================== --- head/sys/dev/iscsi_initiator/isc_subr.c (revision 358492) +++ head/sys/dev/iscsi_initiator/isc_subr.c (revision 358493) @@ -1,273 +1,175 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2011 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* | iSCSI | $Id: isc_subr.c 560 2009-05-07 07:37:49Z danny $ */ #include __FBSDID("$FreeBSD$"); #include "opt_iscsi_initiator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static MALLOC_DEFINE(M_ISC, "iSC", "iSCSI driver options"); static char * i_strdupin(char *s, size_t maxlen) { size_t len; char *p, *q; p = malloc(maxlen, M_ISC, M_WAITOK); if(copyinstr(s, p, maxlen, &len)) { free(p, M_ISC); return NULL; } q = malloc(len, M_ISC, M_WAITOK); bcopy(p, q, len); free(p, M_ISC); return q; } -#if __FreeBSD_version < 800000 -/*****************************************************************/ -/* */ -/* CRC LOOKUP TABLE */ -/* ================ */ -/* The following CRC lookup table was generated automagically */ -/* by the Rocksoft^tm Model CRC Algorithm Table Generation */ -/* Program V1.0 using the following model parameters: */ -/* */ -/* Width : 4 bytes. */ -/* Poly : 0x1EDC6F41L */ -/* Reverse : TRUE. */ -/* */ -/* For more information on the Rocksoft^tm Model CRC Algorithm, */ -/* see the document titled "A Painless Guide to CRC Error */ -/* Detection Algorithms" by Ross Williams */ -/* (ross@guest.adelaide.edu.au.). This document is likely to be */ -/* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */ -/* */ -/*****************************************************************/ - -static uint32_t crc32Table[256] = { - 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L, - 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL, - 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL, - 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L, - 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL, - 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L, - 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L, - 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL, - 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL, - 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L, - 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L, - 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL, - 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L, - 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL, - 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL, - 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L, - 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L, - 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L, - 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L, - 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L, - 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L, - 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L, - 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L, - 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L, - 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L, - 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L, - 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L, - 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L, - 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L, - 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L, - 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L, - 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L, - 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL, - 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L, - 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L, - 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL, - 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L, - 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL, - 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL, - 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L, - 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L, - 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL, - 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL, - 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L, - 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL, - 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L, - 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L, - 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL, - 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L, - 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL, - 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL, - 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L, - 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL, - 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L, - 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L, - 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL, - 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL, - 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L, - 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L, - 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL, - 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L, - 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL, - 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL, - 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L -}; - -static __inline int -calculate_crc32c(uint32_t crc, const void *buf, size_t size) -{ - const uint8_t *p = buf; - - while (size--) - crc = crc32Table[(crc ^ *p++) & 0xff] ^ (crc >> 8); - return crc; -} -#endif static uint32_t i_crc32c(const void *buf, size_t size, uint32_t crc) { crc = crc ^ 0xffffffff; crc = calculate_crc32c(crc, buf, size); crc = crc ^ 0xffffffff; return crc; } /* | XXX: not finished coding */ int i_setopt(isc_session_t *sp, isc_opt_t *opt) { if(opt->maxRecvDataSegmentLength > 0) { sp->opt.maxRecvDataSegmentLength = opt->maxRecvDataSegmentLength; sdebug(2, "maxRecvDataSegmentLength=%d", sp->opt.maxRecvDataSegmentLength); } if(opt->maxXmitDataSegmentLength > 0) { // danny's RFC sp->opt.maxXmitDataSegmentLength = opt->maxXmitDataSegmentLength; sdebug(2, "opt.maXmitDataSegmentLength=%d", sp->opt.maxXmitDataSegmentLength); } if(opt->maxBurstLength != 0) { sp->opt.maxBurstLength = opt->maxBurstLength; sdebug(2, "opt.maxBurstLength=%d", sp->opt.maxBurstLength); } if(opt->targetAddress != NULL) { if(sp->opt.targetAddress != NULL) free(sp->opt.targetAddress, M_ISC); sp->opt.targetAddress = i_strdupin(opt->targetAddress, 128); sdebug(2, "opt.targetAddress='%s'", sp->opt.targetAddress); } if(opt->targetName != NULL) { if(sp->opt.targetName != NULL) free(sp->opt.targetName, M_ISC); sp->opt.targetName = i_strdupin(opt->targetName, 128); sdebug(2, "opt.targetName='%s'", sp->opt.targetName); } if(opt->initiatorName != NULL) { if(sp->opt.initiatorName != NULL) free(sp->opt.initiatorName, M_ISC); sp->opt.initiatorName = i_strdupin(opt->initiatorName, 128); sdebug(2, "opt.initiatorName='%s'", sp->opt.initiatorName); } if(opt->maxluns > 0) { if(opt->maxluns > ISCSI_MAX_LUNS) sp->opt.maxluns = ISCSI_MAX_LUNS; // silently chop it down ... sp->opt.maxluns = opt->maxluns; sdebug(2, "opt.maxluns=%d", sp->opt.maxluns); } if(opt->headerDigest != NULL) { sdebug(2, "opt.headerDigest='%s'", opt->headerDigest); if(strcmp(opt->headerDigest, "CRC32C") == 0) { sp->hdrDigest = (digest_t *)i_crc32c; sdebug(2, "opt.headerDigest set"); } } if(opt->dataDigest != NULL) { sdebug(2, "opt.dataDigest='%s'", opt->headerDigest); if(strcmp(opt->dataDigest, "CRC32C") == 0) { sp->dataDigest = (digest_t *)i_crc32c; sdebug(2, "opt.dataDigest set"); } } return 0; } void i_freeopt(isc_opt_t *opt) { debug_called(8); if(opt->targetAddress != NULL) { free(opt->targetAddress, M_ISC); opt->targetAddress = NULL; } if(opt->targetName != NULL) { free(opt->targetName, M_ISC); opt->targetName = NULL; } if(opt->initiatorName != NULL) { free(opt->initiatorName, M_ISC); opt->initiatorName = NULL; } } Index: head/sys/dev/iscsi_initiator/iscsi_subr.c =================================================================== --- head/sys/dev/iscsi_initiator/iscsi_subr.c (revision 358492) +++ head/sys/dev/iscsi_initiator/iscsi_subr.c (revision 358493) @@ -1,611 +1,603 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2010 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ /* | $Id: iscsi_subr.c 743 2009-08-08 10:54:53Z danny $ */ #include __FBSDID("$FreeBSD$"); #include "opt_iscsi_initiator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* | Interface to the SCSI layer */ void iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq) { union ccb *ccb = opq->ccb; struct ccb_scsiio *csio = &ccb->csio; pdu_t *opp = &opq->pdu; bhs_t *bhp = &opp->ipdu.bhs; r2t_t *r2t = &pq->pdu.ipdu.r2t; pduq_t *wpq; int error; debug_called(8); sdebug(4, "itt=%x r2tSN=%d bo=%x ddtl=%x W=%d", ntohl(r2t->itt), ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl), opp->ipdu.scsi_req.W); switch(bhp->opcode) { case ISCSI_SCSI_CMD: if(opp->ipdu.scsi_req.W) { data_out_t *cmd; u_int ddtl = ntohl(r2t->ddtl); u_int edtl = ntohl(opp->ipdu.scsi_req.edtlen); u_int bleft, bs, dsn, bo; caddr_t bp = csio->data_ptr; bo = ntohl(r2t->bo); bp += MIN(bo, edtl - ddtl); bleft = ddtl; if(sp->opt.maxXmitDataSegmentLength > 0) // danny's RFC bs = MIN(sp->opt.maxXmitDataSegmentLength, ddtl); else bs = ddtl; dsn = 0; sdebug(4, "edtl=%x ddtl=%x bo=%x dsn=%x bs=%x maxX=%x", edtl, ddtl, bo, dsn, bs, sp->opt.maxXmitDataSegmentLength); while(bleft > 0) { wpq = pdu_alloc(sp->isc, M_NOWAIT); // testing ... if(wpq == NULL) { sdebug(3, "itt=%x r2tSN=%d bo=%x ddtl=%x W=%d", ntohl(r2t->itt), ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl), opp->ipdu.scsi_req.W); sdebug(1, "npdu_max=%d npdu_alloc=%d", sp->isc->npdu_max, sp->isc->npdu_alloc); while((wpq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) { sdebug(2, "waiting..."); -#if __FreeBSD_version >= 700000 pause("isc_r2t", 5*hz); -#else - tsleep(sp->isc, 0, "isc_r2t", 5*hz); -#endif } } cmd = &wpq->pdu.ipdu.data_out; cmd->opcode = ISCSI_WRITE_DATA; cmd->lun[0] = r2t->lun[0]; cmd->lun[1] = r2t->lun[1]; cmd->ttt = r2t->ttt; cmd->itt = r2t->itt; cmd->dsn = htonl(dsn); cmd->bo = htonl(bo); cmd->F = (bs < bleft)? 0: 1; // is this the last one? bs = MIN(bs, bleft); wpq->pdu.ds_len = bs; wpq->pdu.ds_addr = bp; error = isc_qout(sp, wpq); sdebug(6, "bs=%x bo=%x bp=%p dsn=%x error=%d", bs, bo, bp, dsn, error); if(error) break; bo += bs; bp += bs; bleft -= bs; dsn++; } } break; default: // XXX: should not happen ... xdebug("huh? opcode=0x%x", bhp->opcode); } } static int getSenseData(u_int status, union ccb *ccb, pduq_t *pq) { pdu_t *pp = &pq->pdu; struct ccb_scsiio *scsi = (struct ccb_scsiio *)ccb; struct scsi_sense_data *sense = &scsi->sense_data; struct mbuf *m = pq->mp; scsi_rsp_t *cmd = &pp->ipdu.scsi_rsp; caddr_t bp; int sense_len, mustfree = 0; int error_code, sense_key, asc, ascq; bp = mtod(pq->mp, caddr_t); if((sense_len = scsi_2btoul(bp)) == 0) return 0; debug(4, "sense_len=%d", sense_len); /* | according to the specs, the sense data cannot | be larger than 252 ... */ if(sense_len > m->m_len) { bp = malloc(sense_len, M_ISCSI, M_WAITOK); debug(3, "calling i_mbufcopy(len=%d)", sense_len); i_mbufcopy(pq->mp, bp, sense_len); mustfree++; } scsi->scsi_status = status; bcopy(bp+2, sense, min(sense_len, scsi->sense_len)); scsi->sense_resid = 0; if(cmd->flag & (BIT(1)|BIT(2))) scsi->sense_resid = ntohl(pp->ipdu.scsi_rsp.rcnt); scsi_extract_sense_len(sense, scsi->sense_len - scsi->sense_resid, &error_code, &sense_key, &asc, &ascq, /*show_errors*/ 1); debug(3, "sense_len=%d rcnt=%d sense_resid=%d dsl=%d error_code=%x flags=%x", sense_len, ntohl(pp->ipdu.scsi_rsp.rcnt), scsi->sense_resid, pp->ds_len, error_code, sense_key); if(mustfree) free(bp, M_ISCSI); return 1; } /* | Some information is from SAM draft. */ static void _scsi_done(isc_session_t *sp, u_int response, u_int status, union ccb *ccb, pduq_t *pq) { struct ccb_hdr *ccb_h = &ccb->ccb_h; debug_called(8); if(status || response) { sdebug(3, "response=%x status=%x ccb=%p pq=%p", response, status, ccb, pq); if(pq != NULL) sdebug(3, "mp=%p buf=%p len=%d", pq->mp, pq->buf, pq->len); } ccb_h->status = 0; switch(response) { case 0: // Command Completed at Target switch(status) { case 0: // Good, all is ok ccb_h->status = CAM_REQ_CMP; break; case 0x02: // Check Condition if((pq != NULL) && (pq->mp != NULL) && getSenseData(status, ccb, pq)) ccb_h->status |= CAM_AUTOSNS_VALID; case 0x14: // Intermediate-Condition Met case 0x10: // Intermediate case 0x04: // Condition Met ccb_h->status |= CAM_SCSI_STATUS_ERROR; break; case 0x08: ccb_h->status = CAM_BUSY; break; case 0x18: // Reservation Conflict case 0x28: // Task Set Full ccb_h->status = CAM_REQUEUE_REQ; break; default: //case 0x22: // Command Terminated //case 0x30: // ACA Active //case 0x40: // Task Aborted ccb_h->status = CAM_REQ_CMP_ERR; //CAM_REQ_ABORTED; } break; default: if((response >= 0x80) && (response <= 0xFF)) { // Vendor specific ... } case 1: // target failure ccb_h->status = CAM_REQ_CMP_ERR; //CAM_REQ_ABORTED; break; } sdebug(5, "ccb_h->status=%x", ccb_h->status); - XPT_DONE(sp, ccb); + xpt_done(sp, ccb); } /* | returns the lowest cmdseq that was not acked */ int iscsi_requeue(isc_session_t *sp) { pduq_t *pq; u_int i, n, last; debug_called(8); i = last = 0; sp->flags |= ISC_HOLD; while((pq = i_dqueue_hld(sp)) != NULL) { i++; if(pq->ccb != NULL) { _scsi_done(sp, 0, 0x28, pq->ccb, NULL); n = ntohl(pq->pdu.ipdu.bhs.CmdSN); if(last==0 || (last > n)) last = n; sdebug(2, "last=%x n=%x", last, n); } pdu_free(sp->isc, pq); } sp->flags &= ~ISC_HOLD; return i? last: sp->sn.cmd; } int i_pdu_flush(isc_session_t *sp) { int n = 0; pduq_t *pq; debug_called(8); while((pq = i_dqueue_rsp(sp)) != NULL) { pdu_free(sp->isc, pq); n++; } while((pq = i_dqueue_rsv(sp)) != NULL) { pdu_free(sp->isc, pq); n++; } while((pq = i_dqueue_snd(sp, -1)) != NULL) { pdu_free(sp->isc, pq); n++; } while((pq = i_dqueue_hld(sp)) != NULL) { pdu_free(sp->isc, pq); n++; } while((pq = i_dqueue_wsnd(sp)) != NULL) { pdu_free(sp->isc, pq); n++; } if(n != 0) xdebug("%d pdus recovered, should have been ZERO!", n); return n; } /* | called from ism_destroy. */ void iscsi_cleanup(isc_session_t *sp) { pduq_t *pq, *pqtmp; debug_called(8); TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, pqtmp) { sdebug(3, "hld pq=%p", pq); if(pq->ccb) _scsi_done(sp, 1, 0x40, pq->ccb, NULL); TAILQ_REMOVE(&sp->hld, pq, pq_link); if(pq->buf) { free(pq->buf, M_ISCSIBUF); pq->buf = NULL; } pdu_free(sp->isc, pq); } while((pq = i_dqueue_snd(sp, BIT(0)|BIT(1)|BIT(2))) != NULL) { sdebug(3, "pq=%p", pq); if(pq->ccb) _scsi_done(sp, 1, 0x40, pq->ccb, NULL); if(pq->buf) { free(pq->buf, M_ISCSIBUF); pq->buf = NULL; } pdu_free(sp->isc, pq); } wakeup(&sp->rsp); } void iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq) { pdu_t *pp = &pq->pdu; scsi_rsp_t *cmd = &pp->ipdu.scsi_rsp; debug_called(8); _scsi_done(sp, cmd->response, cmd->status, opq->ccb, pq); pdu_free(sp->isc, opq); } // see RFC 3720, 10.9.1 page 146 /* | NOTE: | the call to isc_stop_receiver is a kludge, | instead, it should be handled by the userland controller, | but that means that there should be a better way, other than | sending a signal. Somehow, this packet should be supplied to | the userland via read. */ void iscsi_async(isc_session_t *sp, pduq_t *pq) { pdu_t *pp = &pq->pdu; async_t *cmd = &pp->ipdu.async; debug_called(8); sdebug(3, "asyncevent=0x%x asyncVCode=0x%0x", cmd->asyncEvent, cmd->asyncVCode); switch(cmd->asyncEvent) { case 0: // check status ... break; case 1: // target request logout isc_stop_receiver(sp); // XXX: temporary solution break; case 2: // target indicates it wants to drop connection isc_stop_receiver(sp); // XXX: temporary solution break; case 3: // target indicates it will drop all connections. isc_stop_receiver(sp); // XXX: temporary solution break; case 4: // target request parameter negotiation break; default: break; } } void iscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq) { union ccb *ccb = opq->ccb; //reject_t *reject = &pq->pdu.ipdu.reject; debug_called(8); //XXX: check RFC 10.17.1 (page 176) ccb->ccb_h.status = CAM_REQ_ABORTED; - XPT_DONE(sp, ccb); + xpt_done(sp, ccb); pdu_free(sp->isc, opq); } /* | deal with lun */ static int dwl(isc_session_t *sp, int lun, u_char *lp) { debug_called(8); sdebug(4, "lun=%d", lun); /* | mapping LUN to iSCSI LUN | check the SAM-2 specs | hint: maxLUNS is a small number, cam's LUN is 32bits | iSCSI is 64bits, scsi is ? */ // XXX: check if this will pass the endian test if(lun < 256) { lp[0] = 0; lp[1] = lun; } else if(lun < 16384) { lp[0] = (1 << 5) | ((lun >> 8) & 0x3f); lp[1] = lun & 0xff; } else { xdebug("lun %d: is unsupported!", lun); return -1; } return 0; } /* | encapsulate the scsi command and */ int scsi_encap(struct cam_sim *sim, union ccb *ccb) { isc_session_t *sp = cam_sim_softc(sim); struct ccb_scsiio *csio = &ccb->csio; struct ccb_hdr *ccb_h = &ccb->ccb_h; pduq_t *pq; scsi_req_t *cmd; debug_called(8); debug(4, "ccb->sp=%p", ccb_h->spriv_ptr0); sp = ccb_h->spriv_ptr0; if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) { debug(2, "ccb->sp=%p", ccb_h->spriv_ptr0); sdebug(1, "pdu_alloc failed sc->npdu_max=%d npdu_alloc=%d", sp->isc->npdu_max, sp->isc->npdu_alloc); while((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) { sdebug(2, "waiting..."); -#if __FreeBSD_version >= 700000 pause("isc_encap", 5*hz); -#else - tsleep(sp->isc, 0, "isc_encap", 5*hz); -#endif } } cmd = &pq->pdu.ipdu.scsi_req; cmd->opcode = ISCSI_SCSI_CMD; cmd->F = 1; #if 0 // this breaks at least Isilon's iscsi target. /* | map tag option, default is UNTAGGED */ switch(csio->tag_action) { case MSG_SIMPLE_Q_TAG: cmd->attr = iSCSI_TASK_SIMPLE; break; case MSG_HEAD_OF_Q_TAG: cmd->attr = iSCSI_TASK_HOFQ; break; case MSG_ORDERED_Q_TAG: cmd->attr = iSCSI_TASK_ORDER; break; case MSG_ACA_TASK: cmd->attr = iSCSI_TASK_ACA; break; } #else cmd->attr = iSCSI_TASK_SIMPLE; #endif dwl(sp, ccb_h->target_lun, (u_char *)&cmd->lun); if((ccb_h->flags & CAM_CDB_POINTER) != 0) { if((ccb_h->flags & CAM_CDB_PHYS) == 0) { if(csio->cdb_len > 16) { sdebug(3, "oversize cdb %d > 16", csio->cdb_len); goto invalid; } } else { sdebug(3, "not phys"); goto invalid; } } if(csio->cdb_len > sizeof(cmd->cdb)) xdebug("guevalt! %d > %ld", csio->cdb_len, (long)sizeof(cmd->cdb)); memcpy(cmd->cdb, ccb_h->flags & CAM_CDB_POINTER? csio->cdb_io.cdb_ptr: csio->cdb_io.cdb_bytes, csio->cdb_len); cmd->W = (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT; cmd->R = (ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN; cmd->edtlen = htonl(csio->dxfer_len); pq->ccb = ccb; /* | place it in the out queue */ if(isc_qout(sp, pq) == 0) return 1; invalid: ccb->ccb_h.status = CAM_REQ_INVALID; pdu_free(sp->isc, pq); return 0; } int scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq) { union ccb *ccb = opq->ccb; struct ccb_scsiio *csio = &ccb->csio; pdu_t *opp = &opq->pdu; bhs_t *bhp = &opp->ipdu.bhs; debug_called(8); sdebug(6, "pq=%p opq=%p bhp->opcode=0x%x len=%d", pq, opq, bhp->opcode, pq->pdu.ds_len); if(ccb == NULL) { sdebug(1, "itt=0x%x pq=%p opq=%p bhp->opcode=0x%x len=%d", ntohl(pq->pdu.ipdu.bhs.itt), pq, opq, bhp->opcode, pq->pdu.ds_len); xdebug("%d] ccb == NULL!", sp->sid); return 0; } if(pq->pdu.ds_len != 0) { switch(bhp->opcode) { case ISCSI_SCSI_CMD: { scsi_req_t *cmd = &opp->ipdu.scsi_req; sdebug(5, "itt=0x%x opcode=%x R=%d", ntohl(pq->pdu.ipdu.bhs.itt), pq->pdu.ipdu.bhs.opcode, cmd->R); switch(pq->pdu.ipdu.bhs.opcode) { case ISCSI_READ_DATA: // SCSI Data in { caddr_t bp = NULL; // = mtod(pq->mp, caddr_t); data_in_t *rcmd = &pq->pdu.ipdu.data_in; if(cmd->R) { sdebug(5, "copy to=%p from=%p l1=%d l2=%d mp@%p", csio->data_ptr, bp? mtod(pq->mp, caddr_t): 0, ntohl(cmd->edtlen), pq->pdu.ds_len, pq->mp); if(ntohl(cmd->edtlen) >= pq->pdu.ds_len) { int offset, len = pq->pdu.ds_len; if(pq->mp != NULL) { caddr_t dp; offset = ntohl(rcmd->bo); dp = csio->data_ptr + offset; i_mbufcopy(pq->mp, dp, len); } } else { xdebug("edtlen=%d < ds_len=%d", ntohl(cmd->edtlen), pq->pdu.ds_len); } } if(rcmd->S) { /* | contains also the SCSI Status */ _scsi_done(sp, 0, rcmd->status, opq->ccb, NULL); return 0; } else return 1; } break; } } default: sdebug(3, "opcode=%02x", bhp->opcode); break; } } /* | XXX: error ... */ return 1; } Index: head/sys/dev/iscsi_initiator/iscsivar.h =================================================================== --- head/sys/dev/iscsi_initiator/iscsivar.h (revision 358492) +++ head/sys/dev/iscsi_initiator/iscsivar.h (revision 358493) @@ -1,604 +1,571 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2005-2011 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* | $Id: iscsivar.h 743 2009-08-08 10:54:53Z danny $ */ #include #include #define ISCSI_MAX_LUNS 128 // don't touch this #if ISCSI_MAX_LUNS > 8 /* | for this to work | sysctl kern.cam.cam_srch_hi=1 */ #endif #ifndef ISCSI_INITIATOR_DEBUG #define ISCSI_INITIATOR_DEBUG 1 #endif #ifdef ISCSI_INITIATOR_DEBUG extern int iscsi_debug; #define debug(level, fmt, args...) do {if(level <= iscsi_debug)\ printf("%s: " fmt "\n", __func__ , ##args);} while(0) #define sdebug(level, fmt, args...) do {if(level <= iscsi_debug)\ printf("%d] %s: " fmt "\n", sp->sid, __func__ , ##args);} while(0) #define debug_called(level) do {if(level <= iscsi_debug)\ printf("%s: called\n", __func__);} while(0) #else #define debug(level, fmt, args...) #define debug_called(level) #define sdebug(level, fmt, args...) #endif /* ISCSI_INITIATOR_DEBUG */ #define xdebug(fmt, args...) printf(">>> %s: " fmt "\n", __func__ , ##args) #define MAX_SESSIONS ISCSI_MAX_TARGETS #define MAX_PDUS (MAX_SESSIONS*256) // XXX: at the moment this is arbitrary typedef uint32_t digest_t(const void *, int len, uint32_t ocrc); MALLOC_DECLARE(M_ISCSI); MALLOC_DECLARE(M_ISCSIBUF); #define ISOK2DIG(dig, pp) ((dig != NULL) && ((pp->ipdu.bhs.opcode & 0x1f) != ISCSI_LOGIN_CMD)) #ifndef BIT #define BIT(n) (1 <<(n)) #endif #define ISC_SM_RUN BIT(0) #define ISC_SM_RUNNING BIT(1) #define ISC_LINK_UP BIT(2) #define ISC_CON_RUN BIT(3) #define ISC_CON_RUNNING BIT(4) #define ISC_KILL BIT(5) #define ISC_OQNOTEMPTY BIT(6) #define ISC_OWAITING BIT(7) #define ISC_FFPHASE BIT(8) #define ISC_CAMDEVS BIT(9) #define ISC_SCANWAIT BIT(10) #define ISC_MEMWAIT BIT(11) #define ISC_SIGNALED BIT(12) #define ISC_HOLD BIT(15) #define ISC_HOLDED BIT(16) #define ISC_SHUTDOWN BIT(31) /* | some stats */ struct i_stats { int npdu; // number of pdus malloc'ed. int nrecv; // unprocessed received pdus int nsent; // sent pdus int nrsp, max_rsp; int nrsv, max_rsv; int ncsnd, max_csnd; int nisnd, max_isnd; int nwsnd, max_wsnd; int nhld, max_hld; struct bintime t_sent; struct bintime t_recv; }; /* | one per 'session' */ typedef TAILQ_HEAD(, pduq) queue_t; typedef struct isc_session { TAILQ_ENTRY(isc_session) sp_link; int flags; struct cdev *dev; struct socket *soc; struct file *fp; struct thread *td; struct proc *proc; // the userland process int signal; struct proc *soc_proc; struct proc *stp; // the sm thread struct isc_softc *isc; digest_t *hdrDigest; // the digest alg. if any digest_t *dataDigest; // the digest alg. if any int sid; // Session ID sn_t sn; // sequence number stuff; int cws; // current window size int target_nluns; // this and target_lun are // hopefully temporal till I // figure out a better way. int target_lun[ISCSI_MAX_LUNS/(sizeof(int)*8) + 1]; struct mtx rsp_mtx; struct mtx rsv_mtx; struct mtx snd_mtx; struct mtx hld_mtx; struct mtx io_mtx; queue_t rsp; queue_t rsv; queue_t csnd; queue_t isnd; queue_t wsnd; queue_t hld; isc_opt_t opt; // negotiable values struct i_stats stats; bhs_t bhs; struct uio uio; struct iovec iov; /* | cam stuff */ struct cam_sim *cam_sim; struct cam_path *cam_path; struct mtx cam_mtx; /* | sysctl stuff */ struct sysctl_ctx_list clist; struct sysctl_oid *oid; int douio; //XXX: turn on/off uio on read } isc_session_t; typedef struct pduq { TAILQ_ENTRY(pduq) pq_link; caddr_t buf; u_int len; // the total length of the pdu pdu_t pdu; union ccb *ccb; struct uio uio; struct iovec iov[5]; // XXX: careful ... struct mbuf *mp; struct bintime ts; queue_t *pduq; } pduq_t; /* */ struct isc_softc { struct mtx isc_mtx; TAILQ_HEAD(,isc_session) isc_sess; int nsess; struct cdev *dev; char isid[6]; // Initiator Session ID (48 bits) struct unrhdr *unit; struct sx unit_sx; uma_zone_t pdu_zone; // pool of free pdu's TAILQ_HEAD(,pduq) freepdu; #ifdef ISCSI_INITIATOR_DEBUG int npdu_alloc, npdu_max; // for instrumentation #endif #ifdef DO_EVENTHANDLER eventhandler_tag eh; #endif /* | sysctl stuff */ struct sysctl_ctx_list clist; struct sysctl_oid *oid; }; #ifdef ISCSI_INITIATOR_DEBUG extern struct mtx iscsi_dbg_mtx; #endif void isc_start_receiver(isc_session_t *sp); void isc_stop_receiver(isc_session_t *sp); int isc_sendPDU(isc_session_t *sp, pduq_t *pq); int isc_qout(isc_session_t *sp, pduq_t *pq); int i_prepPDU(isc_session_t *sp, pduq_t *pq); int ism_fullfeature(struct cdev *dev, int flag); int i_pdu_flush(isc_session_t *sc); int i_setopt(isc_session_t *sp, isc_opt_t *opt); void i_freeopt(isc_opt_t *opt); int ic_init(isc_session_t *sp); void ic_destroy(isc_session_t *sp); void ic_lost_target(isc_session_t *sp, int target); int ic_getCamVals(isc_session_t *sp, iscsi_cam_t *cp); void ism_recv(isc_session_t *sp, pduq_t *pq); int ism_start(isc_session_t *sp); void ism_restart(isc_session_t *sp); void ism_stop(isc_session_t *sp); int scsi_encap(struct cam_sim *sim, union ccb *ccb); int scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq); void iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq); void iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq); void iscsi_reject(isc_session_t *sp, pduq_t *opq, pduq_t *pq); void iscsi_async(isc_session_t *sp, pduq_t *pq); void iscsi_cleanup(isc_session_t *sp); int iscsi_requeue(isc_session_t *sp); // Serial Number Arithmetic #define _MAXINCR 0x7FFFFFFF // 2 ^ 31 - 1 #define SNA_GT(i1, i2) ((i1 != i2) && (\ (i1 < i2 && i2 - i1 > _MAXINCR) ||\ (i1 > i2 && i1 - i2 < _MAXINCR))?1: 0) /* | inlines */ -#ifdef _CAM_CAM_XPT_SIM_H - -#if __FreeBSD_version < 600000 -#define CAM_LOCK(arg) -#define CAM_ULOCK(arg) - -static __inline void -XPT_DONE(isc_session_t *sp, union ccb *ccb) -{ - mtx_lock(&Giant); - xpt_done(ccb); - mtx_unlock(&Giant); -} -#elif __FreeBSD_version >= 700000 -#define CAM_LOCK(arg) mtx_lock(&arg->cam_mtx) -#define CAM_UNLOCK(arg) mtx_unlock(&arg->cam_mtx) - -static __inline void -XPT_DONE(isc_session_t *sp, union ccb *ccb) -{ - CAM_LOCK(sp); - xpt_done(ccb); - CAM_UNLOCK(sp); -} -#else -//__FreeBSD_version >= 600000 -#define CAM_LOCK(arg) -#define CAM_UNLOCK(arg) -#define XPT_DONE(ignore, arg) xpt_done(arg) -#endif - -#endif /* _CAM_CAM_XPT_SIM_H */ - static __inline pduq_t * pdu_alloc(struct isc_softc *isc, int wait) { pduq_t *pq; pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/); if(pq == NULL) { debug(7, "out of mem"); return NULL; } #ifdef ISCSI_INITIATOR_DEBUG mtx_lock(&iscsi_dbg_mtx); isc->npdu_alloc++; if(isc->npdu_alloc > isc->npdu_max) isc->npdu_max = isc->npdu_alloc; mtx_unlock(&iscsi_dbg_mtx); #endif memset(pq, 0, sizeof(pduq_t)); return pq; } static __inline void pdu_free(struct isc_softc *isc, pduq_t *pq) { if(pq->mp) m_freem(pq->mp); #ifdef NO_USE_MBUF if(pq->buf != NULL) free(pq->buf, M_ISCSIBUF); #endif uma_zfree(isc->pdu_zone, pq); #ifdef ISCSI_INITIATOR_DEBUG mtx_lock(&iscsi_dbg_mtx); isc->npdu_alloc--; mtx_unlock(&iscsi_dbg_mtx); #endif } static __inline void i_nqueue_rsp(isc_session_t *sp, pduq_t *pq) { mtx_lock(&sp->rsp_mtx); if(++sp->stats.nrsp > sp->stats.max_rsp) sp->stats.max_rsp = sp->stats.nrsp; TAILQ_INSERT_TAIL(&sp->rsp, pq, pq_link); mtx_unlock(&sp->rsp_mtx); } static __inline pduq_t * i_dqueue_rsp(isc_session_t *sp) { pduq_t *pq; mtx_lock(&sp->rsp_mtx); if((pq = TAILQ_FIRST(&sp->rsp)) != NULL) { sp->stats.nrsp--; TAILQ_REMOVE(&sp->rsp, pq, pq_link); } mtx_unlock(&sp->rsp_mtx); return pq; } static __inline void i_nqueue_rsv(isc_session_t *sp, pduq_t *pq) { mtx_lock(&sp->rsv_mtx); if(++sp->stats.nrsv > sp->stats.max_rsv) sp->stats.max_rsv = sp->stats.nrsv; TAILQ_INSERT_TAIL(&sp->rsv, pq, pq_link); mtx_unlock(&sp->rsv_mtx); } static __inline pduq_t * i_dqueue_rsv(isc_session_t *sp) { pduq_t *pq; mtx_lock(&sp->rsv_mtx); if((pq = TAILQ_FIRST(&sp->rsv)) != NULL) { sp->stats.nrsv--; TAILQ_REMOVE(&sp->rsv, pq, pq_link); } mtx_unlock(&sp->rsv_mtx); return pq; } static __inline void i_nqueue_csnd(isc_session_t *sp, pduq_t *pq) { mtx_lock(&sp->snd_mtx); if(++sp->stats.ncsnd > sp->stats.max_csnd) sp->stats.max_csnd = sp->stats.ncsnd; TAILQ_INSERT_TAIL(&sp->csnd, pq, pq_link); mtx_unlock(&sp->snd_mtx); } static __inline pduq_t * i_dqueue_csnd(isc_session_t *sp) { pduq_t *pq; mtx_lock(&sp->snd_mtx); if((pq = TAILQ_FIRST(&sp->csnd)) != NULL) { sp->stats.ncsnd--; TAILQ_REMOVE(&sp->csnd, pq, pq_link); } mtx_unlock(&sp->snd_mtx); return pq; } static __inline void i_nqueue_isnd(isc_session_t *sp, pduq_t *pq) { mtx_lock(&sp->snd_mtx); if(++sp->stats.nisnd > sp->stats.max_isnd) sp->stats.max_isnd = sp->stats.nisnd; TAILQ_INSERT_TAIL(&sp->isnd, pq, pq_link); mtx_unlock(&sp->snd_mtx); } static __inline pduq_t * i_dqueue_isnd(isc_session_t *sp) { pduq_t *pq; mtx_lock(&sp->snd_mtx); if((pq = TAILQ_FIRST(&sp->isnd)) != NULL) { sp->stats.nisnd--; TAILQ_REMOVE(&sp->isnd, pq, pq_link); } mtx_unlock(&sp->snd_mtx); return pq; } static __inline void i_nqueue_wsnd(isc_session_t *sp, pduq_t *pq) { mtx_lock(&sp->snd_mtx); if(++sp->stats.nwsnd > sp->stats.max_wsnd) sp->stats.max_wsnd = sp->stats.nwsnd; TAILQ_INSERT_TAIL(&sp->wsnd, pq, pq_link); mtx_unlock(&sp->snd_mtx); } static __inline pduq_t * i_dqueue_wsnd(isc_session_t *sp) { pduq_t *pq; mtx_lock(&sp->snd_mtx); if((pq = TAILQ_FIRST(&sp->wsnd)) != NULL) { sp->stats.nwsnd--; TAILQ_REMOVE(&sp->wsnd, pq, pq_link); } mtx_unlock(&sp->snd_mtx); return pq; } static __inline pduq_t * i_dqueue_snd(isc_session_t *sp, int which) { pduq_t *pq; pq = NULL; mtx_lock(&sp->snd_mtx); if((which & BIT(0)) && (pq = TAILQ_FIRST(&sp->isnd)) != NULL) { sp->stats.nisnd--; TAILQ_REMOVE(&sp->isnd, pq, pq_link); pq->pduq = &sp->isnd; // remember where you came from } else if((which & BIT(1)) && (pq = TAILQ_FIRST(&sp->wsnd)) != NULL) { sp->stats.nwsnd--; TAILQ_REMOVE(&sp->wsnd, pq, pq_link); pq->pduq = &sp->wsnd; // remember where you came from } else if((which & BIT(2)) && (pq = TAILQ_FIRST(&sp->csnd)) != NULL) { sp->stats.ncsnd--; TAILQ_REMOVE(&sp->csnd, pq, pq_link); pq->pduq = &sp->csnd; // remember where you came from } mtx_unlock(&sp->snd_mtx); return pq; } static __inline void i_rqueue_pdu(isc_session_t *sp, pduq_t *pq) { mtx_lock(&sp->snd_mtx); KASSERT(pq->pduq != NULL, ("pq->pduq is NULL")); TAILQ_INSERT_TAIL(pq->pduq, pq, pq_link); mtx_unlock(&sp->snd_mtx); } /* | Waiting for ACK (or something :-) */ static __inline void i_nqueue_hld(isc_session_t *sp, pduq_t *pq) { getbintime(&pq->ts); mtx_lock(&sp->hld_mtx); if(++sp->stats.nhld > sp->stats.max_hld) sp->stats.max_hld = sp->stats.nhld; TAILQ_INSERT_TAIL(&sp->hld, pq, pq_link); mtx_unlock(&sp->hld_mtx); return; } static __inline void i_remove_hld(isc_session_t *sp, pduq_t *pq) { mtx_lock(&sp->hld_mtx); sp->stats.nhld--; TAILQ_REMOVE(&sp->hld, pq, pq_link); mtx_unlock(&sp->hld_mtx); } static __inline pduq_t * i_dqueue_hld(isc_session_t *sp) { pduq_t *pq; mtx_lock(&sp->hld_mtx); if((pq = TAILQ_FIRST(&sp->hld)) != NULL) { sp->stats.nhld--; TAILQ_REMOVE(&sp->hld, pq, pq_link); } mtx_unlock(&sp->hld_mtx); return pq; } static __inline pduq_t * i_search_hld(isc_session_t *sp, int itt, int keep) { pduq_t *pq, *tmp; pq = NULL; mtx_lock(&sp->hld_mtx); TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) { if(pq->pdu.ipdu.bhs.itt == itt) { if(!keep) { sp->stats.nhld--; TAILQ_REMOVE(&sp->hld, pq, pq_link); } break; } } mtx_unlock(&sp->hld_mtx); return pq; } static __inline void i_acked_hld(isc_session_t *sp, pdu_t *op) { pduq_t *pq, *tmp; u_int exp = sp->sn.expCmd; pq = NULL; mtx_lock(&sp->hld_mtx); TAILQ_FOREACH_SAFE(pq, &sp->hld, pq_link, tmp) { if((op && op->ipdu.bhs.itt == pq->pdu.ipdu.bhs.itt) || (pq->ccb == NULL && (pq->pdu.ipdu.bhs.opcode != ISCSI_WRITE_DATA) && SNA_GT(exp, ntohl(pq->pdu.ipdu.bhs.ExpStSN)))) { sp->stats.nhld--; TAILQ_REMOVE(&sp->hld, pq, pq_link); pdu_free(sp->isc, pq); } } mtx_unlock(&sp->hld_mtx); } static __inline void i_mbufcopy(struct mbuf *mp, caddr_t dp, int len) { struct mbuf *m; caddr_t bp; for(m = mp; m != NULL; m = m->m_next) { bp = mtod(m, caddr_t); /* | the pdu is word (4 octed) aligned | so len <= packet */ memcpy(dp, bp, MIN(len, m->m_len)); dp += m->m_len; len -= m->m_len; if(len <= 0) break; } }