sandbox: scsi: Move request-handling code to scsi_emul
authorSimon Glass <sjg@chromium.org>
Wed, 21 Sep 2022 14:21:45 +0000 (16:21 +0200)
committerSimon Glass <sjg@chromium.org>
Sun, 25 Sep 2022 19:59:38 +0000 (13:59 -0600)
Move this code into the emulator file so it can be used by multiple
drivers.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/scsi/Makefile
drivers/scsi/scsi_emul.c [new file with mode: 0644]
drivers/usb/emul/sandbox_flash.c
include/scsi_emul.h

index 25194ee..d1b40c6 100644 (file)
@@ -17,4 +17,5 @@ endif
 
 ifdef CONFIG_SCSI
 obj-$(CONFIG_SANDBOX) += sandbox_scsi.o
+obj-$(CONFIG_SANDBOX) += scsi_emul.o
 endif
diff --git a/drivers/scsi/scsi_emul.c b/drivers/scsi/scsi_emul.c
new file mode 100644 (file)
index 0000000..5ba364b
--- /dev/null
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Emulation of enough SCSI commands to find and read from a unit
+ *
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * implementation of SCSI functions required so that CONFIG_SCSI can be enabled
+ * for sandbox.
+ */
+
+#define LOG_CATEGORY UCLASS_SCSI
+
+#include <common.h>
+#include <dm.h>
+#include <log.h>
+#include <scsi.h>
+#include <scsi_emul.h>
+
+int sb_scsi_emul_command(struct scsi_emul_info *info,
+                        const struct scsi_cmd *req, int len)
+{
+       int ret = 0;
+
+       info->buff_used = 0;
+       log_debug("emul %x\n", *req->cmd);
+       switch (*req->cmd) {
+       case SCSI_INQUIRY: {
+               struct scsi_inquiry_resp *resp = (void *)info->buff;
+
+               info->alloc_len = req->cmd[4];
+               memset(resp, '\0', sizeof(*resp));
+               resp->data_format = 1;
+               resp->additional_len = 0x1f;
+               strncpy(resp->vendor, info->vendor, sizeof(resp->vendor));
+               strncpy(resp->product, info->product, sizeof(resp->product));
+               strncpy(resp->revision, "1.0", sizeof(resp->revision));
+               info->buff_used = sizeof(*resp);
+               break;
+       }
+       case SCSI_TST_U_RDY:
+               break;
+       case SCSI_RD_CAPAC: {
+               struct scsi_read_capacity_resp *resp = (void *)info->buff;
+               uint blocks;
+
+               if (info->file_size)
+                       blocks = info->file_size / info->block_size - 1;
+               else
+                       blocks = 0;
+               resp->last_block_addr = cpu_to_be32(blocks);
+               resp->block_len = cpu_to_be32(info->block_size);
+               info->buff_used = sizeof(*resp);
+               break;
+       }
+       case SCSI_READ10: {
+               const struct scsi_read10_req *read_req = (void *)req;
+
+               info->seek_block = be32_to_cpu(read_req->lba);
+               info->read_len = be16_to_cpu(read_req->xfer_len);
+               info->buff_used = info->read_len * info->block_size;
+               ret = SCSI_EMUL_DO_READ;
+               break;
+       }
+       default:
+               debug("Command not supported: %x\n", req->cmd[0]);
+               ret = -EPROTONOSUPPORT;
+       }
+       if (ret >= 0)
+               info->phase = info->transfer_len ? SCSIPH_DATA : SCSIPH_STATUS;
+       log_debug("   - done %x: ret=%d\n", *req->cmd, ret);
+
+       return ret;
+}
index 2059fc7..2589c70 100644 (file)
@@ -180,97 +180,30 @@ static void setup_response(struct sandbox_flash_priv *priv)
        csw->bCSWStatus = CSWSTATUS_GOOD;
 }
 
