git: 7d5d54dec54f - main - ufshci: report the SCSI status and sense to CAM

From: Jaeyoon Choi <jaeyoon_at_FreeBSD.org>
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);
 }
 
 /*