Properly handle residual count in Data-In PDUs with S bit set.

Approved by:	re (gjb)
Sponsored by:	FreeBSD Foundation
This commit is contained in:
Edward Tomasz Napierala 2013-10-09 20:09:58 +00:00
parent 5239e66cc2
commit 69647b7bcd
1 changed files with 35 additions and 14 deletions

View File

@ -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");
}
io->io_ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR | CAM_DEV_QFRZN;
csio->scsi_status = bhsdi->bhsdi_status;
}
xpt_done(io->io_ccb);
iscsi_outstanding_remove(is, io);
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);
}
csio->resid = csio->dxfer_len - io->io_received;
}
}
xpt_done(io->io_ccb);
iscsi_outstanding_remove(is, io);
icl_pdu_free(response);
}