ata: libata-scsi: fix requeue of deferred ATA PASS-THROUGH commands

Commit 0ea84089db ("ata: libata-scsi: avoid Non-NCQ command starvation")
introduced ata_scsi_requeue_deferred_qc() to handle commands deferred
during resets or NCQ failures. This deferral logic completed commands
with DID_SOFT_ERROR to trigger a retry in the SCSI mid-layer.

However, DID_SOFT_ERROR is subject to scsi_cmd_retry_allowed() checks.
ATA PASS-THROUGH commands sent via SG_IO ioctl have scmd->allowed set
to zero. This causes the mid-layer to fail the command immediately
instead of retrying, even though the command was never actually issued
to the hardware.

Switch to DID_REQUEUE to ensure these commands are inserted back into
the request queue regardless of retry limits.

Fixes: 0ea84089db ("ata: libata-scsi: avoid Non-NCQ command starvation")
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Igor Pylypiv <ipylypiv@google.com>
Signed-off-by: Niklas Cassel <cassel@kernel.org>
This commit is contained in:
Igor Pylypiv
2026-04-12 08:36:37 -07:00
committed by Niklas Cassel
parent 797f629856
commit 8ebf408e7d

View File

@@ -1695,12 +1695,12 @@ void ata_scsi_requeue_deferred_qc(struct ata_port *ap)
/*
* If we have a deferred qc when a reset occurs or NCQ commands fail,
* do not try to be smart about what to do with this deferred command
* and simply retry it by completing it with DID_SOFT_ERROR.
* and simply requeue it by completing it with DID_REQUEUE.
*/
if (qc) {
ap->deferred_qc = NULL;
cancel_work(&ap->deferred_qc_work);
ata_scsi_qc_done(qc, true, DID_SOFT_ERROR << 16);
ata_scsi_qc_done(qc, true, DID_REQUEUE << 16);
}
}