diff --git a/qla_isp/common/isp.c b/qla_isp/common/isp.c index 7949fe07d..76ab50787 100644 --- a/qla_isp/common/isp.c +++ b/qla_isp/common/isp.c @@ -4316,12 +4316,12 @@ int isp_start(XS_T *xs) { ispsoftc_t *isp; - uint32_t nxti, optr, handle; + uint32_t handle; uint8_t local[QENTRY_LEN]; - ispreq_t *reqp, *qep; - void *cdbp; + ispreq_t *reqp; + void *cdbp, *qep; uint16_t *tptr; - int target, i, hdlidx = 0; + int target, dmaresult, hdlidx = 0; XS_INITERR(xs); isp = XS_ISP(xs); @@ -4344,9 +4344,7 @@ isp_start(XS_T *xs) */ if (XS_CDBLEN(xs) > (IS_FC(isp)? 16 : 44) || XS_CDBLEN(xs) == 0) { - isp_prt(isp, ISP_LOGERR, - "unsupported cdb length (%d, CDB[0]=0x%x)", - XS_CDBLEN(xs), XS_CDBP(xs)[0] & 0xff); + isp_prt(isp, ISP_LOGERR, "unsupported cdb length (%d, CDB[0]=0x%x)", XS_CDBLEN(xs), XS_CDBP(xs)[0] & 0xff); XS_SETERR(xs, HBA_BOTCH); return (CMD_COMPLETE); } @@ -4378,8 +4376,7 @@ isp_start(XS_T *xs) } hdlidx = fcp->isp_dev_map[XS_TGT(xs)] - 1; - isp_prt(isp, ISP_LOGDEBUG1, "XS_TGT(xs)=%d- hdlidx value %d", - XS_TGT(xs), hdlidx); + isp_prt(isp, ISP_LOGDEBUG2, "XS_TGT(xs)=%d- hdlidx value %d", XS_TGT(xs), hdlidx); if (hdlidx < 0 || hdlidx >= MAX_FC_TARG) { XS_SETERR(xs, HBA_SELTIMEOUT); return (CMD_COMPLETE); @@ -4405,11 +4402,13 @@ isp_start(XS_T *xs) start_again: - if (isp_getrqentry(isp, &nxti, &optr, (void *)&qep)) { + qep = isp_getrqentry(isp); + if (qep == NULL) { isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow"); XS_SETERR(xs, HBA_BOTCH); return (CMD_EAGAIN); } + XS_SETERR(xs, HBA_NOERROR); /* * Now see if we need to synchronize the ISP with respect to anything. @@ -4417,39 +4416,38 @@ isp_start(XS_T *xs) * than which we got here to send a command to. */ reqp = (ispreq_t *) local; + ISP_MEMZERO(local, QENTRY_LEN); if (ISP_TST_SENDMARKER(isp, XS_CHANNEL(xs))) { if (IS_24XX(isp)) { - isp_marker_24xx_t *m = (isp_marker_24xx_t *) qep; - ISP_MEMZERO(m, QENTRY_LEN); + isp_marker_24xx_t *m = (isp_marker_24xx_t *) reqp; m->mrk_header.rqs_entry_count = 1; m->mrk_header.rqs_entry_type = RQSTYPE_MARKER; m->mrk_modifier = SYNC_ALL; - isp_put_marker_24xx(isp, m, (isp_marker_24xx_t *)qep); + isp_put_marker_24xx(isp, m, qep); } else { - isp_marker_t *m = (isp_marker_t *) qep; - ISP_MEMZERO(m, QENTRY_LEN); + isp_marker_t *m = (isp_marker_t *) reqp; m->mrk_header.rqs_entry_count = 1; m->mrk_header.rqs_entry_type = RQSTYPE_MARKER; m->mrk_target = (XS_CHANNEL(xs) << 7); /* bus # */ m->mrk_modifier = SYNC_ALL; - isp_put_marker(isp, m, (isp_marker_t *) qep); + isp_put_marker(isp, m, qep); } - ISP_ADD_REQUEST(isp, nxti); + ISP_SYNC_REQUEST(isp); ISP_SET_SENDMARKER(isp, XS_CHANNEL(xs), 0); goto start_again; } - ISP_MEMZERO((void *)reqp, QENTRY_LEN); reqp->req_header.rqs_entry_count = 1; if (IS_24XX(isp)) { reqp->req_header.rqs_entry_type = RQSTYPE_T7RQS; } else if (IS_FC(isp)) { reqp->req_header.rqs_entry_type = RQSTYPE_T2RQS; } else { - if (XS_CDBLEN(xs) > 12) + if (XS_CDBLEN(xs) > 12) { reqp->req_header.rqs_entry_type = RQSTYPE_CMDONLY; - else + } else { reqp->req_header.rqs_entry_type = RQSTYPE_REQUEST; + } } /* reqp->req_header.rqs_flags = 0; */ /* reqp->req_header.rqs_seqno = 0; */ @@ -4497,8 +4495,7 @@ isp_start(XS_T *xs) } } else { sdparam *sdp = SDPARAM(isp, XS_CHANNEL(xs)); - if ((sdp->isp_devparam[target].actv_flags & DPARM_TQING) && - XS_TAG_P(xs)) { + if ((sdp->isp_devparam[target].actv_flags & DPARM_TQING) && XS_TAG_P(xs)) { reqp->req_flags = XS_TAG_TYPE(xs); } } @@ -4553,24 +4550,21 @@ isp_start(XS_T *xs) reqp->req_handle = handle; /* - * Set up DMA and/or do any bus swizzling of the request entry + * Set up DMA and/or do any platform dependent swizzling of the request entry * so that the Qlogic F/W understands what is being asked of it. + * + * The callee is responsible for adding all requests at this point. */ - i = ISP_DMASETUP(isp, xs, reqp, &nxti, optr); - if (i != CMD_QUEUED) { + dmaresult = ISP_DMASETUP(isp, xs, reqp); + if (dmaresult != CMD_QUEUED) { isp_destroy_handle(isp, handle); /* * dmasetup sets actual error in packet, and * return what we were given to return. */ - return (i); + return (dmaresult); } - XS_SETERR(xs, HBA_NOERROR); - isp_prt(isp, ISP_LOGDEBUG0, - "START cmd for %d.%d.%d cmd 0x%x datalen %ld", - XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), XS_CDBP(xs)[0], - (long) XS_XFRLEN(xs)); - ISP_ADD_REQUEST(isp, nxti); + isp_prt(isp, ISP_LOGDEBUG0, "START cmd for %d.%d.%d cmd 0x%x datalen %ld", XS_CHANNEL(xs), XS_TGT(xs), XS_LUN(xs), XS_CDBP(xs)[0], (long) XS_XFRLEN(xs)); isp->isp_nactive++; return (CMD_QUEUED); } diff --git a/qla_isp/common/isp_library.c b/qla_isp/common/isp_library.c index 1af740d0c..8a841cac2 100644 --- a/qla_isp/common/isp_library.c +++ b/qla_isp/common/isp_library.c @@ -79,6 +79,200 @@ const char *isp_class3_roles[4] = { "None", "Target", "Initiator", "Target/Initiator" }; +/* + * Command shipping- finish off first queue entry and do dma mapping and + * additional segments as needed. + * + * Called with the first queue entry at least partially filled out. + */ +int +isp_send_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_t totalcnt, isp_ddir_t ddir) +{ + uint8_t storage[QENTRY_LEN]; + uint8_t type, nqe; + uint32_t seg, curseg, seglim, nxt, nxtnxt, ddf; + ispds_t *dsp = NULL; + ispds64_t *dsp64 = NULL; + void *qe0, *qe1; + + qe0 = isp_getrqentry(isp); + if (qe0 == NULL) { + return (CMD_EAGAIN); + } + nxt = ISP_NXT_QENTRY(isp->isp_reqidx, RQUEST_QUEUE_LEN(isp)); + + type = ((isphdr_t *)fqe)->rqs_entry_type; + nqe = 1; + + /* + * If we have no data to transmit, just copy the first IOCB and start it up. + */ + if (ddir == ISP_NOXFR) { + if (type == RQSTYPE_T2RQS || type == RQSTYPE_T3RQS) { + ddf = CT2_NO_DATA; + } else { + ddf = 0; + } + goto copy_and_sync; + } + + /* + * First figure out how many pieces of data to transfer and what kind and how many we can put into the first queue entry. + */ + switch (type) { + case RQSTYPE_REQUEST: + ddf = (ddir == ISP_TO_DEVICE)? REQFLAG_DATA_OUT : REQFLAG_DATA_IN; + dsp = ((ispreq_t *)fqe)->req_dataseg; + seglim = ISP_RQDSEG; + break; + case RQSTYPE_CMDONLY: + ddf = (ddir == ISP_TO_DEVICE)? REQFLAG_DATA_OUT : REQFLAG_DATA_IN; + seglim = 0; + break; + case RQSTYPE_T2RQS: + ddf = (ddir == ISP_TO_DEVICE)? REQFLAG_DATA_OUT : REQFLAG_DATA_IN; + dsp = ((ispreqt2_t *)fqe)->req_dataseg; + seglim = ISP_RQDSEG_T2; + break; + case RQSTYPE_A64: + ddf = (ddir == ISP_TO_DEVICE)? REQFLAG_DATA_OUT : REQFLAG_DATA_IN; + dsp64 = ((ispreqt3_t *)fqe)->req_dataseg; + seglim = ISP_RQDSEG_T3; + break; + case RQSTYPE_T3RQS: + ddf = (ddir == ISP_TO_DEVICE)? CT2_DATA_OUT : CT2_DATA_IN; + dsp64 = ((ispreqt3_t *)fqe)->req_dataseg; + seglim = ISP_RQDSEG_T3; + break; + case RQSTYPE_T7RQS: + ddf = (ddir == ISP_TO_DEVICE)? FCP_CMND_DATA_WRITE : FCP_CMND_DATA_READ; + dsp64 = &((ispreqt7_t *)fqe)->req_dataseg; + seglim = 1; + break; + default: + return (CMD_COMPLETE); + } + + if (seglim > nsegs) { + seglim = nsegs; + } + + for (seg = curseg = 0; curseg < seglim; curseg++) { + if (dsp64) { + XS_GET_DMA64_SEG(dsp64++, segp, seg++); + } else { + XS_GET_DMA_SEG(dsp++, segp, seg++); + } + } + + + /* + * Second, start building additional continuation segments as needed. + */ + while (seg < nsegs) { + nxtnxt = ISP_NXT_QENTRY(nxt, RQUEST_QUEUE_LEN(isp)); + if (nxtnxt == isp->isp_reqodx) { + return (CMD_EAGAIN); + } + ISP_MEMZERO(storage, QENTRY_LEN); + qe1 = ISP_QUEUE_ENTRY(isp->isp_rquest, nxt); + nxt = nxtnxt; + if (dsp64) { + ispcontreq64_t *crq = (ispcontreq64_t *) storage; + seglim = ISP_CDSEG64; + crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; + crq->req_header.rqs_entry_count = 1; + dsp64 = crq->req_dataseg; + } else { + ispcontreq_t *crq = (ispcontreq_t *) storage; + seglim = ISP_CDSEG; + crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; + crq->req_header.rqs_entry_count = 1; + dsp = crq->req_dataseg; + } + if (seg + seglim > nsegs) { + seglim = nsegs - seg; + } + for (curseg = 0; curseg < seglim; curseg++) { + if (dsp64) { + XS_GET_DMA64_SEG(dsp64++, segp, seg++); + } else { + XS_GET_DMA_SEG(dsp++, segp, seg++); + } + } + if (dsp64) { + isp_put_cont64_req(isp, (ispcontreq64_t *)storage, qe1); + } else { + isp_put_cont_req(isp, (ispcontreq_t *)storage, qe1); + } + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "additional queue entry", QENTRY_LEN, storage); + } + nqe++; + } + +copy_and_sync: + ((isphdr_t *)fqe)->rqs_entry_count = nqe; + switch (type) { + case RQSTYPE_REQUEST: + ((ispreq_t *)fqe)->req_flags |= ddf; + /* + * This is historical and not clear whether really needed. + */ + if (nsegs == 0) { + nsegs = 1; + } + ((ispreq_t *)fqe)->req_seg_count = nsegs; + isp_put_request(isp, fqe, qe0); + break; + case RQSTYPE_CMDONLY: + ((ispreq_t *)fqe)->req_flags |= ddf; + /* + * This is historical and not clear whether really needed. + */ + if (nsegs == 0) { + nsegs = 1; + } + ((ispextreq_t *)fqe)->req_seg_count = nsegs; + isp_put_extended_request(isp, fqe, qe0); + break; + case RQSTYPE_T2RQS: + ((ispreqt2_t *)fqe)->req_flags |= ddf; + ((ispreqt2_t *)fqe)->req_seg_count = nsegs; + ((ispreqt2_t *)fqe)->req_totalcnt = totalcnt; + if (ISP_CAP_SCCFW(isp)) { + isp_put_request_t2e(isp, fqe, qe0); + } else { + isp_put_request_t2(isp, fqe, qe0); + } + break; + case RQSTYPE_A64: + case RQSTYPE_T3RQS: + ((ispreqt3_t *)fqe)->req_flags |= ddf; + ((ispreqt3_t *)fqe)->req_seg_count = nsegs; + ((ispreqt3_t *)fqe)->req_totalcnt = totalcnt; + if (ISP_CAP_SCCFW(isp)) { + isp_put_request_t3e(isp, fqe, qe0); + } else { + isp_put_request_t3(isp, fqe, qe0); + } + break; + case RQSTYPE_T7RQS: + ((ispreqt7_t *)fqe)->req_alen_datadir = ddf; + ((ispreqt7_t *)fqe)->req_seg_count = nsegs; + ((ispreqt7_t *)fqe)->req_dl = totalcnt; + isp_put_request_t7(isp, fqe, qe0); + break; + default: + return (CMD_COMPLETE); + } + if (isp->isp_dblev & ISP_LOGDEBUG1) { + isp_print_bytes(isp, "first queue entry", QENTRY_LEN, fqe); + } + ISP_ADD_REQUEST(isp, nxt); + return (CMD_QUEUED); +} + int isp_save_xs(ispsoftc_t *isp, XS_T *xs, uint32_t *handlep) { @@ -142,24 +336,20 @@ isp_destroy_handle(ispsoftc_t *isp, uint32_t handle) } } -int -isp_getrqentry(ispsoftc_t *isp, uint32_t *iptrp, - uint32_t *optrp, void **resultp) +/* + * Make sure we have space to put something on the request queue. + * Return a pointer to that entry if we do. A side effect of this + * function is to update the output index. The input index + * stays the same. + */ +void * +isp_getrqentry(ispsoftc_t *isp) { - volatile uint32_t iptr, optr; - - optr = isp->isp_reqodx = ISP_READ(isp, isp->isp_rqstoutrp); - iptr = isp->isp_reqidx; - *resultp = ISP_QUEUE_ENTRY(isp->isp_rquest, iptr); - iptr = ISP_NXT_QENTRY(iptr, RQUEST_QUEUE_LEN(isp)); - if (iptr == optr) { - return (1); + isp->isp_reqodx = ISP_READ(isp, isp->isp_rqstoutrp); + if (ISP_NXT_QENTRY(isp->isp_reqidx, RQUEST_QUEUE_LEN(isp)) == isp->isp_reqodx) { + return (NULL); } - if (optrp) - *optrp = optr; - if (iptrp) - *iptrp = iptr; - return (0); + return (ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx)); } #define TBA (4 * (((QENTRY_LEN >> 2) * 3) + 1) + 1) @@ -1718,6 +1908,253 @@ isp_put_ct_hdr(ispsoftc_t *isp, ct_hdr_t *src, ct_hdr_t *dst) } #ifdef ISP_TARGET_MODE + +/* + * Command shipping- finish off first queue entry and do dma mapping and + * additional segments as needed. + * + * Called with the first queue entry at least partially filled out. + */ +int +isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_t totalcnt, isp_ddir_t ddir, void *snsptr, uint32_t snslen) +{ + uint8_t storage[QENTRY_LEN], storage2[QENTRY_LEN]; + uint8_t type, nqe; + uint32_t seg, curseg, seglim, nxt, nxtnxt; + ispds_t *dsp = NULL; + ispds64_t *dsp64 = NULL; + void *qe0, *qe1, *sqe = NULL; + + qe0 = isp_getrqentry(isp); + if (qe0 == NULL) { + return (CMD_EAGAIN); + } + nxt = ISP_NXT_QENTRY(isp->isp_reqidx, RQUEST_QUEUE_LEN(isp)); + + type = ((isphdr_t *)fqe)->rqs_entry_type; + nqe = 1; + seglim = 0; + + /* + * If we have no data to transmit, just copy the first IOCB and start it up. + */ + if (ddir != ISP_NOXFR) { + /* + * First, figure out how many pieces of data to transfer and what kind and how many we can put into the first queue entry. + */ + switch (type) { + case RQSTYPE_CTIO: + dsp = ((ct_entry_t *)fqe)->ct_dataseg; + seglim = ISP_RQDSEG; + break; + case RQSTYPE_CTIO2: + case RQSTYPE_CTIO3: + { + ct2_entry_t *ct = fqe, *ct2 = (ct2_entry_t *) storage2; + uint16_t swd = ct->rsp.m0.ct_scsi_status & 0xff; + + if ((ct->ct_flags & CT2_SENDSTATUS) && (swd || ct->ct_resid)) { + memcpy(ct2, ct, QENTRY_LEN); + /* + * Clear fields from first CTIO2 that now need to be cleared + */ + ct->ct_header.rqs_seqno = 0; + ct->ct_flags &= ~(CT2_SENDSTATUS|CT2_CCINCR|CT2_FASTPOST); + ct->ct_resid = 0; + ct->ct_syshandle = 0; + ct->rsp.m0.ct_scsi_status = 0; + + /* + * Reset fields in the second CTIO2 as appropriate. + */ + ct2->ct_flags &= ~(CT2_FLAG_MMASK|CT2_DATAMASK|CT2_FASTPOST); + ct2->ct_flags |= CT2_NO_DATA|CT2_FLAG_MODE1; + ct2->ct_seg_count = 0; + ct2->ct_reloff = 0; + memset(&ct2->rsp, 0, sizeof (ct2->rsp)); + if (swd == SCSI_CHECK && snsptr && snslen) { + ct2->rsp.m1.ct_senselen = min(snslen, MAXRESPLEN); + memcpy(ct2->rsp.m1.ct_resp, snsptr, ct2->rsp.m1.ct_senselen); + swd |= CT2_SNSLEN_VALID; + } + if (ct2->ct_resid > 0) { + swd |= CT2_DATA_UNDER; + } else if (ct2->ct_resid < 0) { + swd |= CT2_DATA_OVER; + } + ct2->rsp.m1.ct_scsi_status = swd; + sqe = storage2; + } + if (type == RQSTYPE_CTIO2) { + dsp = ct->rsp.m0.u.ct_dataseg; + seglim = ISP_RQDSEG_T2; + } else { + dsp64 = ct->rsp.m0.u.ct_dataseg64; + seglim = ISP_RQDSEG_T3; + } + break; + } + case RQSTYPE_CTIO7: + { + ct7_entry_t *ct = fqe, *ct2 = (ct7_entry_t *)storage2; + uint16_t swd = ct->ct_scsi_status & 0xff; + + dsp64 = &ct->rsp.m0.ds; + seglim = 1; + if ((ct->ct_flags & CT7_SENDSTATUS) && (swd || ct->ct_resid)) { + memcpy(ct2, ct, sizeof (ct7_entry_t)); + + /* + * Clear fields from first CTIO7 that now need to be cleared + */ + ct->ct_header.rqs_seqno = 0; + ct->ct_flags &= ~CT7_SENDSTATUS; + ct->ct_resid = 0; + ct->ct_syshandle = 0; + ct->ct_scsi_status = 0; + + /* + * Reset fields in the second CTIO7 as appropriate. + */ + ct2->ct_flags &= ~(CT7_FLAG_MMASK|CT7_DATAMASK); + ct2->ct_flags |= CT7_NO_DATA|CT7_NO_DATA|CT7_FLAG_MODE1; + ct2->ct_seg_count = 0; + memset(&ct2->rsp, 0, sizeof (ct2->rsp)); + if (swd == SCSI_CHECK && snsptr && snslen) { + ct2->rsp.m1.ct_resplen = min(snslen, MAXRESPLEN_24XX); + memcpy(ct2->rsp.m1.ct_resp, snsptr, ct2->rsp.m1.ct_resplen); + swd |= (FCP_SNSLEN_VALID << 8); + } + if (ct2->ct_resid < 0) { + swd |= (FCP_RESID_OVERFLOW << 8); + } else if (ct2->ct_resid > 0) { + swd |= (FCP_RESID_UNDERFLOW << 8); + } + ct2->ct_scsi_status = swd; + sqe = storage2; + } + break; + } + default: + return (CMD_COMPLETE); + } + } + + /* + * Fill out the data transfer stuff in the first queue entry + */ + if (seglim > nsegs) { + seglim = nsegs; + } + + for (seg = curseg = 0; curseg < seglim; curseg++) { + if (dsp64) { + XS_GET_DMA64_SEG(dsp64++, segp, seg++); + } else { + XS_GET_DMA_SEG(dsp++, segp, seg++); + } + } + + /* + * First, if we are sending status with data and we have a non-zero + * status or non-zero residual, we have to make a synthetic extra CTIO + * that contains the status that we'll ship separately (FC cards only). + */ + + /* + * Second, start building additional continuation segments as needed. + */ + while (seg < nsegs) { + nxtnxt = ISP_NXT_QENTRY(nxt, RQUEST_QUEUE_LEN(isp)); + if (nxtnxt == isp->isp_reqodx) { + return (CMD_EAGAIN); + } + ISP_MEMZERO(storage, QENTRY_LEN); + qe1 = ISP_QUEUE_ENTRY(isp->isp_rquest, nxt); + nxt = nxtnxt; + if (dsp64) { + ispcontreq64_t *crq = (ispcontreq64_t *) storage; + seglim = ISP_CDSEG64; + crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; + crq->req_header.rqs_entry_count = 1; + dsp64 = crq->req_dataseg; + } else { + ispcontreq_t *crq = (ispcontreq_t *) storage; + seglim = ISP_CDSEG; + crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; + crq->req_header.rqs_entry_count = 1; + dsp = crq->req_dataseg; + } + if (seg + seglim > nsegs) { + seglim = nsegs - seg; + } + for (curseg = 0; curseg < seglim; curseg++) { + if (dsp64) { + XS_GET_DMA64_SEG(dsp64++, segp, seg++); + } else { + XS_GET_DMA_SEG(dsp++, segp, seg++); + } + } + if (dsp64) { + isp_put_cont64_req(isp, (ispcontreq64_t *)storage, qe1); + } else { + isp_put_cont_req(isp, (ispcontreq_t *)storage, qe1); + } + if (isp->isp_dblev & ISP_LOGTDEBUG1) { + isp_print_bytes(isp, "additional queue entry", QENTRY_LEN, storage); + } + nqe++; + } + + /* + * If we have a synthetic queue entry to complete things, do it here. + */ + if (sqe) { + nxtnxt = ISP_NXT_QENTRY(nxt, RQUEST_QUEUE_LEN(isp)); + if (nxtnxt == isp->isp_reqodx) { + return (CMD_EAGAIN); + } + qe1 = ISP_QUEUE_ENTRY(isp->isp_rquest, nxt); + nxt = nxtnxt; + if (type == RQSTYPE_CTIO7) { + isp_put_ctio7(isp, sqe, qe1); + } else { + isp_put_ctio2(isp, sqe, qe1); + } + if (isp->isp_dblev & ISP_LOGTDEBUG1) { + isp_print_bytes(isp, "synthetic final queue entry", QENTRY_LEN, storage2); + } + } + + ((isphdr_t *)fqe)->rqs_entry_count = nqe; + switch (type) { + case RQSTYPE_CTIO: + ((ct_entry_t *)fqe)->ct_seg_count = nsegs; + isp_put_ctio(isp, fqe, qe0); + break; + case RQSTYPE_CTIO2: + case RQSTYPE_CTIO3: + ((ct2_entry_t *)fqe)->ct_seg_count = nsegs; + if (ISP_CAP_2KLOGIN(isp)) { + isp_put_ctio2e(isp, fqe, qe0); + } else { + isp_put_ctio2(isp, fqe, qe0); + } + break; + case RQSTYPE_CTIO7: + ((ct7_entry_t *)fqe)->ct_seg_count = nsegs; + isp_put_ctio7(isp, fqe, qe0); + break; + default: + return (CMD_COMPLETE); + } + if (isp->isp_dblev & ISP_LOGTDEBUG1) { + isp_print_bytes(isp, "first queue entry", QENTRY_LEN, fqe); + } + ISP_ADD_REQUEST(isp, nxt); + return (CMD_QUEUED); +} + int isp_save_xs_tgt(ispsoftc_t *isp, void *xs, uint32_t *handlep) { diff --git a/qla_isp/common/isp_library.h b/qla_isp/common/isp_library.h index 96a8bb06e..ded7baf5a 100644 --- a/qla_isp/common/isp_library.h +++ b/qla_isp/common/isp_library.h @@ -54,24 +54,59 @@ */ #ifndef _ISP_LIBRARY_H #define _ISP_LIBRARY_H -extern const char *isp_class3_roles[4]; -/* XXXXXX BARF - CLEAN UP THIS MESS XXXXXXXX*/ +/* + * Common command shipping routine. + * + * This used to be platform specific, but basically once you get the segment + * stuff figured out, you can make all the code in one spot. + */ +typedef enum { ISP_TO_DEVICE, ISP_FROM_DEVICE, ISP_NOXFR} isp_ddir_t; +int isp_send_cmd(ispsoftc_t *, void *, void *, uint32_t, uint32_t, isp_ddir_t); + +/* + * Handle management functions. + * + * These handles are associate with a command. + */ int isp_save_xs(ispsoftc_t *, XS_T *, uint32_t *); XS_T * isp_find_xs(ispsoftc_t *, uint32_t); uint32_t isp_find_handle(ispsoftc_t *, XS_T *); uint32_t isp_handle_index(uint32_t); void isp_destroy_handle(ispsoftc_t *, uint32_t); -int isp_getrqentry(ispsoftc_t *, uint32_t *, uint32_t *, void **); + +/* + * Request Queue allocation + */ +void *isp_getrqentry(ispsoftc_t *); + +/* + * Queue Entry debug functions + */ void isp_print_qentry (ispsoftc_t *, const char *, int, void *); void isp_print_bytes(ispsoftc_t *, const char *, int, void *); + +/* + * Fibre Channel specific routines and data. + */ +extern const char *isp_class3_roles[4]; int isp_fc_runstate(ispsoftc_t *, int, int); void isp_dump_portdb(ispsoftc_t *, int); + + +/* + * Common chip shutdown function + */ void isp_shutdown(ispsoftc_t *); + +/* + * Put/Get routines to push from CPU view to device view + * or to pull from device view to CPU view for various + * data structures (IOCB) + */ void isp_put_hdr(ispsoftc_t *, isphdr_t *, isphdr_t *); void isp_get_hdr(ispsoftc_t *, isphdr_t *, isphdr_t *); int isp_get_response_type(ispsoftc_t *, isphdr_t *); - void isp_put_request(ispsoftc_t *, ispreq_t *, ispreq_t *); void isp_put_marker(ispsoftc_t *, isp_marker_t *, isp_marker_t *); void isp_put_marker_24xx(ispsoftc_t *, isp_marker_24xx_t *, isp_marker_24xx_t *); @@ -134,6 +169,8 @@ void isp_put_ct_hdr(ispsoftc_t *isp, ct_hdr_t *, ct_hdr_t *); #include "isp_target.h" #endif +int isp_send_tgt_cmd(ispsoftc_t *, void *, void *, uint32_t, uint32_t, isp_ddir_t, void *, uint32_t); + #define IS_TARGET_HANDLE(x) ((x) & 0x8000) int isp_save_xs_tgt(ispsoftc_t *, void *, uint32_t *); diff --git a/qla_isp/common/isp_target.c b/qla_isp/common/isp_target.c index b0b995a12..7026b03b2 100644 --- a/qla_isp/common/isp_target.c +++ b/qla_isp/common/isp_target.c @@ -1,4 +1,4 @@ -/* $Id: isp_target.c,v 1.83 2009/02/01 23:49:49 mjacob Exp $ */ +/* $Id: isp_target.c,v 1.84 2009/02/13 23:58:38 mjacob Exp $ */ /*- * Copyright (c) 1997-2008 by Matthew Jacob * All rights reserved. @@ -468,7 +468,6 @@ int isp_lun_cmd(ispsoftc_t *isp, int cmd, int bus, int lun, int cmd_cnt, int inot_cnt) { lun_entry_t el; - uint32_t nxti, optr; void *outp; ISP_MEMZERO(&el, sizeof (el)); @@ -503,25 +502,25 @@ isp_lun_cmd(ispsoftc_t *isp, int cmd, int bus, int lun, int cmd_cnt, int inot_cn } el.le_timeout = 30; - if (isp_getrqentry(isp, &nxti, &optr, &outp)) { + outp = isp_getrqentry(isp); + if (outp == NULL) { isp_prt(isp, ISP_LOGERR, rqo, __func__); return (-1); } - ISP_TDQE(isp, "isp_lun_cmd", (int) optr, &el); isp_put_enable_lun(isp, &el, outp); - ISP_ADD_REQUEST(isp, nxti); + ISP_TDQE(isp, "isp_lun_cmd", isp->isp_reqidx, &el); + ISP_SYNC_REQUEST(isp); return (0); } - int isp_target_put_entry(ispsoftc_t *isp, void *ap) { void *outp; - uint32_t nxti, optr; uint8_t etype = ((isphdr_t *) ap)->rqs_entry_type; - if (isp_getrqentry(isp, &nxti, &optr, &outp)) { + outp = isp_getrqentry(isp); + if (outp == NULL) { isp_prt(isp, ISP_LOGWARN, rqo, __func__); return (-1); } @@ -553,8 +552,8 @@ isp_target_put_entry(ispsoftc_t *isp, void *ap) isp_prt(isp, ISP_LOGERR, "%s: Unknown type 0x%x", __func__, etype); return (-1); } - ISP_TDQE(isp, __func__, (int) optr, ap); - ISP_ADD_REQUEST(isp, nxti); + ISP_TDQE(isp, __func__, isp->isp_reqidx, ap); + ISP_SYNC_REQUEST(isp); return (0); } @@ -1041,7 +1040,6 @@ int isp_notify_ack(ispsoftc_t *isp, void *arg) { char storage[QENTRY_LEN]; - uint32_t nxti, optr; void *outp; /* @@ -1052,7 +1050,8 @@ isp_notify_ack(ispsoftc_t *isp, void *arg) return (isp_endcmd(isp, aep, NIL_HANDLE, 0, 0, 0)); } - if (isp_getrqentry(isp, &nxti, &optr, &outp)) { + outp = isp_getrqentry(isp); + if (outp == NULL) { isp_prt(isp, ISP_LOGWARN, rqo, __func__); return (1); } @@ -1139,11 +1138,10 @@ isp_notify_ack(ispsoftc_t *isp, void *arg) na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; na->na_header.rqs_entry_count = 1; isp_put_notify_ack(isp, na, (na_entry_t *)outp); - isp_prt(isp, ISP_LOGTDEBUG0, "notify ack loopid %u lun %u tgt %u seqid %x event %x", na->na_iid, na->na_lun, na->na_tgt, - na->na_seqid, na->na_event); + isp_prt(isp, ISP_LOGTDEBUG0, "notify ack loopid %u lun %u tgt %u seqid %x event %x", na->na_iid, na->na_lun, na->na_tgt, na->na_seqid, na->na_event); } - ISP_TDQE(isp, "isp_notify_ack", (int) optr, storage); - ISP_ADD_REQUEST(isp, nxti); + ISP_TDQE(isp, "isp_notify_ack", isp->isp_reqidx, storage); + ISP_SYNC_REQUEST(isp); return (0); } @@ -1155,7 +1153,6 @@ isp_acknak_abts(ispsoftc_t *isp, void *arg, int errno) uint8_t tmpb; abts_t *abts = arg; abts_rsp_t *rsp = (abts_rsp_t *) storage; - uint32_t nxti, optr; void *outp; if (!IS_24XX(isp)) { @@ -1168,7 +1165,8 @@ isp_acknak_abts(ispsoftc_t *isp, void *arg, int errno) return (0); } - if (isp_getrqentry(isp, &nxti, &optr, &outp)) { + outp = isp_getrqentry(isp); + if (outp == NULL) { isp_prt(isp, ISP_LOGWARN, rqo, __func__); return (1); } @@ -1221,8 +1219,8 @@ isp_acknak_abts(ispsoftc_t *isp, void *arg, int errno) * in the ABTS structure just before calling us. */ isp_put_abts_rsp(isp, rsp, (abts_rsp_t *)outp); - ISP_TDQE(isp, "isp_acknak_abts", (int) optr, storage); - ISP_ADD_REQUEST(isp, nxti); + ISP_TDQE(isp, "isp_acknak_abts", isp->isp_reqidx, storage); + ISP_SYNC_REQUEST(isp); return (0); } diff --git a/qla_isp/common/isp_target.h b/qla_isp/common/isp_target.h index f04cc689e..b0a768157 100644 --- a/qla_isp/common/isp_target.h +++ b/qla_isp/common/isp_target.h @@ -1,4 +1,4 @@ -/* $Id: isp_target.h,v 1.63 2009/02/01 23:49:49 mjacob Exp $ */ +/* $Id: isp_target.h,v 1.64 2009/02/13 23:58:38 mjacob Exp $ */ /*- * Copyright (c) 1997-2008 by Matthew Jacob * All rights reserved. diff --git a/qla_isp/common/isp_tpublic.h b/qla_isp/common/isp_tpublic.h index 95c853296..f69368eba 100644 --- a/qla_isp/common/isp_tpublic.h +++ b/qla_isp/common/isp_tpublic.h @@ -1,4 +1,4 @@ -/* $Id: isp_tpublic.h,v 1.44 2008/12/03 18:35:05 mjacob Exp $ */ +/* $Id: isp_tpublic.h,v 1.45 2009/02/13 23:58:38 mjacob Exp $ */ /*- * Copyright (c) 1997-2008 by Matthew Jacob * All rights reserved. diff --git a/qla_isp/common/ispvar.h b/qla_isp/common/ispvar.h index a4ae1ce6c..b18c8b640 100644 --- a/qla_isp/common/ispvar.h +++ b/qla_isp/common/ispvar.h @@ -1,4 +1,4 @@ -/* $Id: ispvar.h,v 1.103 2009/02/01 23:49:49 mjacob Exp $ */ +/* $Id: ispvar.h,v 1.104 2009/02/13 23:58:38 mjacob Exp $ */ /*- * Copyright (c) 1997-2008 by Matthew Jacob * All rights reserved. @@ -76,7 +76,7 @@ #include "ispmbox.h" #endif -#define ISP_CORE_VERSION_MAJOR 5 +#define ISP_CORE_VERSION_MAJOR 6 #define ISP_CORE_VERSION_MINOR 0 /* @@ -84,13 +84,11 @@ */ typedef struct ispsoftc ispsoftc_t; struct ispmdvec { - int (*dv_rd_isr) - (ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); + int (*dv_rd_isr) (ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); uint32_t (*dv_rd_reg) (ispsoftc_t *, int); void (*dv_wr_reg) (ispsoftc_t *, int, uint32_t); int (*dv_mbxdma) (ispsoftc_t *); - int (*dv_dmaset) - (ispsoftc_t *, XS_T *, ispreq_t *, uint32_t *, uint32_t); + int (*dv_dmaset) (ispsoftc_t *, XS_T *, void *); void (*dv_dmaclr) (ispsoftc_t *, XS_T *, uint32_t); void (*dv_reset0) (ispsoftc_t *); void (*dv_reset1) (ispsoftc_t *); @@ -126,8 +124,8 @@ struct ispmdvec { #define ISP_MBOXDMASETUP(isp) \ (*(isp)->isp_mdvec->dv_mbxdma)((isp)) -#define ISP_DMASETUP(isp, xs, req, iptrp, optr) \ - (*(isp)->isp_mdvec->dv_dmaset)((isp), (xs), (req), (iptrp), (optr)) +#define ISP_DMASETUP(isp, xs, req) \ + (*(isp)->isp_mdvec->dv_dmaset)((isp), (xs), (req)) #define ISP_DMAFREE(isp, xs, hndl) \ if ((isp)->isp_mdvec->dv_dmaclr) \ @@ -187,6 +185,11 @@ struct ispmdvec { ISP_WRITE(isp, isp->isp_rqstinrp, nxti); \ isp->isp_reqidx = nxti +#define ISP_SYNC_REQUEST(isp) \ + MEMORYBARRIER(isp, SYNC_REQUEST, isp->isp_reqidx, QENTRY_LEN); \ + isp->isp_reqidx = ISP_NXT_QENTRY(isp->isp_reqidx, RQUEST_QUEUE_LEN(isp)); \ + ISP_WRITE(isp, isp->isp_rqstinrp, isp->isp_reqidx) + /* * SCSI Specific Host Adapter Parameters- per bus, per target */ @@ -975,25 +978,27 @@ void isp_async(ispsoftc_t *, ispasync_t, ...); * SCSI_BUSY SCSI 'Busy' Status * SCSI_QFULL SCSI 'Queue Full' Status * - * XS_T Platform SCSI transaction type (i.e., command for HBA) - * XS_DMA_ADDR_T Platform PCI DMA Address Type - * XS_ISP(xs) gets an instance out of an XS_T - * XS_CHANNEL(xs) gets the channel (bus # for DUALBUS cards) "" - * XS_TGT(xs) gets the target "" - * XS_LUN(xs) gets the lun "" - * XS_CDBP(xs) gets a pointer to the scsi CDB "" - * XS_CDBLEN(xs) gets the CDB's length "" - * XS_XFRLEN(xs) gets the associated data transfer length "" - * XS_TIME(xs) gets the time (in milliseconds) for this command + * XS_T Platform SCSI transaction type (i.e., command for HBA) + * XS_DMA_ADDR_T Platform PCI DMA Address Type + * XS_GET_DMA_SEG(..) Get 32 bit dma segment list value + * XS_GET_DMA64_SEG(..) Get 64 bit dma segment list value + * XS_ISP(xs) gets an instance out of an XS_T + * XS_CHANNEL(xs) gets the channel (bus # for DUALBUS cards) "" + * XS_TGT(xs) gets the target "" + * XS_LUN(xs) gets the lun "" + * XS_CDBP(xs) gets a pointer to the scsi CDB "" + * XS_CDBLEN(xs) gets the CDB's length "" + * XS_XFRLEN(xs) gets the associated data transfer length "" + * XS_TIME(xs) gets the time (in milliseconds) for this command * XS_GET_RESID(xs) gets the current residual count * XS_GET_RESID(xs, resid) sets the current residual count - * XS_STSP(xs) gets a pointer to the SCSI status byte "" - * XS_SNSP(xs) gets a pointer to the associate sense data - * XS_SNSLEN(xs) gets the length of sense data storage - * XS_SNSKEY(xs) dereferences XS_SNSP to get the current stored Sense Key - * XS_TAG_P(xs) predicate of whether this command should be tagged - * XS_TAG_TYPE(xs) which type of tag to use - * XS_SETERR(xs) set error state + * XS_STSP(xs) gets a pointer to the SCSI status byte "" + * XS_SNSP(xs) gets a pointer to the associate sense data + * XS_SNSLEN(xs) gets the length of sense data storage + * XS_SNSKEY(xs) dereferences XS_SNSP to get the current stored Sense Key + * XS_TAG_P(xs) predicate of whether this command should be tagged + * XS_TAG_TYPE(xs) which type of tag to use + * XS_SETERR(xs) set error state * * HBA_NOERROR command has no erros * HBA_BOTCH hba botched something diff --git a/qla_isp/linux/isp_cb_ops.c b/qla_isp/linux/isp_cb_ops.c index 6d54ccba3..b7f7fa5be 100644 --- a/qla_isp/linux/isp_cb_ops.c +++ b/qla_isp/linux/isp_cb_ops.c @@ -767,9 +767,10 @@ isp_run_cmd(ispsoftc_t *isp, isp_xcmd_t *cmd) struct scsi_device *dev = NULL; struct scsi_cmnd *Cmnd = NULL; struct Scsi_Host *host = NULL; - uint32_t nxti, optr, handle; + uint32_t handle; uint8_t local[QENTRY_LEN]; ispreq_t *reqp; + void *qep; int time, result = 0; struct semaphore rsem; unsigned long flags; @@ -800,7 +801,8 @@ isp_run_cmd(ispsoftc_t *isp, isp_xcmd_t *cmd) sema_init(&rsem, 0); ISP_LOCKU_SOFTC(isp); - if (isp_getrqentry(isp, &nxti, &optr, (void *)&reqp)) { + qep = isp_getrqentry(isp); + if (qep == NULL) { ISP_UNLKU_SOFTC(isp); isp_prt(isp, ISP_LOGDEBUG0, "%s: Request Queue Overflow", __func__); result = -ENOMEM; @@ -881,7 +883,7 @@ isp_run_cmd(ispsoftc_t *isp, isp_xcmd_t *cmd) Cmnd->sc_data_direction = SCSI_DATA_NONE; } - result = ISP_DMASETUP(isp, Cmnd, reqp, &nxti, optr); + result = ISP_DMASETUP(isp, Cmnd, reqp); switch (result) { default: isp_prt(isp, ISP_LOGWARN, "isp_run_cmd: dma setup returned %d", result); @@ -891,7 +893,7 @@ isp_run_cmd(ispsoftc_t *isp, isp_xcmd_t *cmd) result = -ENOMEM; break; case CMD_QUEUED: - ISP_ADD_REQUEST(isp, nxti); + ISP_SYNC_REQUEST(isp); isp->isp_nactive++; result = 0; break; diff --git a/qla_isp/linux/isp_linux.c b/qla_isp/linux/isp_linux.c index 224c2d039..5c5e3a1a6 100644 --- a/qla_isp/linux/isp_linux.c +++ b/qla_isp/linux/isp_linux.c @@ -1,4 +1,4 @@ -/* $Id: isp_linux.c,v 1.240 2009/02/01 23:49:55 mjacob Exp $ */ +/* $Id: isp_linux.c,v 1.241 2009/02/13 23:58:38 mjacob Exp $ */ /* * Copyright (c) 1997-2008 by Matthew Jacob * All rights reserved. @@ -1511,7 +1511,6 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_xact_t *xact) { void *qe; uint32_t handle, orig_xfrlen = 0; - uint32_t nxti, optr; uint8_t local[QENTRY_LEN]; unsigned long flags; int32_t resid; @@ -1533,6 +1532,12 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_xact_t *xact) orig_xfrlen = xact->td_xfrlen; tmd->cd_moved += orig_xfrlen; + /* + * Set the residual to be equal to the total length less the amount previously moved plus this transfer size + */ + resid = tmd->cd_totlen - tmd->cd_moved; + + /* * Check for commands that are already dead */ @@ -1575,11 +1580,6 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_xact_t *xact) memset(local, 0, QENTRY_LEN); - /* - * Set the residual to be equal to the total length less the amount previously moved plus this transfer size - */ - resid = tmd->cd_totlen - tmd->cd_moved; - /* * We're either moving data or completing a command here (or both). */ @@ -1589,6 +1589,7 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_xact_t *xact) cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; cto->ct_header.rqs_entry_count = 1; + cto->ct_header.rqs_seqno = 1; cto->ct_nphdl = tmd->cd_nphdl; cto->ct_rxid = tmd->cd_tagval; cto->ct_iid_lo = tmd->cd_portid; @@ -1625,6 +1626,8 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_xact_t *xact) cto->ct_scsi_status |= (FCP_SNSLEN_VALID << 8); } } else { + cto->rsp.m0.ct_xfrlen = xact->td_xfrlen; + cto->rsp.m0.reloff = tmd->cd_moved - orig_xfrlen; cto->ct_flags |= CT7_FLAG_MODE0; if (xact->td_hflags & TDFH_DATA_IN) { cto->ct_flags |= CT7_DATA_IN; @@ -1651,6 +1654,7 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_xact_t *xact) cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; cto->ct_header.rqs_entry_count = 1; + cto->ct_header.rqs_seqno = 1; if (ISP_CAP_2KLOGIN(isp)) { ((ct2e_entry_t *)cto)->ct_iid = tmd->cd_nphdl; } else { @@ -1683,6 +1687,7 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_xact_t *xact) cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; } } else { + cto->ct_reloff = tmd->cd_moved - orig_xfrlen; cto->ct_flags |= CT2_FLAG_MODE0; if (xact->td_hflags & TDFH_DATA_IN) { cto->ct_flags |= CT2_DATA_IN; @@ -1717,6 +1722,7 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_xact_t *xact) cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; cto->ct_header.rqs_entry_count = 1; + cto->ct_header.rqs_seqno = 1; cto->ct_iid = tmd->cd_iid; cto->ct_tgt = tmd->cd_tgt; cto->ct_lun = L0LUN_TO_FLATLUN(tmd->cd_lun); @@ -1755,7 +1761,8 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_xact_t *xact) isp_prt(isp, ISP_LOGTDEBUG0, "CTIO[%llx] scsi sts %x resid %d cd_lflags %x", (ull) tmd->cd_tagval, tmd->cd_scsi_status, resid, xact->td_hflags); } - if (isp_getrqentry(isp, &nxti, &optr, &qe)) { + qe = isp_getrqentry(isp); + if (qe == NULL) { isp_prt(isp, ISP_LOGWARN, "%s: request queue overflow", __func__); xact->td_error = -ENOMEM; goto out; @@ -1784,9 +1791,8 @@ isp_target_start_ctio(ispsoftc_t *isp, tmd_xact_t *xact) * format. */ - switch (ISP_DMASETUP(isp, (XS_T *)xact, (ispreq_t *) local, &nxti, optr)) { + switch (ISP_DMASETUP(isp, (XS_T *)xact, local)) { case CMD_QUEUED: - ISP_ADD_REQUEST(isp, nxti); tmd->cd_req_cnt += 1; ISP_UNLK_SOFTC(isp); return; @@ -2534,7 +2540,6 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg) static int isp_target_putback_atio(ispsoftc_t *isp, tmd_cmd_t *tmd) { - uint32_t nxti; uint8_t local[QENTRY_LEN]; void *qe; @@ -2542,7 +2547,8 @@ isp_target_putback_atio(ispsoftc_t *isp, tmd_cmd_t *tmd) if (IS_24XX(isp)) { return (0); } - if (isp_getrqentry(isp, &nxti, NULL, &qe)) { + qe = isp_getrqentry(isp); + if (qe == NULL) { isp_prt(isp, ISP_LOGWARN, "%s: Request Queue Overflow", __func__); return (-ENOMEM); } @@ -2579,7 +2585,7 @@ isp_target_putback_atio(ispsoftc_t *isp, tmd_cmd_t *tmd) isp_put_atio(isp, at, qe); } ISP_TDQE(isp, "isp_target_putback_atio", isp->isp_reqidx, qe); - ISP_ADD_REQUEST(isp, nxti); + ISP_SYNC_REQUEST(isp); return (0); } @@ -4456,6 +4462,7 @@ isp_thread_event(ispsoftc_t *isp, int action, void *a, int dowait, const char *f if (tap->thread_action == action && tap->arg == a && dowait == 0) { tap->count++; spin_unlock_irqrestore(&isp->isp_osinfo.tlock, flags); + wake_up(&isp->isp_osinfo.trq); isp_prt(isp, ISP_LOGDEBUG1, "async thread event %d from %s:%d now has count %d", action, file, line, tap->count); return (0); } @@ -4527,350 +4534,351 @@ isp_task_thread(void *arg) break; } spin_lock_irqsave(&isp->isp_osinfo.tlock, flags); - if ((tap = isp->isp_osinfo.t_busy) != NULL) { + while ((tap = isp->isp_osinfo.t_busy) != NULL) { if ((isp->isp_osinfo.t_busy = tap->next) == NULL) { isp->isp_osinfo.t_busy_t = NULL; } - } - spin_unlock_irqrestore(&isp->isp_osinfo.tlock, flags); - if (tap == NULL) { - continue; - } - isp_prt(isp, ISP_LOGDEBUG0, "isp_task_thread: action %d", tap->thread_action); - switch (tap->thread_action) { - case ISP_THREAD_NIL: - break; - case ISP_THREAD_SCSI_SCAN: - { - unsigned long arg = (unsigned long) tap->arg; - int tgt, chan, rescan; - tgt = arg & 0xffff; - chan = (arg >> 16) & 0xff; - rescan = (arg >> 31) & 1; - if (rescan == 0) { - scsi_scan_target(&isp->isp_osinfo.host->shost_gendev, chan, tgt, 0, rescan); - } else { - struct scsi_device *sdev; - sdev = scsi_device_lookup(isp->isp_osinfo.host, 0, tgt, 0); - if (sdev) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } - } - break; - } - case ISP_THREAD_REINIT: - ISP_LOCKU_SOFTC(isp); - if (isp->isp_dead) { - isp_prt(isp, ISP_LOGERR, "chip marked dead- not restarting"); - isp_shutdown(isp); - ISP_DISABLE_INTS(isp); - ISP_UNLKU_SOFTC(isp); + spin_unlock_irqrestore(&isp->isp_osinfo.tlock, flags); + if (tap == NULL) { break; } - isp_reinit(isp); - if (isp->isp_state == ISP_RUNSTATE) { - for (i = 0; i < isp->isp_nchan; i++) { - ISP_DATA(isp, i)->blocked = 0; + isp_prt(isp, ISP_LOGDEBUG0, "isp_task_thread: action %d", tap->thread_action); + switch (tap->thread_action) { + case ISP_THREAD_NIL: + break; + case ISP_THREAD_SCSI_SCAN: + { + unsigned long arg = (unsigned long) tap->arg; + int tgt, chan, rescan; + tgt = arg & 0xffff; + chan = (arg >> 16) & 0xff; + rescan = (arg >> 31) & 1; + if (rescan == 0) { + scsi_scan_target(&isp->isp_osinfo.host->shost_gendev, chan, tgt, 0, rescan); + } else { + struct scsi_device *sdev; + sdev = scsi_device_lookup(isp->isp_osinfo.host, 0, tgt, 0); + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } } - isp_async(isp, ISPASYNC_FW_RESTARTED); - } else { - isp_prt(isp, ISP_LOGERR, "unable to restart chip"); + break; } - ISP_UNLKU_SOFTC(isp); - break; - case ISP_THREAD_FC_RESCAN: - { - fcparam *fcp = tap->arg; - int chan = fcp - FCPARAM(isp, 0); - - fcp = FCPARAM(isp, chan); - ISP_LOCKU_SOFTC(isp); - ISP_DATA(isp, chan)->nextscan = 0; - if (isp_fc_runstate(isp, chan, 250000) == 0) { - ISP_DATA(isp, chan)->deadloop = 0; - ISP_DATA(isp, chan)->downcount = 0; - ISP_DATA(isp, chan)->blocked = 0; - isplinux_runwaitq(isp); - } else { - if (ISP_DATA(isp, chan)->downcount == 0) { - ISP_DATA(isp, chan)->downcount = jiffies; - } - /* - * Try again in a little while. - */ - if ((jiffies - ISP_DATA(isp, chan)->downcount) > (isp_deadloop_time * HZ)) { - fcp->loop_seen_once = 0; - ISP_DATA(isp, chan)->deadloop = 1; - ISP_DATA(isp, chan)->downcount = 0; - ISP_DATA(isp, chan)->blocked = 0; - isp_prt(isp, ISP_LOGWARN, "Chan %d assuming loop is dead", chan); - isplinux_flushwaitq(isp); + case ISP_THREAD_REINIT: + ISP_LOCKU_SOFTC(isp); + if (isp->isp_dead) { + isp_prt(isp, ISP_LOGERR, "chip marked dead- not restarting"); + isp_shutdown(isp); + ISP_DISABLE_INTS(isp); ISP_UNLKU_SOFTC(isp); break; } - ISP_DATA(isp, chan)->nextscan = jiffies + HZ; + isp_reinit(isp); + if (isp->isp_state == ISP_RUNSTATE) { + for (i = 0; i < isp->isp_nchan; i++) { + ISP_DATA(isp, i)->blocked = 0; + } + isp_async(isp, ISPASYNC_FW_RESTARTED); + } else { + isp_prt(isp, ISP_LOGERR, "unable to restart chip"); + } + ISP_UNLKU_SOFTC(isp); + break; + case ISP_THREAD_FC_RESCAN: + { + fcparam *fcp = tap->arg; + int chan = fcp - FCPARAM(isp, 0); + + fcp = FCPARAM(isp, chan); + ISP_LOCKU_SOFTC(isp); + ISP_DATA(isp, chan)->nextscan = 0; + if (isp_fc_runstate(isp, chan, 250000) == 0) { + ISP_DATA(isp, chan)->deadloop = 0; + ISP_DATA(isp, chan)->downcount = 0; + ISP_DATA(isp, chan)->blocked = 0; + isplinux_runwaitq(isp); + } else { + if (ISP_DATA(isp, chan)->downcount == 0) { + ISP_DATA(isp, chan)->downcount = jiffies; + } + /* + * Try again in a little while. + */ + if ((jiffies - ISP_DATA(isp, chan)->downcount) > (isp_deadloop_time * HZ)) { + fcp->loop_seen_once = 0; + ISP_DATA(isp, chan)->deadloop = 1; + ISP_DATA(isp, chan)->downcount = 0; + ISP_DATA(isp, chan)->blocked = 0; + isp_prt(isp, ISP_LOGWARN, "Chan %d assuming loop is dead", chan); + isplinux_flushwaitq(isp); + ISP_UNLKU_SOFTC(isp); + break; + } + ISP_DATA(isp, chan)->nextscan = jiffies + HZ; + } + ISP_UNLKU_SOFTC(isp); + break; } - ISP_UNLKU_SOFTC(isp); - break; - } #ifdef ISP_TARGET_MODE - case ISP_THREAD_LOGOUT: - { - mbreg_t mbs; - union { - isp_pdb_t pdb; - int id; - } u; - fcportdb_t *lp = tap->arg; + case ISP_THREAD_LOGOUT: + { + mbreg_t mbs; + union { + isp_pdb_t pdb; + int id; + } u; + fcportdb_t *lp = tap->arg; - ISP_LOCKU_SOFTC(isp); - if (lp->state != FC_PORTDB_STATE_VALID) { - isp_prt(isp, ISP_LOGTINFO, "target mode entry no longer valid"); - ISP_UNLKU_SOFTC(isp); - break; - } - memset(&u, 0, sizeof (u)); - u.id = lp->handle; - isp_prt(isp, ISP_LOGTINFO, "Doing Port Logout repair for 0x%016llx@0x%x (loop id) %u", (ull) lp->port_wwn, lp->portid, lp->handle); - memset(&mbs, 0, sizeof (mbs)); - mbs.param[0] = MBOX_FABRIC_LOGOUT; - if (ISP_CAP_2KLOGIN(isp)) { + ISP_LOCKU_SOFTC(isp); + if (lp->state != FC_PORTDB_STATE_VALID) { + isp_prt(isp, ISP_LOGTINFO, "target mode entry no longer valid"); + ISP_UNLKU_SOFTC(isp); + break; + } + memset(&u, 0, sizeof (u)); + u.id = lp->handle; + isp_prt(isp, ISP_LOGTINFO, "Doing Port Logout repair for 0x%016llx@0x%x (loop id) %u", (ull) lp->port_wwn, lp->portid, lp->handle); + memset(&mbs, 0, sizeof (mbs)); + mbs.param[0] = MBOX_FABRIC_LOGOUT; + if (ISP_CAP_2KLOGIN(isp)) { mbs.param[1] = lp->handle; mbs.obits |= (1 << 10); - } else { - mbs.param[1] = lp->handle << 8; - } - mbs.logval = MBLOGNONE; - (void) isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, "failed to get logout loop id %u", lp->handle); - lp->state = FC_PORTDB_STATE_PROBATIONAL; - ISP_UNLKU_SOFTC(isp); - break; - } - memset(&mbs, 0, sizeof (mbs)); - mbs.param[0] = MBOX_FABRIC_LOGIN; - if (ISP_CAP_2KLOGIN(isp)) { + } else { + mbs.param[1] = lp->handle << 8; + } + mbs.logval = MBLOGNONE; + (void) isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, "failed to get logout loop id %u", lp->handle); + lp->state = FC_PORTDB_STATE_PROBATIONAL; + ISP_UNLKU_SOFTC(isp); + break; + } + memset(&mbs, 0, sizeof (mbs)); + mbs.param[0] = MBOX_FABRIC_LOGIN; + if (ISP_CAP_2KLOGIN(isp)) { mbs.param[1] = lp->handle; mbs.obits |= (1 << 10); - } else { + } else { mbs.param[1] = lp->handle << 8; - } - mbs.param[2] = lp->portid >> 16; - mbs.param[3] = lp->portid & 0xffff; - (void) isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); - if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { - isp_prt(isp, ISP_LOGERR, "failed to get login port id %x at loop id %u", lp->portid, lp->handle); - lp->state = FC_PORTDB_STATE_PROBATIONAL; + } + mbs.param[2] = lp->portid >> 16; + mbs.param[3] = lp->portid & 0xffff; + (void) isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, "failed to get login port id %x at loop id %u", lp->portid, lp->handle); + lp->state = FC_PORTDB_STATE_PROBATIONAL; + ISP_UNLKU_SOFTC(isp); + break; + } + lp->state = FC_PORTDB_STATE_VALID; ISP_UNLKU_SOFTC(isp); break; } - lp->state = FC_PORTDB_STATE_VALID; - ISP_UNLKU_SOFTC(isp); - break; - } - case ISP_THREAD_FINDIID: - { - tmd_cmd_t *tmd = tap->arg; - fcportdb_t *lp = NULL; - uint64_t iid = INI_NONE; - uint16_t nphdl = NIL_HANDLE; + case ISP_THREAD_FINDIID: + { + tmd_cmd_t *tmd = tap->arg; + fcportdb_t *lp = NULL; + uint64_t iid = INI_NONE; + uint16_t nphdl = NIL_HANDLE; - if (tmd->cd_lflags & CDFL_ABORTED) { - isp_prt(isp, ISP_LOGTINFO, "[%llx] asking thread to terminate because it was marked aborted", (ull) tmd->cd_tagval); - isp_thread_event(isp, ISP_THREAD_TERMINATE, tmd, 0, __func__, __LINE__); - break; - } - ISP_LOCKU_SOFTC(isp); - if (isp_find_pdb_by_sid(isp, tmd->cd_channel, tmd->cd_portid, &lp)) { - if (!VALID_INI(lp->port_wwn)) { - if (lp->handle == NIL_HANDLE) { - /* - * Ooops- all we have is the port id. - */ - uint16_t nphdl, max; - isp_pdb_t pdb; + if (tmd->cd_lflags & CDFL_ABORTED) { + isp_prt(isp, ISP_LOGTINFO, "[%llx] asking thread to terminate because it was marked aborted", (ull) tmd->cd_tagval); + isp_thread_event(isp, ISP_THREAD_TERMINATE, tmd, 0, __func__, __LINE__); + break; + } + ISP_LOCKU_SOFTC(isp); + if (isp_find_pdb_by_sid(isp, tmd->cd_channel, tmd->cd_portid, &lp)) { + if (!VALID_INI(lp->port_wwn)) { + if (lp->handle == NIL_HANDLE) { + /* + * Ooops- all we have is the port id. + */ + uint16_t nphdl, max; + isp_pdb_t pdb; - if (IS_24XX(isp)) { - max = NPH_MAX_2K; - } else { - max = NPH_MAX; - } - for (nphdl = 0; nphdl != max; nphdl++) { - if (isp_control(isp, ISPCTL_GET_PDB, tmd->cd_channel, nphdl, &pdb)) { - continue; + if (IS_24XX(isp)) { + max = NPH_MAX_2K; + } else { + max = NPH_MAX; } - isp_prt(isp, ISP_LOGTINFO, "%s: nphdl 0x%04x has portid 0x%06x", __func__, nphdl, pdb.portid); - if (pdb.portid == tmd->cd_portid) { - lp->handle = nphdl; + for (nphdl = 0; nphdl != max; nphdl++) { + if (isp_control(isp, ISPCTL_GET_PDB, tmd->cd_channel, nphdl, &pdb)) { + continue; + } + isp_prt(isp, ISP_LOGTINFO, "%s: nphdl 0x%04x has portid 0x%06x", __func__, nphdl, pdb.portid); + if (pdb.portid == tmd->cd_portid) { + lp->handle = nphdl; + break; + } + } + if (nphdl == max) { + ISP_UNLKU_SOFTC(isp); + isp_prt(isp, ISP_LOGTINFO, "[0x%llx] asking thread to terminate cmd [0x%02x] because because we can't find the N-Port handle", (ull) tmd->cd_tagval, tmd->cd_cdb[0] & 0xff); + isp_tgt_dump_pdb(isp, tmd->cd_channel); + isp_thread_event(isp, ISP_THREAD_TERMINATE, tmd, 0, __func__, __LINE__); break; } } - if (nphdl == max) { - ISP_UNLKU_SOFTC(isp); - isp_prt(isp, ISP_LOGTINFO, "[0x%llx] asking thread to terminate cmd [0x%02x] because because we can't find the N-Port handle", (ull) tmd->cd_tagval, tmd->cd_cdb[0] & 0xff); - isp_tgt_dump_pdb(isp, tmd->cd_channel); - isp_thread_event(isp, ISP_THREAD_TERMINATE, tmd, 0, __func__, __LINE__); - break; + if (isp_control(isp, ISPCTL_GET_NAMES, tmd->cd_channel, lp->handle, NULL, &lp->port_wwn) == 0) { + nphdl = lp->handle; + iid = lp->port_wwn; + } else { + isp_prt(isp, ISP_LOGALL, "%s: Chan %d [0x%llx] failed to get name for handle 0x%02x for portid 0x%06x", __func__, tmd->cd_channel, (ull) tmd->cd_tagval, lp->handle, tmd->cd_portid); } - } - if (isp_control(isp, ISPCTL_GET_NAMES, tmd->cd_channel, lp->handle, NULL, &lp->port_wwn) == 0) { + } else { nphdl = lp->handle; iid = lp->port_wwn; - } else { - isp_prt(isp, ISP_LOGALL, "%s: Chan %d [0x%llx] failed to get name for handle 0x%02x for portid 0x%06x", __func__, tmd->cd_channel, (ull) tmd->cd_tagval, lp->handle, tmd->cd_portid); } } else { - nphdl = lp->handle; - iid = lp->port_wwn; + /* + * If it's no longer in the port database, then some event between the receipt of the command and now + * has cleared it out. The command is probably already dead due to initiator port logout. + */ + ISP_UNLKU_SOFTC(isp); + isp_prt(isp, ISP_LOGTINFO, "[0x%llx] asking thread to terminate cmd [0x%02x] because PortID 0x%06x no longer in port database", (ull) tmd->cd_tagval, tmd->cd_cdb[0] & 0xff, tmd->cd_portid); + isp_tgt_dump_pdb(isp, tmd->cd_channel); + isp_thread_event(isp, ISP_THREAD_TERMINATE, tmd, 0, __func__, __LINE__); + break; } - } else { - /* - * If it's no longer in the port database, then some event between the receipt of the command and now - * has cleared it out. The command is probably already dead due to initiator port logout. - */ - ISP_UNLKU_SOFTC(isp); - isp_prt(isp, ISP_LOGTINFO, "[0x%llx] asking thread to terminate cmd [0x%02x] because PortID 0x%06x no longer in port database", (ull) tmd->cd_tagval, tmd->cd_cdb[0] & 0xff, tmd->cd_portid); - isp_tgt_dump_pdb(isp, tmd->cd_channel); - isp_thread_event(isp, ISP_THREAD_TERMINATE, tmd, 0, __func__, __LINE__); - break; - } - if (iid == INI_NONE) { - isp_prt(isp, ISP_LOGTDEBUG0, "%s: [0x%llx] trying to find IID again...", __func__, (ull) tmd->cd_tagval); - tmd->cd_next = isp->isp_osinfo.waiting_t; - isp->isp_osinfo.waiting_t = tmd; - tmd->cd_lastoff = 0; - ISP_UNLKU_SOFTC(isp); - break; - } - tmd->cd_tgt = FCPARAM(isp, tmd->cd_channel)->isp_wwpn; - tmd->cd_nphdl = nphdl; - tmd->cd_iid = iid; - isp_prt(isp, ISP_LOGTINFO, "%s: [0x%llx] Chan %d found initiator @ IID 0x%016llx N-Port Handle 0x%02x Port ID 0x%06x", __func__, - (ull) tmd->cd_tagval, tmd->cd_channel, (ull)tmd->cd_iid, tmd->cd_nphdl, tmd->cd_portid); - CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); - ISP_UNLKU_SOFTC(isp); - isp_tgt_tq(isp); - break; - } - case ISP_THREAD_FINDPORTID: - { - tmd_cmd_t *tmd = tap->arg; - fcportdb_t *lp; - - ISP_LOCKU_SOFTC(isp); - if (isp_find_pdb_by_loopid(isp, tmd->cd_channel, tmd->cd_nphdl, &lp)) { - if (lp->portid == PORT_NONE) { - isp_pdb_t pdb; - if (isp_control(isp, ISPCTL_GET_PDB, tmd->cd_channel, tmd->cd_nphdl, &pdb) == 0) { - tmd->cd_portid = lp->portid = pdb.portid; - } - } else { - tmd->cd_portid = lp->portid; + if (iid == INI_NONE) { + isp_prt(isp, ISP_LOGTDEBUG0, "%s: [0x%llx] trying to find IID again...", __func__, (ull) tmd->cd_tagval); + tmd->cd_next = isp->isp_osinfo.waiting_t; + isp->isp_osinfo.waiting_t = tmd; + tmd->cd_lastoff = 0; + ISP_UNLKU_SOFTC(isp); + break; } - } else { - isp_prt(isp, ISP_LOGTINFO, "[0x%llx] not in port database at all any more", (ull) tmd->cd_tagval); - } - if (tmd->cd_portid != PORT_NONE) { + tmd->cd_tgt = FCPARAM(isp, tmd->cd_channel)->isp_wwpn; + tmd->cd_nphdl = nphdl; + tmd->cd_iid = iid; isp_prt(isp, ISP_LOGTINFO, "%s: [0x%llx] Chan %d found initiator @ IID 0x%016llx N-Port Handle 0x%02x Port ID 0x%06x", __func__, (ull) tmd->cd_tagval, tmd->cd_channel, (ull)tmd->cd_iid, tmd->cd_nphdl, tmd->cd_portid); - } - CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); - ISP_UNLKU_SOFTC(isp); - isp_tgt_tq(isp); - break; - } - case ISP_THREAD_TERMINATE: - { - fcportdb_t *lp; - tmd_cmd_t *tmd = tap->arg; - - ISP_LOCKU_SOFTC(isp); - if (isp_find_pdb_by_sid(isp, tmd->cd_channel, tmd->cd_portid, &lp)) { - tmd->cd_iid = lp->port_wwn; - tmd->cd_nphdl = lp->handle; CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); ISP_UNLKU_SOFTC(isp); isp_tgt_tq(isp); - isp_prt(isp, ISP_LOGINFO, "Chan %d [%llx] reprieved", tmd->cd_channel, (ull) tmd->cd_tagval); break; } + case ISP_THREAD_FINDPORTID: + { + tmd_cmd_t *tmd = tap->arg; + fcportdb_t *lp; - isp_prt(isp, ISP_LOGTINFO, "%s now terminating [%llx] from 0x%06x", __func__, (ull) tmd->cd_tagval, tmd->cd_portid); - if (isp_terminate_cmd(isp, tmd)) { + ISP_LOCKU_SOFTC(isp); + if (isp_find_pdb_by_loopid(isp, tmd->cd_channel, tmd->cd_nphdl, &lp)) { + if (lp->portid == PORT_NONE) { + isp_pdb_t pdb; + if (isp_control(isp, ISPCTL_GET_PDB, tmd->cd_channel, tmd->cd_nphdl, &pdb) == 0) { + tmd->cd_portid = lp->portid = pdb.portid; + } + } else { + tmd->cd_portid = lp->portid; + } + } else { + isp_prt(isp, ISP_LOGTINFO, "[0x%llx] not in port database at all any more", (ull) tmd->cd_tagval); + } + if (tmd->cd_portid != PORT_NONE) { + isp_prt(isp, ISP_LOGTINFO, "%s: [0x%llx] Chan %d found initiator @ IID 0x%016llx N-Port Handle 0x%02x Port ID 0x%06x", __func__, + (ull) tmd->cd_tagval, tmd->cd_channel, (ull)tmd->cd_iid, tmd->cd_nphdl, tmd->cd_portid); + } + CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); ISP_UNLKU_SOFTC(isp); - isp_thread_event(isp, ISP_THREAD_TERMINATE, tmd, 0, __func__, __LINE__); + isp_tgt_tq(isp); break; } - tmd->cd_next = NULL; - if (isp->isp_osinfo.tfreelist) { - isp->isp_osinfo.bfreelist->cd_next = tmd; - } else { - isp->isp_osinfo.tfreelist = tmd; - } - isp->isp_osinfo.bfreelist = tmd; - ISP_UNLKU_SOFTC(isp); - break; - } - case ISP_THREAD_RESTART_AT7: - { - at7_entry_t at; - tmd_cmd_t *tmd = tap->arg; - memcpy(&at, tmd, sizeof (at7_entry_t)); - ISP_LOCKU_SOFTC(isp); - memset(tmd, 0, sizeof (tmd_cmd_t)); - if (isp->isp_osinfo.tfreelist) { - isp->isp_osinfo.bfreelist->cd_next = tmd; - } else { - isp->isp_osinfo.tfreelist = tmd; - } - isp->isp_osinfo.bfreelist = tmd; /* remember to move the list tail pointer */ - isp_handle_platform_atio7(isp, &at); - ISP_UNLKU_SOFTC(isp); - break; - } - case ISP_THREAD_FC_PUTBACK: - { - tmd_cmd_t *tmd = tap->arg; - ISP_LOCKU_SOFTC(isp); - isp_prt(isp, ISP_LOGTINFO, "%s: [%llx] calling putback", __func__, (ull) tmd->cd_tagval); - if (isp_target_putback_atio(isp, tmd)) { + case ISP_THREAD_TERMINATE: + { + fcportdb_t *lp; + tmd_cmd_t *tmd = tap->arg; + + ISP_LOCKU_SOFTC(isp); + if (isp_find_pdb_by_sid(isp, tmd->cd_channel, tmd->cd_portid, &lp)) { + tmd->cd_iid = lp->port_wwn; + tmd->cd_nphdl = lp->handle; + CALL_PARENT_TMD(isp, tmd, QOUT_TMD_START); + ISP_UNLKU_SOFTC(isp); + isp_tgt_tq(isp); + isp_prt(isp, ISP_LOGINFO, "Chan %d [%llx] reprieved", tmd->cd_channel, (ull) tmd->cd_tagval); + break; + } + + isp_prt(isp, ISP_LOGTINFO, "%s now terminating [%llx] from 0x%06x", __func__, (ull) tmd->cd_tagval, tmd->cd_portid); + if (isp_terminate_cmd(isp, tmd)) { + ISP_UNLKU_SOFTC(isp); + isp_thread_event(isp, ISP_THREAD_TERMINATE, tmd, 0, __func__, __LINE__); + break; + } + tmd->cd_next = NULL; + if (isp->isp_osinfo.tfreelist) { + isp->isp_osinfo.bfreelist->cd_next = tmd; + } else { + isp->isp_osinfo.tfreelist = tmd; + } + isp->isp_osinfo.bfreelist = tmd; ISP_UNLKU_SOFTC(isp); - isp_thread_event(isp, ISP_THREAD_FC_PUTBACK, tmd, 0, __func__, __LINE__); break; } - if (tmd->cd_lflags & CDFL_NEED_CLNUP) { - tmd->cd_lflags ^= CDFL_NEED_CLNUP; - isp_prt(isp, ISP_LOGTINFO, "Terminating %llx too", (ull) tmd->cd_tagval); - (void) isp_terminate_cmd(isp, tmd); + case ISP_THREAD_RESTART_AT7: + { + at7_entry_t at; + tmd_cmd_t *tmd = tap->arg; + memcpy(&at, tmd, sizeof (at7_entry_t)); + ISP_LOCKU_SOFTC(isp); + memset(tmd, 0, sizeof (tmd_cmd_t)); + if (isp->isp_osinfo.tfreelist) { + isp->isp_osinfo.bfreelist->cd_next = tmd; + } else { + isp->isp_osinfo.tfreelist = tmd; + } + isp->isp_osinfo.bfreelist = tmd; /* remember to move the list tail pointer */ + isp_handle_platform_atio7(isp, &at); + ISP_UNLKU_SOFTC(isp); + break; } - memset(tmd, 0, sizeof (tmd_cmd_t)); - if (isp->isp_osinfo.tfreelist) { - isp->isp_osinfo.bfreelist->cd_next = tmd; - } else { - isp->isp_osinfo.tfreelist = tmd; + case ISP_THREAD_FC_PUTBACK: + { + tmd_cmd_t *tmd = tap->arg; + ISP_LOCKU_SOFTC(isp); + isp_prt(isp, ISP_LOGTINFO, "%s: [%llx] calling putback", __func__, (ull) tmd->cd_tagval); + if (isp_target_putback_atio(isp, tmd)) { + ISP_UNLKU_SOFTC(isp); + isp_thread_event(isp, ISP_THREAD_FC_PUTBACK, tmd, 0, __func__, __LINE__); + break; + } + if (tmd->cd_lflags & CDFL_NEED_CLNUP) { + tmd->cd_lflags ^= CDFL_NEED_CLNUP; + isp_prt(isp, ISP_LOGTINFO, "Terminating %llx too", (ull) tmd->cd_tagval); + (void) isp_terminate_cmd(isp, tmd); + } + memset(tmd, 0, sizeof (tmd_cmd_t)); + if (isp->isp_osinfo.tfreelist) { + isp->isp_osinfo.bfreelist->cd_next = tmd; + } else { + isp->isp_osinfo.tfreelist = tmd; + } + isp->isp_osinfo.bfreelist = tmd; /* remember to move the list tail pointer */ + isp_prt(isp, ISP_LOGTDEBUG0, "DONE freeing tmd %p [%llx] after retry", tmd, (ull) tmd->cd_tagval); + ISP_UNLKU_SOFTC(isp); + break; } - isp->isp_osinfo.bfreelist = tmd; /* remember to move the list tail pointer */ - isp_prt(isp, ISP_LOGTDEBUG0, "DONE freeing tmd %p [%llx] after retry", tmd, (ull) tmd->cd_tagval); - ISP_UNLKU_SOFTC(isp); - break; - } #endif - default: - break; - } - tap->done = 0; - if (tap->waiting) { - isp_prt(isp, ISP_LOGDEBUG0, "isp_task_thread signalling"); - tap->waiting = 0; - wake_up(&tap->thread_waiter); - } else { - spin_lock_irqsave(&isp->isp_osinfo.tlock, flags); - tap->next = isp->isp_osinfo.t_free; - isp->isp_osinfo.t_free = tap; - spin_unlock_irqrestore(&isp->isp_osinfo.tlock, flags); + default: + break; + } + tap->done = 0; + if (tap->waiting) { + isp_prt(isp, ISP_LOGDEBUG0, "isp_task_thread signalling"); + tap->waiting = 0; + wake_up(&tap->thread_waiter); + spin_lock_irqsave(&isp->isp_osinfo.tlock, flags); + } else { + spin_lock_irqsave(&isp->isp_osinfo.tlock, flags); + tap->next = isp->isp_osinfo.t_free; + isp->isp_osinfo.t_free = tap; + } } + spin_unlock_irqrestore(&isp->isp_osinfo.tlock, flags); } isp_prt(isp, ISP_LOGDEBUG0, "isp_task_thread exiting"); return (0); diff --git a/qla_isp/linux/isp_linux.h b/qla_isp/linux/isp_linux.h index 4dd1a10bc..7ed3ffcd5 100644 --- a/qla_isp/linux/isp_linux.h +++ b/qla_isp/linux/isp_linux.h @@ -1,4 +1,4 @@ -/* $Id: isp_linux.h,v 1.168 2009/01/24 17:55:55 mjacob Exp $ */ +/* $Id: isp_linux.h,v 1.169 2009/02/13 23:58:38 mjacob Exp $ */ /* * Copyright (c) 1997-2008 by Matthew Jacob * All rights reserved. @@ -331,11 +331,10 @@ struct isposinfo { wait_queue_head_t mboxwq; struct semaphore mbox_c_sem; spinlock_t slock; - unsigned volatile int - : 20, + uint32_t dogcnt : 5, isopen : 1, - : 1, + is_64bit_dma : 1, dogactive : 1, mboxcmd_done : 1, mbintsok : 1, @@ -413,10 +412,6 @@ struct isposinfo { * Required Macros/Defines */ -#if defined(CONFIG_HIGHMEM64G) || defined(CONFIG_X86_64) /* BOGUS */ -#define ISP_DAC_SUPPORTED 1 -#endif - #define ISP_FC_SCRLEN 0x1000 #define ISP_MEMZERO(b, a) memset(b, 0, a) @@ -477,7 +472,8 @@ struct isposinfo { #define XS_T Scsi_Cmnd #define XS_DMA_ADDR_T dma_addr_t - +#define XS_GET_DMA64_SEG isp_get_dma64_seg +#define XS_GET_DMA_SEG isp_get_dma_seg #define XS_HOST(Cmnd) Cmnd->device->host #define XS_CHANNEL(Cmnd) (Cmnd)->device->channel #define XS_TGT(Cmnd) (Cmnd)->device->id @@ -913,6 +909,23 @@ isp_kzalloc(size_t size, int flags) #define COPYIN(uarg, karg, amt) copy_from_user(karg, uarg, amt) #define COPYOUT(karg, uarg, amt) copy_to_user(uarg, karg, amt) +static __inline void +isp_get_dma64_seg(ispds64_t *dsp, struct scatterlist *sg, uint32_t sgidx) +{ + sg += sgidx; + dsp->ds_base = DMA_LO32(sg_dma_address(sg)); + dsp->ds_basehi = DMA_HI32(sg_dma_address(sg)); + dsp->ds_count = sg_dma_len(sg); +} + +static __inline void +isp_get_dma_seg(ispds_t *dsp, struct scatterlist *sg, uint32_t sgidx) +{ + sg += sgidx; + dsp->ds_base = sg_dma_address(sg); + dsp->ds_count = sg_dma_len(sg); +} + /* * Common inline functions */ diff --git a/qla_isp/linux/isp_pci.c b/qla_isp/linux/isp_pci.c index 06d99f632..3ed717fd0 100644 --- a/qla_isp/linux/isp_pci.c +++ b/qla_isp/linux/isp_pci.c @@ -1,4 +1,4 @@ -/* $Id: isp_pci.c,v 1.175 2009/01/24 17:55:55 mjacob Exp $ */ +/* $Id: isp_pci.c,v 1.176 2009/02/13 23:58:38 mjacob Exp $ */ /* * Copyright (c) 1997-2008 by Matthew Jacob * All rights reserved. @@ -81,10 +81,9 @@ static int isp_pci_rd_isr_2300(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *) static uint32_t isp_pci_rd_reg_2400(ispsoftc_t *, int); static void isp_pci_wr_reg_2400(ispsoftc_t *, int, uint32_t); static int isp_pci_rd_isr_2400(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *); -static int isp_pci_2400_dmasetup(ispsoftc_t *, XS_T *, ispreq_t *, uint32_t *, uint32_t); #endif static int isp_pci_mbxdma(ispsoftc_t *); -static int isp_pci_dmasetup(ispsoftc_t *, XS_T *, ispreq_t *, uint32_t *, uint32_t); +static int isp_pci_dmasetup(ispsoftc_t *, XS_T *, void *); static void isp_pci_dmateardown(ispsoftc_t *, XS_T *, uint32_t); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6) @@ -105,17 +104,6 @@ static void isp_pci_dmateardown(ispsoftc_t *, XS_T *, uint32_t); #define ISP_IRQ_FLAGS IRQF_SHARED #endif -#ifdef ISP_DAC_SUPPORTED -#define ISP_A64 1 -#define HIWD(x) ((x) >> 32) -#define IS_HIGH_ISP_ADDR(addr) (((u64) addr) > DMA_32BIT_MASK) -#else -#define ISP_A64 0 -#define HIWD(x) 0 -#define IS_HIGH_ISP_ADDR(addr) 0 -#endif -#define LOWD(x) x - static void isp_pci_reset0(ispsoftc_t *); static void isp_pci_reset1(ispsoftc_t *); static void isp_pci_dumpregs(ispsoftc_t *, const char *); @@ -270,7 +258,7 @@ static struct ispmdvec mdvec_2400 = { isp_pci_rd_reg_2400, isp_pci_wr_reg_2400, isp_pci_mbxdma, - isp_pci_2400_dmasetup, + isp_pci_dmasetup, isp_pci_dmateardown, isp_pci_reset0, isp_pci_reset1, @@ -881,26 +869,20 @@ isplinux_pci_init_one(struct Scsi_Host *host) * * We can turn on highmem_io for all of them as we use the PCI dma mapping * API. - * - * We use our synthetic ISP_A64 define here because this allows us to - * remove code we wouldn't want to try and use if we don't have - * CONFIG_HIGHMEM64G defined. */ - if (ISP_A64) { - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { - isp_prt(isp, ISP_LOGERR, "cannot even set 32 bit dma mask"); + if (IS_1020(isp)) { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(24))) { + isp_prt(isp, ISP_LOGERR, "cannot set dma mask"); goto bad; - } - } else { - isp_prt(isp, ISP_LOGCONFIG, "enabling 64 bit DMA"); } - } else { - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { - isp_prt(isp, ISP_LOGERR, "cannot even set 32 bit dma mask"); + } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + isp_prt(isp, ISP_LOGERR, "cannot set dma mask"); goto bad; } + } else { + isp->isp_osinfo.is_64bit_dma = 1; } #if !defined(DISABLE_FW_LOADER) && (defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)) @@ -1583,1611 +1565,196 @@ bad: } #ifdef ISP_TARGET_MODE -static int tdma_mk(ispsoftc_t *, tmd_xact_t *, ct_entry_t *, uint32_t *, uint32_t); -static int tdma_mkfc(ispsoftc_t *, tmd_xact_t *, ct2_entry_t *, uint32_t *, uint32_t); - -#define STATUS_WITH_DATA 1 - -/* - * We need to handle DMA for target mode differently from initiator mode. - * - * DMA mapping and construction and submission of CTIO Request Entries - * and rendevous for completion are very tightly coupled because we start - * out by knowing (per platform) how much data we have to move, but we - * don't know, up front, how many DMA mapping segments will have to be used - * cover that data, so we don't know how many CTIO and Continuation Request - * Entries we will end up using. Further, for performance reasons we may want - * to (on the last CTIO for Fibre Channel), send status too (if all went well). - * - * The standard vector still goes through isp_pci_dmasetup, but the callback - * for the DMA mapping routines comes here instead with a pointer to a - * partially filled in already allocated request queue entry. - */ - static int -tdma_mk(ispsoftc_t *isp, tmd_xact_t *xact, ct_entry_t *cto, uint32_t *nxtip, uint32_t optr) +isp_pci_dmasetup_tgt(ispsoftc_t *isp, tmd_xact_t *xact, void *fqe) { - static const char ctx[] = "CTIO[%x] cdb0 0x%02x lun %u for iid %u flags 0x%x SSTS 0x%02x resid %u "; - static const char mid[] = "CTIO[%x] cdb0 0x%02x lun %u for iid %u flags 0x%x xfr %u moved %u/%u "; - struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; - struct scatterlist *sg; - ct_entry_t *qe; - uint8_t scsi_status; - uint32_t curi, nxti, handle; - uint32_t sflags; - int32_t resid; - tmd_cmd_t *tmd; - int nth_ctio, nctios, send_status, nseg, new_seg_cnt; + struct scatterlist *sg = NULL; + isp_ddir_t ddir; + uint32_t nseg; + int ret; - tmd = xact->td_cmd; - curi = isp->isp_reqidx; - qe = (ct_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx); - - if (cto->ct_flags & CT_SENDSTATUS) { - int level; - if (cto->ct_resid || cto->ct_scsi_status) { - level = ISP_LOGTINFO; + switch (((isphdr_t *)fqe)->rqs_entry_type) { + case RQSTYPE_CTIO: + if ((((ct_entry_t *)fqe)->ct_flags & CT_DATAMASK) == CT_DATA_OUT) { + ddir = ISP_FROM_DEVICE; + } else if ((((ct_entry_t *)fqe)->ct_flags & CT_DATAMASK) == CT_DATA_IN) { + ddir = ISP_TO_DEVICE; } else { - level = ISP_LOGTDEBUG0; + ddir = ISP_NOXFR; } - isp_prt(isp, level, ctx, cto->ct_fwhandle, tmd->cd_cdb[0], L0LUN_TO_FLATLUN(tmd->cd_lun), cto->ct_iid, cto->ct_flags, - cto->ct_scsi_status, cto->ct_resid); - } else { - isp_prt(isp, ISP_LOGTDEBUG0, mid, tmd->cd_cdb[0], cto->ct_fwhandle, L0LUN_TO_FLATLUN(tmd->cd_lun), cto->ct_iid, cto->ct_flags, - xact->td_xfrlen, tmd->cd_moved, tmd->cd_totlen); - } - - cto->ct_xfrlen = 0; - cto->ct_seg_count = 0; - cto->ct_header.rqs_entry_count = 1; - memset(cto->ct_dataseg, 0, sizeof (cto->ct_dataseg)); - - if (xact->td_xfrlen == 0) { - ISP_TDQE(isp, "tdma_mk[no data]", curi, cto); - isp_put_ctio(isp, cto, qe); - if (cto->ct_flags & CT_CCINCR) { - tmd->cd_lflags &= ~CDFL_RESRC_FILL; + break; + case RQSTYPE_CTIO2: + if ((((ct2_entry_t *)fqe)->ct_flags & CT2_DATAMASK) == CT2_DATA_OUT) { + ddir = ISP_FROM_DEVICE; + } else if ((((ct2_entry_t *)fqe)->ct_flags & CT2_DATAMASK) == CT2_DATA_IN) { + ddir = ISP_TO_DEVICE; + } else { + ddir = ISP_NOXFR; } - return (CMD_QUEUED); - } - - if (xact->td_xfrlen <= 1024) { - nseg = 0; - } else if (xact->td_xfrlen <= 4096) { - nseg = 1; - } else if (xact->td_xfrlen <= 32768) { - nseg = 2; - } else if (xact->td_xfrlen <= 65536) { - nseg = 3; - } else if (xact->td_xfrlen <= 131372) { - nseg = 4; - } else if (xact->td_xfrlen <= 262144) { - nseg = 5; - } else if (xact->td_xfrlen <= 524288) { - nseg = 6; - } else { - nseg = 7; - } - isp->isp_osinfo.bins[nseg]++; - - sg = xact->td_data; - nseg = 0; - resid = (int32_t) xact->td_xfrlen; - while (resid > 0) { - if (sg->length == 0) { - isp_prt(isp, ISP_LOGWARN, "%s: zero length segment #%d for tag %llx\n", __func__, nseg, tmd->cd_tagval); - cto->ct_resid = -EINVAL; - return (CMD_COMPLETE); + if (ddir != ISP_NOXFR && isp->isp_osinfo.is_64bit_dma) { + ((isphdr_t *)fqe)->rqs_entry_type = RQSTYPE_CTIO3; } - nseg++; - resid -= sg->length; - sg++; - } - sg = xact->td_data; - - new_seg_cnt = pci_map_sg(pcs->pci_dev, sg, nseg, (cto->ct_flags & CT_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - - if (new_seg_cnt == 0) { - isp_prt(isp, ISP_LOGWARN, "%s: unable to dma map request", __func__); - cto->ct_resid = -ENOMEM; + break; + case RQSTYPE_CTIO7: + if (((ct7_entry_t *)fqe)->ct_flags & CT7_DATA_OUT) { + ddir = ISP_FROM_DEVICE; + } else if (((ct7_entry_t *)fqe)->ct_flags & CT7_DATA_IN) { + ddir = ISP_TO_DEVICE; + } else { + ddir = ISP_NOXFR; + } + break; + default: + xact->td_error = -EINVAL; return (CMD_COMPLETE); } - tmd->cd_nseg = new_seg_cnt; - nctios = nseg / ISP_RQDSEG; - if (nseg % ISP_RQDSEG) { - nctios++; - } - - /* - * Save handle, and potentially any SCSI status, which - * we'll reinsert on the last CTIO we're going to send. - */ - handle = cto->ct_syshandle; - cto->ct_syshandle = 0; - cto->ct_header.rqs_seqno = 0; - send_status = (cto->ct_flags & CT_SENDSTATUS) != 0; - - if (send_status) { - sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR); - cto->ct_flags &= ~(CT_SENDSTATUS|CT_CCINCR); - /* - * Preserve residual. - */ - resid = cto->ct_resid; - - /* - * Save actual SCSI status. - */ - scsi_status = cto->ct_scsi_status; - -#ifndef STATUS_WITH_DATA - sflags |= CT_NO_DATA; - /* - * We can't do a status at the same time as a data CTIO, so - * we need to synthesize an extra CTIO at this level. - */ - nctios++; -#endif - } else { - sflags = scsi_status = resid = 0; - } - - cto->ct_resid = 0; - cto->ct_scsi_status = 0; - - nxti = *nxtip; - - for (nth_ctio = 0; nth_ctio < nctios; nth_ctio++) { - int seglim; - - seglim = nseg; - if (seglim) { - int seg; - - if (seglim > ISP_RQDSEG) - seglim = ISP_RQDSEG; - - for (seg = 0; seg < seglim; seg++, nseg--) { - XS_DMA_ADDR_T addr = sg_dma_address(sg); - - /* - * We could actually do the work to support this, - * but it's extra code to write and test with things - * pretty unlikely to ever be used. - */ - if (ISP_A64 && IS_HIGH_ISP_ADDR(addr)) { - isp_prt(isp, ISP_LOGERR, "%s: 64 bit tgt mode not supported", __func__); - cto->ct_resid = -EFAULT; - pci_unmap_sg(pcs->pci_dev, xact->td_data, nseg, (cto->ct_flags & CT_DATA_IN)? PCI_DMA_TODEVICE: PCI_DMA_FROMDEVICE); - return (CMD_COMPLETE); - } - /* - * Unlike normal initiator commands, we don't do any swizzling here. - */ - cto->ct_dataseg[seg].ds_base = LOWD(addr); - cto->ct_dataseg[seg].ds_count = (uint32_t) sg_dma_len(sg); - cto->ct_xfrlen += sg_dma_len(sg); - sg++; - } - cto->ct_seg_count = seg; - } else { - /* - * This case should only happen when we're - * sending an extra CTIO with final status. - */ - if (send_status == 0) { - isp_prt(isp, ISP_LOGERR, "%s: ran out of segments, no status to send", __func__); - return (CMD_EAGAIN); - } - } - - /* - * At this point, the fields ct_lun, ct_iid, ct_tagval, ct_tagtype, and - * ct_timeout have been carried over unchanged from what our caller had - * set. - * - * The dataseg fields and the seg_count fields we just got through - * setting. The data direction we've preserved all along and only - * clear it if we're now sending status. - */ - if (nth_ctio == nctios - 1) { - /* - * We're the last in a sequence of CTIOs, so mark this - * CTIO and save the handle to the command such that when - * this CTIO completes we can free dma resources and - * do whatever else we need to do to finish the rest - * of the command. - */ - cto->ct_syshandle = handle; - cto->ct_header.rqs_seqno = 1; - - if (send_status) { - cto->ct_scsi_status = scsi_status; - cto->ct_flags |= sflags; - cto->ct_resid = resid; - } - isp_put_ctio(isp, cto, qe); - ISP_TDQE(isp, "last tdma_mk", curi, cto); - if (nctios > 1) { - MEMORYBARRIER(isp, SYNC_REQUEST, curi, QENTRY_LEN); - } - } else { - ct_entry_t *oqe = qe; - - /* - * Make sure handle fields are clean - */ - cto->ct_syshandle = 0; - cto->ct_header.rqs_seqno = 0; - - isp_prt(isp, ISP_LOGTDEBUG1, "CTIO[%x] lun%d for ID%d ct_flags 0x%x", cto->ct_fwhandle, L0LUN_TO_FLATLUN(tmd->cd_lun), (int) cto->ct_iid, cto->ct_flags); - - /* - * Get a new CTIO - */ - qe = (ct_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); - nxti = ISP_NXT_QENTRY(nxti, RQUEST_QUEUE_LEN(isp)); - if (nxti == optr) { - isp_prt(isp, ISP_LOGERR, "%s: request queue overflow", __func__); - return (CMD_EAGAIN); - } - - /* - * Now that we're done with the old CTIO, - * flush it out to the request queue. - */ - ISP_TDQE(isp, "tdma_mk", curi, cto); - isp_put_ctio(isp, cto, oqe); - if (nth_ctio != 0) { - MEMORYBARRIER(isp, SYNC_REQUEST, curi, QENTRY_LEN); - } - curi = ISP_NXT_QENTRY(curi, RQUEST_QUEUE_LEN(isp)); - - /* - * Reset some fields in the CTIO so we can reuse - * for the next one we'll flush to the request - * queue. - */ - cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; - cto->ct_header.rqs_entry_count = 1; - cto->ct_header.rqs_flags = 0; - cto->ct_status = 0; - cto->ct_scsi_status = 0; - cto->ct_xfrlen = 0; - cto->ct_resid = 0; - cto->ct_seg_count = 0; - memset(cto->ct_dataseg, 0, sizeof (cto->ct_dataseg)); - } - } - *nxtip = nxti; - isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: map %d segments at %p for handle 0x%x", tmd->cd_tagval, new_seg_cnt, xact->td_data, cto->ct_syshandle); - if (sflags & CT_CCINCR) { - tmd->cd_lflags &= ~CDFL_RESRC_FILL; - } - return (CMD_QUEUED); -} - -/* - * We're passed a pointer to a prototype ct2_entry_t. - * - * If it doesn't contain any data movement, it has to be for sending status, - * possibly with Sense Data as well, so we send a single CTIO2. This should - * be a Mode 1 CTIO2, and it's up to the caller to set up the Sense Data - * and flags appropriately. - * - * If it does contain data movement, it may *also* be for sending status - * (possibly with Sense Data also). It's possible to describe to the firmware - * what we want in one CTIO2. However, under some conditions it is not, - * so we must also send a *second* CTIO2 after the first one. - * - * If the data to be sent is in segments that exceeds that which we can - * fit into a CTIO2 (likely, as there's only room for 3 segments), we - * utilize normal continuation entries, which get pushed after the - * first CTIO2, and possibly are followed by a final CTIO2. - * - * In any case, it's up to the caller to send us a Mode 0 CTIO2 describing - * the data to be moved (if any) and the appropriate flags indicating - * status. We'll clear and set as appropriate. We'll also check to see - * whether Sense Data is attempting to be sent and retrieve it as appropriate. - * - * In all cases the caller should not assume that the prototype CTIO2 - * has been left unchanged. - */ -#ifndef ISP_DISABLE_2400_SUPPORT -static int tdma_mk_2400(ispsoftc_t *, tmd_xact_t *, ct7_entry_t *, uint32_t *, uint32_t); -static int -tdma_mk_2400(ispsoftc_t *isp, tmd_xact_t *xact, ct7_entry_t *cto, uint32_t *nxtip, uint32_t optr) -{ - struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; - static const char ctx[] = "CTIO7[%llx] cdb0 0x%02x lun %u nphdl 0x%x flgs 0x%x ssts 0x%x xfr %u moved %u/%u resid %d "; - static const char mid[] = "CTIO7[%llx] cdb0 0x%02x lun %u nphdl 0x%x flgs 0x%x xfr %u moved %u/%u "; - XS_DMA_ADDR_T addr, last_synthetic_addr; - tmd_cmd_t *tmd = xact->td_cmd; - struct scatterlist *sg; - void *qe; - uint16_t swd; - uint32_t curi, nxti; - uint32_t bc, last_synthetic_count; - long xfcnt; /* must be signed */ - int nseg, seg, ovseg, seglim, new_seg_cnt; - ct7_entry_t *cto2 = NULL, ct2; -#if 0 -{ - static int fred = 0; - if (fred++ == 100) { - fred = 0; - printk("YAGGA!\n"); - return (CMD_EAGAIN); - } -} -#endif - - nxti = *nxtip; - curi = isp->isp_reqidx; - qe = ISP_QUEUE_ENTRY(isp->isp_rquest, curi); - - if (cto->ct_flags & CT7_SENDSTATUS) { - int level; - if (cto->ct_resid || cto->ct_scsi_status) { - level = ISP_LOGTINFO; - } else { - level = ISP_LOGTDEBUG0; - } - isp_prt(isp, level, ctx, (unsigned long long) tmd->cd_tagval, tmd->cd_cdb[0], L0LUN_TO_FLATLUN(tmd->cd_lun), cto->ct_nphdl, cto->ct_flags, - cto->ct_scsi_status, xact->td_xfrlen, tmd->cd_moved, tmd->cd_totlen, cto->ct_resid); - } else { - isp_prt(isp, ISP_LOGTDEBUG0, mid, (unsigned long long) tmd->cd_tagval, tmd->cd_cdb[0], L0LUN_TO_FLATLUN(tmd->cd_lun), cto->ct_nphdl, cto->ct_flags, - xact->td_xfrlen, tmd->cd_moved, tmd->cd_totlen); - } - - /* - * Handle commands that transfer no data right away. - */ - if (xact->td_xfrlen == 0) { - cto->ct_header.rqs_entry_count = 1; - cto->ct_header.rqs_seqno = 1; - - /* ct_syshandle contains the synchronization handle set by caller */ - isp_put_ctio7(isp, cto, qe); - ISP_TDQE(isp, "tdma_mk_2400[no data]", curi, qe); - return (CMD_QUEUED); - } - - if (xact->td_xfrlen <= 1024) { - nseg = 0; - } else if (xact->td_xfrlen <= 4096) { - nseg = 1; - } else if (xact->td_xfrlen <= 32768) { - nseg = 2; - } else if (xact->td_xfrlen <= 65536) { - nseg = 3; - } else if (xact->td_xfrlen <= 131372) { - nseg = 4; - } else if (xact->td_xfrlen <= 262144) { - nseg = 5; - } else if (xact->td_xfrlen <= 524288) { - nseg = 6; - } else { - nseg = 7; - } - isp->isp_osinfo.bins[nseg]++; - - /* - * First, count and map all S/G segments - * - * The byte counter has to be signed because - * we can have descriptors that are, in fact, - * longer than our data transfer count. - */ - sg = xact->td_data; - nseg = 0; - xfcnt = xact->td_xfrlen; - while (xfcnt > 0) { - if (sg->length == 0) { - isp_prt(isp, ISP_LOGWARN, "%s: zero length segment #%d for tag %llx\n", __func__, nseg, tmd->cd_tagval); - cto->ct_resid = -EINVAL; - return (CMD_COMPLETE); - } - nseg++; - xfcnt -= sg->length; - sg++; - } - sg = xact->td_data; - new_seg_cnt = pci_map_sg(pcs->pci_dev, sg, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - if (new_seg_cnt == 0) { - isp_prt(isp, ISP_LOGWARN, "%s: unable to dma map request", __func__); - cto->ct_resid = -EFAULT; - return (CMD_COMPLETE); - } - tmd->cd_nseg = new_seg_cnt; - - /* - * Check for sequential ordering of data frames - */ - if (tmd->cd_lastoff + tmd->cd_lastsize != xact->td_offset) { - isp_prt(isp, ISP_LOGWARN, "%s: [0x%llx] lastoff %u lastsize %u but curoff %u (totlen %u)", __func__, (unsigned long long) tmd->cd_tagval, tmd->cd_lastoff, tmd->cd_lastsize, xact->td_offset, tmd->cd_totlen); - } - tmd->cd_lastsize = xact->td_xfrlen; - tmd->cd_lastoff = xact->td_offset; - - /* - * Second, figure out whether we'll need to send a separate status CTIO. - */ - swd = cto->ct_scsi_status; - - if ((cto->ct_flags & CT7_SENDSTATUS) && ((swd & 0xff) || cto->ct_resid)) { - cto2 = &ct2; - /* - * Copy over CTIO2 - */ - memcpy(cto2, cto, sizeof (ct7_entry_t)); - - /* - * Clear fields from first CTIO7 that now need to be cleared - */ - cto->ct_flags &= ~CT7_SENDSTATUS; - cto->ct_resid = 0; - cto->ct_syshandle = 0; - cto->ct_scsi_status = 0; - - /* - * Reset fields in the second CTIO7 as appropriate. - */ - cto2->ct_flags &= ~(CT7_FLAG_MMASK|CT7_DATAMASK); - cto2->ct_flags |= CT7_NO_DATA|CT7_NO_DATA|CT7_FLAG_MODE1; - cto2->ct_seg_count = 0; - memset(&cto2->rsp, 0, sizeof (cto2->rsp)); - cto2->ct_scsi_status = swd; - if ((swd & 0xff) == SCSI_CHECK && (xact->td_hflags & TDFH_SNSVALID)) { - cto2->rsp.m1.ct_resplen = min(TMD_SENSELEN, MAXRESPLEN_24XX); - memcpy(cto2->rsp.m1.ct_resp, tmd->cd_sense, cto2->rsp.m1.ct_resplen); - cto2->ct_scsi_status |= (FCP_SNSLEN_VALID << 8); - } - } - - /* - * Third, fill in the data segments in the first CTIO2 itself. - * This is also a good place to set the relative offset. - */ - xfcnt = xact->td_xfrlen; - - cto->rsp.m0.reloff = xact->td_offset; - - seglim = 1; - - last_synthetic_count = 0; - last_synthetic_addr = 0; - cto->ct_seg_count = 1; - seg = 1; - - bc = min(sg_dma_len(sg), xfcnt); - addr = sg_dma_address(sg); - cto->rsp.m0.ds.ds_base = LOWD(addr); - cto->rsp.m0.ds.ds_basehi = HIWD(addr); - if (!SAME_4G(addr, bc)) { - isp_prt(isp, ISP_LOGTDEBUG1, "seg0[%d]%x%08x:%u (TRUNC'd)", seg, (uint32_t) HIWD(addr), (uint32_t)LOWD(addr), bc); - cto->rsp.m0.ds.ds_count = (unsigned int) (FOURG_SEG(addr + bc) - addr); - addr += cto->rsp.m0.ds.ds_count; - bc -= cto->rsp.m0.ds.ds_count; - last_synthetic_count = bc; - last_synthetic_addr = addr; - } else { - cto->rsp.m0.ds.ds_count = bc; - isp_prt(isp, ISP_LOGTDEBUG1, "%s: seg%d[%d]%llx:%u", __func__, 0, 0, (unsigned long long) addr, bc); - } - cto->rsp.m0.ct_xfrlen += bc; - xfcnt -= bc; - sg++; - - - if (seg == nseg && last_synthetic_count == 0) { - goto mbxsync; - } - - /* - * Now do any continuation segments that are required. - */ - do { - int lim; - uint32_t curip; - ispcontreq64_t local, *crq = &local, *qep; - - curip = nxti; - qep = (ispcontreq64_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curip); - nxti = ISP_NXT_QENTRY((curip), RQUEST_QUEUE_LEN(isp)); - if (nxti == optr) { - pci_unmap_sg(pcs->pci_dev, xact->td_data, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - isp_prt(isp, ISP_LOGTDEBUG0, "%s: out of space for continuations (%d of %d segs done)", __func__, cto->ct_seg_count, nseg); - return (CMD_EAGAIN); - } - cto->ct_header.rqs_entry_count++; - BUG_ON(cto->ct_header.rqs_entry_count == 0); - memset((void *)crq, 0, sizeof (*crq)); - crq->req_header.rqs_entry_count = 1; - crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; - lim = ISP_CDSEG64; - - for (ovseg = 0; (seg < nseg || last_synthetic_count) && ovseg < lim; seg++, ovseg++, sg++) { - if (last_synthetic_count) { - addr = last_synthetic_addr; - bc = last_synthetic_count; - last_synthetic_count = 0; - sg--; - seg--; - } else { - addr = sg_dma_address(sg); - bc = min(sg_dma_len(sg), xfcnt); - } - isp_prt(isp, ISP_LOGTDEBUG1, "%s: seg%d[%d]%llx:%u", __func__, cto->ct_header.rqs_entry_count-1, ovseg, (unsigned long long) addr, bc); - - cto->ct_seg_count++; - cto->rsp.m0.ct_xfrlen += bc; - - crq->req_dataseg[ovseg].ds_count = bc; - crq->req_dataseg[ovseg].ds_base = LOWD(addr); - crq->req_dataseg[ovseg].ds_basehi = HIWD(addr); - /* - * Make sure we don't cross a 4GB boundary. - */ - if (!SAME_4G(addr, bc)) { - isp_prt(isp, ISP_LOGTDEBUG1, "seg%d[%d]%llx:%u (TRUNC'd)", cto->ct_header.rqs_entry_count-1, ovseg, (long long)addr, bc); - crq->req_dataseg[ovseg].ds_count = (unsigned int) (FOURG_SEG(addr + bc) - addr); - addr += crq->req_dataseg[ovseg].ds_count; - bc -= crq->req_dataseg[ovseg].ds_count; - xfcnt -= crq->req_dataseg[ovseg].ds_count; - /* - * Do we have space to split it here? - */ - if (ovseg == lim - 1) { - last_synthetic_count = bc; - last_synthetic_addr = addr; - cto->ct_seg_count++; - } else { - ovseg++; - crq->req_dataseg[ovseg].ds_count = bc; - crq->req_dataseg[ovseg].ds_base = LOWD(addr); - crq->req_dataseg[ovseg].ds_basehi = HIWD(addr); - } - } - } - ISP_TDQE(isp, "tdma_mk_2400 cont", curip, crq); - MEMORYBARRIER(isp, SYNC_REQUEST, curip, QENTRY_LEN); - isp_put_cont64_req(isp, (ispcontreq64_t *)crq, (ispcontreq64_t *)qep); - } while (seg < nseg || last_synthetic_count); - - isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: map %d segments at %p for handle 0x%x", tmd->cd_tagval, new_seg_cnt, xact->td_data, cto->ct_syshandle); - -mbxsync: - - /* - * If we have a final CTIO2, allocate and push *that* - * onto the request queue. - */ - if (cto2) { - qe = (ct7_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); - curi = nxti; - nxti = ISP_NXT_QENTRY(curi, RQUEST_QUEUE_LEN(isp)); - if (nxti == optr) { - pci_unmap_sg(pcs->pci_dev, xact->td_data, nseg, (cto->ct_flags & CT7_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - isp_prt(isp, ISP_LOGTDEBUG0, "%s: request queue overflow", __func__); - return (CMD_EAGAIN); - } - MEMORYBARRIER(isp, SYNC_REQUEST, curi, QENTRY_LEN); - isp_put_ctio7(isp, cto2, (ct7_entry_t *)qe); - ISP_TDQE(isp, "tdma_mk_2400:final", curi, cto2); - } - qe = ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx); - isp_put_ctio7(isp, cto, qe); - if (cto->ct_flags & CT2_FASTPOST) { - isp_prt(isp, ISP_LOGTDEBUG1, "[%x] fastpost (0x%x) with entry count %d", cto->ct_rxid, tmd->cd_cdb[0], cto->ct_header.rqs_entry_count); - } - ISP_TDQE(isp, "tdma_mk_2400", isp->isp_reqidx, cto); - *nxtip = nxti; - return (CMD_QUEUED); -} -#endif - -static int -tdma_mkfc(ispsoftc_t *isp, tmd_xact_t *xact, ct2_entry_t *cto, uint32_t *nxtip, uint32_t optr) -{ - struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; - static const char ctx[] = "CTIO2[%x] cdb0 0x%02x lun %u for 0x%016llx flags 0x%x SSTS 0x%04x resid %u "; - static const char mid[] = "CTIO2[%x] cdb0 0x%02x lun %u for 0x%016llx flags 0x%x xfr %u moved %u/%u "; - XS_DMA_ADDR_T addr, last_synthetic_addr; - tmd_cmd_t *tmd = xact->td_cmd; - struct scatterlist *sg; - void *qe; - uint16_t swd; - uint32_t curi, nxti; - uint32_t bc, last_synthetic_count; - long xfcnt; /* must be signed */ - int nseg, seg, ovseg, seglim, new_seg_cnt; - ct2_entry_t *cto2 = NULL, ct2; - - nxti = *nxtip; - curi = isp->isp_reqidx; - qe = ISP_QUEUE_ENTRY(isp->isp_rquest, curi); - - - if (cto->ct_flags & CT2_SENDSTATUS) { - int level; - if ((cto->ct_flags & CT2_FLAG_MMASK) == CT2_FLAG_MODE0) { - swd = cto->rsp.m0.ct_scsi_status; - } else if ((cto->ct_flags & CT2_FLAG_MMASK) == CT2_FLAG_MODE1) { - swd = cto->rsp.m1.ct_scsi_status; - } else { - swd = 0; - } - if (cto->ct_resid || swd) { - level = ISP_LOGTINFO; - } else { - level = ISP_LOGTDEBUG0; - } - isp_prt(isp, level, ctx, cto->ct_rxid, tmd->cd_cdb[0], L0LUN_TO_FLATLUN(tmd->cd_lun), (unsigned long long) tmd->cd_iid, cto->ct_flags, swd, cto->ct_resid); - } else { - isp_prt(isp, ISP_LOGTDEBUG0, mid, cto->ct_rxid, tmd->cd_cdb[0], L0LUN_TO_FLATLUN(tmd->cd_lun), (unsigned long long) tmd->cd_iid, cto->ct_flags, - xact->td_xfrlen, tmd->cd_moved, tmd->cd_totlen); - swd = 0; - } - - if (cto->ct_flags & CT2_FASTPOST) { - if ((xact->td_hflags & (TDFH_STSVALID|TDFH_SNSVALID)) != TDFH_STSVALID) { - cto->ct_flags &= ~CT2_FASTPOST; - } - } - - /* - * Handle commands that transfer no data right away. - */ - if (xact->td_xfrlen == 0) { - cto->ct_header.rqs_entry_count = 1; - cto->ct_header.rqs_seqno = 1; - /* ct_syshandle contains the synchronization handle set by caller */ - cto->ct_seg_count = 0; - cto->ct_reloff = 0; - if (ISP_CAP_2KLOGIN(isp)) { - isp_put_ctio2e(isp, (ct2e_entry_t *)cto, (ct2e_entry_t *)qe); - } else { - isp_put_ctio2(isp, cto, qe); - } - if (cto->ct_flags & CT2_FASTPOST) { - isp_prt(isp, ISP_LOGTDEBUG1, "[%x] faspost (0x%x)", cto->ct_rxid, tmd->cd_cdb[0]); - } - ISP_TDQE(isp, "tdma_mkfc[no data]", curi, qe); - if (cto->ct_flags & CT2_CCINCR) { - tmd->cd_lflags &= ~CDFL_RESRC_FILL; - } - return (CMD_QUEUED); - } - - if (xact->td_xfrlen <= 1024) { - nseg = 0; - } else if (xact->td_xfrlen <= 4096) { - nseg = 1; - } else if (xact->td_xfrlen <= 32768) { - nseg = 2; - } else if (xact->td_xfrlen <= 65536) { - nseg = 3; - } else if (xact->td_xfrlen <= 131372) { - nseg = 4; - } else if (xact->td_xfrlen <= 262144) { - nseg = 5; - } else if (xact->td_xfrlen <= 524288) { - nseg = 6; - } else { - nseg = 7; - } - isp->isp_osinfo.bins[nseg]++; - - - /* - * First, count and map all S/G segments - * - * The byte counter has to be signed because - * we can have descriptors that are, in fact, - * longer than our data transfer count. - */ - sg = xact->td_data; - nseg = 0; - xfcnt = xact->td_xfrlen; - while (xfcnt > 0) { - if (sg->length == 0) { - isp_prt(isp, ISP_LOGWARN, "%s: zero length segment #%d for tag %llx\n", __func__, nseg, tmd->cd_tagval); - cto->ct_resid = -EINVAL; - return (CMD_COMPLETE); - } - nseg++; - xfcnt -= sg->length; - sg++; - } - sg = xact->td_data; - new_seg_cnt = pci_map_sg(pcs->pci_dev, sg, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - if (new_seg_cnt == 0) { - isp_prt(isp, ISP_LOGWARN, "%s: unable to dma map request", __func__); - cto->ct_resid = -EFAULT; - return (CMD_COMPLETE); - } - tmd->cd_nseg = new_seg_cnt; - - /* - * Second, figure out whether we'll need to send a separate status CTIO. - */ - - if ((cto->ct_flags & CT2_SENDSTATUS) && ((swd & 0xff) || cto->ct_resid)) { - cto2 = &ct2; - /* - * Copy over CTIO2 - */ - memcpy(cto2, cto, sizeof (ct2_entry_t)); - - /* - * Clear fields from first CTIO2 that now need to be cleared - */ - cto->ct_flags &= ~(CT2_SENDSTATUS|CT2_CCINCR|CT2_FASTPOST); - cto->ct_resid = 0; - cto->ct_syshandle = 0; - cto->rsp.m0.ct_scsi_status = 0; - - /* - * Reset fields in the second CTIO2 as appropriate. - */ - cto2->ct_flags &= ~(CT2_FLAG_MMASK|CT2_DATAMASK|CT2_FASTPOST); - cto2->ct_flags |= CT2_NO_DATA|CT2_FLAG_MODE1; - cto2->ct_seg_count = 0; - cto2->ct_reloff = 0; - memset(&cto2->rsp, 0, sizeof (cto2->rsp)); - if ((swd & 0xff) == SCSI_CHECK && (swd & CT2_SNSLEN_VALID)) { - cto2->rsp.m1.ct_senselen = min(TMD_SENSELEN, MAXRESPLEN); - memcpy(cto2->rsp.m1.ct_resp, tmd->cd_sense, cto2->rsp.m1.ct_senselen); - swd |= CT2_SNSLEN_VALID; - } - if (cto2->ct_resid > 0) { - swd |= CT2_DATA_UNDER; - } else if (cto2->ct_resid < 0) { - swd |= CT2_DATA_OVER; - } - cto2->rsp.m1.ct_scsi_status = swd; - if (cto2->ct_flags & CT2_CCINCR) { - tmd->cd_lflags &= ~CDFL_RESRC_FILL; - } - } else if ((cto->ct_flags & (CT2_SENDSTATUS|CT2_CCINCR)) == (CT2_SENDSTATUS|CT2_CCINCR)) { - tmd->cd_lflags &= ~CDFL_RESRC_FILL; - } - - /* - * Third, fill in the data segments in the first CTIO2 itself. - * This is also a good place to set the relative offset. - */ - xfcnt = xact->td_xfrlen; - cto->ct_reloff = xact->td_offset; - - /* - * This is a good place to return to if we need to redo this with - * 64 bit PCI addressing. We really want to use 32 bit addressing - * if we can because it's a lot more efficient. - */ - if (IS_2322(isp)) { - seglim = ISP_RQDSEG_T3; - cto->ct_header.rqs_entry_type = RQSTYPE_CTIO3; - if (cto2) { - cto2->ct_header.rqs_entry_type = RQSTYPE_CTIO3; - } - } else { - seglim = ISP_RQDSEG_T2; - cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; - if (cto2) { - cto2->ct_header.rqs_entry_type = RQSTYPE_CTIO2; - } - } - -again: - last_synthetic_count = 0; - last_synthetic_addr = 0; - cto->ct_seg_count = min(nseg, seglim); - - for (seg = 0; seg < cto->ct_seg_count; seg++) { - bc = min(sg_dma_len(sg), xfcnt); - addr = sg_dma_address(sg); -#ifdef ISP_DAC_SUPPORTED - if (seglim == ISP_RQDSEG_T2) { - if (IS_HIGH_ISP_ADDR(addr)) { - cto->ct_header.rqs_entry_type = RQSTYPE_CTIO3; - if (cto2) { - cto2->ct_header.rqs_entry_type = RQSTYPE_CTIO3; - } - xfcnt = xact->td_xfrlen; - cto->rsp.m0.ct_xfrlen = 0; - sg = xact->td_data; - seglim = ISP_RQDSEG_T3; - isp_prt(isp, ISP_LOGTDEBUG2, "%s: found hi page", __func__); - goto again; - } - cto->rsp.m0.u.ct_dataseg[seg].ds_base = LOWD(addr); - cto->rsp.m0.u.ct_dataseg[seg].ds_count = bc; - isp_prt(isp, ISP_LOGTDEBUG1, "%s: seg0[%d]%x:%u", __func__, seg, cto->rsp.m0.u.ct_dataseg[seg].ds_base, bc); - } else { - cto->rsp.m0.u.ct_dataseg64[seg].ds_base = LOWD(addr); - cto->rsp.m0.u.ct_dataseg64[seg].ds_basehi = HIWD(addr); - if (!SAME_4G(addr, bc)) { - isp_prt(isp, ISP_LOGTDEBUG1, "seg0[%d]%x%08x:%u (TRUNC'd)", seg, (uint32_t) HIWD(addr), (uint32_t)LOWD(addr), bc); - cto->rsp.m0.u.ct_dataseg64[seg].ds_count = (unsigned int) (FOURG_SEG(addr + bc) - addr); - addr += cto->rsp.m0.u.ct_dataseg64[seg].ds_count; - bc -= cto->rsp.m0.u.ct_dataseg64[seg].ds_count; - /* - * Do we have space to split it here? - */ - if (seg == seglim - 1) { - last_synthetic_count = bc; - last_synthetic_addr = addr; - } else { - cto->ct_seg_count++; - seg++; - cto->rsp.m0.u.ct_dataseg64[seg].ds_count = bc; - cto->rsp.m0.u.ct_dataseg64[seg].ds_base = LOWD(addr); - cto->rsp.m0.u.ct_dataseg64[seg].ds_basehi = HIWD(addr); - isp_prt(isp, ISP_LOGALL, "%s: seg0[%d]%lx%08lx:%u", __func__, seg, - (unsigned long)cto->rsp.m0.u.ct_dataseg64[seg].ds_basehi, (unsigned long)cto->rsp.m0.u.ct_dataseg64[seg].ds_base, bc); - } - } else { - cto->rsp.m0.u.ct_dataseg64[seg].ds_count = bc; - isp_prt(isp, ISP_LOGTDEBUG1, "%s: seg0[%d]%lx%08lx:%u", __func__, seg, - (unsigned long)cto->rsp.m0.u.ct_dataseg64[seg].ds_basehi, (unsigned long)cto->rsp.m0.u.ct_dataseg64[seg].ds_base, bc); - } - } -#else - if (seglim == ISP_RQDSEG_T2) { - cto->rsp.m0.u.ct_dataseg[seg].ds_base = addr; - cto->rsp.m0.u.ct_dataseg[seg].ds_count = bc; - isp_prt(isp, ISP_LOGTDEBUG1, "%s: seg0[%d]%x:%u", __func__, seg, cto->rsp.m0.u.ct_dataseg[seg].ds_base, bc); - } else { - cto->rsp.m0.u.ct_dataseg64[seg].ds_base = addr; - cto->rsp.m0.u.ct_dataseg64[seg].ds_basehi = 0; - cto->rsp.m0.u.ct_dataseg64[seg].ds_count = bc; - isp_prt(isp, ISP_LOGTDEBUG1, "%s: seg0[%d]%lx:%u", __func__, seg, (unsigned long) cto->rsp.m0.u.ct_dataseg64[seg].ds_base, bc); - } -#endif - cto->rsp.m0.ct_xfrlen += bc; - xfcnt -= bc; - sg++; - } - - - if (seg == nseg && last_synthetic_count == 0) { - goto mbxsync; - } - - /* - * Now do any continuation segments that are required. - */ - do { - int lim; - uint32_t curip; - ispcontreq_t local, *crq = &local, *qep; - - curip = nxti; - qep = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curip); - nxti = ISP_NXT_QENTRY((curip), RQUEST_QUEUE_LEN(isp)); - if (nxti == optr) { - pci_unmap_sg(pcs->pci_dev, xact->td_data, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - isp_prt(isp, ISP_LOGTDEBUG0, "%s: out of space for continuations (%d of %d segs done)", __func__, cto->ct_seg_count, nseg); - return (CMD_EAGAIN); - } - cto->ct_header.rqs_entry_count++; - memset((void *)crq, 0, sizeof (*crq)); - crq->req_header.rqs_entry_count = 1; - if (cto->ct_header.rqs_entry_type == RQSTYPE_CTIO3) { - crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; - lim = ISP_CDSEG64; - } else { - crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; - lim = ISP_CDSEG; - } - - for (ovseg = 0; (seg < nseg || last_synthetic_count) && ovseg < lim; seg++, ovseg++, sg++) { - if (last_synthetic_count) { - addr = last_synthetic_addr; - bc = last_synthetic_count; - last_synthetic_count = 0; - sg--; - seg--; - } else { - addr = sg_dma_address(sg); - bc = min(sg_dma_len(sg), xfcnt); - } - isp_prt(isp, ISP_LOGTDEBUG1, "%s: seg%d[%d]%llx:%u", __func__, cto->ct_header.rqs_entry_count-1, ovseg, (unsigned long long) addr, bc); - - cto->ct_seg_count++; - cto->rsp.m0.ct_xfrlen += bc; - - if (crq->req_header.rqs_entry_type == RQSTYPE_A64_CONT) { - ispcontreq64_t *xrq = (ispcontreq64_t *) crq; - xrq->req_dataseg[ovseg].ds_count = bc; - xrq->req_dataseg[ovseg].ds_base = LOWD(addr); - xrq->req_dataseg[ovseg].ds_basehi = HIWD(addr); - /* - * Make sure we don't cross a 4GB boundary. - */ - if (!SAME_4G(addr, bc)) { - isp_prt(isp, ISP_LOGTDEBUG1, "seg%d[%d]%llx:%u (TRUNC'd)", cto->ct_header.rqs_entry_count-1, ovseg, (long long)addr, bc); - xrq->req_dataseg[ovseg].ds_count = (unsigned int) (FOURG_SEG(addr + bc) - addr); - addr += xrq->req_dataseg[ovseg].ds_count; - bc -= xrq->req_dataseg[ovseg].ds_count; - xfcnt -= xrq->req_dataseg[ovseg].ds_count; - /* - * Do we have space to split it here? - */ - if (ovseg == lim - 1) { - last_synthetic_count = bc; - last_synthetic_addr = addr; - cto->ct_seg_count++; - } else { - ovseg++; - xrq->req_dataseg[ovseg].ds_count = bc; - xrq->req_dataseg[ovseg].ds_base = LOWD(addr); - xrq->req_dataseg[ovseg].ds_basehi = HIWD(addr); - } - } - continue; - } - /* - * We get here if we're a 32 bit continuation entry. - * We also check for being over 32 bits with our PCI - * address. If we are, we set ourselves up to do 64 - * bit addressing and start the whole mapping process - * all over again- we apparently can't really mix types - */ - if (ISP_A64 && IS_HIGH_ISP_ADDR(addr)) { - nxti = *nxtip; - cto->ct_header.rqs_entry_count = 1; - xfcnt = xact->td_xfrlen; - cto->ct_header.rqs_entry_type = RQSTYPE_CTIO3; - if (cto2) { - cto2->ct_header.rqs_entry_type = RQSTYPE_CTIO3; - } - cto->rsp.m0.ct_xfrlen = 0; - sg = xact->td_data; - seglim = ISP_RQDSEG_T3; - isp_prt(isp, ISP_LOGTDEBUG1, "%s: found hi page in continuation, restarting", __func__); - goto again; - } - crq->req_dataseg[ovseg].ds_count = bc; - crq->req_dataseg[ovseg].ds_base = addr; - xfcnt -= bc; - } - - ISP_TDQE(isp, "tdma_mkfc cont", curip, crq); - MEMORYBARRIER(isp, SYNC_REQUEST, curip, QENTRY_LEN); - if (crq->req_header.rqs_entry_type == RQSTYPE_A64_CONT) { - isp_put_cont64_req(isp, (ispcontreq64_t *)crq, (ispcontreq64_t *)qep); - } else { - isp_put_cont_req(isp, crq, qep); - } - } while (seg < nseg || last_synthetic_count); - - isp_prt(isp, ISP_LOGTDEBUG2, "[%llx]: map %d segments at %p for handle 0x%x", tmd->cd_tagval, new_seg_cnt, xact->td_data, cto->ct_syshandle); - -mbxsync: - - /* - * If we have a final CTIO2, allocate and push *that* - * onto the request queue. - */ - if (cto2) { - qe = (ct2_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti); - curi = nxti; - nxti = ISP_NXT_QENTRY(curi, RQUEST_QUEUE_LEN(isp)); - if (nxti == optr) { - pci_unmap_sg(pcs->pci_dev, xact->td_data, nseg, (cto->ct_flags & CT2_DATA_IN)? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - isp_prt(isp, ISP_LOGTDEBUG0, "%s: request queue overflow", __func__); - return (CMD_EAGAIN); - } - MEMORYBARRIER(isp, SYNC_REQUEST, curi, QENTRY_LEN); - isp_put_ctio2(isp, cto2, (ct2_entry_t *)qe); - ISP_TDQE(isp, "tdma_mkfc:final", curi, cto2); - } - qe = ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx); - if (ISP_CAP_2KLOGIN(isp)) { - isp_put_ctio2e(isp, (ct2e_entry_t *)cto, (ct2e_entry_t *)qe); - } else { - isp_put_ctio2(isp, cto, qe); - } - if (cto->ct_flags & CT2_FASTPOST) { - isp_prt(isp, ISP_LOGTDEBUG1, "[%x] fastpost (0x%x) with entry count %d", cto->ct_rxid, tmd->cd_cdb[0], cto->ct_header.rqs_entry_count); - } - ISP_TDQE(isp, "tdma_mkfc", isp->isp_reqidx, cto); - *nxtip = nxti; - return (CMD_QUEUED); -} -#endif - -static int -isp_pci_dmasetup(ispsoftc_t *isp, Scsi_Cmnd *Cmnd, ispreq_t *rq, uint32_t *nxi, uint32_t optr) -{ - struct scatterlist *sg, *savesg; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - XS_DMA_ADDR_T one_shot_addr, last_synthetic_addr; - unsigned int one_shot_length, last_synthetic_count; -#else - XS_DMA_ADDR_T last_synthetic_addr; - unsigned int last_synthetic_count; -#endif - int segcnt, seg, ovseg, seglim; - void *h; - uint32_t nxti; - -#ifdef ISP_TARGET_MODE - if (rq->req_header.rqs_entry_type == RQSTYPE_CTIO || rq->req_header.rqs_entry_type == RQSTYPE_CTIO2 || rq->req_header.rqs_entry_type == RQSTYPE_CTIO3) { - int s; - if (IS_FC(isp)) { - s = tdma_mkfc(isp, (tmd_xact_t *)Cmnd, (ct2_entry_t *)rq, nxi, optr); - } else { - s = tdma_mk(isp, (tmd_xact_t *)Cmnd, (ct_entry_t *)rq, nxi, optr); - } - return (s); - } -#endif - - nxti = *nxi; - h = (void *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx); - - if (Cmnd->sc_data_direction == SCSI_DATA_NONE || XS_XFRLEN(Cmnd) == 0) { - rq->req_seg_count = 1; - goto mbxsync; - } - - if (XS_XFRLEN(Cmnd) <= 1024) { - seg = 0; - } else if (XS_XFRLEN(Cmnd) <= 4096) { - seg = 1; - } else if (XS_XFRLEN(Cmnd) <= 32768) { - seg = 2; - } else if (XS_XFRLEN(Cmnd) <= 65536) { - seg = 3; - } else if (XS_XFRLEN(Cmnd) <= 131372) { - seg = 4; - } else if (XS_XFRLEN(Cmnd) <= 262144) { - seg = 5; - } else if (XS_XFRLEN(Cmnd) <= 524288) { - seg = 6; - } else { - seg = 7; - } - isp->isp_osinfo.bins[seg]++; - - if (IS_FC(isp)) { - seglim = ISP_RQDSEG_T2; - ((ispreqt2_t *)rq)->req_totalcnt = XS_XFRLEN(Cmnd); - if (Cmnd->sc_data_direction == SCSI_DATA_WRITE) { - ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT; - } else if (Cmnd->sc_data_direction == SCSI_DATA_READ) { - ((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN; - } else { - isp_prt(isp, ISP_LOGERR, "%s: unkown data direction (%x) for %d byte request (opcode 0x%x)", __func__, - Cmnd->sc_data_direction, XS_XFRLEN(Cmnd), Cmnd->cmnd[0]); - XS_SETERR(Cmnd, HBA_BOTCH); - return (CMD_COMPLETE); - } - } else { - if (Cmnd->cmd_len > 12) { - seglim = 0; - } else { - seglim = ISP_RQDSEG; - } - if (Cmnd->sc_data_direction == SCSI_DATA_WRITE) { - rq->req_flags |= REQFLAG_DATA_OUT; - } else if (Cmnd->sc_data_direction == SCSI_DATA_READ) { - rq->req_flags |= REQFLAG_DATA_IN; - } else { - isp_prt(isp, ISP_LOGERR, "%s: unkown data direction (%x) for %d byte request (opcode 0x%x)", __func__, - Cmnd->sc_data_direction, XS_XFRLEN(Cmnd), Cmnd->cmnd[0]); - XS_SETERR(Cmnd, HBA_BOTCH); - return (CMD_COMPLETE); - } - } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - one_shot_addr = (XS_DMA_ADDR_T) 0; - one_shot_length = 0; - if ((segcnt = Cmnd->use_sg) == 0) { + if (ddir != ISP_NOXFR) { struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; - segcnt = 1; - sg = NULL; - one_shot_length = XS_XFRLEN(Cmnd); - one_shot_addr = pci_map_single(pcs->pci_dev, Cmnd->request_buffer, XS_XFRLEN(Cmnd), scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); - QLA_HANDLE(Cmnd) = (DMA_HTYPE_T) one_shot_addr; - } else { - struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; - sg = (struct scatterlist *) Cmnd->request_buffer; - segcnt = pci_map_sg(pcs->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); - } - if (segcnt == 0) { - isp_prt(isp, ISP_LOGWARN, "%s: unable to dma map request", __func__); - XS_SETERR(Cmnd, HBA_BOTCH); - return (CMD_COMPLETE); - } -#else - segcnt = scsi_dma_map(Cmnd); - if (segcnt <= 0) { - isp_prt(isp, ISP_LOGWARN, "%s: unable to dma map request", __func__); - XS_SETERR(Cmnd, HBA_BOTCH); - return (CMD_COMPLETE); - } - sg = scsi_sglist(Cmnd); -#endif - savesg = sg; + uint32_t xfcnt; -again: - last_synthetic_count = 0; - last_synthetic_addr = 0; - for (seg = 0, rq->req_seg_count = 0; seg < segcnt && rq->req_seg_count < seglim; seg++, rq->req_seg_count++) { - XS_DMA_ADDR_T addr; - unsigned int length; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - if (sg) { - length = sg_dma_len(sg); - addr = sg_dma_address(sg); + sg = xact->td_data; + xfcnt = xact->td_xfrlen; + nseg = 0; + while (xfcnt > 0) { + xfcnt -= sg->length; sg++; - } else { - length = one_shot_length; - addr = one_shot_addr; + nseg++; } -#else - length = sg_dma_len(sg); - addr = sg_dma_address(sg); - sg++; -#endif - - if (ISP_A64 && IS_HIGH_ISP_ADDR(addr)) { - if (IS_FC(isp)) { - if (rq->req_header.rqs_entry_type != RQSTYPE_T3RQS) { - rq->req_header.rqs_entry_type = RQSTYPE_T3RQS; - seglim = ISP_RQDSEG_T3; - sg = savesg; - goto again; - } - } else { - if (rq->req_header.rqs_entry_type != RQSTYPE_A64) { - rq->req_header.rqs_entry_type = RQSTYPE_A64; - seglim = ISP_RQDSEG_A64; - sg = savesg; - goto again; - } - } - } - - if (ISP_A64 && rq->req_header.rqs_entry_type == RQSTYPE_T3RQS) { - ispreqt3_t *rq3 = (ispreqt3_t *)rq; - rq3->req_dataseg[rq3->req_seg_count].ds_count = length; - rq3->req_dataseg[rq3->req_seg_count].ds_base = LOWD(addr); - rq3->req_dataseg[rq3->req_seg_count].ds_basehi = HIWD(addr); - /* - * Make sure we don't cross a 4GB boundary. - */ - if (!SAME_4G(addr, length)) { - isp_prt(isp, ISP_LOGDEBUG1, "seg0[%d]%08x%08x:%u (TRUNC'd)", rq->req_seg_count, (uint32_t)HIWD(addr), (uint32_t)LOWD(addr), length); - rq3->req_dataseg[rq3->req_seg_count].ds_count = (unsigned int) (FOURG_SEG(addr + length) - addr); - addr += rq3->req_dataseg[rq3->req_seg_count].ds_count; - length -= rq3->req_dataseg[rq3->req_seg_count].ds_count; - /* - * Do we have space to split it here? - */ - if (rq3->req_seg_count == seglim - 1) { - last_synthetic_count = length; - last_synthetic_addr = addr; - } else { - rq3->req_seg_count++; - rq3->req_dataseg[rq3->req_seg_count].ds_count = length; - rq3->req_dataseg[rq3->req_seg_count].ds_base = LOWD(addr); - rq3->req_dataseg[rq3->req_seg_count].ds_basehi = HIWD(addr); - } - } - } else if (ISP_A64 && rq->req_header.rqs_entry_type == RQSTYPE_A64) { - ispreq64_t *rq6 = (ispreq64_t *)rq; - rq6->req_dataseg[rq6->req_seg_count].ds_count = length; - rq6->req_dataseg[rq6->req_seg_count].ds_base = LOWD(addr); - rq6->req_dataseg[rq6->req_seg_count].ds_basehi = HIWD(addr); - /* - * Make sure we don't cross a dma boundary. - */ - if (!SAME_4G(addr, length) || (IS_1020(isp) && !SAME_SIXTEENM(addr, length))) { - isp_prt(isp, ISP_LOGDEBUG1, "seg0[%d]%llx:%u (TRUNC'd)", rq->req_seg_count, (long long)addr, length); - if (IS_1020(isp) && !SAME_SIXTEENM(addr, length)) { - rq6->req_dataseg[rq6->req_seg_count].ds_count = (unsigned int) (SIXTEENM_SEG(addr + length) - addr); - } else { - rq6->req_dataseg[rq6->req_seg_count].ds_count = (unsigned int) (FOURG_SEG(addr + length) - addr); - } - addr += rq6->req_dataseg[rq6->req_seg_count].ds_count; - length -= rq6->req_dataseg[rq6->req_seg_count].ds_count; - /* - * Do we have space to split it here? - */ - if (rq6->req_seg_count == seglim - 1) { - last_synthetic_count = length; - last_synthetic_addr = addr; - } else { - rq6->req_seg_count++; - rq6->req_dataseg[rq6->req_seg_count].ds_count = length; - rq6->req_dataseg[rq6->req_seg_count].ds_base = LOWD(addr); - rq6->req_dataseg[rq6->req_seg_count].ds_basehi = HIWD(addr); - } - } - } else if (rq->req_header.rqs_entry_type == RQSTYPE_T2RQS) { - ispreqt2_t *rq2 = (ispreqt2_t *)rq; - rq2->req_dataseg[rq2->req_seg_count].ds_count = length; - rq2->req_dataseg[rq2->req_seg_count].ds_base = addr; - } else if (IS_1020(isp) && !SAME_SIXTEENM(addr, length)) { - isp_prt(isp, ISP_LOGDEBUG1, "seg0[%d]%llx:%u (TRUNC'd)", rq->req_seg_count, (long long)addr, length); - rq->req_dataseg[rq->req_seg_count].ds_count = (unsigned int) (SIXTEENM_SEG(addr + length) - addr); - addr += rq->req_dataseg[rq->req_seg_count].ds_count; - length -= rq->req_dataseg[rq->req_seg_count].ds_count; - /* - * Do we have space to split it here? - */ - if (rq->req_seg_count == seglim - 1) { - last_synthetic_count = length; - last_synthetic_addr = addr; - } else { - rq->req_seg_count++; - rq->req_dataseg[rq->req_seg_count].ds_count = length; - rq->req_dataseg[rq->req_seg_count].ds_base = LOWD(addr); - } - } else { - rq->req_dataseg[rq->req_seg_count].ds_count = length; - rq->req_dataseg[rq->req_seg_count].ds_base = addr; - } - isp_prt(isp, ISP_LOGDEBUG1, "seg0[%d]%llx:%u", rq->req_seg_count, (long long)addr, length); - } - - if (sg == NULL || (seg == segcnt && last_synthetic_count == 0)) { - goto mbxsync; - } - - do { - int lim; - uint32_t curip; - ispcontreq_t local, *crq = &local, *qep; - - curip = nxti; - qep = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curip); - nxti = ISP_NXT_QENTRY((curip), RQUEST_QUEUE_LEN(isp)); - if (nxti == optr) { - isp_pci_dmateardown(isp, Cmnd, 0); - isp_prt(isp, ISP_LOGDEBUG0, "%s: Chan %d out of space for continuations (did %d of %d segments)", __func__, XS_CHANNEL(Cmnd), seg, segcnt); - XS_SETERR(Cmnd, HBA_BOTCH); - return (CMD_EAGAIN); - } - rq->req_header.rqs_entry_count++; - memset((void *)crq, 0, sizeof (*crq)); - crq->req_header.rqs_entry_count = 1; - if (rq->req_header.rqs_entry_type == RQSTYPE_T3RQS || rq->req_header.rqs_entry_type == RQSTYPE_A64) { - crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; - lim = ISP_CDSEG64; - } else { - crq->req_header.rqs_entry_type = RQSTYPE_DATASEG; - lim = ISP_CDSEG; - } - - for (ovseg = 0; (seg < segcnt || last_synthetic_count) && ovseg < lim; rq->req_seg_count++, seg++, ovseg++, sg++) { - XS_DMA_ADDR_T addr; - unsigned int length; - - if (last_synthetic_count) { - addr = last_synthetic_addr; - length = last_synthetic_count; - last_synthetic_count = 0; - sg--; - seg--; - } else { - addr = sg_dma_address(sg); - length = sg_dma_len(sg); - } - - if (length == 0) { - panic("zero length s-g element at line %d", __LINE__); - } - isp_prt(isp, ISP_LOGDEBUG1, "seg%d[%d]%llx:%u", rq->req_header.rqs_entry_count-1, ovseg, (unsigned long long) addr, length); - - if (crq->req_header.rqs_entry_type == RQSTYPE_A64_CONT) { - ispcontreq64_t *xrq = (ispcontreq64_t *) crq; - xrq->req_dataseg[ovseg].ds_count = length; - xrq->req_dataseg[ovseg].ds_base = LOWD(addr); - xrq->req_dataseg[ovseg].ds_basehi = HIWD(addr); - /* - * Make sure we don't cross a 4GB boundary. - */ - if (!SAME_4G(addr, length)) { - isp_prt(isp, ISP_LOGDEBUG1, "seg%d[%d]%llx:%u (TRUNC'd)", rq->req_header.rqs_entry_count-1, ovseg, (long long)addr, length); - xrq->req_dataseg[ovseg].ds_count = (unsigned int) (FOURG_SEG(addr + length) - addr); - addr += xrq->req_dataseg[ovseg].ds_count; - length -= xrq->req_dataseg[ovseg].ds_count; - /* - * Do we have space to split it here? - */ - if (ovseg == lim - 1) { - last_synthetic_count = length; - last_synthetic_addr = addr; - } else { - ovseg++; - xrq->req_dataseg[ovseg].ds_count = length; - xrq->req_dataseg[ovseg].ds_base = LOWD(addr); - xrq->req_dataseg[ovseg].ds_basehi = HIWD(addr); - } - } - continue; - } - /* - * We get here if we're a 32 bit continuation entry. - * We also check for being over 32 bits with our PCI - * address. If we are, we set ourselves up to do 64 - * bit addressing and start the whole mapping process - * all over again- we apparently can't really mix types - */ - if (ISP_A64 && IS_HIGH_ISP_ADDR(addr)) { - if (IS_FC(isp)) { - rq->req_header.rqs_entry_type = RQSTYPE_T3RQS; - seglim = ISP_RQDSEG_T3; - } else { - rq->req_header.rqs_entry_type = RQSTYPE_A64; - seglim = ISP_RQDSEG_A64; - } - sg = savesg; - nxti = *nxi; - rq->req_header.rqs_entry_count = 1; - goto again; - } - crq->req_dataseg[ovseg].ds_count = length; - crq->req_dataseg[ovseg].ds_base = addr; - } - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_qentry(isp, "isp_pci_dmasetup: continuation", curip, crq); - } - MEMORYBARRIER(isp, SYNC_REQUEST, curip, QENTRY_LEN); - if (crq->req_header.rqs_entry_type == RQSTYPE_A64_CONT) { - isp_put_cont64_req(isp, (ispcontreq64_t *)crq, (ispcontreq64_t *)qep); - } else { - isp_put_cont_req(isp, crq, qep); - } - } while (seg < segcnt || last_synthetic_count); -mbxsync: - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_qentry(isp, "isp_pci_dmasetup", isp->isp_reqidx, rq); - } - - if (rq->req_header.rqs_entry_type == RQSTYPE_T3RQS) { - if (ISP_CAP_2KLOGIN(isp)) - isp_put_request_t3e(isp, (ispreqt3e_t *) rq, (ispreqt3e_t *) h); - else - isp_put_request_t3(isp, (ispreqt3_t *) rq, (ispreqt3_t *) h); - } else if (rq->req_header.rqs_entry_type == RQSTYPE_T2RQS) { - if (ISP_CAP_2KLOGIN(isp)) - isp_put_request_t2e(isp, (ispreqt2e_t *) rq, (ispreqt2e_t *) h); - else - isp_put_request_t2(isp, (ispreqt2_t *) rq, (ispreqt2_t *) h); + sg = xact->td_data; + nseg = pci_map_sg(pcs->pci_dev, sg, nseg, ddir == ISP_TO_DEVICE? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); } else { - isp_put_request(isp, (ispreq_t *) rq, (ispreq_t *) h); + sg = NULL; + nseg = 0; } - *nxi = nxti; - return (CMD_QUEUED); + + ret = isp_send_tgt_cmd(isp, fqe, sg, nseg, xact->td_xfrlen, ddir, xact->td_cmd->cd_sense, TMD_SENSELEN); + if (ret == CMD_QUEUED) { + int bin; + if (xact->td_xfrlen <= 1024) { + bin = 0; + } else if (xact->td_xfrlen <= 4096) { + bin = 1; + } else if (xact->td_xfrlen <= 32768) { + bin = 2; + } else if (xact->td_xfrlen <= 65536) { + bin = 3; + } else if (xact->td_xfrlen <= 131372) { + bin = 4; + } else if (xact->td_xfrlen <= 262144) { + bin = 5; + } else if (xact->td_xfrlen <= 524288) { + bin = 6; + } else { + bin = 7; + } + isp->isp_osinfo.bins[bin]++; + } + return (ret); } +#endif -#ifndef ISP_DISABLE_2400_SUPPORT static int -isp_pci_2400_dmasetup(ispsoftc_t *isp, Scsi_Cmnd *Cmnd, ispreq_t *orig_rq, uint32_t *nxi, uint32_t optr) +isp_pci_dmasetup(ispsoftc_t *isp, Scsi_Cmnd *Cmnd, void *fqe) { - struct scatterlist *sg, *savesg; - ispreqt7_t *rq; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - XS_DMA_ADDR_T addr, one_shot_addr, last_synthetic_addr; - unsigned int one_shot_length, last_synthetic_count, length; -#else - XS_DMA_ADDR_T addr, last_synthetic_addr; - unsigned int last_synthetic_count, length; + struct scatterlist one_shot; #endif - int segcnt, seg, ovseg; - void *h; - uint32_t nxti; + struct scatterlist *sg = NULL; + isphdr_t *hp; + isp_ddir_t ddir; + uint32_t nseg; + int ret; + hp = fqe; + switch (hp->rqs_entry_type) { #ifdef ISP_TARGET_MODE - if (orig_rq->req_header.rqs_entry_type == RQSTYPE_CTIO7) { - return tdma_mk_2400(isp, (tmd_xact_t *)Cmnd, (ct7_entry_t *)orig_rq, nxi, optr); - } + case RQSTYPE_CTIO: + case RQSTYPE_CTIO2: + case RQSTYPE_CTIO7: + return (isp_pci_dmasetup_tgt(isp, (tmd_xact_t *)Cmnd, fqe)); #endif - rq = (ispreqt7_t *) orig_rq; - nxti = *nxi; - h = (void *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx); - - if (Cmnd->sc_data_direction == SCSI_DATA_NONE || XS_XFRLEN(Cmnd) == 0) { - rq->req_seg_count = 0; - goto mbxsync; - } - - if (XS_XFRLEN(Cmnd) <= 1024) { - seg = 0; - } else if (XS_XFRLEN(Cmnd) <= 4096) { - seg = 1; - } else if (XS_XFRLEN(Cmnd) <= 32768) { - seg = 2; - } else if (XS_XFRLEN(Cmnd) <= 65536) { - seg = 3; - } else if (XS_XFRLEN(Cmnd) <= 131372) { - seg = 4; - } else if (XS_XFRLEN(Cmnd) <= 262144) { - seg = 5; - } else if (XS_XFRLEN(Cmnd) <= 524288) { - seg = 6; - } else { - seg = 7; - } - isp->isp_osinfo.bins[seg]++; - - rq->req_dl = XS_XFRLEN(Cmnd); - rq->req_seg_count = 1; - if (Cmnd->sc_data_direction == SCSI_DATA_WRITE) { - rq->req_alen_datadir = FCP_CMND_DATA_WRITE; - } else if (Cmnd->sc_data_direction == SCSI_DATA_READ) { - rq->req_alen_datadir = FCP_CMND_DATA_READ; - } else { - isp_prt(isp, ISP_LOGERR, "unknown data direction (%x) for %d byte request (opcode 0x%x)", - Cmnd->sc_data_direction, XS_XFRLEN(Cmnd), Cmnd->cmnd[0]); - XS_SETERR(Cmnd, HBA_BOTCH); + case RQSTYPE_REQUEST: + if (isp->isp_osinfo.is_64bit_dma) { + hp->rqs_entry_type = RQSTYPE_A64; + } + break; + case RQSTYPE_T2RQS: + if (isp->isp_osinfo.is_64bit_dma) { + hp->rqs_entry_type = RQSTYPE_T3RQS; + } + break; + default: + isp_prt(isp, ISP_LOGERR, "%s: unknwon type 0x%x", __func__, hp->rqs_entry_type); return (CMD_COMPLETE); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - one_shot_addr = (XS_DMA_ADDR_T) 0; - one_shot_length = 0; - if ((segcnt = Cmnd->use_sg) == 0) { - struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; - segcnt = 1; - sg = NULL; - one_shot_length = XS_XFRLEN(Cmnd); - one_shot_addr = pci_map_single(pcs->pci_dev, Cmnd->request_buffer, XS_XFRLEN(Cmnd), scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); - QLA_HANDLE(Cmnd) = (DMA_HTYPE_T) one_shot_addr; + if (Cmnd->sc_data_direction == SCSI_DATA_NONE) { + ddir = ISP_NOXFR; + } else if (Cmnd->sc_data_direction == SCSI_DATA_WRITE) { + ddir = ISP_TO_DEVICE; } else { - struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; - sg = (struct scatterlist *) Cmnd->request_buffer; - segcnt = pci_map_sg(pcs->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + ddir = ISP_FROM_DEVICE; } - if (segcnt == 0) { - isp_prt(isp, ISP_LOGWARN, "unable to dma map request"); - XS_SETERR(Cmnd, HBA_BOTCH); - return (CMD_EAGAIN); - } -#else - segcnt = scsi_dma_map(Cmnd); - if (segcnt <= 0) { - isp_prt(isp, ISP_LOGWARN, "unable to dma map request"); - XS_SETERR(Cmnd, HBA_BOTCH); - return (CMD_EAGAIN); - } - sg = scsi_sglist(Cmnd); -#endif - - savesg = sg; - - last_synthetic_count = 0; - last_synthetic_addr = 0; - + if (ddir != ISP_NOXFR) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) - if (sg) { - length = sg_dma_len(sg); - addr = sg_dma_address(sg); - sg++; - } else { - length = one_shot_length; - addr = one_shot_addr; - } -#else - length = sg_dma_len(sg); - addr = sg_dma_address(sg); - sg++; -#endif - seg = 1; - - rq->req_dataseg.ds_base = LOWD(addr); - rq->req_dataseg.ds_basehi = HIWD(addr); - rq->req_dataseg.ds_count = length; - - /* - * Make sure we don't cross a 4GB boundary. - */ - if (!SAME_4G(addr, length)) { - isp_prt(isp, ISP_LOGDEBUG1, "seg0[%d]0x%016llx:%u (TRUNC'd)", rq->req_seg_count, (unsigned long long) addr, length); - rq->req_dataseg.ds_count = (unsigned int) (FOURG_SEG(addr + length) - addr); - addr += rq->req_dataseg.ds_count; - length -= rq->req_dataseg.ds_count; - last_synthetic_count = length; - last_synthetic_addr = addr; - } - isp_prt(isp, ISP_LOGDEBUG1, "seg0[%d]0x%016llx:%u", rq->req_seg_count, (unsigned long long) addr, length); - - if (sg == NULL || (seg == segcnt && last_synthetic_count == 0)) { - goto mbxsync; - } - - do { - int lim; - uint32_t curip; - ispcontreq64_t local, *xrq = &local, *qep; - - curip = nxti; - qep = (ispcontreq64_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curip); - nxti = ISP_NXT_QENTRY((curip), RQUEST_QUEUE_LEN(isp)); - if (nxti == optr) { - isp_pci_dmateardown(isp, Cmnd, 0); - isp_prt(isp, ISP_LOGDEBUG0, "%s: Chan %d out of space for continuations (did %d of %d segments)", __func__, XS_CHANNEL(Cmnd), seg, segcnt); + if ((nseg = Cmnd->use_sg) == 0) { + struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; + nseg = 1; + sg = &one_shot; + sg_dma_address(sg) = pci_map_single(pcs->pci_dev, Cmnd->request_buffer, XS_XFRLEN(Cmnd), scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + sg_dma_len(sg) = XS_XFRLEN(Cmnd); + QLA_HANDLE(Cmnd) = (DMA_HTYPE_T) sg_dma_address(sg); + } else { + struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp; + sg = (struct scatterlist *) Cmnd->request_buffer; + nseg = pci_map_sg(pcs->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + } + if (nseg == 0) { + isp_prt(isp, ISP_LOGWARN, "%s: unable to dma map request", __func__); XS_SETERR(Cmnd, HBA_BOTCH); - return (CMD_EAGAIN); + return (CMD_COMPLETE); } - rq->req_header.rqs_entry_count++; - memset((void *)xrq, 0, sizeof (*xrq)); - xrq->req_header.rqs_entry_count = 1; - xrq->req_header.rqs_entry_type = RQSTYPE_A64_CONT; - lim = ISP_CDSEG64; - - for (ovseg = 0; (seg < segcnt || last_synthetic_count) && ovseg < lim; rq->req_seg_count++, seg++, ovseg++, sg++) { - XS_DMA_ADDR_T addr; - unsigned int length; - - if (last_synthetic_count) { - addr = last_synthetic_addr; - length = last_synthetic_count; - last_synthetic_count = 0; - sg--; - seg--; - } else { - addr = sg_dma_address(sg); - length = sg_dma_len(sg); - } - - if (length == 0) { - panic("zero length s-g element at line %d", __LINE__); - } - isp_prt(isp, ISP_LOGDEBUG1, "seg%d[%d]0x%016llx:%u", rq->req_header.rqs_entry_count-1, ovseg, (unsigned long long) addr, length); - - xrq->req_dataseg[ovseg].ds_count = length; - xrq->req_dataseg[ovseg].ds_base = LOWD(addr); - xrq->req_dataseg[ovseg].ds_basehi = HIWD(addr); - /* - * Make sure we don't cross a 4GB boundary. - */ - if (!SAME_4G(addr, length)) { - isp_prt(isp, ISP_LOGDEBUG1, "seg%d[%d]%llx:%u (TRUNC'd)", rq->req_header.rqs_entry_count-1, ovseg, (unsigned long long)addr, length); - xrq->req_dataseg[ovseg].ds_count = (unsigned int) (FOURG_SEG(addr + length) - addr); - addr += xrq->req_dataseg[ovseg].ds_count; - length -= xrq->req_dataseg[ovseg].ds_count; - /* - * Do we have space to split it here? - */ - if (ovseg == lim - 1) { - last_synthetic_count = length; - last_synthetic_addr = addr; - } else { - ovseg++; - xrq->req_dataseg[ovseg].ds_count = length; - xrq->req_dataseg[ovseg].ds_base = LOWD(addr); - xrq->req_dataseg[ovseg].ds_basehi = HIWD(addr); - } - } +#else + nseg = scsi_dma_map(Cmnd); + if (nseg <= 0) { + isp_prt(isp, ISP_LOGWARN, "%s: unable to dma map request", __func__); + XS_SETERR(Cmnd, HBA_BOTCH); + return (CMD_COMPLETE); } - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_qentry(isp, "isp_pci_2400_dmasetup continuation", curip, xrq); - } - MEMORYBARRIER(isp, SYNC_REQUEST, curip, QENTRY_LEN); - isp_put_cont64_req(isp, xrq, qep); - } while (seg < segcnt || last_synthetic_count); -mbxsync: - if (isp->isp_dblev & ISP_LOGDEBUG1) { - isp_print_qentry(isp, "isp_pci_2400_dmasetup", isp->isp_reqidx, rq); - } - isp_put_request_t7(isp, rq, (ispreqt7_t *) h); - *nxi = nxti; - return (CMD_QUEUED); -} + sg = scsi_sglist(Cmnd); #endif + } else { + sg = NULL; + nseg = 0; + } + ret = isp_send_cmd(isp, fqe, sg, nseg, XS_XFRLEN(Cmnd), ddir); + if (ret == CMD_QUEUED) { + int bin; + if (XS_XFRLEN(Cmnd) <= 1024) { + bin = 0; + } else if (XS_XFRLEN(Cmnd) <= 4096) { + bin = 1; + } else if (XS_XFRLEN(Cmnd) <= 32768) { + bin = 2; + } else if (XS_XFRLEN(Cmnd) <= 65536) { + bin = 3; + } else if (XS_XFRLEN(Cmnd) <= 131372) { + bin = 4; + } else if (XS_XFRLEN(Cmnd) <= 262144) { + bin = 5; + } else if (XS_XFRLEN(Cmnd) <= 524288) { + bin = 6; + } else { + bin = 7; + } + isp->isp_osinfo.bins[bin]++; + } else if (ret == CMD_COMPLETE) { + XS_SETERR(Cmnd, HBA_BOTCH); + } + return (ret); +} static void isp_pci_dmateardown(ispsoftc_t *isp, Scsi_Cmnd *Cmnd, uint32_t handle)