* [PATCH 0/5] Recover from persistent UNIT ATTENTION conditions
@ 2026-10-30 22:42 Bart Van Assche
2026-10-30 22:42 ` [PATCH 1/5] scsi: core: Introduce scsi_cmd_needs_stu() Bart Van Assche
` (4 more replies)
0 siblings, 5 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
Hi Martin,
Some SCSI targets do not clear a power-on or reset UNIT ATTENTION
condition for all commands. BIWIN BWU2A05* UFS devices, for example,
keep reporting UNIT ATTENTION for WRITE commands while TEST UNIT READY,
READ and SYNCHRONIZE CACHE clear the condition. Today such WRITE
commands are retried until the command runtime limit is exceeded. A
quirk has been proposed for these devices [1]. This patch series instead
makes the SCSI core recover from persistent UNIT ATTENTION conditions,
so that no per-device quirk list has to be maintained:
- Patches 1 and 2 prepare the SCSI error handler for the changes in
the later patches.
- Patch 3 makes the SCSI error handler send TEST UNIT READY to clear
UNIT ATTENTION conditions before it falls back to resetting the
device.
- Patch 4 makes scsi_decide_disposition() invoke the error handler if
a command receives the same UNIT ATTENTION repeatedly. The behavior
of the exported scsi_check_sense() function, used by libata, is not
changed.
- Patch 5 limits the number of retries in scsi_io_completion_action()
of commands that keep receiving UNIT ATTENTION.
Please consider this patch series for the next merge window.
[1] https://lore.kernel.org/linux-scsi/20261028-biwin-tua-quirk-v1-1-767a12c9b9cc@flipper.net/
Thanks,
Bart.
Bart Van Assche (5):
scsi: core: Introduce scsi_cmd_needs_stu()
scsi: core: Simplify scsi_eh_ready_devs()
scsi: core: Clear UNIT ATTENTION conditions with TEST UNIT READY
scsi: core: Escalate persistent UNIT ATTENTION conditions
scsi: core: Limit retries of commands that receive UNIT ATTENTION
drivers/scsi/scsi_error.c | 255 +++++++++++++++++++++++++++++++++++---
drivers/scsi/scsi_lib.c | 5 +
include/scsi/scsi_cmnd.h | 7 ++
3 files changed, 249 insertions(+), 18 deletions(-)
^ permalink raw reply [flat|nested] 6+ messages in thread
* [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
end of thread, other threads:[~2026-10-30 22:43 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH 3/5] scsi: core: Clear UNIT ATTENTION conditions with TEST UNIT READY 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
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.