UFS devices uses the block and scsi frameworks. Enable UFS erase support by adding erase support to SCSI.
Signed-off-by: Varadarajan Narayanan <quic_var...@quicinc.com> --- v2: Remove the scsi_get_blk() function prototype in include/scsi.h. That is not related to this series. --- cmd/scsi.c | 3 +- drivers/scsi/scsi.c | 92 +++++++++++++++++++++++++++++++++++++++++++++ include/scsi.h | 2 + 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/cmd/scsi.c b/cmd/scsi.c index c286bdc0726..9f7613424e5 100644 --- a/cmd/scsi.c +++ b/cmd/scsi.c @@ -60,7 +60,8 @@ U_BOOT_CMD( "scsi read addr blk# cnt - read `cnt' blocks starting at block `blk#'\n" " to memory address `addr'\n" "scsi write addr blk# cnt - write `cnt' blocks starting at block\n" - " `blk#' from memory address `addr'" + " `blk#' from memory address `addr'\n" + "scsi erase blk# cnt - erase `cnt' blocks starting at block `blk#'" ); U_BOOT_CMD( diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index cd0b84c0622..dc93392642d 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -28,6 +28,10 @@ DEFINE_CACHE_ALIGN_BUFFER(u8, tempbuff, 512); /* temporary data buffer */ #define SCSI_MAX_BLK 0xFFFF #define SCSI_LBA48_READ 0xFFFFFFF +#define SCSI_UNMAP_PARAM_RESERVED 0 +#define SCSI_UNMAP_PARAM_LEN 22 +#define SCSI_UNMAP_PARAM_DATA_LEN 16 + static void scsi_print_error(struct scsi_cmd *pccb) { /* Dummy function that could print an error for debugging */ @@ -121,6 +125,51 @@ static void scsi_setup_write_ext(struct scsi_cmd *pccb, lbaint_t start, pccb->cmd[7], pccb->cmd[8]); } +static void scsi_setup_erase_ext(struct scsi_cmd *pccb, lbaint_t start, + unsigned short blocks) +{ + u8 *param = tempbuff; + const u8 param_size = 24; + + memset(param, 0, param_size); + param[0] = SCSI_UNMAP_PARAM_RESERVED; + param[1] = SCSI_UNMAP_PARAM_LEN; + param[2] = SCSI_UNMAP_PARAM_RESERVED; + param[3] = SCSI_UNMAP_PARAM_DATA_LEN; + + param[8] = 0x0; + param[9] = 0x0; + param[10] = 0x0; + param[11] = 0x0; + param[12] = (start >> 24) & 0xff; + param[13] = (start >> 16) & 0xff; + param[14] = (start >> 8) & 0xff; + param[15] = (start) & 0xff; + param[16] = (blocks >> 24) & 0xff; + param[17] = (blocks >> 16) & 0xff; + param[18] = (blocks >> 8) & 0xff; + param[19] = (blocks) & 0xff; + + memset(pccb->cmd, 0, sizeof(pccb->cmd)); + pccb->cmd[0] = SCSI_UNMAP; + pccb->cmd[1] = 0; + pccb->cmd[6] = 0; + pccb->cmd[7] = 0; + pccb->cmd[8] = param_size; + pccb->cmd[9] = 0; + pccb->cmdlen = 10; + + pccb->pdata = param; + pccb->datalen = param_size; + pccb->dma_dir = DMA_TO_DEVICE; + + debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n", + __func__, + pccb->cmd[0], pccb->cmd[1], + pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5], + pccb->cmd[7], pccb->cmd[8]); +} + static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, void *buffer) { @@ -245,6 +294,48 @@ static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, return blkcnt; } +/******************************************************************************* + * scsi_erase + */ +static ulong scsi_erase(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt) +{ + struct blk_desc *block_dev = dev_get_uclass_plat(dev); + struct udevice *bdev = dev->parent; + struct scsi_plat *uc_plat = dev_get_uclass_plat(bdev); + lbaint_t start, blks, max_blks; + struct scsi_cmd *pccb = (struct scsi_cmd *)&tempccb; + + /* Setup device */ + pccb->target = block_dev->target; + pccb->lun = block_dev->lun; + start = blknr; + blks = blkcnt; + if (uc_plat->max_bytes_per_req) + max_blks = uc_plat->max_bytes_per_req / block_dev->blksz; + else + max_blks = SCSI_MAX_BLK; + + debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF "\n", + __func__, block_dev->devnum, start, blks); + do { + if (blks > max_blks) { + scsi_setup_erase_ext(pccb, start, max_blks); + start += max_blks; + blks -= max_blks; + } else { + scsi_setup_erase_ext(pccb, start, blks); + start += blks; + blks = 0; + } + if (scsi_exec(bdev, pccb)) { + scsi_print_error(pccb); + blkcnt -= blks; + break; + } + } while (blks != 0); + return blkcnt; +} + #if IS_ENABLED(CONFIG_BOUNCE_BUFFER) static int scsi_buffer_aligned(struct udevice *dev, struct bounce_buffer *state) { @@ -592,6 +683,7 @@ int scsi_scan(bool verbose) static const struct blk_ops scsi_blk_ops = { .read = scsi_read, .write = scsi_write, + .erase = scsi_erase, #if IS_ENABLED(CONFIG_BOUNCE_BUFFER) .buffer_aligned = scsi_buffer_aligned, #endif /* CONFIG_BOUNCE_BUFFER */ diff --git a/include/scsi.h b/include/scsi.h index b18ae37b861..ab53b47b58f 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -9,6 +9,7 @@ #include <asm/cache.h> #include <bouncebuf.h> #include <linux/dma-direction.h> +#include <part.h> struct udevice; @@ -181,6 +182,7 @@ struct scsi_cmd { #define SCSI_WRT_VERIFY 0x2E /* Write and Verify (O) */ #define SCSI_WRITE_LONG 0x3F /* Write Long (O) */ #define SCSI_WRITE_SAME 0x41 /* Write Same (O) */ +#define SCSI_UNMAP 0x42 /* Write 10-Byte (MANDATORY) */ /** * enum scsi_cmd_phase - current phase of the SCSI protocol -- 2.34.1