Simon Glass | 4d3b00d | 2022-09-21 16:21:45 +0200 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * Emulation of enough SCSI commands to find and read from a unit |
| 4 | * |
| 5 | * Copyright 2022 Google LLC |
| 6 | * Written by Simon Glass <sjg@chromium.org> |
| 7 | * |
| 8 | * implementation of SCSI functions required so that CONFIG_SCSI can be enabled |
| 9 | * for sandbox. |
| 10 | */ |
| 11 | |
| 12 | #define LOG_CATEGORY UCLASS_SCSI |
| 13 | |
Simon Glass | 4d3b00d | 2022-09-21 16:21:45 +0200 | [diff] [blame] | 14 | #include <dm.h> |
| 15 | #include <log.h> |
| 16 | #include <scsi.h> |
| 17 | #include <scsi_emul.h> |
| 18 | |
| 19 | int sb_scsi_emul_command(struct scsi_emul_info *info, |
| 20 | const struct scsi_cmd *req, int len) |
| 21 | { |
| 22 | int ret = 0; |
| 23 | |
| 24 | info->buff_used = 0; |
| 25 | log_debug("emul %x\n", *req->cmd); |
| 26 | switch (*req->cmd) { |
| 27 | case SCSI_INQUIRY: { |
| 28 | struct scsi_inquiry_resp *resp = (void *)info->buff; |
| 29 | |
| 30 | info->alloc_len = req->cmd[4]; |
| 31 | memset(resp, '\0', sizeof(*resp)); |
| 32 | resp->data_format = 1; |
| 33 | resp->additional_len = 0x1f; |
| 34 | strncpy(resp->vendor, info->vendor, sizeof(resp->vendor)); |
| 35 | strncpy(resp->product, info->product, sizeof(resp->product)); |
| 36 | strncpy(resp->revision, "1.0", sizeof(resp->revision)); |
| 37 | info->buff_used = sizeof(*resp); |
| 38 | break; |
| 39 | } |
| 40 | case SCSI_TST_U_RDY: |
| 41 | break; |
| 42 | case SCSI_RD_CAPAC: { |
| 43 | struct scsi_read_capacity_resp *resp = (void *)info->buff; |
| 44 | uint blocks; |
| 45 | |
| 46 | if (info->file_size) |
| 47 | blocks = info->file_size / info->block_size - 1; |
| 48 | else |
| 49 | blocks = 0; |
| 50 | resp->last_block_addr = cpu_to_be32(blocks); |
| 51 | resp->block_len = cpu_to_be32(info->block_size); |
| 52 | info->buff_used = sizeof(*resp); |
| 53 | break; |
| 54 | } |
| 55 | case SCSI_READ10: { |
| 56 | const struct scsi_read10_req *read_req = (void *)req; |
| 57 | |
| 58 | info->seek_block = be32_to_cpu(read_req->lba); |
| 59 | info->read_len = be16_to_cpu(read_req->xfer_len); |
| 60 | info->buff_used = info->read_len * info->block_size; |
| 61 | ret = SCSI_EMUL_DO_READ; |
| 62 | break; |
| 63 | } |
Simon Glass | 31b4f9e | 2022-10-20 18:22:55 -0600 | [diff] [blame] | 64 | case SCSI_WRITE10: { |
| 65 | const struct scsi_write10_req *write_req = (void *)req; |
| 66 | |
| 67 | info->seek_block = be32_to_cpu(write_req->lba); |
| 68 | info->write_len = be16_to_cpu(write_req->xfer_len); |
| 69 | info->buff_used = info->write_len * info->block_size; |
| 70 | ret = SCSI_EMUL_DO_WRITE; |
| 71 | break; |
| 72 | } |
Simon Glass | 4d3b00d | 2022-09-21 16:21:45 +0200 | [diff] [blame] | 73 | default: |
| 74 | debug("Command not supported: %x\n", req->cmd[0]); |
| 75 | ret = -EPROTONOSUPPORT; |
| 76 | } |
| 77 | if (ret >= 0) |
| 78 | info->phase = info->transfer_len ? SCSIPH_DATA : SCSIPH_STATUS; |
| 79 | log_debug(" - done %x: ret=%d\n", *req->cmd, ret); |
| 80 | |
| 81 | return ret; |
| 82 | } |