-/**
- * handle_read() - prepare for reading data from the backing file
- *
- * This seeks to the correct file position and sets info->buff_used to the
- * correct size.
- *
- * @priv: Private information
- * @lba: Start block to read from
- * @transfer_length: Number of blocks to read
- * @return 0 if OK, -EIO on failure
- */
-static int handle_read(struct sandbox_flash_priv *priv, ulong lba,
-                      ulong transfer_len)
-{
-       struct scsi_emul_info *info = &priv->eminfo;
-
-       debug("%s: lba=%lx, transfer_len=%lx\n", __func__, lba, transfer_len);
-       info->read_len = transfer_len;
-       if (priv->fd != -1) {
-               os_lseek(priv->fd, lba * info->block_size, OS_SEEK_SET);
-               info->buff_used = transfer_len * info->block_size;
-               return 0;
-       }
-
-       return -EIO;
-}
-
-static int handle_ufi_command(struct sandbox_flash_plat *plat,
-                             struct sandbox_flash_priv *priv, const void *buff,
+static int handle_ufi_command(struct sandbox_flash_priv *priv, const void *buff,
                              int len)
 {
        struct scsi_emul_info *info = &priv->eminfo;
        const struct scsi_cmd *req = buff;
+       int ret;
 
-       info->buff_used = 0;
-       switch (*req->cmd) {
-       case SCSI_INQUIRY: {
-               struct scsi_inquiry_resp *resp = (void *)info->buff;
-
-               info->alloc_len = req->cmd[4];
-               memset(resp, '\0', sizeof(*resp));
-               resp->data_format = 1;
-               resp->additional_len = 0x1f;
-               strncpy(resp->vendor, info->vendor, sizeof(resp->vendor));
-               strncpy(resp->product, info->product, sizeof(resp->product));
-               strncpy(resp->revision, "1.0", sizeof(resp->revision));
-               info->buff_used = sizeof(*resp);
-               setup_response(priv);
-               break;
-       }
-       case SCSI_TST_U_RDY:
+       ret = sb_scsi_emul_command(info, req, len);
+       if (!ret) {
                setup_response(priv);
-               break;
-       case SCSI_RD_CAPAC: {
-               struct scsi_read_capacity_resp *resp = (void *)info->buff;
-               uint blocks;
-
-               if (info->file_size)
-                       blocks = info->file_size / info->block_size - 1;
-               else
-                       blocks = 0;
-               resp->last_block_addr = cpu_to_be32(blocks);
-               resp->block_len = cpu_to_be32(info->block_size);
-               info->buff_used = sizeof(*resp);
+       } else if (ret == SCSI_EMUL_DO_READ && priv->fd != -1) {
+               os_lseek(priv->fd, info->seek_block * info->block_size,
+                        OS_SEEK_SET);
                setup_response(priv);
-               break;
+       } else {
+               setup_fail_response(priv);
        }
-       case SCSI_READ10: {
-               struct scsi_read10_req *req = (void *)buff;
 
-               if (!handle_read(priv, be32_to_cpu(req->lba),
-                                be16_to_cpu(req->xfer_len)))
-                       setup_response(priv);
-               else
-                       setup_fail_response(priv);
-
-               break;
-       }
-       default:
-               debug("Command not supported: %x\n", req->cmd[0]);
-               return -EPROTONOSUPPORT;
-       }
-
-       info->phase = info->transfer_len ? SCSIPH_DATA : SCSIPH_STATUS;
        return 0;
 }
 
 static int sandbox_flash_bulk(struct udevice *dev, struct usb_device *udev,
                              unsigned long pipe, void *buff, int len)
 {
-       struct sandbox_flash_plat *plat = dev_get_plat(dev);
        struct sandbox_flash_priv *priv = dev_get_priv(dev);
        struct scsi_emul_info *info = &priv->eminfo;
        int ep = usb_pipeendpoint(pipe);
@@ -294,7 +227,7 @@ static int sandbox_flash_bulk(struct udevice *dev, struct usb_device *udev,
                                goto err;
                        info->transfer_len = cbw->dCBWDataTransferLength;
                        priv->tag = cbw->dCBWTag;
-                       return handle_ufi_command(plat, priv, cbw->CBWCDB,
+                       return handle_ufi_command(priv, cbw->CBWCDB,
                                                  cbw->bCDBLength);
                case SCSIPH_DATA:
                        debug("data out\n");
index 3c52398..13c3f86 100644 (file)
@@ -19,6 +19,7 @@
  * @product: Product name
  * @block_size: Block size of device in bytes (normally 512)
  * @file_size: Size of the backing file for this emulator, in bytes
+ * @seek_block: Seek position for file (block number)
  *
  * @phase: Current SCSI phase
  * @buff_used: Number of bytes ready to transfer back to host
@@ -34,13 +35,36 @@ struct scsi_emul_info {
        const char *product;
        int block_size;
        loff_t file_size;
+       int seek_block;
 
        /* state maintained by the emulator: */
        enum scsi_cmd_phase phase;
        int buff_used;
        int read_len;
+       uint seek_pos;
        int alloc_len;
        uint transfer_len;
 };
 
+/* Indicates that a read is being started */
+#define SCSI_EMUL_DO_READ      1
+
+/**
+ * sb_scsi_emul_command() - Process a SCSI command
+ *
+ * This sets up the response in info->buff and updates various other values
+ * in info.
+ *
+ * If SCSI_EMUL_DO_READ is returned then the caller should set up so that the
+ * backing file can be read, or return an error status if there is no file.
+ *
+ * @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
+ */
+int sb_scsi_emul_command(struct scsi_emul_info *info,
+                        const struct scsi_cmd *req, int len);
+
 #endif