git: 7d5d54dec54f - main - ufshci: report the SCSI status and sense to CAM
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 03 Nov 2026 04:33:53 UTC
The branch main has been updated by jaeyoon:
URL: https://cgit.FreeBSD.org/src/commit/?id=7d5d54dec54fc377b422d94e8c578c10281f28ff
commit 7d5d54dec54fc377b422d94e8c578c10281f28ff
Author: Jaeyoon Choi <jaeyoon@FreeBSD.org>
AuthorDate: 2026-11-03 04:26:56 +0000
Commit: Jaeyoon Choi <jaeyoon@FreeBSD.org>
CommitDate: 2026-11-03 04:29:46 +0000
ufshci: report the SCSI status and sense to CAM
A CHECK CONDITION was reported to CAM as a transport error without
valid sense, so CAM retried blindly. After a reset the device answers
NOT READY, and those retries ran out and detached the disk.
Report the SCSI status and sense with CAM_AUTOSNS_VALID, and freeze the
device queue on a SCSI status error. A GOOD status with a failed
response is still an error. Stop logging every CHECK CONDITION.
Reviewed by: imp
Sponsored by: Samsung Electronics
Differential Revision: https://reviews.freebsd.org/D61122
---
sys/dev/ufshci/ufshci_req_queue.c | 17 ++++++---
sys/dev/ufshci/ufshci_sim.c | 76 ++++++++++++++++++++++++++-------------
2 files changed, 63 insertions(+), 30 deletions(-)
diff --git a/sys/dev/ufshci/ufshci_req_queue.c b/sys/dev/ufshci/ufshci_req_queue.c
index 868ff0b2c1ca..8faa4c4072e4 100644
--- a/sys/dev/ufshci/ufshci_req_queue.c
+++ b/sys/dev/ufshci/ufshci_req_queue.c
@@ -187,12 +187,19 @@ ufshci_req_queue_response_is_error(struct ufshci_req_queue *req_queue,
is_error = true;
}
- /* Check response UPIU header */
+ /*
+ * Check response UPIU header. A SCSI command that ends in CHECK
+ * CONDITION reports a target failure here, which is a normal
+ * answer rather than a driver problem. The status and the sense
+ * in that response say what happened, so do not log it.
+ */
if (response->header.response != UFSHCI_RESPONSE_CODE_TARGET_SUCCESS) {
- ufshci_printf(req_queue->ctrlr,
- "Function(0x%x) Invalid response code = 0x%x\n",
- response->header.ext_iid_or_function,
- response->header.response);
+ if (response->header.trans_code !=
+ UFSHCI_UPIU_TRANSACTION_CODE_RESPONSE)
+ ufshci_printf(req_queue->ctrlr,
+ "Function(0x%x) Invalid response code = 0x%x\n",
+ response->header.ext_iid_or_function,
+ response->header.response);
is_error = true;
}
diff --git a/sys/dev/ufshci/ufshci_sim.c b/sys/dev/ufshci/ufshci_sim.c
index edbb4930cb78..b282ef69c772 100644
--- a/sys/dev/ufshci/ufshci_sim.c
+++ b/sys/dev/ufshci/ufshci_sim.c
@@ -21,31 +21,23 @@
#define sim2ctrlr(sim) ((struct ufshci_controller *)cam_sim_softc(sim))
+/*
+ * The transport says whether the command reached the device, and the
+ * response says what the device made of it. The SCSI result is read out
+ * of the response here, so the error flag is not used.
+ */
static void
ufshci_sim_scsiio_done(void *ccb_arg, const struct ufshci_completion *cpl,
bool error)
{
- const uint8_t *sense_data;
- uint16_t sense_data_max_size;
- uint16_t sense_data_len;
-
union ccb *ccb = (union ccb *)ccb_arg;
-
- /*
- * Let the periph know the completion, and let it sort out what
- * it means. Report an error or success based on OCS and UPIU
- * response code. And We need to copy the sense data to be handled
- * by the CAM.
- */
- sense_data = cpl->response_upiu.cmd_response_upiu.sense_data;
- sense_data_max_size = sizeof(
- cpl->response_upiu.cmd_response_upiu.sense_data);
- sense_data_len = be16toh(
- cpl->response_upiu.cmd_response_upiu.sense_data_len);
- memcpy(&ccb->csio.sense_data, sense_data,
- min(sense_data_len, sense_data_max_size));
+ struct ccb_scsiio *csio = &ccb->csio;
+ const struct ufshci_cmd_response_upiu *resp =
+ &cpl->response_upiu.cmd_response_upiu;
+ uint16_t sense_len;
ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
+
if (cpl->ocs == UFSHCI_DESC_ABORTED) {
/*
* A reset took the request back, so requeue it without a
@@ -54,18 +46,52 @@ ufshci_sim_scsiio_done(void *ccb_arg, const struct ufshci_completion *cpl,
*/
ccb->ccb_h.status = CAM_REQUEUE_REQ;
xpt_done(ccb);
- } else if (error) {
- printf("ufshci: SCSI command completion error, Status(0x%x)"
- " Key(0x%x), ASC(0x%x), ASCQ(0x%x)\n",
- cpl->response_upiu.cmd_response_upiu.header
- .ext_iid_or_status,
- sense_data[2], sense_data[12], sense_data[13]);
+ return;
+ }
+
+ if (cpl->ocs != UFSHCI_DESC_SUCCESS) {
+ /* The command never reached the device intact. */
+ ccb->ccb_h.status = CAM_REQ_CMP_ERR;
+ xpt_done(ccb);
+ return;
+ }
+
+ csio->scsi_status = resp->header.ext_iid_or_status;
+
+ /* A failed response with a GOOD status carries no result. */
+ if (csio->scsi_status == SCSI_STATUS_OK &&
+ resp->header.response != UFSHCI_RESPONSE_CODE_TARGET_SUCCESS) {
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
xpt_done(ccb);
- } else {
+ return;
+ }
+
+ if (csio->scsi_status == SCSI_STATUS_OK) {
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done_direct(ccb);
+ return;
}
+
+ ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
+
+ if (csio->scsi_status == SCSI_STATUS_CHECK_COND) {
+ sense_len = be16toh(resp->sense_data_len);
+ sense_len = min(sense_len, sizeof(resp->sense_data));
+ sense_len = min(sense_len, csio->sense_len);
+ memcpy(&csio->sense_data, resp->sense_data, sense_len);
+ csio->sense_resid = csio->sense_len - sense_len;
+ if (sense_len > 0)
+ ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
+ }
+
+ /*
+ * Hold the device queue until CAM has read this. Without the
+ * freeze it reissues at once and spends its retries on a device
+ * that is telling it to wait.
+ */
+ ccb->ccb_h.status |= CAM_DEV_QFRZN;
+ xpt_freeze_devq(ccb->ccb_h.path, 1);
+ xpt_done(ccb);
}
/*