[PATCH] scsi: use ATA-12 pass-thru for OPAL as fallback

From: Milan Broz
Date: Mon Oct 16 2023 - 03:02:26 EST


USB attached storage (handled by UAS or usb-storage driver) does not
support SCSI SECURITY IN/OUT commands. (USB adapters usually do not
support it, and USB drivers also turn off SCSI command enumeration).

The original sedutils (used to configure OPAL from userspace)
always used the ATA-12 pass-through command.

Internal kernel implementation for OPAL interface (sed-opal ioctls)
currently supports only SCSI SECURITY IN/OUT command wrapper.

This patch adds an optional wrapper to the SCSI layer for the ATA-12
pass-thru command as an alternative if SECURITY IN/OUT is unavailable.
The wrapper has the same structure as tools that talk to OPAL drives
through ioctl from userspace.

All common USB/SATA or USB/NVMe adapters I tested need this patch.

In short, these steps are run for OPAL support check:
1) Storage driver enables security driver flag (security_supported).
USB-attached storage drivers will enable it in a separate patchset.
SCSI and NNVMe drivers do it already. If the flag is not enabled,
no following steps are run, and OPAL remains disabled.
2) SCSI device enumerates SECURITY IN/OUT command support. If detected,
SECURITY ON/OUT wrapper is used (as in the current code).
If not, new ATA-12 pass-thru wrapper is used instead.
3) SED OPAL code tries OPAL discovery command for the device.
If it receives a correct reply, OPAL is enabled for the device.
If SCSI SECURITY or ATA-12 command with discovery command is rejected,
OPAL remains disabled.

Note, USB attached storage needs an additional patchset sent separately
as requested by USB driver maintainers (it contains required changes
related to USB quirk processing).

Signed-off-by: Milan Broz <gmazyland@xxxxxxxxx>
---
drivers/scsi/sd.c | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 83b6a3f3863b..3782556cb461 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -686,6 +686,32 @@ static int sd_sec_submit(void *data, u16 spsp, u8 secp, void *buffer,
&exec_args);
return ret <= 0 ? ret : -EIO;
}
+
+static int sd_ata12_submit(void *data, u16 spsp, u8 secp, void *buffer,
+ size_t len, bool send)
+{
+ struct scsi_disk *sdkp = data;
+ struct scsi_device *sdev = sdkp->device;
+ u8 cdb[12] = { 0, };
+ const struct scsi_exec_args exec_args = {
+ .req_flags = BLK_MQ_REQ_PM,
+ };
+ int ret;
+
+ cdb[0] = ATA_12;
+ cdb[1] = (send ? 5 /* ATA_PROTOCOL_PIO_DATA_IN */ : 4 /* ATA_PROTOCOL_PIO_DATA_OUT */) << 1;
+ cdb[2] = 2 /* t_length */ | (1 << 2) /* byt_blok */ | ((send ? 0 : 1) << 3) /* t_dir */;
+ cdb[3] = secp;
+ put_unaligned_le16(len / 512, &cdb[4]);
+ put_unaligned_le16(spsp, &cdb[6]);
+ cdb[9] = send ? 0x5e /* ATA_CMD_TRUSTED_SND */: 0x5c /* ATA_CMD_TRUSTED_RCV */;
+
+ ret = scsi_execute_cmd(sdev, cdb, send ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN,
+ buffer, len, SD_TIMEOUT, sdkp->max_retries,
+ &exec_args);
+ return ret <= 0 ? ret : -EIO;
+}
+
#endif /* CONFIG_BLK_SED_OPAL */

/*
@@ -3699,8 +3725,11 @@ static int sd_probe(struct device *dev)
goto out;
}

- if (sdkp->security) {
- sdkp->opal_dev = init_opal_dev(sdkp, &sd_sec_submit);
+ if (sdp->security_supported) {
+ if (sdkp->security)
+ sdkp->opal_dev = init_opal_dev(sdkp, &sd_sec_submit);
+ else
+ sdkp->opal_dev = init_opal_dev(sdkp, &sd_ata12_submit);
if (sdkp->opal_dev)
sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n");
}
--
2.42.0