aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2017-02-26 12:52:44 +0000
committerAlexander Motin <mav@FreeBSD.org>2017-02-26 12:52:44 +0000
commita6036a44fd17881d98853f50d819edbdf4c2c618 (patch)
tree2b0dfb32bf9df456e374d4a9b92d16fdd68449cd
parentdd93b628e9b858904aa3c00f9f0a73f6a836a8d6 (diff)
downloadsrc-a6036a44fd17881d98853f50d819edbdf4c2c618.tar.gz
src-a6036a44fd17881d98853f50d819edbdf4c2c618.zip
Fix residual length reporting in target mode.
This allows to properly handle cases when target wants to receive or send more data then initiator wants to send or receive. Previously in such cases isp(4) returned CAM_DATA_RUN_ERR, while now it returns resid > 0. MFC after: 2 weeks
Notes
Notes: svn path=/head/; revision=314299
-rw-r--r--sys/dev/isp/isp_freebsd.c48
-rw-r--r--sys/dev/isp/isp_target.c8
2 files changed, 28 insertions, 28 deletions
diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c
index e66fd46bced1..36561f5dec0e 100644
--- a/sys/dev/isp/isp_freebsd.c
+++ b/sys/dev/isp/isp_freebsd.c
@@ -1316,13 +1316,24 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how)
/*
* Check for overflow
*/
- tmp = atp->bytes_xfered + atp->bytes_in_transit + xfrlen;
- if (tmp > atp->orig_datalen) {
- isp_prt(isp, ISP_LOGERR, "%s: [0x%x] data overflow by %u bytes", __func__, cso->tag_id, tmp - atp->orig_datalen);
+ tmp = atp->bytes_xfered + atp->bytes_in_transit;
+ if (xfrlen > 0 && tmp > atp->orig_datalen) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: [0x%x] data overflow by %u bytes", __func__,
+ cso->tag_id, tmp + xfrlen - atp->orig_datalen);
ccb->ccb_h.status = CAM_DATA_RUN_ERR;
xpt_done(ccb);
continue;
}
+ if (xfrlen > atp->orig_datalen - tmp) {
+ xfrlen = atp->orig_datalen - tmp;
+ if (xfrlen == 0 && !sendstatus) {
+ cso->resid = cso->dxfer_len;
+ ccb->ccb_h.status = CAM_REQ_CMP;
+ xpt_done(ccb);
+ continue;
+ }
+ }
if (IS_24XX(isp)) {
ct7_entry_t *cto = (ct7_entry_t *) local;
@@ -1352,16 +1363,13 @@ isp_target_start_ctio(ispsoftc_t *isp, union ccb *ccb, enum Start_Ctio_How how)
cto->ct_flags |= CT7_SENDSTATUS | CT7_NO_DATA;
resid = atp->orig_datalen - atp->bytes_xfered - atp->bytes_in_transit;
if (sense_length <= MAXRESPLEN_24XX) {
- if (resid < 0) {
- cto->ct_resid = -resid;
- } else if (resid > 0) {
- cto->ct_resid = resid;
- }
cto->ct_flags |= CT7_FLAG_MODE1;
cto->ct_scsi_status = cso->scsi_status;
if (resid < 0) {
+ cto->ct_resid = -resid;
cto->ct_scsi_status |= (FCP_RESID_OVERFLOW << 8);
} else if (resid > 0) {
+ cto->ct_resid = resid;
cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8);
}
if (fctape) {
@@ -2238,10 +2246,10 @@ static void
isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
{
union ccb *ccb;
- int sentstatus = 0, ok = 0, notify_cam = 0, resid = 0, failure = 0;
+ int sentstatus = 0, ok = 0, notify_cam = 0, failure = 0;
atio_private_data_t *atp = NULL;
int bus;
- uint32_t handle, moved_data = 0, data_requested;
+ uint32_t handle, data_requested, resid;
handle = ((ct2_entry_t *)arg)->ct_syshandle;
ccb = isp_find_xs(isp, handle);
@@ -2250,7 +2258,7 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
return;
}
isp_destroy_handle(isp, handle);
- data_requested = PISP_PCMD(ccb)->datalen;
+ resid = data_requested = PISP_PCMD(ccb)->datalen;
isp_free_pcmd(isp, ccb);
if (isp->isp_nactive) {
isp->isp_nactive--;
@@ -2296,10 +2304,8 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
sentstatus = ct->ct_flags & CT7_SENDSTATUS;
ok = (ct->ct_nphdl == CT7_OK);
notify_cam = (ct->ct_header.rqs_seqno & ATPD_SEQ_NOTIFY_CAM) != 0;
- if ((ct->ct_flags & CT7_DATAMASK) != CT7_NO_DATA) {
+ if ((ct->ct_flags & CT7_DATAMASK) != CT7_NO_DATA)
resid = ct->ct_resid;
- moved_data = data_requested - resid;
- }
}
isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO7[%x] seq %u nc %d sts 0x%x flg 0x%x sns %d resid %d %s", __func__, ct->ct_rxid, ATPD_GET_SEQNO(ct),
notify_cam, ct->ct_nphdl, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
@@ -2320,22 +2326,20 @@ isp_handle_platform_ctio(ispsoftc_t *isp, void *arg)
sentstatus = ct->ct_flags & CT2_SENDSTATUS;
ok = (ct->ct_status & ~QLTM_SVALID) == CT_OK;
notify_cam = (ct->ct_header.rqs_seqno & ATPD_SEQ_NOTIFY_CAM) != 0;
- if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
+ if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA)
resid = ct->ct_resid;
- moved_data = data_requested - resid;
- }
}
isp_prt(isp, ok? ISP_LOGTDEBUG0 : ISP_LOGWARN, "%s: CTIO2[%x] seq %u nc %d sts 0x%x flg 0x%x sns %d resid %d %s", __func__, ct->ct_rxid, ATPD_GET_SEQNO(ct),
notify_cam, ct->ct_status, ct->ct_flags, (ccb->ccb_h.status & CAM_SENT_SENSE) != 0, resid, sentstatus? "FIN" : "MID");
}
if (ok) {
- if (moved_data) {
- atp->bytes_xfered += moved_data;
- ccb->csio.resid = atp->orig_datalen - atp->bytes_xfered - atp->bytes_in_transit;
+ if (data_requested > 0) {
+ atp->bytes_xfered += data_requested - resid;
+ ccb->csio.resid = ccb->csio.dxfer_len -
+ (data_requested - resid);
}
- if (sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE)) {
+ if (sentstatus && (ccb->ccb_h.flags & CAM_SEND_SENSE))
ccb->ccb_h.status |= CAM_SENT_SENSE;
- }
ccb->ccb_h.status |= CAM_REQ_CMP;
} else {
notify_cam = 1;
diff --git a/sys/dev/isp/isp_target.c b/sys/dev/isp/isp_target.c
index 5a31ea766540..f86792ec86fc 100644
--- a/sys/dev/isp/isp_target.c
+++ b/sys/dev/isp/isp_target.c
@@ -558,13 +558,9 @@ isp_endcmd(ispsoftc_t *isp, ...)
} else {
cto->ct_flags |= CT7_FLAG_MODE1 | CT7_SENDSTATUS;
}
- if (aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl) {
+ if (aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl != 0) {
cto->ct_resid = aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl;
- if (cto->ct_resid < 0) {
- cto->ct_scsi_status |= (FCP_RESID_OVERFLOW << 8);
- } else if (cto->ct_resid > 0) {
- cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8);
- }
+ cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8);
}
cto->ct_syshandle = hdl;
} else {