summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortrasz <trasz@FreeBSD.org>2013-10-09 20:09:58 +0000
committertrasz <trasz@FreeBSD.org>2013-10-09 20:09:58 +0000
commit6688f4bb9adb911294807a0ee13bcf22fe783feb (patch)
treeac4d163a371ba6365b4d77a6653568550873a78c
parent2e79a7108a09265e41a8b96f3e76108968f55c50 (diff)
downloadFreeBSD-src-6688f4bb9adb911294807a0ee13bcf22fe783feb.zip
FreeBSD-src-6688f4bb9adb911294807a0ee13bcf22fe783feb.tar.gz
Properly handle residual count in Data-In PDUs with S bit set.
Approved by: re (gjb) Sponsored by: FreeBSD Foundation
-rw-r--r--sys/dev/iscsi/iscsi.c45
1 files changed, 33 insertions, 12 deletions
diff --git a/sys/dev/iscsi/iscsi.c b/sys/dev/iscsi/iscsi.c
index 3004777..1e65416 100644
--- a/sys/dev/iscsi/iscsi.c
+++ b/sys/dev/iscsi/iscsi.c
@@ -966,22 +966,43 @@ iscsi_pdu_handle_data_in(struct icl_pdu *response)
* XXX: Check DataSN.
* XXX: Check F.
*/
- if (bhsdi->bhsdi_flags & BHSDI_FLAGS_S) {
- //ISCSI_SESSION_DEBUG(is, "got S flag; status 0x%x", bhsdi->bhsdi_status);
- if (bhsdi->bhsdi_status == 0) {
- io->io_ccb->ccb_h.status = CAM_REQ_CMP;
- } else {
- if ((io->io_ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
- xpt_freeze_devq(io->io_ccb->ccb_h.path, 1);
- ISCSI_SESSION_DEBUG(is, "freezing devq");
+ if ((bhsdi->bhsdi_flags & BHSDI_FLAGS_S) == 0) {
+ /*
+ * Nothing more to do.
+ */
+ icl_pdu_free(response);
+ return;
+ }
+
+ //ISCSI_SESSION_DEBUG(is, "got S flag; status 0x%x", bhsdi->bhsdi_status);
+ if (bhsdi->bhsdi_status == 0) {
+ io->io_ccb->ccb_h.status = CAM_REQ_CMP;
+ } else {
+ if ((io->io_ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
+ xpt_freeze_devq(io->io_ccb->ccb_h.path, 1);
+ ISCSI_SESSION_DEBUG(is, "freezing devq");
+ }
+ io->io_ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_DEV_QFRZN;
+ csio->scsi_status = bhsdi->bhsdi_status;
+ }
+
+ if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
+ KASSERT(io->io_received <= csio->dxfer_len,
+ ("io->io_received > csio->dxfer_len"));
+ if (io->io_received < csio->dxfer_len) {
+ csio->resid = ntohl(bhsdi->bhsdi_residual_count);
+ if (csio->resid != csio->dxfer_len - io->io_received) {
+ ISCSI_SESSION_WARN(is, "underflow mismatch: "
+ "target indicates %d, we calculated %zd",
+ csio->resid,
+ csio->dxfer_len - io->io_received);
}
- io->io_ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_DEV_QFRZN;
- csio->scsi_status = bhsdi->bhsdi_status;
+ csio->resid = csio->dxfer_len - io->io_received;
}
- xpt_done(io->io_ccb);
- iscsi_outstanding_remove(is, io);
}
+ xpt_done(io->io_ccb);
+ iscsi_outstanding_remove(is, io);
icl_pdu_free(response);
}
OpenPOWER on IntegriCloud