summaryrefslogtreecommitdiffstats
path: root/sys/pci
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>2000-01-15 01:54:36 +0000
committermjacob <mjacob@FreeBSD.org>2000-01-15 01:54:36 +0000
commitaf62fb2de857c569df950db8e4b7c76372166501 (patch)
tree99731d71fe14cde5b026ac20b466e1ef9d49bc2f /sys/pci
parentf12357ba4991bd91f856b7f38680c170ba71f8c6 (diff)
downloadFreeBSD-src-af62fb2de857c569df950db8e4b7c76372166501.zip
FreeBSD-src-af62fb2de857c569df950db8e4b7c76372166501.tar.gz
Redo FC target mode dma routine to try and generate an extra CTIO
in the not so odd case of Moving Data *AND* Sending Status in last CTIO *AND* status is a CHECK CONDITION *AND* we have Sense Data to send.
Diffstat (limited to 'sys/pci')
-rw-r--r--sys/pci/isp_pci.c339
1 files changed, 232 insertions, 107 deletions
diff --git a/sys/pci/isp_pci.c b/sys/pci/isp_pci.c
index ecc70e2..d2d1aad 100644
--- a/sys/pci/isp_pci.c
+++ b/sys/pci/isp_pci.c
@@ -1009,15 +1009,26 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
return;
}
- if (nseg < 1) {
- printf("%s: bad segment count (%d)\n", mp->isp->isp_name, nseg);
- mp->error = EFAULT;
- return;
- }
-
csio = mp->cmd_token;
cto = mp->rq;
+ cto->ct_xfrlen = 0;
+ cto->ct_resid = 0;
+ cto->ct_seg_count = 0;
+ bzero(cto->ct_dataseg, sizeof (cto->ct_dataseg));
+ if (nseg == 0) {
+ cto->ct_header.rqs_entry_count = 1;
+ ISP_TDQE(mp->isp, "dma2_tgt[no data]", *mp->iptrp, cto);
+ if (isp_tdebug) {
+ printf("%s:CTIO lun %d->iid%d flgs 0x%x sts 0x%x ssts "
+ "0x%x res %u\n", mp->isp->isp_name,
+ csio->ccb_h.target_lun, cto->ct_iid, cto->ct_flags,
+ cto->ct_status, cto->ct_scsi_status, cto->ct_resid);
+ }
+ ISP_SWIZ_CTIO(isp, cto, cto);
+ return;
+ }
+
/*
* Save handle, and potentially any SCSI status, which
* we'll reinsert on the last CTIO we're going to send.
@@ -1029,6 +1040,11 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
send_status = cto->ct_flags & CT_SENDSTATUS;
cto->ct_flags &= ~CT_SENDSTATUS;
+ nctios = nseg / ISP_RQDSEG;
+ if (nseg % ISP_RQDSEG) {
+ nctios++;
+ }
+
pci = (struct isp_pcisoftc *)mp->isp;
dp = &pci->dmaps[handle - 1];
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
@@ -1037,15 +1053,6 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
}
- nctios = nseg / ISP_RQDSEG;
- if (nseg % ISP_RQDSEG) {
- nctios++;
- }
-
- cto->ct_xfrlen = 0;
- cto->ct_resid = 0;
- cto->ct_seg_count = 0;
- bzero(cto->ct_dataseg, sizeof (cto->ct_dataseg));
while (nctios--) {
int seg, seglim;
@@ -1062,6 +1069,7 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
}
cto->ct_seg_count = seg;
+ cto->ct_flags &= CT_DATAMASK;
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
cto->ct_flags |= CT_DATA_IN;
} else {
@@ -1088,6 +1096,7 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
cto->ct_iid, cto->ct_flags, cto->ct_status,
cto->ct_scsi_status, cto->ct_resid);
}
+ ISP_SWIZ_CTIO(isp, cto, cto);
} else {
ct_entry_t *octo = cto;
cto->ct_reserved = 0;
@@ -1130,6 +1139,7 @@ dma2_tgt(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
cto->ct_timeout = octo->ct_timeout;
cto->ct_seg_count = 0;
bzero(cto->ct_dataseg, sizeof (cto->ct_dataseg));
+ ISP_SWIZ_CTIO(isp, octo, octo);
}
}
}
@@ -1142,9 +1152,11 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
struct isp_pcisoftc *pci;
bus_dmamap_t *dp;
ct2_entry_t *cto;
- u_int16_t scsi_status, send_status;
- u_int32_t handle, reloff;
+ u_int16_t scsi_status, send_status, send_sense;
+ u_int32_t handle, totxfr;
+ u_int8_t sense[QLTM_SENSELEN];
int nctios;
+ int32_t resid;
mp = (mush_t *) arg;
if (error) {
@@ -1152,24 +1164,100 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
return;
}
- if (nseg < 1) {
- printf("%s: bad segment count (%d)\n", mp->isp->isp_name, nseg);
- mp->error = EFAULT;
+ csio = mp->cmd_token;
+ cto = mp->rq;
+
+ if (nseg == 0) {
+ if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) {
+ printf("%s: dma2_tgt_fc, a status CTIO2 without MODE1 "
+ "set (0x%x)\n", mp->isp->isp_name, cto->ct_flags);
+ mp->error = EINVAL;
+ return;
+ }
+ cto->ct_header.rqs_entry_count = 1;
+ /* ct_reserved contains the handle set by caller */
+ /*
+ * We preserve ct_lun, ct_iid, ct_rxid. We set the data
+ * flags to NO DATA and clear relative offset flags.
+ * We preserve the ct_resid and the response area.
+ */
+ cto->ct_flags |= CT2_NO_DATA;
+ cto->ct_seg_count = 0;
+ cto->ct_reloff = 0;
+ ISP_TDQE(mp->isp, "dma2_tgt_fc[no data]", *mp->iptrp, cto);
+ if (isp_tdebug) {
+ scsi_status = cto->rsp.m1.ct_scsi_status;
+ printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs 0x%x "
+ "sts 0x%x ssts 0x%x res %u\n", mp->isp->isp_name,
+ cto->ct_rxid, csio->ccb_h.target_lun, cto->ct_iid,
+ cto->ct_flags, cto->ct_status,
+ cto->rsp.m1.ct_scsi_status, cto->ct_resid);
+ }
+ ISP_SWIZ_CTIO2(isp, cto, cto);
return;
}
- csio = mp->cmd_token;
- cto = mp->rq;
+ if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) {
+ printf("%s: dma2_tgt_fc, a data CTIO2 without MODE0 set "
+ "(0x%x)\n\n", mp->isp->isp_name, cto->ct_flags);
+ mp->error = EINVAL;
+ return;
+ }
+
+
+ nctios = nseg / ISP_RQDSEG_T2;
+ if (nseg % ISP_RQDSEG_T2) {
+ nctios++;
+ }
+
/*
- * Save handle, and potentially any SCSI status, which
- * we'll reinsert on the last CTIO we're going to send.
+ * Save the handle, status, reloff, and residual. We'll reinsert the
+ * handle into the last CTIO2 we're going to send, and reinsert status
+ * and residual (and possibly sense data) if that's to be sent as well.
+ *
+ * We preserve ct_reloff and adjust it for each data CTIO2 we send past
+ * the first one. This is needed so that the FCP DATA IUs being sent
+ * out have the correct offset (they can arrive at the other end out
+ * of order).
*/
+
handle = cto->ct_reserved;
cto->ct_reserved = 0;
- scsi_status = cto->rsp.m0.ct_scsi_status;
+
+ if ((send_status = (cto->ct_flags & CT2_SENDSTATUS)) != 0) {
+ cto->ct_flags &= ~CT2_SENDSTATUS;
+
+ /*
+ * Preserve residual.
+ */
+ resid = cto->ct_resid;
+
+ /*
+ * Save actual SCSI status. We'll reinsert the
+ * CT2_SNSLEN_VALID later if appropriate.
+ */
+ scsi_status = cto->rsp.m0.ct_scsi_status & 0xff;
+ send_sense = cto->rsp.m0.ct_scsi_status & CT2_SNSLEN_VALID;
+
+ /*
+ * If we're sending status and have a CHECK CONDTION and
+ * have sense data, we send one more CTIO2 with just the
+ * status and sense data. The upper layers have stashed
+ * the sense data in the dataseg structure for us.
+ */
+
+ if ((scsi_status & 0xf) == SCSI_STATUS_CHECK_COND &&
+ send_sense) {
+ bcopy(cto->rsp.m0.ct_dataseg, sense, QLTM_SENSELEN);
+ nctios++;
+ }
+ } else {
+ scsi_status = send_sense = resid = 0;
+ }
+
+ totxfr = cto->ct_resid = 0;
cto->rsp.m0.ct_scsi_status = 0;
- send_status = cto->ct_flags & CT2_SENDSTATUS;
- cto->ct_flags &= ~CT2_SENDSTATUS;
+ bzero(&cto->rsp, sizeof (cto->rsp));
pci = (struct isp_pcisoftc *)mp->isp;
dp = &pci->dmaps[handle - 1];
@@ -1179,74 +1267,113 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
bus_dmamap_sync(pci->parent_dmat, *dp, BUS_DMASYNC_PREWRITE);
}
- nctios = nseg / ISP_RQDSEG_T2;
- if (nseg % ISP_RQDSEG_T2) {
- nctios++;
- }
-
- cto->ct_reloff = 0;
- cto->ct_resid = 0;
- cto->ct_seg_count = 0;
- cto->ct_reloff = reloff = 0;
- bzero(&cto->rsp, sizeof (cto->rsp));
-
while (nctios--) {
int seg, seglim;
seglim = nseg;
- if (seglim > ISP_RQDSEG_T2)
- seglim = ISP_RQDSEG_T2;
-
- for (seg = 0; seg < seglim; seg++) {
- cto->rsp.m0.ct_dataseg[seg].ds_base = dm_segs->ds_addr;
- cto->rsp.m0.ct_dataseg[seg].ds_count = dm_segs->ds_len;
- cto->rsp.m0.ct_xfrlen += dm_segs->ds_len;
- reloff += dm_segs->ds_len;
- dm_segs++;
- }
-
- cto->ct_seg_count = seg;
- if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
- cto->ct_flags |= CT2_DATA_IN;
+ if (seglim) {
+ if (seglim > ISP_RQDSEG_T2)
+ seglim = ISP_RQDSEG_T2;
+
+ for (seg = 0; seg < seglim; seg++) {
+ cto->rsp.m0.ct_dataseg[seg].ds_base =
+ dm_segs->ds_addr;
+ cto->rsp.m0.ct_dataseg[seg].ds_count =
+ dm_segs->ds_len;
+ cto->rsp.m0.ct_xfrlen += dm_segs->ds_len;
+ totxfr += dm_segs->ds_len;
+ dm_segs++;
+ }
+ cto->ct_seg_count = seg;
} else {
- cto->ct_flags |= CT2_DATA_OUT;
+ /*
+ * This case should only happen when we're sending a
+ * synthesized MODE1 final status with sense data.
+ */
+ if (send_sense == 0) {
+ printf("%s: dma2_tgt_fc ran out of segments, "
+ "no SENSE DATA\n", mp->isp->isp_name);
+ mp->error = EINVAL;
+ return;
+ }
}
+ /*
+ * At this point, the fields ct_lun, ct_iid, ct_rxid,
+ * ct_timeout have been carried over unchanged from what
+ * our caller had set.
+ *
+ * The field ct_reloff is either what the caller set, or
+ * what we've added to below.
+ *
+ * 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 sending a MODE1 status
+ * as the last CTIO.
+ *
+ */
+
if (nctios == 0) {
+
/*
- * We're the last in a sequence of CTIOs, so mark this
- * CTIO and save the handle to the CCB such that when
- * this CTIO completes we can free dma resources and
+ * We're the last in a sequence of CTIO2s, so mark this
+ * CTIO2 and save the handle to the CCB such that when
+ * this CTIO2 completes we can free dma resources and
* do whatever else we need to do to finish the rest
* of the command.
*/
- cto->ct_header.rqs_seqno = 1;
+
cto->ct_reserved = handle;
- cto->rsp.m0.ct_scsi_status = scsi_status;
- cto->ct_flags |= send_status;
+ cto->ct_header.rqs_seqno = 1;
+
+ if (send_status) {
+ if (send_sense) {
+ bcopy(sense, cto->rsp.m1.ct_resp,
+ QLTM_SENSELEN);
+ cto->rsp.m1.ct_senselen =
+ QLTM_SENSELEN;
+ scsi_status |= CT2_SNSLEN_VALID;
+ cto->rsp.m1.ct_scsi_status =
+ scsi_status;
+ cto->ct_flags &= CT2_FLAG_MMASK;
+ cto->ct_flags |= CT2_FLAG_MODE1 |
+ CT2_NO_DATA| CT2_SENDSTATUS;
+ } else {
+ cto->rsp.m0.ct_scsi_status =
+ scsi_status;
+ cto->ct_flags |= CT2_SENDSTATUS;
+ }
+ cto->ct_resid = resid - totxfr;
+ }
ISP_TDQE(mp->isp, "last dma2_tgt_fc", *mp->iptrp, cto);
if (isp_tdebug) {
- printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs "
- "0x%x sts 0x%x ssts 0x%x roff %u res "
- "%u\n", mp->isp->isp_name, cto->ct_rxid,
- csio->ccb_h.target_lun, cto->ct_iid,
+ printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs"
+ "0x%x sts 0x%x ssts 0x%x res %u\n",
+ mp->isp->isp_name, cto->ct_rxid,
+ csio->ccb_h.target_lun, (int) cto->ct_iid,
cto->ct_flags, cto->ct_status,
- cto->rsp.m0.ct_scsi_status,
- cto->ct_reloff, cto->ct_resid);
+ cto->rsp.m1.ct_scsi_status, cto->ct_resid);
}
+ ISP_SWIZ_CTIO2(isp, cto, cto);
} else {
ct2_entry_t *octo = cto;
+
+ /*
+ * Make sure handle fields are clean
+ */
cto->ct_reserved = 0;
cto->ct_header.rqs_seqno = 0;
+
ISP_TDQE(mp->isp, "dma2_tgt_fc", *mp->iptrp, cto);
if (isp_tdebug) {
- printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs "
- "0x%x ro %u res %u\n",
- mp->isp->isp_name,
- cto->ct_rxid, csio->ccb_h.target_lun,
- cto->ct_iid, cto->ct_flags, cto->ct_reloff,
- cto->ct_resid);
+ printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs"
+ "0x%x\n", mp->isp->isp_name, cto->ct_rxid,
+ csio->ccb_h.target_lun, (int) cto->ct_iid,
+ cto->ct_flags);
}
+ /*
+ * Get a new CTIO2
+ */
cto = (ct2_entry_t *)
ISP_QUEUE_ENTRY(mp->isp->isp_rquest, *mp->iptrp);
*mp->iptrp =
@@ -1257,23 +1384,30 @@ dma2_tgt_fc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
mp->error = MUSHERR_NOQENTRIES;
return;
}
+
/*
- * Fill in the new CTIO with info from the old one.
+ * Fill in the new CTIO2 with info from the old one.
*/
cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
cto->ct_header.rqs_entry_count = 1;
cto->ct_header.rqs_flags = 0;
- /* ct_header.rqs_seqno && ct_reserved filled in later */
+ /* ct_header.rqs_seqno && ct_reserved done later */
cto->ct_lun = octo->ct_lun;
cto->ct_iid = octo->ct_iid;
cto->ct_rxid = octo->ct_rxid;
- cto->ct_flags = octo->ct_flags & ~CT2_DATAMASK;
+ cto->ct_flags = octo->ct_flags;
cto->ct_status = 0;
cto->ct_resid = 0;
cto->ct_timeout = octo->ct_timeout;
cto->ct_seg_count = 0;
- cto->ct_reloff = reloff;
+ /*
+ * Adjust the new relative offset by the amount which
+ * is recorded in the data segment of the old CTIO2 we
+ * just finished filling out.
+ */
+ cto->ct_reloff += octo->rsp.m0.ct_xfrlen;
bzero(&cto->rsp, sizeof (cto->rsp));
+ ISP_SWIZ_CTIO2(isp, cto, cto);
}
}
}
@@ -1424,38 +1558,6 @@ isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
mush_t mush, *mp;
void (*eptr) __P((void *, bus_dma_segment_t *, int, int));
- /*
- * NB: if we need to do request queue entry swizzling,
- * NB: this is where it would need to be done for cmds
- * NB: that move no data. For commands that move data,
- * NB: swizzling would take place in those functions.
- */
- if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) {
- rq->req_seg_count = 1;
-#ifdef ISP_TARGET_MODE
- if (isp_tdebug && csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
- if (IS_FC(isp)) {
- ct2_entry_t *cto = (ct2_entry_t *) rq;
- printf("%s:CTIO2 RX_ID 0x%x lun %d->iid%d flgs "
- "0x%x sts 0x%x ssts 0x%x res %u\n",
- isp->isp_name, cto->ct_rxid,
- csio->ccb_h.target_lun, cto->ct_iid,
- cto->ct_flags, cto->ct_status,
- cto->rsp.m0.ct_scsi_status,
- cto->ct_resid);
- } else {
- ct_entry_t *cto = (ct_entry_t *) rq;
- printf("%s:CTIO lun %d->iid%d flgs 0x%x sts "
- "0x%x ssts 0x%x res %u\n",
- isp->isp_name, csio->ccb_h.target_lun,
- cto->ct_iid, cto->ct_flags, cto->ct_status,
- cto->ct_scsi_status, cto->ct_resid);
- }
- }
-#endif
- return (CMD_QUEUED);
- }
-
#ifdef ISP_TARGET_MODE
if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
if (IS_FC(isp)) {
@@ -1463,10 +1565,32 @@ isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
} else {
eptr = dma2_tgt;
}
+ if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) {
+ rq->req_seg_count = 1;
+ mp = &mush;
+ mp->isp = isp;
+ mp->cmd_token = csio;
+ mp->rq = rq;
+ mp->iptrp = iptrp;
+ mp->optr = optr;
+ mp->error = 0;
+ (*eptr)(mp, NULL, 0, 0);
+ goto exit;
+ }
} else
#endif
eptr = dma2;
+ /*
+ * NB: if we need to do request queue entry swizzling,
+ * NB: this is where it would need to be done for cmds
+ * NB: that move no data. For commands that move data,
+ * NB: swizzling would take place in those functions.
+ */
+ if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) {
+ rq->req_seg_count = 1;
+ return (CMD_QUEUED);
+ }
/*
* Do a virtual grapevine step to collect info for
@@ -1524,6 +1648,7 @@ isp_pci_dmasetup(struct ispsoftc *isp, struct ccb_scsiio *csio, ispreq_t *rq,
(*eptr)(mp, segs, csio->sglist_cnt, 0);
}
}
+exit:
if (mp->error) {
int retval = CMD_COMPLETE;
if (mp->error == MUSHERR_NOQENTRIES) {
OpenPOWER on IntegriCloud