aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2021-03-02 15:17:45 +0000
committerPeter Maydell <peter.maydell@linaro.org>2021-03-02 15:17:45 +0000
commit07dbfdd290cea5d75d3e21948dc54fdb6f5174ac (patch)
tree0929d4483d347afc7082f0c6e4c9ddbaf8e59571 /hw
parentcbcf09872a936ccefef6a34298046d3b9aefc148 (diff)
parentc45b426acd1ad8e30fbe1b9af8c07b2889c28c6b (diff)
downloadqemu-07dbfdd290cea5d75d3e21948dc54fdb6f5174ac.zip
qemu-07dbfdd290cea5d75d3e21948dc54fdb6f5174ac.tar.gz
qemu-07dbfdd290cea5d75d3e21948dc54fdb6f5174ac.tar.bz2
Merge remote-tracking branch 'remotes/bonzini-gitlab/tags/for-upstream' into staging
* fix --enable-fuzzing linker failures (Alexander) * target/i386: Add bus lock debug exception support (Chenyi) * update documentation for preferred boolean option syntax (Daniel) * make SCSI io_timeout configurable (Hannes) * fix handling of guest recoverable SCSI errors (myself) * misc fixes (Pavel, Zheng Zhan Liang, Zihao) * fix installation of binaries with entitlements (Akihiko) # gpg: Signature made Thu 25 Feb 2021 14:41:56 GMT # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] # 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-gitlab/tags/for-upstream: (29 commits) tcg/i386: rdpmc: fix the the condtions chardev: do not use short form boolean options in non-QemuOpts character device descriptions vl: deprecate -writeconfig target/i386: Add bus lock debug exception support qom/object.c: Fix typo target/i386: update to show preferred boolean syntax for -cpu docs: update to show preferred boolean syntax for -cpu docs: update to show preferred boolean syntax for -vnc docs: update to show preferred boolean syntax for -chardev qemu-options: update to show preferred boolean syntax for -vnc qemu-options: update to show preferred boolean syntax for -incoming qemu-options: update to show preferred boolean syntax for -netdev qemu-options: update to show preferred boolean syntax for -spice qemu-options: update to show preferred boolean syntax for -chardev gdbstub: use preferred boolean option syntax char: don't fail when client is not connected scsi: drop 'result' argument from command_complete callback scsi-disk: pass guest recoverable errors through even for rerror=stop scsi-disk: pass SCSI status to scsi_handle_rw_error scsi: introduce scsi_sense_from_errno() ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/scsi/esp-pci.c5
-rw-r--r--hw/scsi/esp.c7
-rw-r--r--hw/scsi/lsi53c895a.c6
-rw-r--r--hw/scsi/megasas.c6
-rw-r--r--hw/scsi/mptsas.c5
-rw-r--r--hw/scsi/scsi-bus.c2
-rw-r--r--hw/scsi/scsi-disk.c172
-rw-r--r--hw/scsi/scsi-generic.c28
-rw-r--r--hw/scsi/spapr_vscsi.c12
-rw-r--r--hw/scsi/trace-events4
-rw-r--r--hw/scsi/virtio-scsi-dataplane.c24
-rw-r--r--hw/scsi/virtio-scsi.c5
-rw-r--r--hw/scsi/vmw_pvscsi.c4
-rw-r--r--hw/usb/dev-storage.c6
-rw-r--r--hw/usb/dev-uas.c7
15 files changed, 151 insertions, 142 deletions
diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
index 2ce96dc..4d7c2ca 100644
--- a/hw/scsi/esp-pci.c
+++ b/hw/scsi/esp-pci.c
@@ -329,13 +329,12 @@ static const VMStateDescription vmstate_esp_pci_scsi = {
}
};
-static void esp_pci_command_complete(SCSIRequest *req, uint32_t status,
- size_t resid)
+static void esp_pci_command_complete(SCSIRequest *req, size_t resid)
{
ESPState *s = req->hba_private;
PCIESPState *pci = container_of(s, PCIESPState, esp);
- esp_command_complete(req, status, resid);
+ esp_command_complete(req, resid);
pci->dma_regs[DMA_WBC] = 0;
pci->dma_regs[DMA_STAT] |= DMA_STAT_DONE;
}
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index b84e0fe..93d9c9c 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -485,8 +485,7 @@ static void esp_report_command_complete(ESPState *s, uint32_t status)
}
}
-void esp_command_complete(SCSIRequest *req, uint32_t status,
- size_t resid)
+void esp_command_complete(SCSIRequest *req, size_t resid)
{
ESPState *s = req->hba_private;
@@ -495,11 +494,11 @@ void esp_command_complete(SCSIRequest *req, uint32_t status,
* interrupt has been handled.
*/
trace_esp_command_complete_deferred();
- s->deferred_status = status;
+ s->deferred_status = req->status;
s->deferred_complete = true;
return;
}
- esp_report_command_complete(s, status);
+ esp_report_command_complete(s, req->status);
}
void esp_transfer_data(SCSIRequest *req, uint32_t len)
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index 7d13c7d..a4e58580 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -787,14 +787,14 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len)
}
/* Callback to indicate that the SCSI layer has completed a command. */
-static void lsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
+static void lsi_command_complete(SCSIRequest *req, size_t resid)
{
LSIState *s = LSI53C895A(req->bus->qbus.parent);
int out;
out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
- trace_lsi_command_complete(status);
- s->status = status;
+ trace_lsi_command_complete(req->status);
+ s->status = req->status;
s->command_complete = 2;
if (s->waiting && s->dbc != 0) {
/* Raise phase mismatch for short transfers. */
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 5bfc92f..8f2389d 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -1852,13 +1852,12 @@ static void megasas_xfer_complete(SCSIRequest *req, uint32_t len)
}
}
-static void megasas_command_complete(SCSIRequest *req, uint32_t status,
- size_t resid)
+static void megasas_command_complete(SCSIRequest *req, size_t resid)
{
MegasasCmd *cmd = req->hba_private;
uint8_t cmd_status = MFI_STAT_OK;
- trace_megasas_command_complete(cmd->index, status, resid);
+ trace_megasas_command_complete(cmd->index, req->status, resid);
if (req->io_canceled) {
return;
@@ -1873,7 +1872,6 @@ static void megasas_command_complete(SCSIRequest *req, uint32_t status,
return;
}
} else {
- req->status = status;
trace_megasas_scsi_complete(cmd->index, req->status,
cmd->iov_size, req->cmd.xfer);
if (req->status != GOOD) {
diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c
index f866165..7416e78 100644
--- a/hw/scsi/mptsas.c
+++ b/hw/scsi/mptsas.c
@@ -1133,7 +1133,7 @@ static QEMUSGList *mptsas_get_sg_list(SCSIRequest *sreq)
}
static void mptsas_command_complete(SCSIRequest *sreq,
- uint32_t status, size_t resid)
+ size_t resid)
{
MPTSASRequest *req = sreq->hba_private;
MPTSASState *s = req->dev;
@@ -1143,7 +1143,8 @@ static void mptsas_command_complete(SCSIRequest *sreq,
hwaddr sense_buffer_addr = req->dev->sense_buffer_high_addr |
req->scsi_io.SenseBufferLowAddr;
- trace_mptsas_command_complete(s, req->scsi_io.MsgContext, status, resid);
+ trace_mptsas_command_complete(s, req->scsi_io.MsgContext,
+ sreq->status, resid);
sense_len = scsi_req_get_sense(sreq, sense_buf, SCSI_SENSE_BUF_SIZE);
if (sense_len > 0) {
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index c349fb7..dc4141e 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -1483,7 +1483,7 @@ void scsi_req_complete(SCSIRequest *req, int status)
scsi_req_ref(req);
scsi_req_dequeue(req);
- req->bus->info->complete(req, req->status, req->resid);
+ req->bus->info->complete(req, req->resid);
/* Cancelled requests might end up being completed instead of cancelled */
notifier_list_notify(&req->cancel_notifiers, req);
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index ed52fcd..a5a58d7 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -111,8 +111,6 @@ struct SCSIDiskState {
uint16_t rotation_rate;
};
-static bool scsi_handle_rw_error(SCSIDiskReq *r, int error, bool acct_failed);
-
static void scsi_free_request(SCSIRequest *req)
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
@@ -182,6 +180,78 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req)
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
}
+/*
+ * 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 bool scsi_handle_rw_error(SCSIDiskReq *r, int ret, bool acct_failed)
+{
+ bool is_read = (r->req.cmd.mode == SCSI_XFER_FROM_DEV);
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
+ SCSISense sense = SENSE_CODE(NO_SENSE);
+ int error = 0;
+ bool req_has_sense = false;
+ BlockErrorAction action;
+ int status;
+
+ if (ret < 0) {
+ status = scsi_sense_from_errno(-ret, &sense);
+ error = -ret;
+ } else {
+ /* A passthrough command has completed with nonzero status. */
+ status = ret;
+ if (status == CHECK_CONDITION) {
+ req_has_sense = true;
+ error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
+ } else {
+ error = EINVAL;
+ }
+ }
+
+ /*
+ * Check whether the error has to be handled by the guest or should
+ * rather follow the rerror=/werror= settings. Guest-handled errors
+ * are usually retried immediately, so do not post them to QMP and
+ * do not account them as failed I/O.
+ */
+ if (req_has_sense &&
+ scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) {
+ action = BLOCK_ERROR_ACTION_REPORT;
+ acct_failed = false;
+ } else {
+ action = blk_get_error_action(s->qdev.conf.blk, is_read, error);
+ blk_error_action(s->qdev.conf.blk, action, is_read, error);
+ }
+
+ switch (action) {
+ case BLOCK_ERROR_ACTION_REPORT:
+ if (acct_failed) {
+ block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
+ }
+ if (req_has_sense) {
+ sdc->update_sense(&r->req);
+ } else if (status == CHECK_CONDITION) {
+ scsi_req_build_sense(&r->req, sense);
+ }
+ scsi_req_complete(&r->req, status);
+ return true;
+
+ case BLOCK_ERROR_ACTION_IGNORE:
+ return false;
+
+ case BLOCK_ERROR_ACTION_STOP:
+ scsi_req_retry(&r->req);
+ return true;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed)
{
if (r->req.io_canceled) {
@@ -189,8 +259,10 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed)
return true;
}
- if (ret < 0 || (r->status && *r->status)) {
- return scsi_handle_rw_error(r, -ret, acct_failed);
+ if (ret < 0) {
+ return scsi_handle_rw_error(r, ret, acct_failed);
+ } else if (r->status && *r->status) {
+ return scsi_handle_rw_error(r, *r->status, acct_failed);
}
return false;
@@ -428,89 +500,6 @@ static void scsi_read_data(SCSIRequest *req)
}
}
-/*
- * 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 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);
- SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s));
- BlockErrorAction action = blk_get_error_action(s->qdev.conf.blk,
- is_read, error);
-
- if (action == BLOCK_ERROR_ACTION_REPORT) {
- if (acct_failed) {
- block_acct_failed(blk_get_stats(s->qdev.conf.blk), &r->acct);
- }
- switch (error) {
- case 0:
- /* A passthrough command has run and has produced sense data; check
- * whether the error has to be handled by the guest or should rather
- * pause the host.
- */
- assert(r->status && *r->status);
- if (scsi_sense_buf_is_guest_recoverable(r->req.sense, sizeof(r->req.sense))) {
- /* These errors are handled by guest. */
- sdc->update_sense(&r->req);
- scsi_req_complete(&r->req, *r->status);
- return true;
- }
- error = scsi_sense_buf_to_errno(r->req.sense, sizeof(r->req.sense));
- break;
-#ifdef CONFIG_LINUX
- /* These errno mapping are specific to Linux. For more information:
- * - scsi_decide_disposition in drivers/scsi/scsi_error.c
- * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c
- * - blk_errors[] in block/blk-core.c
- */
- case EBADE:
- /* DID_NEXUS_FAILURE -> BLK_STS_NEXUS. */
- scsi_req_complete(&r->req, RESERVATION_CONFLICT);
- break;
- case ENODATA:
- /* DID_MEDIUM_ERROR -> BLK_STS_MEDIUM. */
- scsi_check_condition(r, SENSE_CODE(READ_ERROR));
- break;
- case EREMOTEIO:
- /* DID_TARGET_FAILURE -> BLK_STS_TARGET. */
- scsi_req_complete(&r->req, HARDWARE_ERROR);
- break;
-#endif
- case ENOMEDIUM:
- scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
- break;
- case ENOMEM:
- scsi_check_condition(r, SENSE_CODE(TARGET_FAILURE));
- break;
- case EINVAL:
- scsi_check_condition(r, SENSE_CODE(INVALID_FIELD));
- break;
- case ENOSPC:
- scsi_check_condition(r, SENSE_CODE(SPACE_ALLOC_FAILED));
- break;
- default:
- scsi_check_condition(r, SENSE_CODE(IO_ERROR));
- break;
- }
- }
-
- blk_error_action(s->qdev.conf.blk, action, is_read, error);
- if (action == BLOCK_ERROR_ACTION_IGNORE) {
- scsi_req_complete(&r->req, 0);
- return true;
- }
-
- if (action == BLOCK_ERROR_ACTION_STOP) {
- scsi_req_retry(&r->req);
- }
- return true;
-}
-
static void scsi_write_complete_noio(SCSIDiskReq *r, int ret)
{
uint32_t n;
@@ -2624,7 +2613,7 @@ static int get_device_type(SCSIDiskState *s)
cmd[4] = sizeof(buf);
ret = scsi_SG_IO_FROM_DEV(s->qdev.conf.blk, cmd, sizeof(cmd),
- buf, sizeof(buf));
+ buf, sizeof(buf), s->qdev.io_timeout);
if (ret < 0) {
return -1;
}
@@ -2785,10 +2774,11 @@ static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req,
/* The rest is as in scsi-generic.c. */
io_header->mx_sb_len = sizeof(r->req.sense);
io_header->sbp = r->req.sense;
- io_header->timeout = UINT_MAX;
+ io_header->timeout = s->qdev.io_timeout * 1000;
io_header->usr_ptr = r;
io_header->flags |= SG_FLAG_DIRECT_IO;
-
+ trace_scsi_disk_aio_sgio_command(r->req.tag, req->cdb[0], lba,
+ nb_logical_blocks, io_header->timeout);
aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, cb, opaque);
assert(aiocb != NULL);
return aiocb;
@@ -3103,6 +3093,8 @@ static Property scsi_block_properties[] = {
DEFAULT_MAX_IO_SIZE),
DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version,
-1),
+ DEFINE_PROP_UINT32("io_timeout", SCSIDiskState, qdev.io_timeout,
+ DEFAULT_IO_TIMEOUT),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c
index ab22014..cf7e11c 100644
--- a/hw/scsi/scsi-generic.c
+++ b/hw/scsi/scsi-generic.c
@@ -115,6 +115,8 @@ static int execute_command(BlockBackend *blk,
SCSIGenericReq *r, int direction,
BlockCompletionFunc *complete)
{
+ SCSIDevice *s = r->req.dev;
+
r->io_header.interface_id = 'S';
r->io_header.dxfer_direction = direction;
r->io_header.dxferp = r->buf;
@@ -123,10 +125,12 @@ static int execute_command(BlockBackend *blk,
r->io_header.cmd_len = r->req.cmd.len;
r->io_header.mx_sb_len = sizeof(r->req.sense);
r->io_header.sbp = r->req.sense;
- r->io_header.timeout = MAX_UINT;
+ r->io_header.timeout = s->io_timeout * 1000;
r->io_header.usr_ptr = r;
r->io_header.flags |= SG_FLAG_DIRECT_IO;
+ trace_scsi_generic_aio_sgio_command(r->req.tag, r->req.cmd.buf[0],
+ r->io_header.timeout);
r->req.aiocb = blk_aio_ioctl(blk, SG_IO, &r->io_header, complete, r);
if (r->req.aiocb == NULL) {
return -EIO;
@@ -506,7 +510,7 @@ static int read_naa_id(const uint8_t *p, uint64_t *p_wwn)
}
int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size,
- uint8_t *buf, uint8_t buf_size)
+ uint8_t *buf, uint8_t buf_size, uint32_t timeout)
{
sg_io_hdr_t io_header;
uint8_t sensebuf[8];
@@ -521,10 +525,14 @@ int scsi_SG_IO_FROM_DEV(BlockBackend *blk, uint8_t *cmd, uint8_t cmd_size,
io_header.cmd_len = cmd_size;
io_header.mx_sb_len = sizeof(sensebuf);
io_header.sbp = sensebuf;
- io_header.timeout = 6000; /* XXX */
+ io_header.timeout = timeout * 1000;
+ trace_scsi_generic_ioctl_sgio_command(cmd[0], io_header.timeout);
ret = blk_ioctl(blk, SG_IO, &io_header);
- if (ret < 0 || io_header.driver_status || io_header.host_status) {
+ if (ret < 0 || io_header.status ||
+ io_header.driver_status || io_header.host_status) {
+ trace_scsi_generic_ioctl_sgio_done(cmd[0], ret, io_header.status,
+ io_header.host_status);
return -1;
}
return 0;
@@ -551,7 +559,7 @@ static void scsi_generic_set_vpd_bl_emulation(SCSIDevice *s)
cmd[4] = sizeof(buf);
ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd),
- buf, sizeof(buf));
+ buf, sizeof(buf), s->io_timeout);
if (ret < 0) {
/*
* Do not assume anything if we can't retrieve the
@@ -587,7 +595,7 @@ static void scsi_generic_read_device_identification(SCSIDevice *s)
cmd[4] = sizeof(buf);
ret = scsi_SG_IO_FROM_DEV(s->conf.blk, cmd, sizeof(cmd),
- buf, sizeof(buf));
+ buf, sizeof(buf), s->io_timeout);
if (ret < 0) {
return;
}
@@ -638,7 +646,7 @@ static int get_stream_blocksize(BlockBackend *blk)
cmd[0] = MODE_SENSE;
cmd[4] = sizeof(buf);
- ret = scsi_SG_IO_FROM_DEV(blk, cmd, sizeof(cmd), buf, sizeof(buf));
+ ret = scsi_SG_IO_FROM_DEV(blk, cmd, sizeof(cmd), buf, sizeof(buf), 6);
if (ret < 0) {
return -1;
}
@@ -665,7 +673,8 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp)
return;
}
- if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC) {
+ if (blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
+ blk_get_on_error(s->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
error_setg(errp, "Device doesn't support drive option werror");
return;
}
@@ -728,6 +737,7 @@ static void scsi_generic_realize(SCSIDevice *s, Error **errp)
/* Only used by scsi-block, but initialize it nevertheless to be clean. */
s->default_scsi_version = -1;
+ s->io_timeout = DEFAULT_IO_TIMEOUT;
scsi_generic_read_device_inquiry(s);
}
@@ -751,6 +761,8 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
static Property scsi_generic_properties[] = {
DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.blk),
DEFINE_PROP_BOOL("share-rw", SCSIDevice, conf.share_rw, false),
+ DEFINE_PROP_UINT32("io_timeout", SCSIDevice, io_timeout,
+ DEFAULT_IO_TIMEOUT),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index 4aa0224..ca5c13c 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -551,19 +551,19 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
}
/* Callback to indicate that the SCSI layer has completed a transfer. */
-static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t resid)
+static void vscsi_command_complete(SCSIRequest *sreq, size_t resid)
{
VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent);
vscsi_req *req = sreq->hba_private;
int32_t res_in = 0, res_out = 0;
- trace_spapr_vscsi_command_complete(sreq->tag, status, req);
+ trace_spapr_vscsi_command_complete(sreq->tag, sreq->status, req);
if (req == NULL) {
fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
return;
}
- if (status == CHECK_CONDITION) {
+ if (sreq->status == CHECK_CONDITION) {
req->senselen = scsi_req_get_sense(req->sreq, req->sense,
sizeof(req->sense));
trace_spapr_vscsi_command_complete_sense_data1(req->senselen,
@@ -574,8 +574,8 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t re
req->sense[12], req->sense[13], req->sense[14], req->sense[15]);
}
- trace_spapr_vscsi_command_complete_status(status);
- if (status == 0) {
+ trace_spapr_vscsi_command_complete_status(sreq->status);
+ if (sreq->status == 0) {
/* We handle overflows, not underflows for normal commands,
* but hopefully nobody cares
*/
@@ -585,7 +585,7 @@ static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t re
res_in = req->data_len;
}
}
- vscsi_send_rsp(s, req, status, res_in, res_out);
+ vscsi_send_rsp(s, req, sreq->status, res_in, res_out);
vscsi_put_req(req);
}
diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events
index 0e0aa98..9788661 100644
--- a/hw/scsi/trace-events
+++ b/hw/scsi/trace-events
@@ -331,6 +331,7 @@ scsi_disk_emulate_command_UNKNOWN(int cmd, const char *name) "Unknown SCSI comma
scsi_disk_dma_command_READ(uint64_t lba, uint32_t len) "Read (sector %" PRId64 ", count %u)"
scsi_disk_dma_command_WRITE(const char *cmd, uint64_t lba, int len) "Write %s(sector %" PRId64 ", count %u)"
scsi_disk_new_request(uint32_t lun, uint32_t tag, const char *line) "Command: lun=%d tag=0x%x data=%s"
+scsi_disk_aio_sgio_command(uint32_t tag, uint8_t cmd, uint64_t lba, int len, uint32_t timeout) "disk aio sgio: tag=0x%x cmd=0x%x (sector %" PRId64 ", count %d) timeout=%u"
# scsi-generic.c
scsi_generic_command_complete_noio(void *req, uint32_t tag, int statuc) "Command complete %p tag=0x%x status=%d"
@@ -342,3 +343,6 @@ scsi_generic_write_data(uint32_t tag) "scsi_write_data tag=0x%x"
scsi_generic_send_command(const char *line) "Command: data=%s"
scsi_generic_realize_type(int type) "device type %d"
scsi_generic_realize_blocksize(int blocksize) "block size %d"
+scsi_generic_aio_sgio_command(uint32_t tag, uint8_t cmd, uint32_t timeout) "generic aio sgio: tag=0x%x cmd=0x%x timeout=%u"
+scsi_generic_ioctl_sgio_command(uint8_t cmd, uint32_t timeout) "generic ioctl sgio: cmd=0x%x timeout=%u"
+scsi_generic_ioctl_sgio_done(uint8_t cmd, int ret, uint8_t status, uint8_t host_status) "generic ioctl sgio: cmd=0x%x ret=%d status=0x%x host_status=0x%x"
diff --git a/hw/scsi/virtio-scsi-dataplane.c b/hw/scsi/virtio-scsi-dataplane.c
index 2c83a0a..4ad8793 100644
--- a/hw/scsi/virtio-scsi-dataplane.c
+++ b/hw/scsi/virtio-scsi-dataplane.c
@@ -52,12 +52,14 @@ void virtio_scsi_dataplane_setup(VirtIOSCSI *s, Error **errp)
static bool virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev,
VirtQueue *vq)
{
- bool progress;
+ bool progress = false;
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
virtio_scsi_acquire(s);
- assert(s->ctx && s->dataplane_started);
- progress = virtio_scsi_handle_cmd_vq(s, vq);
+ if (!s->dataplane_fenced) {
+ assert(s->ctx && s->dataplane_started);
+ progress = virtio_scsi_handle_cmd_vq(s, vq);
+ }
virtio_scsi_release(s);
return progress;
}
@@ -65,12 +67,14 @@ static bool virtio_scsi_data_plane_handle_cmd(VirtIODevice *vdev,
static bool virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev,
VirtQueue *vq)
{
- bool progress;
+ bool progress = false;
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
virtio_scsi_acquire(s);
- assert(s->ctx && s->dataplane_started);
- progress = virtio_scsi_handle_ctrl_vq(s, vq);
+ if (!s->dataplane_fenced) {
+ assert(s->ctx && s->dataplane_started);
+ progress = virtio_scsi_handle_ctrl_vq(s, vq);
+ }
virtio_scsi_release(s);
return progress;
}
@@ -78,12 +82,14 @@ static bool virtio_scsi_data_plane_handle_ctrl(VirtIODevice *vdev,
static bool virtio_scsi_data_plane_handle_event(VirtIODevice *vdev,
VirtQueue *vq)
{
- bool progress;
+ bool progress = false;
VirtIOSCSI *s = VIRTIO_SCSI(vdev);
virtio_scsi_acquire(s);
- assert(s->ctx && s->dataplane_started);
- progress = virtio_scsi_handle_event_vq(s, vq);
+ if (!s->dataplane_fenced) {
+ assert(s->ctx && s->dataplane_started);
+ progress = virtio_scsi_handle_event_vq(s, vq);
+ }
virtio_scsi_release(s);
return progress;
}
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 99ff261..358c0e7 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -500,8 +500,7 @@ static void virtio_scsi_complete_cmd_req(VirtIOSCSIReq *req)
virtio_scsi_complete_req(req);
}
-static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
- size_t resid)
+static void virtio_scsi_command_complete(SCSIRequest *r, size_t resid)
{
VirtIOSCSIReq *req = r->hba_private;
uint8_t sense[SCSI_SENSE_BUF_SIZE];
@@ -513,7 +512,7 @@ static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status,
}
req->resp.cmd.response = VIRTIO_SCSI_S_OK;
- req->resp.cmd.status = status;
+ req->resp.cmd.status = r->status;
if (req->resp.cmd.status == GOOD) {
req->resp.cmd.resid = virtio_tswap32(vdev, resid);
} else {
diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c
index a63d25d..0da378e 100644
--- a/hw/scsi/vmw_pvscsi.c
+++ b/hw/scsi/vmw_pvscsi.c
@@ -511,7 +511,7 @@ pvscsi_write_sense(PVSCSIRequest *r, uint8_t *sense, int len)
}
static void
-pvscsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
+pvscsi_command_complete(SCSIRequest *req, size_t resid)
{
PVSCSIRequest *pvscsi_req = req->hba_private;
PVSCSIState *s;
@@ -528,7 +528,7 @@ pvscsi_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
pvscsi_req->cmp.hostStatus = BTSTAT_DATARUN;
}
- pvscsi_req->cmp.scsiStatus = status;
+ pvscsi_req->cmp.scsiStatus = req->status;
if (pvscsi_req->cmp.scsiStatus == CHECK_CONDITION) {
uint8_t sense[SCSI_SENSE_BUF_SIZE];
int sense_len =
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index c49e8b8..a5f76fc 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -277,17 +277,17 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
}
}
-static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t resid)
+static void usb_msd_command_complete(SCSIRequest *req, size_t resid)
{
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet;
- trace_usb_msd_cmd_complete(status, req->tag);
+ trace_usb_msd_cmd_complete(req->status, req->tag);
s->csw.sig = cpu_to_le32(0x53425355);
s->csw.tag = cpu_to_le32(req->tag);
s->csw.residue = cpu_to_le32(s->data_len);
- s->csw.status = status != 0;
+ s->csw.status = req->status != 0;
if (s->packet) {
if (s->data_len == 0 && s->mode == USB_MSDM_DATAOUT) {
diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c
index a51402b..d2bd85d 100644
--- a/hw/usb/dev-uas.c
+++ b/hw/usb/dev-uas.c
@@ -598,17 +598,16 @@ static void usb_uas_scsi_transfer_data(SCSIRequest *r, uint32_t len)
}
}
-static void usb_uas_scsi_command_complete(SCSIRequest *r,
- uint32_t status, size_t resid)
+static void usb_uas_scsi_command_complete(SCSIRequest *r, size_t resid)
{
UASRequest *req = r->hba_private;
- trace_usb_uas_scsi_complete(req->uas->dev.addr, req->tag, status, resid);
+ trace_usb_uas_scsi_complete(req->uas->dev.addr, req->tag, r->status, resid);
req->complete = true;
if (req->data) {
usb_uas_complete_data_packet(req);
}
- usb_uas_queue_sense(req, status);
+ usb_uas_queue_sense(req, r->status);
scsi_req_unref(req->req);
}