From 6688f4bb9adb911294807a0ee13bcf22fe783feb Mon Sep 17 00:00:00 2001 From: trasz Date: Wed, 9 Oct 2013 20:09:58 +0000 Subject: Properly handle residual count in Data-In PDUs with S bit set. Approved by: re (gjb) Sponsored by: FreeBSD Foundation --- sys/dev/iscsi/iscsi.c | 45 +++++++++++++++++++++++++++++++++------------ 1 file 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); } -- cgit v1.1