mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-17 02:15:02 +00:00
drivers: scsi: Add 'erase' support
UFS devices uses the block and scsi frameworks. Enable UFS erase support by adding erase support to SCSI. Signed-off-by: Varadarajan Narayanan <quic_varada@quicinc.com>
This commit is contained in:
parent
6a5177a58c
commit
7dd49a9264
3 changed files with 96 additions and 1 deletions
|
@ -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(
|
||||
|
|
|
@ -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 */
|
||||
|
@ -138,6 +142,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)
|
||||
{
|
||||
|
@ -268,6 +317,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)
|
||||
{
|
||||
|
@ -615,6 +706,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 */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue