aboutsummaryrefslogtreecommitdiff
path: root/hw/scsi
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-09-19 15:44:07 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-09-19 15:44:07 +0100
commit7ec6a364916c0d1eba01128481e503a550a2b466 (patch)
treeb88db8c6396c5e4ae6560da723e726729cc0e42c /hw/scsi
parent11e06ce1ed28fd0ffcbc1e2436b72f3412b4ecc8 (diff)
parent7437866bfc3b25663f415a8c660fd78360e84598 (diff)
downloadqemu-7ec6a364916c0d1eba01128481e503a550a2b466.zip
qemu-7ec6a364916c0d1eba01128481e503a550a2b466.tar.gz
qemu-7ec6a364916c0d1eba01128481e503a550a2b466.tar.bz2
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* warning improvements (Alistair) * KVM code cleanup (David) * scsi-block support for rerror/werror (Fam) * support for >64 vCPUs in Windows (Gonglei) * SCSI fix (Hannes) * SSE bugfixes (Joseph) * SmartOS compilation fixes (Kamil) * Hyper-V frequency MSR support (Ladi) * move more files to accel/tcg (Philippe, Thomas) * multiboot validation (PJP) * virtqueue size configuration for virtio-scsi (Richard) * Hyper-V header cleanup (Roman) * Maintainer email update (Guangrong) * checkpatch.pl --branch (Daniel), fixes (Greg) * introducing scsi/ (me) # gpg: Signature made Tue 19 Sep 2017 15:21:26 BST # gpg: using RSA key 0xBFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: (51 commits) docker: fix creation of archives default-configs: Replace $(and ...) with $(call land, ...) osdep.h: Prohibit disabling assert() in supported builds checkpatch: add hwaddr to @typeList accel/hax: move hax-stub.c to accel/stubs/ target/i386: fix "info mem" for LA57 mode scripts: let checkpatch.pl process an entire GIT branch update-linux-headers: prepare for hyperv.h removal hyperv: add header with protocol definitions i386/cpu/hyperv: support over 64 vcpus for windows guests Convert remaining single line fprintf() to warn_report() Makefile: Remove libqemustub.a ptimer-test: do not link to libqemustub.a/libqemuutil.a target/mips: Convert VM clock update prints to warn_report General warn report fixups Convert multi-line fprintf() to warn_report() Convert single line fprintf(.../n) to warn_report() Convert remaining error_report() to warn_report() hw/i386: Improve some of the warning messages test-qga: add missing qemu-ga tool dependency ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/scsi')
-rw-r--r--hw/scsi/esp.c10
-rw-r--r--hw/scsi/megasas.c2
-rw-r--r--hw/scsi/mptendian.c2
-rw-r--r--hw/scsi/mptsas.c8
-rw-r--r--hw/scsi/scsi-bus.c440
-rw-r--r--hw/scsi/scsi-disk.c43
-rw-r--r--hw/scsi/scsi-generic.c50
-rw-r--r--hw/scsi/spapr_vscsi.c2
-rw-r--r--hw/scsi/virtio-scsi-dataplane.c2
-rw-r--r--hw/scsi/virtio-scsi.c10
-rw-r--r--hw/scsi/vmw_pvscsi.c2
11 files changed, 82 insertions, 489 deletions
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index eee831e..22c2d91 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -593,7 +593,7 @@ const VMStateDescription vmstate_esp = {
};
#define TYPE_ESP "esp"
-#define ESP(obj) OBJECT_CHECK(SysBusESPState, (obj), TYPE_ESP)
+#define ESP_STATE(obj) OBJECT_CHECK(SysBusESPState, (obj), TYPE_ESP)
typedef struct {
/*< private >*/
@@ -644,7 +644,7 @@ void esp_init(hwaddr espaddr, int it_shift,
ESPState *esp;
dev = qdev_create(NULL, TYPE_ESP);
- sysbus = ESP(dev);
+ sysbus = ESP_STATE(dev);
esp = &sysbus->esp;
esp->dma_memory_read = dma_memory_read;
esp->dma_memory_write = dma_memory_write;
@@ -672,7 +672,7 @@ static const struct SCSIBusInfo esp_scsi_info = {
static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
{
- SysBusESPState *sysbus = ESP(opaque);
+ SysBusESPState *sysbus = ESP_STATE(opaque);
ESPState *s = &sysbus->esp;
switch (irq) {
@@ -688,7 +688,7 @@ static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
static void sysbus_esp_realize(DeviceState *dev, Error **errp)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
- SysBusESPState *sysbus = ESP(dev);
+ SysBusESPState *sysbus = ESP_STATE(dev);
ESPState *s = &sysbus->esp;
sysbus_init_irq(sbd, &s->irq);
@@ -706,7 +706,7 @@ static void sysbus_esp_realize(DeviceState *dev, Error **errp)
static void sysbus_esp_hard_reset(DeviceState *dev)
{
- SysBusESPState *sysbus = ESP(dev);
+ SysBusESPState *sysbus = ESP_STATE(dev);
esp_hard_reset(&sysbus->esp);
}
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 734fdae..0db68aa 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -27,7 +27,7 @@
#include "hw/pci/msix.h"
#include "qemu/iov.h"
#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
#include "trace.h"
#include "qapi/error.h"
#include "mfi.h"
diff --git a/hw/scsi/mptendian.c b/hw/scsi/mptendian.c
index b7fe2a2..3415229 100644
--- a/hw/scsi/mptendian.c
+++ b/hw/scsi/mptendian.c
@@ -28,7 +28,7 @@
#include "hw/pci/msi.h"
#include "qemu/iov.h"
#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
#include "trace.h"
#include "mptsas.h"
diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
index 765ab53..d05fa9f 100644
--- a/hw/scsi/mptsas.c
+++ b/hw/scsi/mptsas.c
@@ -30,7 +30,7 @@
#include "hw/pci/msi.h"
#include "qemu/iov.h"
#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
#include "trace.h"
#include "qapi/error.h"
#include "mptsas.h"
@@ -1236,11 +1236,9 @@ static void *mptsas_load_request(QEMUFile *f, SCSIRequest *sreq)
n = qemu_get_be32(f);
/* TODO: add a way for SCSIBusInfo's load_request to fail,
* and fail migration instead of asserting here.
- * When we do, we might be able to re-enable NDEBUG below.
+ * This is just one thing (there are probably more) that must be
+ * fixed before we can allow NDEBUG compilation.
*/
-#ifdef NDEBUG
-#error building with NDEBUG is not supported
-#endif
assert(n >= 0);
pci_dma_sglist_init(&req->qsg, pci, n);
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index e364410..977f7bc 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -3,7 +3,7 @@
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
#include "hw/qdev.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
@@ -516,8 +516,10 @@ static size_t scsi_sense_len(SCSIRequest *req)
static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
{
SCSITargetReq *r = DO_UPCAST(SCSITargetReq, req, req);
+ int fixed_sense = (req->cmd.buf[1] & 1) == 0;
- if (req->lun != 0) {
+ if (req->lun != 0 &&
+ buf[0] != INQUIRY && buf[0] != REQUEST_SENSE) {
scsi_req_build_sense(req, SENSE_CODE(LUN_NOT_SUPPORTED));
scsi_req_complete(req, CHECK_CONDITION);
return 0;
@@ -535,9 +537,28 @@ static int32_t scsi_target_send_command(SCSIRequest *req, uint8_t *buf)
break;
case REQUEST_SENSE:
scsi_target_alloc_buf(&r->req, scsi_sense_len(req));
- r->len = scsi_device_get_sense(r->req.dev, r->buf,
- MIN(req->cmd.xfer, r->buf_len),
- (req->cmd.buf[1] & 1) == 0);
+ if (req->lun != 0) {
+ const struct SCSISense sense = SENSE_CODE(LUN_NOT_SUPPORTED);
+
+ if (fixed_sense) {
+ r->buf[0] = 0x70;
+ r->buf[2] = sense.key;
+ r->buf[10] = 10;
+ r->buf[12] = sense.asc;
+ r->buf[13] = sense.ascq;
+ r->len = MIN(req->cmd.xfer, SCSI_SENSE_LEN);
+ } else {
+ r->buf[0] = 0x72;
+ r->buf[1] = sense.key;
+ r->buf[2] = sense.asc;
+ r->buf[3] = sense.ascq;
+ r->len = 8;
+ }
+ } else {
+ r->len = scsi_device_get_sense(r->req.dev, r->buf,
+ MIN(req->cmd.xfer, r->buf_len),
+ fixed_sense);
+ }
if (r->req.dev->sense_is_ua) {
scsi_device_unit_attention_reported(req->dev);
r->req.dev->sense_len = 0;
@@ -769,7 +790,7 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
return 0;
}
- ret = scsi_build_sense(req->sense, req->sense_len, buf, len, true);
+ ret = scsi_convert_sense(req->sense, req->sense_len, buf, len, true);
/*
* FIXME: clearing unit attention conditions upon autosense should be done
@@ -790,20 +811,14 @@ int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len)
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed)
{
- return scsi_build_sense(dev->sense, dev->sense_len, buf, len, fixed);
+ return scsi_convert_sense(dev->sense, dev->sense_len, buf, len, fixed);
}
void scsi_req_build_sense(SCSIRequest *req, SCSISense sense)
{
trace_scsi_req_build_sense(req->dev->id, req->lun, req->tag,
sense.key, sense.asc, sense.ascq);
- memset(req->sense, 0, 18);
- req->sense[0] = 0x70;
- req->sense[2] = sense.key;
- req->sense[7] = 10;
- req->sense[12] = sense.asc;
- req->sense[13] = sense.ascq;
- req->sense_len = 18;
+ req->sense_len = scsi_build_sense(req->sense, sense);
}
static void scsi_req_enqueue_internal(SCSIRequest *req)
@@ -935,36 +950,6 @@ static int ata_passthrough_16_xfer(SCSIDevice *dev, uint8_t *buf)
return xfer * unit;
}
-uint32_t scsi_data_cdb_xfer(uint8_t *buf)
-{
- if ((buf[0] >> 5) == 0 && buf[4] == 0) {
- return 256;
- } else {
- return scsi_cdb_xfer(buf);
- }
-}
-
-uint32_t scsi_cdb_xfer(uint8_t *buf)
-{
- switch (buf[0] >> 5) {
- case 0:
- return buf[4];
- break;
- case 1:
- case 2:
- return lduw_be_p(&buf[7]);
- break;
- case 4:
- return ldl_be_p(&buf[10]) & 0xffffffffULL;
- break;
- case 5:
- return ldl_be_p(&buf[6]) & 0xffffffffULL;
- break;
- default:
- return -1;
- }
-}
-
static int scsi_req_xfer(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
{
cmd->xfer = scsi_cdb_xfer(buf);
@@ -1277,53 +1262,6 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
}
}
-static uint64_t scsi_cmd_lba(SCSICommand *cmd)
-{
- uint8_t *buf = cmd->buf;
- uint64_t lba;
-
- switch (buf[0] >> 5) {
- case 0:
- lba = ldl_be_p(&buf[0]) & 0x1fffff;
- break;
- case 1:
- case 2:
- case 5:
- lba = ldl_be_p(&buf[2]) & 0xffffffffULL;
- break;
- case 4:
- lba = ldq_be_p(&buf[2]);
- break;
- default:
- lba = -1;
-
- }
- return lba;
-}
-
-int scsi_cdb_length(uint8_t *buf) {
- int cdb_len;
-
- switch (buf[0] >> 5) {
- case 0:
- cdb_len = 6;
- break;
- case 1:
- case 2:
- cdb_len = 10;
- break;
- case 4:
- cdb_len = 16;
- break;
- case 5:
- cdb_len = 12;
- break;
- default:
- cdb_len = -1;
- }
- return cdb_len;
-}
-
int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
{
int rc;
@@ -1370,326 +1308,6 @@ void scsi_device_report_change(SCSIDevice *dev, SCSISense sense)
}
}
-/*
- * Predefined sense codes
- */
-
-/* No sense data available */
-const struct SCSISense sense_code_NO_SENSE = {
- .key = NO_SENSE , .asc = 0x00 , .ascq = 0x00
-};
-
-/* LUN not ready, Manual intervention required */
-const struct SCSISense sense_code_LUN_NOT_READY = {
- .key = NOT_READY, .asc = 0x04, .ascq = 0x03
-};
-
-/* LUN not ready, Medium not present */
-const struct SCSISense sense_code_NO_MEDIUM = {
- .key = NOT_READY, .asc = 0x3a, .ascq = 0x00
-};
-
-/* LUN not ready, medium removal prevented */
-const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
- .key = NOT_READY, .asc = 0x53, .ascq = 0x02
-};
-
-/* Hardware error, internal target failure */
-const struct SCSISense sense_code_TARGET_FAILURE = {
- .key = HARDWARE_ERROR, .asc = 0x44, .ascq = 0x00
-};
-
-/* Illegal request, invalid command operation code */
-const struct SCSISense sense_code_INVALID_OPCODE = {
- .key = ILLEGAL_REQUEST, .asc = 0x20, .ascq = 0x00
-};
-
-/* Illegal request, LBA out of range */
-const struct SCSISense sense_code_LBA_OUT_OF_RANGE = {
- .key = ILLEGAL_REQUEST, .asc = 0x21, .ascq = 0x00
-};
-
-/* Illegal request, Invalid field in CDB */
-const struct SCSISense sense_code_INVALID_FIELD = {
- .key = ILLEGAL_REQUEST, .asc = 0x24, .ascq = 0x00
-};
-
-/* Illegal request, Invalid field in parameter list */
-const struct SCSISense sense_code_INVALID_PARAM = {
- .key = ILLEGAL_REQUEST, .asc = 0x26, .ascq = 0x00
-};
-
-/* Illegal request, Parameter list length error */
-const struct SCSISense sense_code_INVALID_PARAM_LEN = {
- .key = ILLEGAL_REQUEST, .asc = 0x1a, .ascq = 0x00
-};
-
-/* Illegal request, LUN not supported */
-const struct SCSISense sense_code_LUN_NOT_SUPPORTED = {
- .key = ILLEGAL_REQUEST, .asc = 0x25, .ascq = 0x00
-};
-
-/* Illegal request, Saving parameters not supported */
-const struct SCSISense sense_code_SAVING_PARAMS_NOT_SUPPORTED = {
- .key = ILLEGAL_REQUEST, .asc = 0x39, .ascq = 0x00
-};
-
-/* Illegal request, Incompatible medium installed */
-const struct SCSISense sense_code_INCOMPATIBLE_FORMAT = {
- .key = ILLEGAL_REQUEST, .asc = 0x30, .ascq = 0x00
-};
-
-/* Illegal request, medium removal prevented */
-const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
- .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
-};
-
-/* Illegal request, Invalid Transfer Tag */
-const struct SCSISense sense_code_INVALID_TAG = {
- .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01
-};
-
-/* Command aborted, I/O process terminated */
-const struct SCSISense sense_code_IO_ERROR = {
- .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06
-};
-
-/* Command aborted, I_T Nexus loss occurred */
-const struct SCSISense sense_code_I_T_NEXUS_LOSS = {
- .key = ABORTED_COMMAND, .asc = 0x29, .ascq = 0x07
-};
-
-/* Command aborted, Logical Unit failure */
-const struct SCSISense sense_code_LUN_FAILURE = {
- .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01
-};
-
-/* Command aborted, Overlapped Commands Attempted */
-const struct SCSISense sense_code_OVERLAPPED_COMMANDS = {
- .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00
-};
-
-/* Unit attention, Capacity data has changed */
-const struct SCSISense sense_code_CAPACITY_CHANGED = {
- .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09
-};
-
-/* Unit attention, Power on, reset or bus device reset occurred */
-const struct SCSISense sense_code_RESET = {
- .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x00
-};
-
-/* Unit attention, No medium */
-const struct SCSISense sense_code_UNIT_ATTENTION_NO_MEDIUM = {
- .key = UNIT_ATTENTION, .asc = 0x3a, .ascq = 0x00
-};
-
-/* Unit attention, Medium may have changed */
-const struct SCSISense sense_code_MEDIUM_CHANGED = {
- .key = UNIT_ATTENTION, .asc = 0x28, .ascq = 0x00
-};
-
-/* Unit attention, Reported LUNs data has changed */
-const struct SCSISense sense_code_REPORTED_LUNS_CHANGED = {
- .key = UNIT_ATTENTION, .asc = 0x3f, .ascq = 0x0e
-};
-
-/* Unit attention, Device internal reset */
-const struct SCSISense sense_code_DEVICE_INTERNAL_RESET = {
- .key = UNIT_ATTENTION, .asc = 0x29, .ascq = 0x04
-};
-
-/* Data Protection, Write Protected */
-const struct SCSISense sense_code_WRITE_PROTECTED = {
- .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x00
-};
-
-/* Data Protection, Space Allocation Failed Write Protect */
-const struct SCSISense sense_code_SPACE_ALLOC_FAILED = {
- .key = DATA_PROTECT, .asc = 0x27, .ascq = 0x07
-};
-
-/*
- * scsi_build_sense
- *
- * Convert between fixed and descriptor sense buffers
- */
-int scsi_build_sense(uint8_t *in_buf, int in_len,
- uint8_t *buf, int len, bool fixed)
-{
- bool fixed_in;
- SCSISense sense;
- if (!fixed && len < 8) {
- return 0;
- }
-
- if (in_len == 0) {
- sense.key = NO_SENSE;
- sense.asc = 0;
- sense.ascq = 0;
- } else {
- fixed_in = (in_buf[0] & 2) == 0;
-
- if (fixed == fixed_in) {
- memcpy(buf, in_buf, MIN(len, in_len));
- return MIN(len, in_len);
- }
-
- if (fixed_in) {
- sense.key = in_buf[2];
- sense.asc = in_buf[12];
- sense.ascq = in_buf[13];
- } else {
- sense.key = in_buf[1];
- sense.asc = in_buf[2];
- sense.ascq = in_buf[3];
- }
- }
-
- memset(buf, 0, len);
- if (fixed) {
- /* Return fixed format sense buffer */
- buf[0] = 0x70;
- buf[2] = sense.key;
- buf[7] = 10;
- buf[12] = sense.asc;
- buf[13] = sense.ascq;
- return MIN(len, SCSI_SENSE_LEN);
- } else {
- /* Return descriptor format sense buffer */
- buf[0] = 0x72;
- buf[1] = sense.key;
- buf[2] = sense.asc;
- buf[3] = sense.ascq;
- return 8;
- }
-}
-
-const char *scsi_command_name(uint8_t cmd)
-{
- static const char *names[] = {
- [ TEST_UNIT_READY ] = "TEST_UNIT_READY",
- [ REWIND ] = "REWIND",
- [ REQUEST_SENSE ] = "REQUEST_SENSE",
- [ FORMAT_UNIT ] = "FORMAT_UNIT",
- [ READ_BLOCK_LIMITS ] = "READ_BLOCK_LIMITS",
- [ REASSIGN_BLOCKS ] = "REASSIGN_BLOCKS/INITIALIZE ELEMENT STATUS",
- /* LOAD_UNLOAD and INITIALIZE_ELEMENT_STATUS use the same operation code */
- [ READ_6 ] = "READ_6",
- [ WRITE_6 ] = "WRITE_6",
- [ SET_CAPACITY ] = "SET_CAPACITY",
- [ READ_REVERSE ] = "READ_REVERSE",
- [ WRITE_FILEMARKS ] = "WRITE_FILEMARKS",
- [ SPACE ] = "SPACE",
- [ INQUIRY ] = "INQUIRY",
- [ RECOVER_BUFFERED_DATA ] = "RECOVER_BUFFERED_DATA",
- [ MAINTENANCE_IN ] = "MAINTENANCE_IN",
- [ MAINTENANCE_OUT ] = "MAINTENANCE_OUT",
- [ MODE_SELECT ] = "MODE_SELECT",
- [ RESERVE ] = "RESERVE",
- [ RELEASE ] = "RELEASE",
- [ COPY ] = "COPY",
- [ ERASE ] = "ERASE",
- [ MODE_SENSE ] = "MODE_SENSE",
- [ START_STOP ] = "START_STOP/LOAD_UNLOAD",
- /* LOAD_UNLOAD and START_STOP use the same operation code */
- [ RECEIVE_DIAGNOSTIC ] = "RECEIVE_DIAGNOSTIC",
- [ SEND_DIAGNOSTIC ] = "SEND_DIAGNOSTIC",
- [ ALLOW_MEDIUM_REMOVAL ] = "ALLOW_MEDIUM_REMOVAL",
- [ READ_CAPACITY_10 ] = "READ_CAPACITY_10",
- [ READ_10 ] = "READ_10",
- [ WRITE_10 ] = "WRITE_10",
- [ SEEK_10 ] = "SEEK_10/POSITION_TO_ELEMENT",
- /* SEEK_10 and POSITION_TO_ELEMENT use the same operation code */
- [ WRITE_VERIFY_10 ] = "WRITE_VERIFY_10",
- [ VERIFY_10 ] = "VERIFY_10",
- [ SEARCH_HIGH ] = "SEARCH_HIGH",
- [ SEARCH_EQUAL ] = "SEARCH_EQUAL",
- [ SEARCH_LOW ] = "SEARCH_LOW",
- [ SET_LIMITS ] = "SET_LIMITS",
- [ PRE_FETCH ] = "PRE_FETCH/READ_POSITION",
- /* READ_POSITION and PRE_FETCH use the same operation code */
- [ SYNCHRONIZE_CACHE ] = "SYNCHRONIZE_CACHE",
- [ LOCK_UNLOCK_CACHE ] = "LOCK_UNLOCK_CACHE",
- [ READ_DEFECT_DATA ] = "READ_DEFECT_DATA/INITIALIZE_ELEMENT_STATUS_WITH_RANGE",
- /* READ_DEFECT_DATA and INITIALIZE_ELEMENT_STATUS_WITH_RANGE use the same operation code */
- [ MEDIUM_SCAN ] = "MEDIUM_SCAN",
- [ COMPARE ] = "COMPARE",
- [ COPY_VERIFY ] = "COPY_VERIFY",
- [ WRITE_BUFFER ] = "WRITE_BUFFER",
- [ READ_BUFFER ] = "READ_BUFFER",
- [ UPDATE_BLOCK ] = "UPDATE_BLOCK",
- [ READ_LONG_10 ] = "READ_LONG_10",
- [ WRITE_LONG_10 ] = "WRITE_LONG_10",
- [ CHANGE_DEFINITION ] = "CHANGE_DEFINITION",
- [ WRITE_SAME_10 ] = "WRITE_SAME_10",
- [ UNMAP ] = "UNMAP",
- [ READ_TOC ] = "READ_TOC",
- [ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT",
- [ SANITIZE ] = "SANITIZE",
- [ GET_CONFIGURATION ] = "GET_CONFIGURATION",
- [ LOG_SELECT ] = "LOG_SELECT",
- [ LOG_SENSE ] = "LOG_SENSE",
- [ MODE_SELECT_10 ] = "MODE_SELECT_10",
- [ RESERVE_10 ] = "RESERVE_10",
- [ RELEASE_10 ] = "RELEASE_10",
- [ MODE_SENSE_10 ] = "MODE_SENSE_10",
- [ PERSISTENT_RESERVE_IN ] = "PERSISTENT_RESERVE_IN",
- [ PERSISTENT_RESERVE_OUT ] = "PERSISTENT_RESERVE_OUT",
- [ WRITE_FILEMARKS_16 ] = "WRITE_FILEMARKS_16",
- [ EXTENDED_COPY ] = "EXTENDED_COPY",
- [ ATA_PASSTHROUGH_16 ] = "ATA_PASSTHROUGH_16",
- [ ACCESS_CONTROL_IN ] = "ACCESS_CONTROL_IN",
- [ ACCESS_CONTROL_OUT ] = "ACCESS_CONTROL_OUT",
- [ READ_16 ] = "READ_16",
- [ COMPARE_AND_WRITE ] = "COMPARE_AND_WRITE",
- [ WRITE_16 ] = "WRITE_16",
- [ WRITE_VERIFY_16 ] = "WRITE_VERIFY_16",
- [ VERIFY_16 ] = "VERIFY_16",
- [ PRE_FETCH_16 ] = "PRE_FETCH_16",
- [ SYNCHRONIZE_CACHE_16 ] = "SPACE_16/SYNCHRONIZE_CACHE_16",
- /* SPACE_16 and SYNCHRONIZE_CACHE_16 use the same operation code */
- [ LOCATE_16 ] = "LOCATE_16",
- [ WRITE_SAME_16 ] = "ERASE_16/WRITE_SAME_16",
- /* ERASE_16 and WRITE_SAME_16 use the same operation code */
- [ SERVICE_ACTION_IN_16 ] = "SERVICE_ACTION_IN_16",
- [ WRITE_LONG_16 ] = "WRITE_LONG_16",
- [ REPORT_LUNS ] = "REPORT_LUNS",
- [ ATA_PASSTHROUGH_12 ] = "BLANK/ATA_PASSTHROUGH_12",
- [ MOVE_MEDIUM ] = "MOVE_MEDIUM",
- [ EXCHANGE_MEDIUM ] = "EXCHANGE MEDIUM",
- [ READ_12 ] = "READ_12",
- [ WRITE_12 ] = "WRITE_12",
- [ ERASE_12 ] = "ERASE_12/GET_PERFORMANCE",
- /* ERASE_12 and GET_PERFORMANCE use the same operation code */
- [ SERVICE_ACTION_IN_12 ] = "SERVICE_ACTION_IN_12",
- [ WRITE_VERIFY_12 ] = "WRITE_VERIFY_12",
- [ VERIFY_12 ] = "VERIFY_12",
- [ SEARCH_HIGH_12 ] = "SEARCH_HIGH_12",
- [ SEARCH_EQUAL_12 ] = "SEARCH_EQUAL_12",
- [ SEARCH_LOW_12 ] = "SEARCH_LOW_12",
- [ READ_ELEMENT_STATUS ] = "READ_ELEMENT_STATUS",
- [ SEND_VOLUME_TAG ] = "SEND_VOLUME_TAG/SET_STREAMING",
- /* SEND_VOLUME_TAG and SET_STREAMING use the same operation code */
- [ READ_CD ] = "READ_CD",
- [ READ_DEFECT_DATA_12 ] = "READ_DEFECT_DATA_12",
- [ READ_DVD_STRUCTURE ] = "READ_DVD_STRUCTURE",
- [ RESERVE_TRACK ] = "RESERVE_TRACK",
- [ SEND_CUE_SHEET ] = "SEND_CUE_SHEET",
- [ SEND_DVD_STRUCTURE ] = "SEND_DVD_STRUCTURE",
- [ SET_CD_SPEED ] = "SET_CD_SPEED",
- [ SET_READ_AHEAD ] = "SET_READ_AHEAD",
- [ ALLOW_OVERWRITE ] = "ALLOW_OVERWRITE",
- [ MECHANISM_STATUS ] = "MECHANISM_STATUS",
- [ GET_EVENT_STATUS_NOTIFICATION ] = "GET_EVENT_STATUS_NOTIFICATION",
- [ READ_DISC_INFORMATION ] = "READ_DISC_INFORMATION",
- };
-
- if (cmd >= ARRAY_SIZE(names) || names[cmd] == NULL)
- return "*UNKNOWN*";
- return names[cmd];
-}
-
SCSIRequest *scsi_req_ref(SCSIRequest *req)
{
assert(req->refcount > 0);
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index 5f1e5e8..6e841fb 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -32,7 +32,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
#include "sysemu/sysemu.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
@@ -106,7 +106,7 @@ typedef struct SCSIDiskState
bool tray_locked;
} SCSIDiskState;
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed);
+static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed);
static void scsi_free_request(SCSIRequest *req)
{
@@ -184,19 +184,10 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed)
return true;
}
- if (ret < 0) {
+ if (ret < 0 || (r->status && *r->status)) {
return scsi_handle_rw_error(r, -ret, acct_failed);
}
- if (r->status && *r->status) {
- if (acct_failed) {
- SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
- scsi_req_complete(&r->req, *r->status);
- return true;
- }
-
return false;
}
@@ -422,13 +413,13 @@ static void scsi_read_data(SCSIRequest *req)
}
/*
- * scsi_handle_rw_error has two return values. 0 means that the error
- * must be ignored, 1 means that the error has been processed and the
+ * scsi_handle_rw_error has two return values. False means that the error
+ * must be ignored, true means that the error has been processed and the
* caller should not do anything else for this request. Note that
* scsi_handle_rw_error always manages its reference counts, independent
* of the return value.
*/
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
+static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
{
bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
@@ -440,6 +431,11 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
}
switch (error) {
+ case 0:
+ /* The command has run, no need to fake sense. */
+ assert(r->status && *r->status);
+ scsi_req_complete(&r->req, *r->status);
+ break;
case ENOMEDIUM:
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
break;
@@ -457,6 +453,18 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed)
break;
}
}
+ if (!error) {
+ assert(r->status && *r->status);
+ error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
+
+ if (error == ECANCELED || error == EAGAIN || error == ENOTCONN ||
+ error == 0) {
+ /* These errors are handled by guest. */
+ scsi_req_complete(&r->req, *r->status);
+ return true;
+ }
+ }
+
blk_error_action(s->qdev.conf.blk, action, is_read, error);
if (action == BLOCK_ERROR_ACTION_STOP) {
scsi_req_retry(&r->req);
@@ -1978,8 +1986,8 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf)
break;
case REQUEST_SENSE:
/* Just return "NO SENSE". */
- buflen = scsi_build_sense(NULL, 0, outbuf, r->buflen,
- (req->cmd.buf[1] & 1) == 0);
+ buflen = scsi_convert_sense(NULL, 0, outbuf, r->buflen,
+ (req->cmd.buf[1] & 1) == 0);
if (buflen < 0) {
goto illegal_request;
}
@@ -2972,6 +2980,7 @@ static const TypeInfo scsi_cd_info = {
#ifdef __linux__
static Property scsi_block_properties[] = {
+ DEFINE_BLOCK_ERROR_PROPERTIES(SCSIDiskState, qdev.conf), \
DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.blk),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index 7e1cbab..bd0d9ff 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -34,15 +34,7 @@ do { printf("scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#include <scsi/sg.h>
-#include "block/scsi.h"
-
-#define SG_ERR_DRIVER_TIMEOUT 0x06
-#define SG_ERR_DRIVER_SENSE 0x08
-
-#define SG_ERR_DID_OK 0x00
-#define SG_ERR_DID_NO_CONNECT 0x01
-#define SG_ERR_DID_BUS_BUSY 0x02
-#define SG_ERR_DID_TIME_OUT 0x03
+#include "scsi/constants.h"
#ifndef MAX_UINT
#define MAX_UINT ((unsigned int)-1)
@@ -89,6 +81,7 @@ static void scsi_free_request(SCSIRequest *req)
static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
{
int status;
+ SCSISense sense;
assert(r->req.aiocb == NULL);
@@ -96,42 +89,15 @@ static void scsi_command_complete_noio(SCSIGenericReq *r, int ret)
scsi_req_cancel_complete(&r->req);
goto done;
}
- if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
- r->req.sense_len = r->io_header.sb_len_wr;
- }
-
- if (ret != 0) {
- switch (ret) {
- case -EDOM:
- status = TASK_SET_FULL;
- break;
- case -ENOMEM:
- status = CHECK_CONDITION;
- scsi_req_build_sense(&r->req, SENSE_CODE(TARGET_FAILURE));
- break;
- default:
- status = CHECK_CONDITION;
- scsi_req_build_sense(&r->req, SENSE_CODE(IO_ERROR));
- break;
- }
- } else {
- if (r->io_header.host_status == SG_ERR_DID_NO_CONNECT ||
- r->io_header.host_status == SG_ERR_DID_BUS_BUSY ||
- r->io_header.host_status == SG_ERR_DID_TIME_OUT ||
- (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT)) {
- status = BUSY;
- BADF("Driver Timeout\n");
- } else if (r->io_header.host_status) {
- status = CHECK_CONDITION;
- scsi_req_build_sense(&r->req, SENSE_CODE(I_T_NEXUS_LOSS));
- } else if (r->io_header.status) {
- status = r->io_header.status;
- } else if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
- status = CHECK_CONDITION;
+ status = sg_io_sense_from_errno(-ret, &r->io_header, &sense);
+ if (status == CHECK_CONDITION) {
+ if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE) {
+ r->req.sense_len = r->io_header.sb_len_wr;
} else {
- status = GOOD;
+ scsi_req_build_sense(&r->req, sense);
}
}
+
DPRINTF("Command complete 0x%p tag=0x%x status=%d\n",
r, r->req.tag, status);
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index 55ee48c..360db53 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -36,7 +36,7 @@
#include "cpu.h"
#include "hw/hw.h"
#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
#include "srp.h"
#include "hw/qdev.h"
#include "hw/ppc/spapr.h"
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 944ea4e..add4b3f 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -17,7 +17,7 @@
#include "qemu/error-report.h"
#include "sysemu/block-backend.h"
#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index eb63944..3aa9971 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -21,7 +21,7 @@
#include "qemu/iov.h"
#include "sysemu/block-backend.h"
#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/virtio/virtio-access.h"
@@ -867,10 +867,10 @@ void virtio_scsi_common_realize(DeviceState *dev,
s->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
s->cdb_size = VIRTIO_SCSI_CDB_DEFAULT_SIZE;
- s->ctrl_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, ctrl);
- s->event_vq = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, evt);
+ s->ctrl_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, ctrl);
+ s->event_vq = virtio_add_queue(vdev, s->conf.virtqueue_size, evt);
for (i = 0; i < s->conf.num_queues; i++) {
- s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, cmd);
+ s->cmd_vqs[i] = virtio_add_queue(vdev, s->conf.virtqueue_size, cmd);
}
}
@@ -917,6 +917,8 @@ static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp)
static Property virtio_scsi_properties[] = {
DEFINE_PROP_UINT32("num_queues", VirtIOSCSI, parent_obj.conf.num_queues, 1),
+ DEFINE_PROP_UINT32("virtqueue_size", VirtIOSCSI,
+ parent_obj.conf.virtqueue_size, 128),
DEFINE_PROP_UINT32("max_sectors", VirtIOSCSI, parent_obj.conf.max_sectors,
0xFFFF),
DEFINE_PROP_UINT32("cmd_per_lun", VirtIOSCSI, parent_obj.conf.cmd_per_lun,
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index 77d8b6f..6d3f0bf 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -28,7 +28,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/scsi/scsi.h"
-#include "block/scsi.h"
+#include "scsi/constants.h"
#include "hw/pci/msi.h"
#include "vmw_pvscsi.h"
#include "trace.h"