uboot/drivers/scsi/sandbox_scsi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2015 Google, Inc
   4 * Written by Simon Glass <sjg@chromium.org>
   5 *
   6 * This file contains dummy implementations of SCSI functions requried so
   7 * that CONFIG_SCSI can be enabled for sandbox.
   8 */
   9
  10#define LOG_CATEGORY UCLASS_SCSI
  11
  12#include <common.h>
  13#include <dm.h>
  14#include <os.h>
  15#include <malloc.h>
  16#include <scsi.h>
  17#include <scsi_emul.h>
  18
  19enum {
  20        SANDBOX_SCSI_BLOCK_LEN          = 512,
  21        SANDBOX_SCSI_BUF_SIZE           = 512,
  22};
  23
  24/**
  25 * struct sandbox_scsi_priv
  26 *
  27 * @eminfo: emulator state
  28 * @pathanme: Path to the backing file, e.g. 'scsi.img'
  29 * @fd: File descriptor of backing file
  30 */
  31struct sandbox_scsi_priv {
  32        struct scsi_emul_info eminfo;
  33        const char *pathname;
  34        int fd;
  35};
  36
  37static int sandbox_scsi_exec(struct udevice *dev, struct scsi_cmd *req)
  38{
  39        struct sandbox_scsi_priv *priv = dev_get_priv(dev);
  40        struct scsi_emul_info *info = &priv->eminfo;
  41        int ret;
  42
  43        if (req->lun || req->target)
  44                return -EIO;
  45        ret = sb_scsi_emul_command(info, req, req->cmdlen);
  46        if (ret < 0) {
  47                log_debug("SCSI command 0x%02x ret errno %d\n", req->cmd[0],
  48                          ret);
  49                return ret;
  50        } else if (ret == SCSI_EMUL_DO_READ && priv->fd != -1) {
  51                long bytes_read;
  52
  53                log_debug("read %x %x\n", info->seek_block, info->read_len);
  54                os_lseek(priv->fd, info->seek_block * info->block_size,
  55                         OS_SEEK_SET);
  56                bytes_read = os_read(priv->fd, req->pdata, info->buff_used);
  57                if (bytes_read < 0)
  58                        return bytes_read;
  59                if (bytes_read != info->buff_used)
  60                        return -EIO;
  61        } else if (!ret) {
  62                req->pdata = info->buff;
  63                info->phase = SCSIPH_STATUS;
  64                log_debug("sending buf\n");
  65        } else {
  66                log_debug("error\n");
  67                return -EIO;
  68        }
  69
  70        return 0;
  71}
  72
  73static int sandbox_scsi_bus_reset(struct udevice *dev)
  74{
  75        /* Not implemented */
  76
  77        return 0;
  78}
  79
  80static int sandbox_scsi_of_to_plat(struct udevice *dev)
  81{
  82        struct sandbox_scsi_priv *priv = dev_get_priv(dev);
  83
  84        priv->pathname = dev_read_string(dev, "sandbox,filepath");
  85
  86        return 0;
  87}
  88
  89static int sandbox_scsi_probe(struct udevice *dev)
  90{
  91        struct scsi_plat *scsi_plat = dev_get_uclass_plat(dev);
  92        struct sandbox_scsi_priv *priv = dev_get_priv(dev);
  93        struct scsi_emul_info *info = &priv->eminfo;
  94        int ret;
  95
  96        scsi_plat->max_id = 2;
  97        scsi_plat->max_lun = 3;
  98        scsi_plat->max_bytes_per_req = 1 << 20;
  99
 100        info->vendor = "SANDBOX";
 101        info->product = "FAKE DISK";
 102        info->buff = malloc(SANDBOX_SCSI_BUF_SIZE);
 103        if (!info->buff)
 104                return log_ret(-ENOMEM);
 105        info->block_size = SANDBOX_SCSI_BLOCK_LEN;
 106
 107        if (priv->pathname) {
 108                priv->fd = os_open(priv->pathname, OS_O_RDONLY);
 109                if (priv->fd != -1) {
 110                        ret = os_get_filesize(priv->pathname, &info->file_size);
 111                        if (ret)
 112                                return log_msg_ret("sz", ret);
 113                }
 114        } else {
 115                priv->fd = -1;
 116        }
 117        log_debug("filename: %s, fd %d\n", priv->pathname, priv->fd);
 118
 119        return 0;
 120}
 121
 122static int sandbox_scsi_remove(struct udevice *dev)
 123{
 124        struct sandbox_scsi_priv *priv = dev_get_priv(dev);
 125        struct scsi_emul_info *info = &priv->eminfo;
 126
 127        free(info->buff);
 128
 129        return 0;
 130}
 131
 132struct scsi_ops sandbox_scsi_ops = {
 133        .exec           = sandbox_scsi_exec,
 134        .bus_reset      = sandbox_scsi_bus_reset,
 135};
 136
 137static const struct udevice_id sanbox_scsi_ids[] = {
 138        { .compatible = "sandbox,scsi" },
 139        { }
 140};
 141
 142U_BOOT_DRIVER(sandbox_scsi) = {
 143        .name           = "sandbox_scsi",
 144        .id             = UCLASS_SCSI,
 145        .ops            = &sandbox_scsi_ops,
 146        .of_match       = sanbox_scsi_ids,
 147        .of_to_plat     = sandbox_scsi_of_to_plat,
 148        .probe          = sandbox_scsi_probe,
 149        .remove         = sandbox_scsi_remove,
 150        .priv_auto      = sizeof(struct sandbox_scsi_priv),
 151};
 152