scsi: ufs: rpmb: Retry power-on UNIT ATTENTION on the RPMB WLUN

After a power cycle, the first command sent to any UFS logical unit
completes with CHECK CONDITION reporting a power-on UNIT ATTENTION.  The
SCSI core surfaces this condition to the caller rather than retrying it.

For the RPMB well-known LU the first command after boot is the first RPMB
frame, and RPMB has no earlier, guaranteed access that could clear the
condition beforehand. The power-on UNIT ATTENTION therefore reaches RPMB
and fails that first frame, breaking RPMB on every cold boot.

The RPMB WLUN needs the power-on UNIT ATTENTION to be retried so that RPMB
works from the very first access after a power cycle.

Signed-off-by: Jorge Ramirez-Ortiz <jorge.ramirez@oss.qualcomm.com>
Reviewed-by: Bean Huo <beanhuo@micron.com>
Reviewed-by: Stanley Jhu <stanleyjhu@google.com>
Link: https://patch.msgid.link/20260831154804.719528-2-jorge.ramirez@oss.qualcomm.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
Jorge Ramirez-Ortiz 2026-08-31 17:48:00 +02:00 committed by Martin K. Petersen (Oracle)
parent cee9395acd
commit a8a34238e5

View File

@ -21,6 +21,7 @@
#include <linux/unaligned.h> #include <linux/unaligned.h>
#include "ufshcd-priv.h" #include "ufshcd-priv.h"
#define UFS_RPMB_UA_RETRIES 3 /* Retries for the power-on UNIT ATTENTION */
#define UFS_RPMB_SEC_PROTOCOL 0xEC /* JEDEC UFS application */ #define UFS_RPMB_SEC_PROTOCOL 0xEC /* JEDEC UFS application */
#define UFS_RPMB_SEC_PROTOCOL_ID 0x01 /* JEDEC UFS RPMB protocol ID, CDB byte3 */ #define UFS_RPMB_SEC_PROTOCOL_ID 0x01 /* JEDEC UFS RPMB protocol ID, CDB byte3 */
@ -40,6 +41,22 @@ struct ufs_rpmb_dev {
static int ufs_sec_submit(struct ufs_hba *hba, u16 spsp, void *buffer, size_t len, bool send) static int ufs_sec_submit(struct ufs_hba *hba, u16 spsp, void *buffer, size_t len, bool send)
{ {
struct scsi_device *sdev = hba->ufs_rpmb_wlun; struct scsi_device *sdev = hba->ufs_rpmb_wlun;
struct scsi_failure failure_defs[] = {
{
.sense = UNIT_ATTENTION,
.asc = 0x29, /* power on, reset, or bus device reset occurred */
.ascq = SCMD_FAILURE_ASCQ_ANY,
.allowed = UFS_RPMB_UA_RETRIES,
.result = SAM_STAT_CHECK_CONDITION,
},
{}
};
struct scsi_failures failures = {
.failure_definitions = failure_defs,
};
const struct scsi_exec_args exec_args = {
.failures = &failures,
};
u8 cdb[12] = { }; u8 cdb[12] = { };
cdb[0] = send ? SECURITY_PROTOCOL_OUT : SECURITY_PROTOCOL_IN; cdb[0] = send ? SECURITY_PROTOCOL_OUT : SECURITY_PROTOCOL_IN;
@ -48,7 +65,8 @@ static int ufs_sec_submit(struct ufs_hba *hba, u16 spsp, void *buffer, size_t le
put_unaligned_be32(len, &cdb[6]); put_unaligned_be32(len, &cdb[6]);
return scsi_execute_cmd(sdev, cdb, send ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, return scsi_execute_cmd(sdev, cdb, send ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
buffer, len, /*timeout=*/30 * HZ, 0, NULL); buffer, len, /*timeout=*/30 * HZ, /*retries=*/0,
&exec_args);
} }
/* UFS RPMB route frames implementation */ /* UFS RPMB route frames implementation */