diff options
-rw-r--r-- | drivers/scsi/scsi_emul.c | 9 | ||||
-rw-r--r-- | drivers/usb/emul/sandbox_flash.c | 35 | ||||
-rw-r--r-- | include/scsi.h | 10 | ||||
-rw-r--r-- | include/scsi_emul.h | 16 | ||||
-rw-r--r-- | test/dm/usb.c | 19 |
5 files changed, 80 insertions, 9 deletions
diff --git a/drivers/scsi/scsi_emul.c b/drivers/scsi/scsi_emul.c index 5ba364bdac7..6b8468f7994 100644 --- a/drivers/scsi/scsi_emul.c +++ b/drivers/scsi/scsi_emul.c @@ -62,6 +62,15 @@ int sb_scsi_emul_command(struct scsi_emul_info *info, ret = SCSI_EMUL_DO_READ; break; } + case SCSI_WRITE10: { + const struct scsi_write10_req *write_req = (void *)req; + + info->seek_block = be32_to_cpu(write_req->lba); + info->write_len = be16_to_cpu(write_req->xfer_len); + info->buff_used = info->write_len * info->block_size; + ret = SCSI_EMUL_DO_WRITE; + break; + } default: debug("Command not supported: %x\n", req->cmd[0]); ret = -EPROTONOSUPPORT; diff --git a/drivers/usb/emul/sandbox_flash.c b/drivers/usb/emul/sandbox_flash.c index 2589c708d88..6e8cfe1650a 100644 --- a/drivers/usb/emul/sandbox_flash.c +++ b/drivers/usb/emul/sandbox_flash.c @@ -4,6 +4,8 @@ * Written by Simon Glass <sjg@chromium.org> */ +#define LOG_CATEGORY UCLASS_USB + #include <common.h> #include <dm.h> #include <log.h> @@ -190,7 +192,8 @@ static int handle_ufi_command(struct sandbox_flash_priv *priv, const void *buff, ret = sb_scsi_emul_command(info, req, len); if (!ret) { setup_response(priv); - } else if (ret == SCSI_EMUL_DO_READ && priv->fd != -1) { + } else if ((ret == SCSI_EMUL_DO_READ || ret == SCSI_EMUL_DO_WRITE) && + priv->fd != -1) { os_lseek(priv->fd, info->seek_block * info->block_size, OS_SEEK_SET); setup_response(priv); @@ -217,6 +220,7 @@ static int sandbox_flash_bulk(struct udevice *dev, struct usb_device *udev, case SCSIPH_START: info->alloc_len = 0; info->read_len = 0; + info->write_len = 0; if (priv->error || len != UMASS_BBB_CBW_SIZE || cbw->dCBWSignature != CBWSIGNATURE) goto err; @@ -230,8 +234,31 @@ static int sandbox_flash_bulk(struct udevice *dev, struct usb_device *udev, return handle_ufi_command(priv, cbw->CBWCDB, cbw->bCDBLength); case SCSIPH_DATA: - debug("data out\n"); - break; + log_debug("data out, len=%x, info->write_len=%x\n", len, + info->write_len); + info->transfer_len = cbw->dCBWDataTransferLength; + priv->tag = cbw->dCBWTag; + if (!info->write_len) + return 0; + if (priv->fd != -1) { + ulong bytes_written; + + bytes_written = os_write(priv->fd, buff, len); + log_debug("bytes_written=%lx", bytes_written); + if (bytes_written != len) + return -EIO; + info->write_len -= len / info->block_size; + if (!info->write_len) + info->phase = SCSIPH_STATUS; + } else { + if (info->alloc_len && len > info->alloc_len) + len = info->alloc_len; + if (len > SANDBOX_FLASH_BUF_SIZE) + len = SANDBOX_FLASH_BUF_SIZE; + memcpy(info->buff, buff, len); + info->phase = SCSIPH_STATUS; + } + return len; default: break; } @@ -310,7 +337,7 @@ static int sandbox_flash_probe(struct udevice *dev) struct scsi_emul_info *info = &priv->eminfo; int ret; - priv->fd = os_open(plat->pathname, OS_O_RDONLY); + priv->fd = os_open(plat->pathname, OS_O_RDWR); if (priv->fd != -1) { ret = os_get_filesize(plat->pathname, &info->file_size); if (ret) diff --git a/include/scsi.h b/include/scsi.h index 94e1d8ccb28..9efefea99bb 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -255,6 +255,16 @@ struct __packed scsi_read10_req { u8 spare2[3]; }; +/** struct scsi_write10_req - data for the write10 command */ +struct __packed scsi_write10_req { + u8 cmd; + u8 lun_flags; + u32 lba; + u8 spare; + u16 xfer_len; + u8 spare2[3]; +}; + /** * struct scsi_plat - stores information about SCSI controller * diff --git a/include/scsi_emul.h b/include/scsi_emul.h index 13c3f860b40..d439f7c00c2 100644 --- a/include/scsi_emul.h +++ b/include/scsi_emul.h @@ -41,13 +41,20 @@ struct scsi_emul_info { enum scsi_cmd_phase phase; int buff_used; int read_len; + int write_len; uint seek_pos; int alloc_len; uint transfer_len; }; -/* Indicates that a read is being started */ -#define SCSI_EMUL_DO_READ 1 +/** + * Return value from sb_scsi_emul_command() indicates that a read or write is + * being started + */ +enum { + SCSI_EMUL_DO_READ = 1, + SCSI_EMUL_DO_WRITE = 2, +}; /** * sb_scsi_emul_command() - Process a SCSI command @@ -61,8 +68,9 @@ struct scsi_emul_info { * @info: Emulation information * @req: Request to process * @len: Length of request in bytes - * @return SCSI_EMUL_DO_READ if a read has started, 0 if some other operation - * has started, -ve if there was an error + * @return SCSI_EMUL_DO_READ if a read has started, SCSI_EMUL_DO_WRITE if a + * write has started, 0 if some other operation has started, -ve if there + * was an error */ int sb_scsi_emul_command(struct scsi_emul_info *info, const struct scsi_cmd *req, int len); diff --git a/test/dm/usb.c b/test/dm/usb.c index 445b21a560b..7671ef156d8 100644 --- a/test/dm/usb.c +++ b/test/dm/usb.c @@ -61,7 +61,24 @@ static int dm_test_usb_flash(struct unit_test_state *uts) ut_asserteq(512, dev_desc->blksz); memset(cmp, '\0', sizeof(cmp)); ut_asserteq(2, blk_read(blk, 0, 2, cmp)); - ut_assertok(strcmp(cmp, "this is a test")); + ut_asserteq_str("this is a test", cmp); + + strcpy(cmp, "another test"); + ut_asserteq(1, blk_write(blk, 1, 1, cmp)); + + memset(cmp, '\0', sizeof(cmp)); + ut_asserteq(2, blk_read(blk, 0, 2, cmp)); + ut_asserteq_str("this is a test", cmp); + ut_asserteq_str("another test", cmp + 512); + + memset(cmp, '\0', sizeof(cmp)); + ut_asserteq(1, blk_write(blk, 1, 1, cmp)); + + memset(cmp, '\0', sizeof(cmp)); + ut_asserteq(2, blk_read(blk, 0, 2, cmp)); + ut_asserteq_str("this is a test", cmp); + ut_asserteq_str("", cmp + 512); + ut_assertok(usb_stop()); return 0; |