* [PATCH 1/5] scsi: core: Introduce scsi_cmd_needs_stu()
2026-10-30 22:42 [PATCH 0/5] Recover from persistent UNIT ATTENTION conditions Bart Van Assche
@ 2026-10-30 22:42 ` Bart Van Assche
2026-10-30 22:42 ` [PATCH 2/5] scsi: core: Simplify scsi_eh_ready_devs() Bart Van Assche
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Bart Van Assche @ 2026-10-30 22:42 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Alexey Charkov, Bart Van Assche, James E.J. Bottomley,
Martin K. Petersen
Introduce scsi_cmd_needs_stu() and use it in scsi_eh_stu() instead of
testing scsi_check_sense(scmd) == FAILED. This makes it explicit that
START UNIT is only sent for LU_NOT_READY_INITIALIZING_COMMAND_REQUIRED
and prevents that the error handler reports sense data a second time.
This patch prepares for making scsi_decide_disposition() escalate
persistent UNIT ATTENTION conditions to the error handler.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/scsi/scsi_error.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 75442d60c30e..f27186d5262f 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1582,6 +1582,33 @@ static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
return 1;
}
+/*
+ * Return true if @scmd completed with CHECK CONDITION and current (not
+ * deferred) sense data and store the normalized sense data in @sshdr.
+ */
+static bool scsi_cmd_current_sense(const struct scsi_cmnd *scmd,
+ struct scsi_sense_hdr *sshdr)
+{
+ if ((scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) ||
+ host_byte(scmd->result) != DID_OK ||
+ !scsi_status_is_check_condition(scmd->result))
+ return false;
+
+ return scsi_command_normalize_sense(scmd, sshdr) &&
+ !scsi_sense_is_deferred(sshdr);
+}
+
+static bool scsi_cmd_needs_stu(const struct scsi_cmnd *scmd)
+{
+ struct scsi_sense_hdr sshdr;
+
+ return scmd->device->allow_restart &&
+ scsi_cmd_current_sense(scmd, &sshdr) &&
+ (sshdr.sense_key == NOT_READY ||
+ sshdr.sense_key == UNIT_ATTENTION) &&
+ sshdr.sense_code == LU_NOT_READY_INITIALIZING_COMMAND_REQUIRED;
+}
+
/**
* scsi_eh_stu - send START_UNIT if needed
* @shost: &scsi host being recovered.
@@ -1610,8 +1637,7 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
}
stu_scmd = NULL;
list_for_each_entry(scmd, work_q, eh_entry)
- if (scmd->device == sdev && SCSI_SENSE_VALID(scmd) &&
- scsi_check_sense(scmd) == FAILED ) {
+ if (scmd->device == sdev && scsi_cmd_needs_stu(scmd)) {
stu_scmd = scmd;
break;
}
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 2/5] scsi: core: Simplify scsi_eh_ready_devs()
2026-10-30 22:42 [PATCH 0/5] Recover from persistent UNIT ATTENTION conditions Bart Van Assche
2026-10-30 22:42 ` [PATCH 1/5] scsi: core: Introduce scsi_cmd_needs_stu() Bart Van Assche
@ 2026-10-30 22:42 ` Bart Van Assche
2026-10-30 22:42 ` [PATCH 3/5] scsi: core: Clear UNIT ATTENTION conditions with TEST UNIT READY Bart Van Assche
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Bart Van Assche @ 2026-10-30 22:42 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Alexey Charkov, Bart Van Assche, James E.J. Bottomley,
Martin K. Petersen
Replace the nested if-statements in scsi_eh_ready_devs() with a single
if-statement that combines the conditions with the && operator. This
reduces the indentation level and makes it easier to insert additional
recovery steps. No functionality has been changed.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/scsi/scsi_error.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index f27186d5262f..ee80af923a4a 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -2301,13 +2301,12 @@ void scsi_eh_ready_devs(struct Scsi_Host *shost,
struct list_head *work_q,
struct list_head *done_q)
{
- if (!scsi_eh_stu(shost, work_q, done_q))
- if (!scsi_eh_bus_device_reset(shost, work_q, done_q))
- if (!scsi_eh_target_reset(shost, work_q, done_q))
- if (!scsi_eh_bus_reset(shost, work_q, done_q))
- if (!scsi_eh_host_reset(shost, work_q, done_q))
- scsi_eh_offline_sdevs(work_q,
- done_q);
+ if (!scsi_eh_stu(shost, work_q, done_q) &&
+ !scsi_eh_bus_device_reset(shost, work_q, done_q) &&
+ !scsi_eh_target_reset(shost, work_q, done_q) &&
+ !scsi_eh_bus_reset(shost, work_q, done_q) &&
+ !scsi_eh_host_reset(shost, work_q, done_q))
+ scsi_eh_offline_sdevs(work_q, done_q);
}
EXPORT_SYMBOL_GPL(scsi_eh_ready_devs);
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 3/5] scsi: core: Clear UNIT ATTENTION conditions with TEST UNIT READY
2026-10-30 22:42 [PATCH 0/5] Recover from persistent UNIT ATTENTION conditions Bart Van Assche
2026-10-30 22:42 ` [PATCH 1/5] scsi: core: Introduce scsi_cmd_needs_stu() Bart Van Assche
2026-10-30 22:42 ` [PATCH 2/5] scsi: core: Simplify scsi_eh_ready_devs() Bart Van Assche
@ 2026-10-30 22:42 ` Bart Van Assche
2026-10-30 22:42 ` [PATCH 4/5] scsi: core: Escalate persistent UNIT ATTENTION conditions Bart Van Assche
2026-10-30 22:42 ` [PATCH 5/5] scsi: core: Limit retries of commands that receive UNIT ATTENTION Bart Van Assche
4 siblings, 0 replies; 6+ messages in thread
From: Bart Van Assche @ 2026-10-30 22:42 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Alexey Charkov, Bart Van Assche, James E.J. Bottomley,
Martin K. Petersen
Some targets, e.g. BIWIN BWU2A05* UFS devices, fail to clear power-on or
reset UNIT ATTENTION conditions on WRITE commands while clearing these
on commands like TEST UNIT READY, READ, and SYNCHRONIZE CACHE.
Add scsi_eh_clear_ua() to scsi_eh_ready_devs() ahead of device reset
so that the error handler sends TEST UNIT READY to consume a stuck
UNIT ATTENTION and verifies with a follow-up TEST UNIT READY that the
condition cleared before requeueing affected commands. Allow a few
additional TEST UNIT READY attempts for queued UNIT ATTENTION
conditions and busy devices, delay retries, and honor the error
handler deadline. Save and restore scmd->sense_buffer across
scsi_send_eh_cmnd() so that the original sense data remains intact
while filtering work_q and if retries are later exhausted. Log a
rate-limited message when a persistent UNIT ATTENTION is cleared to
make it possible to identify misbehaving devices.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/scsi/scsi_error.c | 131 ++++++++++++++++++++++++++++++++++++++
1 file changed, 131 insertions(+)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index ee80af923a4a..321806cbcf2e 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -27,6 +27,7 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
+#include <linux/ratelimit.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -57,6 +58,11 @@
#define BUS_RESET_SETTLE_TIME (10)
#define HOST_RESET_SETTLE_TIME (10)
+/* Maximum number of TEST UNIT READY commands sent to clear a UNIT ATTENTION. */
+#define SCSI_EH_CLEAR_UA_TURS 4
+/* Delay in milliseconds before a TEST UNIT READY command is retried. */
+#define SCSI_EH_CLEAR_UA_RETRY_DELAY_MS 100
+
static int scsi_eh_try_stu(struct scsi_cmnd *scmd);
static enum scsi_disposition scsi_try_to_abort_cmd(const struct scsi_host_template *,
struct scsi_cmnd *);
@@ -1671,6 +1677,130 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
return list_empty(work_q);
}
+static bool scsi_cmd_has_ua(const struct scsi_cmnd *scmd)
+{
+ struct scsi_sense_hdr sshdr;
+
+ return scsi_cmd_current_sense(scmd, &sshdr) &&
+ sshdr.sense_key == UNIT_ATTENTION;
+}
+
+static bool scsi_eh_send_tur_clear_ua(struct scsi_cmnd *scmd)
+{
+ static unsigned char tur_command[6] = { TEST_UNIT_READY };
+ struct Scsi_Host *shost = scmd->device->host;
+ u8 sense_buf[SCSI_SENSE_BUFFERSIZE];
+ struct scsi_sense_hdr sshdr;
+ enum scsi_disposition rtn;
+ bool cleared = false;
+ int i;
+
+ memcpy(sense_buf, scmd->sense_buffer, sizeof(sense_buf));
+
+ /*
+ * The first TEST UNIT READY command consumes the pending UNIT
+ * ATTENTION and the second TEST UNIT READY command verifies that the
+ * condition has been cleared. Allow additional attempts in case
+ * multiple UNIT ATTENTION conditions have been queued or in case the
+ * device is temporarily busy or becoming ready.
+ */
+ for (i = 0; i < SCSI_EH_CLEAR_UA_TURS; i++) {
+ if (scsi_host_eh_past_deadline(shost))
+ break;
+ rtn = scsi_send_eh_cmnd(scmd, tur_command, sizeof(tur_command),
+ scmd->device->eh_timeout, 0);
+ if (rtn == NEEDS_RETRY) {
+ if (i + 1 < SCSI_EH_CLEAR_UA_TURS)
+ msleep(SCSI_EH_CLEAR_UA_RETRY_DELAY_MS);
+ continue;
+ }
+ if (rtn != SUCCESS)
+ break;
+ if (!scsi_command_normalize_sense(scmd, &sshdr) ||
+ sshdr.sense_key == NO_SENSE ||
+ sshdr.sense_key == RECOVERED_ERROR) {
+ cleared = true;
+ break;
+ }
+ if (sshdr.sense_key != UNIT_ATTENTION)
+ break;
+ }
+
+ memcpy(scmd->sense_buffer, sense_buf, sizeof(sense_buf));
+ return cleared;
+}
+
+/**
+ * scsi_eh_clear_ua - clear pending UNIT ATTENTION conditions if needed
+ * @shost: SCSI host being recovered.
+ * @work_q: &list_head for pending commands.
+ * @done_q: &list_head for processed commands.
+ *
+ * If commands fail repeatedly with UNIT ATTENTION because a target does not
+ * clear the condition for those commands (for example, WRITE), send
+ * TEST UNIT READY to clear the UNIT ATTENTION before escalating to a reset.
+ *
+ * Return: 1 if @work_q is empty, 0 otherwise.
+ */
+static int scsi_eh_clear_ua(struct Scsi_Host *shost,
+ struct list_head *work_q,
+ struct list_head *done_q)
+{
+ static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
+ DEFAULT_RATELIMIT_BURST);
+ struct scsi_cmnd *scmd, *ua_scmd, *next;
+ struct scsi_device *sdev;
+
+ shost_for_each_device(sdev, shost) {
+ if (scsi_host_eh_past_deadline(shost)) {
+ SCSI_LOG_ERROR_RECOVERY(3,
+ sdev_printk(KERN_INFO, sdev,
+ "%s: skip clear UA, past eh deadline\n",
+ current->comm));
+ scsi_device_put(sdev);
+ break;
+ }
+
+ ua_scmd = NULL;
+ list_for_each_entry(scmd, work_q, eh_entry) {
+ if (scmd->device == sdev && scsi_cmd_has_ua(scmd)) {
+ ua_scmd = scmd;
+ break;
+ }
+ }
+
+ if (!ua_scmd)
+ continue;
+
+ SCSI_LOG_ERROR_RECOVERY(3,
+ sdev_printk(KERN_INFO, sdev,
+ "%s: Sending TEST_UNIT_READY to clear UA\n",
+ current->comm));
+
+ if (scsi_device_online(sdev)) {
+ if (!scsi_eh_send_tur_clear_ua(ua_scmd)) {
+ SCSI_LOG_ERROR_RECOVERY(3,
+ sdev_printk(KERN_INFO, sdev,
+ "%s: Failed to clear UA\n",
+ current->comm));
+ continue;
+ }
+ if (__ratelimit(&rs))
+ sdev_printk(KERN_INFO, sdev,
+ "Cleared persistent UNIT ATTENTION\n");
+ }
+
+ sdev->expecting_cc_ua = 0;
+ list_for_each_entry_safe(scmd, next, work_q, eh_entry) {
+ if (scmd->device == sdev &&
+ scsi_cmd_has_ua(scmd) &&
+ scsi_eh_action(scmd, SUCCESS) == SUCCESS)
+ scsi_eh_finish_cmd(scmd, done_q);
+ }
+ }
+
+ return list_empty(work_q);
+}
/**
* scsi_eh_bus_device_reset - send bdr if needed
@@ -2302,6 +2432,7 @@ void scsi_eh_ready_devs(struct Scsi_Host *shost,
struct list_head *done_q)
{
if (!scsi_eh_stu(shost, work_q, done_q) &&
+ !scsi_eh_clear_ua(shost, work_q, done_q) &&
!scsi_eh_bus_device_reset(shost, work_q, done_q) &&
!scsi_eh_target_reset(shost, work_q, done_q) &&
!scsi_eh_bus_reset(shost, work_q, done_q) &&
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 4/5] scsi: core: Escalate persistent UNIT ATTENTION conditions
2026-10-30 22:42 [PATCH 0/5] Recover from persistent UNIT ATTENTION conditions Bart Van Assche
` (2 preceding siblings ...)
2026-10-30 22:42 ` [PATCH 3/5] scsi: core: Clear UNIT ATTENTION conditions with TEST UNIT READY Bart Van Assche
@ 2026-10-30 22:42 ` Bart Van Assche
2026-10-30 22:42 ` [PATCH 5/5] scsi: core: Limit retries of commands that receive UNIT ATTENTION Bart Van Assche
4 siblings, 0 replies; 6+ messages in thread
From: Bart Van Assche @ 2026-10-30 22:42 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Alexey Charkov, Bart Van Assche, James E.J. Bottomley,
Martin K. Petersen
Recover from persistent UNIT ATTENTION conditions in the SCSI midlayer
instead of maintaining a per-device quirk list for targets such as
BIWIN BWU2A05* UFS devices that fail to clear power-on or reset UNIT
ATTENTION on WRITE commands while clearing it on commands such as TEST
UNIT READY, READ, and SYNCHRONIZE CACHE.
If a non-removable block request that is not failfast receives the same
UNIT ATTENTION repeatedly, retry it twice and invoke the error handler
thereafter, instead of letting scsi_io_completion_action() retry
uncounted until the command runtime limit is exceeded. The error
handler clears the UNIT ATTENTION by sending TEST UNIT READY. Track
this with a dedicated per-command counter and the additional sense code
of the most recent UNIT ATTENTION instead of scmd->retries.
scmd->retries is also incremented for other retry reasons and by the
error handler, and a target may report multiple queued UNIT ATTENTION
conditions with different additional sense codes. On most
architectures the new fields occupy an existing hole in struct
scsi_cmnd. Limit the number of error handler invocations for commands
with unlimited retries since scsi_eh_flush_done_q() does not limit
these.
Only apply this escalation when the sense data is evaluated by
scsi_decide_disposition() and leave the behavior of the exported
scsi_check_sense() function unchanged. libata calls scsi_check_sense()
from its own error handler, which translates FAILED into an ATA port
reset and never sends TEST UNIT READY.
Reported-by: Alexey Charkov <alchark@flipper.net>
Closes: https://lore.kernel.org/linux-scsi/20261028-biwin-tua-quirk-v1-1-767a12c9b9cc@flipper.net/
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/scsi/scsi_error.c | 81 ++++++++++++++++++++++++++++++++++-----
drivers/scsi/scsi_lib.c | 2 +
include/scsi/scsi_cmnd.h | 7 ++++
3 files changed, 81 insertions(+), 9 deletions(-)
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 321806cbcf2e..b8d3c6f2ad33 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -58,6 +58,16 @@
#define BUS_RESET_SETTLE_TIME (10)
#define HOST_RESET_SETTLE_TIME (10)
+/*
+ * Number of times a command is retried if it receives the same UNIT ATTENTION
+ * repeatedly before the error handler is invoked to clear that condition.
+ */
+#define SCSI_UA_RETRIES 2
+/*
+ * Maximum number of error handler invocations for a command with unlimited
+ * retries that keeps receiving the same UNIT ATTENTION.
+ */
+#define SCSI_UA_EH_ROUNDS 3
/* Maximum number of TEST UNIT READY commands sent to clear a UNIT ATTENTION. */
#define SCSI_EH_CLEAR_UA_TURS 4
/* Delay in milliseconds before a TEST UNIT READY command is retried. */
@@ -565,17 +575,15 @@ static inline void set_scsi_ml_byte(struct scsi_cmnd *cmd, u8 status)
}
/**
- * scsi_check_sense - Examine scsi cmd sense
+ * __scsi_check_sense - Examine scsi cmd sense
* @scmd: Cmd to have sense checked.
+ * @escalate_ua: Whether to invoke the SCSI error handler for UNIT ATTENTION
+ * conditions that persist after retries.
*
- * Return value:
- * SUCCESS or FAILED or NEEDS_RETRY or ADD_TO_MLQUEUE
- *
- * Notes:
- * When a deferred error is detected the current command has
- * not been executed and needs retrying.
+ * Return: SUCCESS, FAILED, NEEDS_RETRY or ADD_TO_MLQUEUE.
*/
-enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
+static enum scsi_disposition __scsi_check_sense(struct scsi_cmnd *scmd,
+ bool escalate_ua)
{
struct request *req = scsi_cmd_to_rq(scmd);
struct scsi_device *sdev = scmd->device;
@@ -722,6 +730,40 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
sshdr.sense_code ==
LU_NOT_READY_INITIALIZING_COMMAND_REQUIRED)
return FAILED;
+ /*
+ * Retry a UNIT ATTENTION that is reported repeatedly with the
+ * same additional sense code SCSI_UA_RETRIES times on the
+ * normal completion path for non-removable block requests,
+ * then invoke the error handler so TEST UNIT READY can clear a
+ * stuck UNIT ATTENTION. Use a dedicated counter instead of
+ * scmd->retries since the latter is also incremented for
+ * other retry reasons and by the error handler. Comparing the
+ * additional sense code prevents escalation if a target
+ * reports multiple queued UNIT ATTENTION conditions.
+ */
+ if (escalate_ua && sshdr.sense_key == UNIT_ATTENTION &&
+ !sdev->removable && !scsi_noretry_cmd(scmd)) {
+ u8 asc = scsi_sense_asc(&sshdr);
+
+ if (scmd->ua_asc != asc) {
+ scmd->ua_asc = asc;
+ scmd->ua_count = 0;
+ }
+ if (scmd->ua_count < U8_MAX)
+ scmd->ua_count++;
+ if (scmd->ua_count <= SCSI_UA_RETRIES)
+ return NEEDS_RETRY;
+ /*
+ * scsi_eh_flush_done_q() limits the number of error
+ * handler invocations unless retries are unlimited.
+ * Pass the UNIT ATTENTION upwards in the latter case
+ * once SCSI_UA_EH_ROUNDS attempts to clear it failed.
+ */
+ if (scmd->allowed == SCSI_CMD_RETRIES_NO_LIMIT &&
+ scmd->ua_count > SCSI_UA_RETRIES + SCSI_UA_EH_ROUNDS)
+ return SUCCESS;
+ return FAILED;
+ }
/*
* Pass the UA upwards for a determination in the completion
* functions.
@@ -796,6 +838,27 @@ enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
return SUCCESS;
}
}
+
+/**
+ * scsi_check_sense - Examine scsi cmd sense
+ * @scmd: Cmd to have sense checked.
+ *
+ * Return value:
+ * SUCCESS or FAILED or NEEDS_RETRY or ADD_TO_MLQUEUE
+ *
+ * Notes:
+ * When a deferred error is detected the current command has
+ * not been executed and needs retrying.
+ *
+ * Unlike the sense data evaluation by scsi_decide_disposition(), this
+ * function never invokes the SCSI error handler for UNIT ATTENTION
+ * conditions that persist after retries. Callers with their own error
+ * handler, e.g. libata, rely on this.
+ */
+enum scsi_disposition scsi_check_sense(struct scsi_cmnd *scmd)
+{
+ return __scsi_check_sense(scmd, false);
+}
EXPORT_SYMBOL_GPL(scsi_check_sense);
static void scsi_handle_queue_ramp_up(struct scsi_device *sdev)
@@ -2271,7 +2334,7 @@ enum scsi_disposition scsi_decide_disposition(struct scsi_cmnd *scmd)
case SAM_STAT_TASK_ABORTED:
goto maybe_retry;
case SAM_STAT_CHECK_CONDITION:
- rtn = scsi_check_sense(scmd);
+ rtn = __scsi_check_sense(scmd, true);
if (rtn == NEEDS_RETRY)
goto maybe_retry;
/* if rtn == FAILED, we have no sense information;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ab39514cc0c6..ccbc1d4193e0 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -1272,6 +1272,8 @@ static void scsi_initialize_rq(struct request *rq)
init_rcu_head(&cmd->rcu);
cmd->jiffies_at_alloc = jiffies;
cmd->retries = 0;
+ cmd->ua_asc = 0;
+ cmd->ua_count = 0;
}
/**
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 2f2364c96457..5a8f7a45dc6d 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -98,6 +98,13 @@ struct scsi_cmnd {
enum scsi_cmnd_submitter submitter;
unsigned short cmd_len;
+ /*
+ * Additional sense code of the most recent UNIT ATTENTION and the
+ * number of consecutive UNIT ATTENTIONs with that additional sense
+ * code. Only used by the SCSI core.
+ */
+ u8 ua_asc;
+ u8 ua_count;
enum dma_data_direction sc_data_direction;
unsigned char cmnd[32]; /* SCSI CDB */
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH 5/5] scsi: core: Limit retries of commands that receive UNIT ATTENTION
2026-10-30 22:42 [PATCH 0/5] Recover from persistent UNIT ATTENTION conditions Bart Van Assche
` (3 preceding siblings ...)
2026-10-30 22:42 ` [PATCH 4/5] scsi: core: Escalate persistent UNIT ATTENTION conditions Bart Van Assche
@ 2026-10-30 22:42 ` Bart Van Assche
4 siblings, 0 replies; 6+ messages in thread
From: Bart Van Assche @ 2026-10-30 22:42 UTC (permalink / raw)
To: Martin K . Petersen
Cc: linux-scsi, Alexey Charkov, Bart Van Assche, James E.J. Bottomley,
Martin K. Petersen
Fail non-removable commands in scsi_io_completion_action() on UNIT
ATTENTION if retries exceed max(cmd->allowed, 3). This bounds the
number of retries of commands for which scsi_decide_disposition()
exhausted the retries or that have been finished by the error handler,
e.g. because a target keeps reporting UNIT ATTENTION after recovery.
Since scmd->retries is not incremented for failfast commands on this
code path, failfast commands are retried until the command runtime
limit is exceeded, as before.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
drivers/scsi/scsi_lib.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index ccbc1d4193e0..b52b4c5daa42 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -849,6 +849,9 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result)
*/
cmd->device->changed = 1;
action = ACTION_FAIL;
+ } else if (cmd->allowed != SCSI_CMD_RETRIES_NO_LIMIT &&
+ cmd->retries > max(cmd->allowed, 3)) {
+ action = ACTION_FAIL;
} else {
/* Must have been a power glitch, or a
* bus reset. Could not have been a
^ permalink raw reply related [flat|nested] 6+ messages in thread