* [Qemu-devel] [PATCH 54/55] scsi: push request restart to SCSIDevice
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
The request restart mechanism is generic and could be reused for
scsi-generic. In the meanwhile, pushing it to SCSIDevice avoids
that scsi_dma_restart_bh looks at SCSIGenericReqs when working on
a scsi-block device.
The code is the same that is already in hw/scsi-disk.c, with
the type flags replaced by req->cmd.mode and a more generic way to
requeue SCSI_XFER_NONE commands.
I also added a missing call to qemu_del_vm_change_state_handler.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-bus.c | 56 +++++++++++++++++++++++++++++++++++++++++
hw/scsi-disk.c | 76 +++++--------------------------------------------------
hw/scsi.h | 5 +++
3 files changed, 68 insertions(+), 69 deletions(-)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index dfce5fb..e6ebbd5 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -8,6 +8,7 @@
static char *scsibus_get_fw_dev_path(DeviceState *dev);
static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf);
+static void scsi_req_dequeue(SCSIRequest *req);
static int scsi_build_sense(uint8_t *in_buf, int in_len,
uint8_t *buf, int len, bool fixed);
@@ -33,6 +34,53 @@ void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info)
bus->qbus.allow_hotplug = 1;
}
+static void scsi_dma_restart_bh(void *opaque)
+{
+ SCSIDevice *s = opaque;
+ SCSIRequest *req, *next;
+
+ qemu_bh_delete(s->bh);
+ s->bh = NULL;
+
+ QTAILQ_FOREACH_SAFE(req, &s->requests, next, next) {
+ scsi_req_ref(req);
+ if (req->retry) {
+ req->retry = false;
+ switch (req->cmd.mode) {
+ case SCSI_XFER_FROM_DEV:
+ case SCSI_XFER_TO_DEV:
+ scsi_req_continue(req);
+ break;
+ case SCSI_XFER_NONE:
+ scsi_req_dequeue(req);
+ scsi_req_enqueue(req);
+ break;
+ }
+ }
+ scsi_req_unref(req);
+ }
+}
+
+void scsi_req_retry(SCSIRequest *req)
+{
+ /* No need to save a reference, because scsi_dma_restart_bh just
+ * looks at the request list. */
+ req->retry = true;
+}
+
+static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
+{
+ SCSIDevice *s = opaque;
+
+ if (!running) {
+ return;
+ }
+ if (!s->bh) {
+ s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
+ qemu_bh_schedule(s->bh);
+ }
+}
+
static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
{
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
@@ -83,6 +131,10 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
dev->info = info;
QTAILQ_INIT(&dev->requests);
rc = dev->info->init(dev);
+ if (rc == 0) {
+ dev->vmsentry = qemu_add_vm_change_state_handler(scsi_dma_restart_cb,
+ dev);
+ }
err:
return rc;
@@ -92,6 +144,9 @@ static int scsi_qdev_exit(DeviceState *qdev)
{
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+ if (dev->vmsentry) {
+ qemu_del_vm_change_state_handler(dev->vmsentry);
+ }
if (dev->info->destroy) {
dev->info->destroy(dev);
}
@@ -586,6 +641,7 @@ int32_t scsi_req_enqueue(SCSIRequest *req)
static void scsi_req_dequeue(SCSIRequest *req)
{
trace_scsi_req_dequeue(req->dev->id, req->lun, req->tag);
+ req->retry = false;
if (req->enqueued) {
QTAILQ_REMOVE(&req->dev->requests, req, next);
req->enqueued = false;
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index bb07737..352d41f 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -42,12 +42,6 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
#define SCSI_DMA_BUF_SIZE 131072
#define SCSI_MAX_INQUIRY_LEN 256
-#define SCSI_REQ_STATUS_RETRY 0x01
-#define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06
-#define SCSI_REQ_STATUS_RETRY_READ 0x00
-#define SCSI_REQ_STATUS_RETRY_WRITE 0x02
-#define SCSI_REQ_STATUS_RETRY_FLUSH 0x04
-
typedef struct SCSIDiskState SCSIDiskState;
typedef struct SCSIDiskReq {
@@ -58,7 +52,6 @@ typedef struct SCSIDiskReq {
uint32_t buflen;
struct iovec iov;
QEMUIOVector qiov;
- uint32_t status;
BlockAcctCookie acct;
} SCSIDiskReq;
@@ -75,8 +68,7 @@ struct SCSIDiskState
bool tray_locked;
};
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
-static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf);
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error);
static void scsi_free_request(SCSIRequest *req)
{
@@ -102,7 +94,6 @@ static void scsi_cancel_io(SCSIRequest *req)
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
DPRINTF("Cancel tag=0x%x\n", req->tag);
- r->status &= ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
if (r->req.aiocb) {
bdrv_aio_cancel(r->req.aiocb);
@@ -139,7 +130,7 @@ static void scsi_read_complete(void * opaque, int ret)
}
if (ret) {
- if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
+ if (scsi_handle_rw_error(r, -ret)) {
goto done;
}
}
@@ -168,7 +159,7 @@ static void scsi_flush_complete(void * opaque, int ret)
}
if (ret < 0) {
- if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
+ if (scsi_handle_rw_error(r, -ret)) {
goto done;
}
}
@@ -233,9 +224,9 @@ static void scsi_read_data(SCSIRequest *req)
* scsi_handle_rw_error always manages its reference counts, independent
* of the return value.
*/
-static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
+static int scsi_handle_rw_error(SCSIDiskReq *r, int error)
{
- int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
+ int is_read = (r->req.cmd.xfer == SCSI_XFER_FROM_DEV);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
BlockErrorAction action = bdrv_get_on_error(s->qdev.conf.bs, is_read);
@@ -247,17 +238,10 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
|| action == BLOCK_ERR_STOP_ANY) {
- type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
- r->status |= SCSI_REQ_STATUS_RETRY | type;
-
bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_STOP, is_read);
vm_stop(RUN_STATE_IO_ERROR);
bdrv_iostatus_set_err(s->qdev.conf.bs, error);
-
- /* No need to save a reference, because scsi_dma_restart_bh just
- * looks at the request list. If a request is canceled, the
- * retry request is just dropped.
- */
+ scsi_req_retry(&r->req);
} else {
switch (error) {
case ENOMEDIUM:
@@ -290,7 +274,7 @@ static void scsi_write_complete(void * opaque, int ret)
}
if (ret) {
- if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
+ if (scsi_handle_rw_error(r, -ret)) {
goto done;
}
}
@@ -347,51 +331,6 @@ static void scsi_write_data(SCSIRequest *req)
}
}
-static void scsi_dma_restart_bh(void *opaque)
-{
- SCSIDiskState *s = opaque;
- SCSIRequest *req;
- SCSIDiskReq *r;
-
- qemu_bh_delete(s->bh);
- s->bh = NULL;
-
- QTAILQ_FOREACH(req, &s->qdev.requests, next) {
- r = DO_UPCAST(SCSIDiskReq, req, req);
- if (r->status & SCSI_REQ_STATUS_RETRY) {
- int status = r->status;
-
- r->status &=
- ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
-
- switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) {
- case SCSI_REQ_STATUS_RETRY_READ:
- scsi_read_data(&r->req);
- break;
- case SCSI_REQ_STATUS_RETRY_WRITE:
- scsi_write_data(&r->req);
- break;
- case SCSI_REQ_STATUS_RETRY_FLUSH:
- scsi_send_command(&r->req, r->req.cmd.buf);
- break;
- }
- }
- }
-}
-
-static void scsi_dma_restart_cb(void *opaque, int running, RunState state)
-{
- SCSIDiskState *s = opaque;
-
- if (!running) {
- return;
- }
- if (!s->bh) {
- s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
- qemu_bh_schedule(s->bh);
- }
-}
-
/* Return a pointer to the data buffer. */
static uint8_t *scsi_get_buf(SCSIRequest *req)
{
@@ -1591,7 +1530,6 @@ static int scsi_initfn(SCSIDevice *dev)
}
bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
- qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
bdrv_iostatus_enable(s->qdev.conf.bs);
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
return 0;
diff --git a/hw/scsi.h b/hw/scsi.h
index fcc3455..ff8fdd0 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -3,6 +3,7 @@
#include "qdev.h"
#include "block.h"
+#include "sysemu.h"
#define MAX_SCSI_DEVS 255
@@ -52,6 +53,7 @@ struct SCSIRequest {
uint32_t sense_len;
bool enqueued;
bool io_canceled;
+ bool retry;
void *hba_private;
QTAILQ_ENTRY(SCSIRequest) next;
};
@@ -59,6 +61,8 @@ struct SCSIRequest {
struct SCSIDevice
{
DeviceState qdev;
+ VMChangeStateEntry *vmsentry;
+ QEMUBH *bh;
uint32_t id;
BlockConf conf;
SCSIDeviceInfo *info;
@@ -194,6 +198,7 @@ uint8_t *scsi_req_get_buf(SCSIRequest *req);
int scsi_req_get_sense(SCSIRequest *req, uint8_t *buf, int len);
void scsi_req_abort(SCSIRequest *req, int status);
void scsi_req_cancel(SCSIRequest *req);
+void scsi_req_retry(SCSIRequest *req);
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 53/55] scsi-generic: bump SCSIRequest reference count until aio completion runs
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Same as before, but for scsi-generic.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-generic.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 2f95f2d..9594cc1 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -113,6 +113,9 @@ static void scsi_command_complete(void *opaque, int ret)
r, r->req.tag, status);
scsi_req_complete(&r->req, status);
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
}
/* Cancel a pending data transfer. */
@@ -123,6 +126,11 @@ static void scsi_cancel_io(SCSIRequest *req)
DPRINTF("Cancel tag=0x%x\n", req->tag);
if (r->req.aiocb) {
bdrv_aio_cancel(r->req.aiocb);
+
+ /* This reference was left in by scsi_*_data. We take ownership of
+ * it independent of whether bdrv_aio_cancel completes the request
+ * or not. */
+ scsi_req_unref(&r->req);
}
r->req.aiocb = NULL;
}
@@ -183,6 +191,9 @@ static void scsi_read_complete(void * opaque, int ret)
bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
scsi_req_data(&r->req, len);
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
}
}
@@ -194,6 +205,9 @@ static void scsi_read_data(SCSIRequest *req)
int ret;
DPRINTF("scsi_read_data 0x%x\n", req->tag);
+
+ /* The request is used as the AIO opaque value, so add a ref. */
+ scsi_req_ref(&r->req);
if (r->len == -1) {
scsi_command_complete(r, 0);
return;
@@ -242,6 +256,8 @@ static void scsi_write_data(SCSIRequest *req)
return;
}
+ /* The request is used as the AIO opaque value, so add a ref. */
+ scsi_req_ref(&r->req);
ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
if (ret < 0) {
scsi_command_complete(r, ret);
@@ -285,6 +301,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
g_free(r->buf);
r->buflen = 0;
r->buf = NULL;
+ /* The request is used as the AIO opaque value, so add a ref. */
+ scsi_req_ref(&r->req);
ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
if (ret < 0) {
scsi_command_complete(r, ret);
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 48/55] scsi: make reqops const
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Also delete a stale occurrence of SCSIReqOps inside SCSIDeviceInfo.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-bus.c | 10 +++++-----
hw/scsi-disk.c | 2 +-
hw/scsi-generic.c | 2 +-
hw/scsi.h | 7 +++----
4 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index bdd6e94..1f38ac8 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -160,7 +160,7 @@ static int32_t scsi_invalid_command(SCSIRequest *req, uint8_t *buf)
return 0;
}
-struct SCSIReqOps reqops_invalid_opcode = {
+static const struct SCSIReqOps reqops_invalid_opcode = {
.size = sizeof(SCSIRequest),
.send_command = scsi_invalid_command
};
@@ -178,7 +178,7 @@ static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf)
return 0;
}
-struct SCSIReqOps reqops_unit_attention = {
+static const struct SCSIReqOps reqops_unit_attention = {
.size = sizeof(SCSIRequest),
.send_command = scsi_unit_attention
};
@@ -386,7 +386,7 @@ static uint8_t *scsi_target_get_buf(SCSIRequest *req)
return r->buf;
}
-struct SCSIReqOps reqops_target_command = {
+static const struct SCSIReqOps reqops_target_command = {
.size = sizeof(SCSITargetReq),
.send_command = scsi_target_send_command,
.read_data = scsi_target_read_data,
@@ -394,8 +394,8 @@ struct SCSIReqOps reqops_target_command = {
};
-SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag,
- uint32_t lun, void *hba_private)
+SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+ uint32_t tag, uint32_t lun, void *hba_private)
{
SCSIRequest *req;
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 74990a8..77673f2 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1588,7 +1588,7 @@ static int scsi_disk_initfn(SCSIDevice *dev)
}
}
-static SCSIReqOps scsi_disk_reqops = {
+static const SCSIReqOps scsi_disk_reqops = {
.size = sizeof(SCSIDiskReq),
.free_req = scsi_free_request,
.send_command = scsi_send_command,
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index fcf23cd..a5e77cb 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -420,7 +420,7 @@ static int scsi_generic_initfn(SCSIDevice *s)
return 0;
}
-static SCSIReqOps scsi_generic_req_ops = {
+static const SCSIReqOps scsi_generic_req_ops = {
.size = sizeof(SCSIGenericReq),
.free_req = scsi_free_request,
.send_command = scsi_send_command,
diff --git a/hw/scsi.h b/hw/scsi.h
index d56e875..af558c3 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -41,7 +41,7 @@ struct SCSICommand {
struct SCSIRequest {
SCSIBus *bus;
SCSIDevice *dev;
- SCSIReqOps *ops;
+ const SCSIReqOps *ops;
uint32_t refcount;
uint32_t tag;
uint32_t lun;
@@ -96,7 +96,6 @@ struct SCSIDeviceInfo {
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
void *hba_private);
void (*unit_attention_reported)(SCSIDevice *s);
- SCSIReqOps reqops;
};
struct SCSIBusInfo {
@@ -176,8 +175,8 @@ extern const struct SCSISense sense_code_DEVICE_INTERNAL_RESET;
int scsi_sense_valid(SCSISense sense);
-SCSIRequest *scsi_req_alloc(SCSIReqOps *reqops, SCSIDevice *d, uint32_t tag,
- uint32_t lun, void *hba_private);
+SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
+ uint32_t tag, uint32_t lun, void *hba_private);
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
uint8_t *buf, void *hba_private);
int32_t scsi_req_enqueue(SCSIRequest *req);
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 51/55] scsi: do not call transfer_data after canceling a request
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Otherwise, if cancellation is "faked" by the AIO layer and goes
through qemu_aio_flush, the whole request is completed synchronously
during scsi_req_cancel.
Using the enqueued flag would work here, but not in the next patches,
so I'm introducing a new io_canceled flag. That's because scsi_req_data
is a synchronous callback and the enqueued flag might be reset by the
time it returns. scsi-disk cannot unref the request until after calling
scsi_req_data.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-bus.c | 23 +++++++++++++++++++----
hw/scsi.h | 1 +
trace-events | 1 +
3 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 3cf571e..dfce5fb 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1107,8 +1107,12 @@ void scsi_req_continue(SCSIRequest *req)
Once it completes, calling scsi_req_continue will restart I/O. */
void scsi_req_data(SCSIRequest *req, int len)
{
- trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
- req->bus->info->transfer_data(req, len);
+ if (req->io_canceled) {
+ trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len);
+ } else {
+ trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
+ req->bus->info->transfer_data(req, len);
+ }
}
void scsi_req_print(SCSIRequest *req)
@@ -1173,11 +1177,15 @@ void scsi_req_complete(SCSIRequest *req, int status)
void scsi_req_cancel(SCSIRequest *req)
{
- if (req->ops->cancel_io) {
- req->ops->cancel_io(req);
+ if (!req->enqueued) {
+ return;
}
scsi_req_ref(req);
scsi_req_dequeue(req);
+ req->io_canceled = true;
+ if (req->ops->cancel_io) {
+ req->ops->cancel_io(req);
+ }
if (req->bus->info->cancel) {
req->bus->info->cancel(req);
}
@@ -1186,10 +1194,17 @@ void scsi_req_cancel(SCSIRequest *req)
void scsi_req_abort(SCSIRequest *req, int status)
{
+ if (!req->enqueued) {
+ return;
+ }
+ scsi_req_ref(req);
+ scsi_req_dequeue(req);
+ req->io_canceled = true;
if (req->ops->cancel_io) {
req->ops->cancel_io(req);
}
scsi_req_complete(req, status);
+ scsi_req_unref(req);
}
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
diff --git a/hw/scsi.h b/hw/scsi.h
index 8ea744a..fcc3455 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -51,6 +51,7 @@ struct SCSIRequest {
uint8_t sense[SCSI_SENSE_BUF_SIZE];
uint32_t sense_len;
bool enqueued;
+ bool io_canceled;
void *hba_private;
QTAILQ_ENTRY(SCSIRequest) next;
};
diff --git a/trace-events b/trace-events
index a888055..56443af 100644
--- a/trace-events
+++ b/trace-events
@@ -278,6 +278,7 @@ usb_host_claim_port(int bus, int hub, int port) "bus %d, hub addr %d, port %d"
# hw/scsi-bus.c
scsi_req_alloc(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_data(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
+scsi_req_data_canceled(int target, int lun, int tag, int len) "target %d lun %d tag %d len %d"
scsi_req_dequeue(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_continue(int target, int lun, int tag) "target %d lun %d tag %d"
scsi_req_parsed(int target, int lun, int tag, int cmd, int mode, int xfer) "target %d lun %d tag %d command %d dir %d length %d"
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 52/55] scsi-disk: bump SCSIRequest reference count until aio completion runs
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
In some cases a request may be canceled before the completion callback
runs. Keep a reference to the request between starting an AIO operation
and the corresponding scsi_req_cancel or scsi_*_complete.
When a request has to be retried, the request can be dropped because
scsi_dma_restart_bh only looks at requests that are enqueued. As such,
they always have at least a reference.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-disk.c | 48 +++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 415f81d..bb07737 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -102,8 +102,14 @@ static void scsi_cancel_io(SCSIRequest *req)
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
DPRINTF("Cancel tag=0x%x\n", req->tag);
+ r->status &= ~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
if (r->req.aiocb) {
bdrv_aio_cancel(r->req.aiocb);
+
+ /* This reference was left in by scsi_*_data. We take ownership of
+ * it the moment scsi_req_cancel is called, independent of whether
+ * bdrv_aio_cancel completes the request or not. */
+ scsi_req_unref(&r->req);
}
r->req.aiocb = NULL;
}
@@ -134,7 +140,7 @@ static void scsi_read_complete(void * opaque, int ret)
if (ret) {
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_READ)) {
- return;
+ goto done;
}
}
@@ -144,6 +150,11 @@ static void scsi_read_complete(void * opaque, int ret)
r->sector += n;
r->sector_count -= n;
scsi_req_data(&r->req, r->qiov.size);
+
+done:
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
}
static void scsi_flush_complete(void * opaque, int ret)
@@ -158,11 +169,16 @@ static void scsi_flush_complete(void * opaque, int ret)
if (ret < 0) {
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_FLUSH)) {
- return;
+ goto done;
}
}
scsi_req_complete(&r->req, GOOD);
+
+done:
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
}
/* Read more data from scsi device into buffer. */
@@ -188,6 +204,8 @@ static void scsi_read_data(SCSIRequest *req)
/* No data transfer may already be in progress */
assert(r->req.aiocb == NULL);
+ /* The request is used as the AIO opaque value, so add a ref. */
+ scsi_req_ref(&r->req);
if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
DPRINTF("Data transfer direction invalid\n");
scsi_read_complete(r, -EINVAL);
@@ -196,7 +214,9 @@ static void scsi_read_data(SCSIRequest *req)
if (s->tray_open) {
scsi_read_complete(r, -ENOMEDIUM);
+ return;
}
+
n = scsi_init_iovec(r);
bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
@@ -206,6 +226,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
+ * 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, int type)
{
int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
@@ -226,6 +253,11 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_STOP, is_read);
vm_stop(RUN_STATE_IO_ERROR);
bdrv_iostatus_set_err(s->qdev.conf.bs, error);
+
+ /* No need to save a reference, because scsi_dma_restart_bh just
+ * looks at the request list. If a request is canceled, the
+ * retry request is just dropped.
+ */
} else {
switch (error) {
case ENOMEDIUM:
@@ -259,7 +291,7 @@ static void scsi_write_complete(void * opaque, int ret)
if (ret) {
if (scsi_handle_rw_error(r, -ret, SCSI_REQ_STATUS_RETRY_WRITE)) {
- return;
+ goto done;
}
}
@@ -273,6 +305,11 @@ static void scsi_write_complete(void * opaque, int ret)
DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
scsi_req_data(&r->req, r->qiov.size);
}
+
+done:
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
}
static void scsi_write_data(SCSIRequest *req)
@@ -284,6 +321,8 @@ static void scsi_write_data(SCSIRequest *req)
/* No data transfer may already be in progress */
assert(r->req.aiocb == NULL);
+ /* The request is used as the AIO opaque value, so add a ref. */
+ scsi_req_ref(&r->req);
if (r->req.cmd.mode != SCSI_XFER_TO_DEV) {
DPRINTF("Data transfer direction invalid\n");
scsi_write_complete(r, -EINVAL);
@@ -294,6 +333,7 @@ static void scsi_write_data(SCSIRequest *req)
if (n) {
if (s->tray_open) {
scsi_write_complete(r, -ENOMEDIUM);
+ return;
}
bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n,
@@ -1332,6 +1372,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
r->iov.iov_len = rc;
break;
case SYNCHRONIZE_CACHE:
+ /* The request is used as the AIO opaque value, so add a ref. */
+ scsi_req_ref(&r->req);
bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_flush_complete, r);
if (r->req.aiocb == NULL) {
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 49/55] scsi: export scsi_generic_reqops
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-generic.c | 2 +-
hw/scsi.h | 3 +++
2 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index a5e77cb..32f50cd 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -420,7 +420,7 @@ static int scsi_generic_initfn(SCSIDevice *s)
return 0;
}
-static const SCSIReqOps scsi_generic_req_ops = {
+const SCSIReqOps scsi_generic_req_ops = {
.size = sizeof(SCSIGenericReq),
.free_req = scsi_free_request,
.send_command = scsi_send_command,
diff --git a/hw/scsi.h b/hw/scsi.h
index af558c3..01c6655 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -197,4 +197,7 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
+/* scsi-generic.c. */
+extern const SCSIReqOps scsi_generic_req_ops;
+
#endif
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 50/55] scsi: pass cdb to alloc_req
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
This will let scsi-block choose between passthrough and emulation.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-bus.c | 2 +-
hw/scsi-disk.c | 4 ++--
hw/scsi-generic.c | 2 +-
hw/scsi.h | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 1f38ac8..3cf571e 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -451,7 +451,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
req = scsi_req_alloc(&reqops_target_command, d, tag, lun,
hba_private);
} else {
- req = d->info->alloc_req(d, tag, lun, hba_private);
+ req = d->info->alloc_req(d, tag, lun, buf, hba_private);
}
}
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 77673f2..415f81d 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1598,8 +1598,8 @@ static const SCSIReqOps scsi_disk_reqops = {
.get_buf = scsi_get_buf,
};
-static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
- uint32_t lun, void *hba_private)
+static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
+ uint8_t *buf, void *hba_private)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIRequest *req;
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 32f50cd..2f95f2d 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -431,7 +431,7 @@ const SCSIReqOps scsi_generic_req_ops = {
};
static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
- void *hba_private)
+ uint8_t *buf, void *hba_private)
{
SCSIRequest *req;
diff --git a/hw/scsi.h b/hw/scsi.h
index 01c6655..8ea744a 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -94,7 +94,7 @@ struct SCSIDeviceInfo {
scsi_qdev_initfn init;
void (*destroy)(SCSIDevice *s);
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
- void *hba_private);
+ uint8_t *buf, void *hba_private);
void (*unit_attention_reported)(SCSIDevice *s);
};
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 47/55] scsi: move max_lba to SCSIDevice
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
The field is only in scsi-disk for now. Moving it up to SCSIDevice makes
it easier to reuse the scsi-generic reqops elsewhere.
At the same time, make scsi-generic get max_lba from snooped READ CAPACITY
commands as well.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-disk.c | 15 +++++++--------
hw/scsi-generic.c | 2 ++
hw/scsi.h | 1 +
3 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index af1001d..74990a8 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -66,7 +66,6 @@ struct SCSIDiskState
{
SCSIDevice qdev;
uint32_t removable;
- uint64_t max_lba;
bool media_changed;
bool media_event;
QEMUBH *bh;
@@ -1175,7 +1174,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
/* Returned value is the address of the last sector. */
nb_sectors--;
/* Remember the new size for read/write sanity checking. */
- s->max_lba = nb_sectors;
+ s->qdev.max_lba = nb_sectors;
/* Clip to 2TB, instead of returning capacity modulo 2TB. */
if (nb_sectors > UINT32_MAX) {
nb_sectors = UINT32_MAX;
@@ -1230,7 +1229,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
/* Returned value is the address of the last sector. */
nb_sectors--;
/* Remember the new size for read/write sanity checking. */
- s->max_lba = nb_sectors;
+ s->qdev.max_lba = nb_sectors;
outbuf[0] = (nb_sectors >> 56) & 0xff;
outbuf[1] = (nb_sectors >> 48) & 0xff;
outbuf[2] = (nb_sectors >> 40) & 0xff;
@@ -1345,7 +1344,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
case READ_16:
len = r->req.cmd.xfer / s->qdev.blocksize;
DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len);
- if (r->req.cmd.lba > s->max_lba) {
+ if (r->req.cmd.lba > s->qdev.max_lba) {
goto illegal_lba;
}
r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
@@ -1362,7 +1361,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
(command & 0xe) == 0xe ? "And Verify " : "",
r->req.cmd.lba, len);
- if (r->req.cmd.lba > s->max_lba) {
+ if (r->req.cmd.lba > s->qdev.max_lba) {
goto illegal_lba;
}
r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
@@ -1388,7 +1387,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
case SEEK_10:
DPRINTF("Seek(%d) (sector %" PRId64 ")\n", command == SEEK_6 ? 6 : 10,
r->req.cmd.lba);
- if (r->req.cmd.lba > s->max_lba) {
+ if (r->req.cmd.lba > s->qdev.max_lba) {
goto illegal_lba;
}
break;
@@ -1398,7 +1397,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
r->req.cmd.lba, len);
- if (r->req.cmd.lba > s->max_lba) {
+ if (r->req.cmd.lba > s->qdev.max_lba) {
goto illegal_lba;
}
@@ -1457,7 +1456,7 @@ static void scsi_disk_reset(DeviceState *dev)
if (nb_sectors) {
nb_sectors--;
}
- s->max_lba = nb_sectors;
+ s->qdev.max_lba = nb_sectors;
}
static void scsi_destroy(SCSIDevice *dev)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 4d7ad82..fcf23cd 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -174,9 +174,11 @@ static void scsi_read_complete(void * opaque, int ret)
/* Snoop READ CAPACITY output to set the blocksize. */
if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
s->blocksize = ldl_be_p(&r->buf[4]);
+ s->max_lba = ldl_be_p(&r->buf[0]);
} else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
(r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
s->blocksize = ldl_be_p(&r->buf[8]);
+ s->max_lba = ldq_be_p(&r->buf[0]);
}
bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
diff --git a/hw/scsi.h b/hw/scsi.h
index c8649cf..d56e875 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -70,6 +70,7 @@ struct SCSIDevice
uint32_t lun;
int blocksize;
int type;
+ uint64_t max_lba;
};
/* cdrom.c */
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 46/55] scsi-disk: small clean up to INQUIRY
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Set s->removable, s->qdev.blocksize and s->qdev.type in the callers
of scsi_initfn.
With this in place, s->qdev.type is allowed, and we can just reuse it
as the first byte in VPD data (just like we do in standard INQUIRY data).
Also set s->removable is set consistently and we can use it.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-disk.c | 46 +++++++++++++++++++++-------------------------
1 files changed, 21 insertions(+), 25 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index f89e6c5..af1001d 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -381,11 +381,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
return -1;
}
- if (s->qdev.type == TYPE_ROM) {
- outbuf[buflen++] = 5;
- } else {
- outbuf[buflen++] = 0;
- }
+ outbuf[buflen++] = s->qdev.type & 0x1f;
outbuf[buflen++] = page_code ; // this page
outbuf[buflen++] = 0x00;
@@ -529,11 +525,10 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
memset(outbuf, 0, buflen);
outbuf[0] = s->qdev.type & 0x1f;
+ outbuf[1] = s->removable ? 0x80 : 0;
if (s->qdev.type == TYPE_ROM) {
- outbuf[1] = 0x80;
memcpy(&outbuf[16], "QEMU CD-ROM ", 16);
} else {
- outbuf[1] = s->removable ? 0x80 : 0;
memcpy(&outbuf[16], "QEMU HARDDISK ", 16);
}
memcpy(&outbuf[8], "QEMU ", 8);
@@ -1518,7 +1513,7 @@ static void scsi_disk_unit_attention_reported(SCSIDevice *dev)
}
}
-static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
+static int scsi_initfn(SCSIDevice *dev)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
DriveInfo *dinfo;
@@ -1528,7 +1523,7 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
return -1;
}
- if (scsi_type == TYPE_DISK && !bdrv_is_inserted(s->qdev.conf.bs)) {
+ if (!s->removable && !bdrv_is_inserted(s->qdev.conf.bs)) {
error_report("Device needs media, but drive is empty");
return -1;
}
@@ -1550,18 +1545,11 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
return -1;
}
- if (scsi_type == TYPE_ROM) {
+ if (s->removable) {
bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_cd_block_ops, s);
- s->qdev.blocksize = 2048;
- } else if (scsi_type == TYPE_DISK) {
- s->qdev.blocksize = s->qdev.conf.logical_block_size;
- } else {
- error_report("scsi-disk: Unhandled SCSI type %02x", scsi_type);
- return -1;
}
bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
- s->qdev.type = scsi_type;
qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
bdrv_iostatus_enable(s->qdev.conf.bs);
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
@@ -1570,27 +1558,35 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
static int scsi_hd_initfn(SCSIDevice *dev)
{
- return scsi_initfn(dev, TYPE_DISK);
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+ s->qdev.blocksize = s->qdev.conf.logical_block_size;
+ s->qdev.type = TYPE_DISK;
+ return scsi_initfn(&s->qdev);
}
static int scsi_cd_initfn(SCSIDevice *dev)
{
- return scsi_initfn(dev, TYPE_ROM);
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+ s->qdev.blocksize = 2048;
+ s->qdev.type = TYPE_ROM;
+ s->removable = true;
+ return scsi_initfn(&s->qdev);
}
static int scsi_disk_initfn(SCSIDevice *dev)
{
DriveInfo *dinfo;
- uint8_t scsi_type;
if (!dev->conf.bs) {
- scsi_type = TYPE_DISK; /* will die in scsi_initfn() */
- } else {
- dinfo = drive_get_by_blockdev(dev->conf.bs);
- scsi_type = dinfo->media_cd ? TYPE_ROM : TYPE_DISK;
+ return scsi_initfn(dev); /* ... and die there */
}
- return scsi_initfn(dev, scsi_type);
+ dinfo = drive_get_by_blockdev(dev->conf.bs);
+ if (dinfo->media_cd) {
+ return scsi_cd_initfn(dev);
+ } else {
+ return scsi_hd_initfn(dev);
+ }
}
static SCSIReqOps scsi_disk_reqops = {
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 44/55] scsi-disk: do not duplicate BlockDriverState member
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Same as for scsi-generic, avoid duplication even if it causes longer
lines.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-disk.c | 92 +++++++++++++++++++++++++++----------------------------
1 files changed, 45 insertions(+), 47 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index e800ab3..8a05031 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -65,7 +65,6 @@ typedef struct SCSIDiskReq {
struct SCSIDiskState
{
SCSIDevice qdev;
- BlockDriverState *bs;
/* The qemu block layer uses a fixed 512 byte sector size.
This is the number of 512 byte blocks in a single scsi sector. */
int cluster_size;
@@ -119,7 +118,7 @@ static uint32_t scsi_init_iovec(SCSIDiskReq *r)
if (!r->iov.iov_base) {
r->buflen = SCSI_DMA_BUF_SIZE;
- r->iov.iov_base = qemu_blockalign(s->bs, r->buflen);
+ r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
}
r->iov.iov_len = MIN(r->sector_count * 512, r->buflen);
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
@@ -134,7 +133,7 @@ static void scsi_read_complete(void * opaque, int ret)
if (r->req.aiocb != NULL) {
r->req.aiocb = NULL;
- bdrv_acct_done(s->bs, &r->acct);
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
if (ret) {
@@ -158,7 +157,7 @@ static void scsi_flush_complete(void * opaque, int ret)
if (r->req.aiocb != NULL) {
r->req.aiocb = NULL;
- bdrv_acct_done(s->bs, &r->acct);
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
if (ret < 0) {
@@ -203,8 +202,8 @@ static void scsi_read_data(SCSIRequest *req)
scsi_read_complete(r, -ENOMEDIUM);
}
n = scsi_init_iovec(r);
- bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- r->req.aiocb = bdrv_aio_readv(s->bs, r->sector, &r->qiov, n,
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
scsi_read_complete, r);
if (r->req.aiocb == NULL) {
scsi_read_complete(r, -EIO);
@@ -215,10 +214,10 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
{
int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- BlockErrorAction action = bdrv_get_on_error(s->bs, is_read);
+ BlockErrorAction action = bdrv_get_on_error(s->qdev.conf.bs, is_read);
if (action == BLOCK_ERR_IGNORE) {
- bdrv_mon_event(s->bs, BDRV_ACTION_IGNORE, is_read);
+ bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_IGNORE, is_read);
return 0;
}
@@ -228,9 +227,9 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
type &= SCSI_REQ_STATUS_RETRY_TYPE_MASK;
r->status |= SCSI_REQ_STATUS_RETRY | type;
- bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read);
+ bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_STOP, is_read);
vm_stop(RUN_STATE_IO_ERROR);
- bdrv_iostatus_set_err(s->bs, error);
+ bdrv_iostatus_set_err(s->qdev.conf.bs, error);
} else {
switch (error) {
case ENOMEDIUM:
@@ -246,7 +245,7 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
scsi_check_condition(r, SENSE_CODE(IO_ERROR));
break;
}
- bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read);
+ bdrv_mon_event(s->qdev.conf.bs, BDRV_ACTION_REPORT, is_read);
}
return 1;
}
@@ -259,7 +258,7 @@ static void scsi_write_complete(void * opaque, int ret)
if (r->req.aiocb != NULL) {
r->req.aiocb = NULL;
- bdrv_acct_done(s->bs, &r->acct);
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
if (ret) {
@@ -300,8 +299,8 @@ static void scsi_write_data(SCSIRequest *req)
if (s->tray_open) {
scsi_write_complete(r, -ENOMEDIUM);
}
- bdrv_acct_start(s->bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
- r->req.aiocb = bdrv_aio_writev(s->bs, r->sector, &r->qiov, n,
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE);
+ r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n,
scsi_write_complete, r);
if (r->req.aiocb == NULL) {
scsi_write_complete(r, -ENOMEM);
@@ -440,7 +439,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
case 0x83: /* Device identification page, mandatory */
{
int max_len = 255 - 8;
- int id_len = strlen(bdrv_get_device_name(s->bs));
+ int id_len = strlen(bdrv_get_device_name(s->qdev.conf.bs));
if (id_len > max_len) {
id_len = max_len;
@@ -454,7 +453,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
outbuf[buflen++] = 0; // reserved
outbuf[buflen++] = id_len; // length of data following
- memcpy(outbuf+buflen, bdrv_get_device_name(s->bs), id_len);
+ memcpy(outbuf+buflen, bdrv_get_device_name(s->qdev.conf.bs), id_len);
buflen += id_len;
break;
}
@@ -571,10 +570,10 @@ static inline bool media_is_dvd(SCSIDiskState *s)
if (s->qdev.type != TYPE_ROM) {
return false;
}
- if (!bdrv_is_inserted(s->bs)) {
+ if (!bdrv_is_inserted(s->qdev.conf.bs)) {
return false;
}
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
return nb_sectors > CD_MAX_SECTORS;
}
@@ -584,10 +583,10 @@ static inline bool media_is_cd(SCSIDiskState *s)
if (s->qdev.type != TYPE_ROM) {
return false;
}
- if (!bdrv_is_inserted(s->bs)) {
+ if (!bdrv_is_inserted(s->qdev.conf.bs)) {
return false;
}
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
return nb_sectors <= CD_MAX_SECTORS;
}
@@ -615,7 +614,7 @@ static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
}
if (format != 0xff) {
- if (s->tray_open || !bdrv_is_inserted(s->bs)) {
+ if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
return -1;
}
@@ -637,7 +636,7 @@ static int scsi_read_dvd_structure(SCSIDiskState *s, SCSIDiskReq *r,
if (layer != 0) {
goto fail;
}
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
outbuf[4] = 1; /* DVD-ROM, part version 1 */
outbuf[5] = 0xf; /* 120mm disc, minimum rate unspecified */
@@ -692,7 +691,7 @@ static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
media_status = 0;
if (s->tray_open) {
media_status = MS_TRAY_OPEN;
- } else if (bdrv_is_inserted(s->bs)) {
+ } else if (bdrv_is_inserted(s->qdev.conf.bs)) {
media_status = MS_MEDIA_PRESENT;
}
@@ -795,7 +794,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
[MODE_PAGE_CAPABILITIES] = (1 << TYPE_ROM),
};
- BlockDriverState *bdrv = s->bs;
+ BlockDriverState *bdrv = s->qdev.conf.bs;
int cylinders, heads, secs;
uint8_t *p = *p_outbuf;
@@ -887,7 +886,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
if (page_control == 1) { /* Changeable Values */
break;
}
- if (bdrv_enable_write_cache(s->bs)) {
+ if (bdrv_enable_write_cache(s->qdev.conf.bs)) {
p[2] = 4; /* WCE */
}
break;
@@ -959,7 +958,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
memset(outbuf, 0, r->req.cmd.xfer);
p = outbuf;
- if (bdrv_is_read_only(s->bs)) {
+ if (bdrv_is_read_only(s->qdev.conf.bs)) {
dev_specific_param = 0x80; /* Readonly. */
} else {
dev_specific_param = 0x00;
@@ -977,7 +976,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
p += 8;
}
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
if (!dbd && nb_sectors) {
if (r->req.cmd.buf[0] == MODE_SENSE) {
outbuf[3] = 8; /* Block descriptor length */
@@ -1043,7 +1042,7 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
msf = req->cmd.buf[1] & 2;
format = req->cmd.buf[2] & 0xf;
start_track = req->cmd.buf[6];
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
nb_sectors /= s->cluster_size;
switch (format) {
@@ -1080,12 +1079,12 @@ static int scsi_disk_emulate_start_stop(SCSIDiskReq *r)
if (s->qdev.type == TYPE_ROM && loej) {
if (!start && !s->tray_open && s->tray_locked) {
scsi_check_condition(r,
- bdrv_is_inserted(s->bs)
+ bdrv_is_inserted(s->qdev.conf.bs)
? SENSE_CODE(ILLEGAL_REQ_REMOVAL_PREVENTED)
: SENSE_CODE(NOT_READY_REMOVAL_PREVENTED));
return -1;
}
- bdrv_eject(s->bs, !start);
+ bdrv_eject(s->qdev.conf.bs, !start);
s->tray_open = !start;
}
return 0;
@@ -1112,13 +1111,13 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
goto illegal_request;
}
r->buflen = MAX(4096, req->cmd.xfer);
- r->iov.iov_base = qemu_blockalign(s->bs, r->buflen);
+ r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen);
}
outbuf = r->iov.iov_base;
switch (req->cmd.buf[0]) {
case TEST_UNIT_READY:
- if (s->tray_open || !bdrv_is_inserted(s->bs)) {
+ if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
goto not_ready;
}
break;
@@ -1168,12 +1167,12 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
break;
case ALLOW_MEDIUM_REMOVAL:
s->tray_locked = req->cmd.buf[4] & 1;
- bdrv_lock_medium(s->bs, req->cmd.buf[4] & 1);
+ bdrv_lock_medium(s->qdev.conf.bs, req->cmd.buf[4] & 1);
break;
case READ_CAPACITY_10:
/* The normal LEN field for this command is zero. */
memset(outbuf, 0, 8);
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
if (!nb_sectors) {
goto not_ready;
}
@@ -1228,7 +1227,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
if ((req->cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
DPRINTF("SAI READ CAPACITY(16)\n");
memset(outbuf, 0, req->cmd.xfer);
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
if (!nb_sectors) {
goto not_ready;
}
@@ -1275,7 +1274,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
return buflen;
not_ready:
- if (s->tray_open || !bdrv_is_inserted(s->bs)) {
+ if (s->tray_open || !bdrv_is_inserted(s->qdev.conf.bs)) {
scsi_check_condition(r, SENSE_CODE(NO_MEDIUM));
} else {
scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY));
@@ -1342,8 +1341,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
r->iov.iov_len = rc;
break;
case SYNCHRONIZE_CACHE:
- bdrv_acct_start(s->bs, &r->acct, 0, BDRV_ACCT_FLUSH);
- r->req.aiocb = bdrv_aio_flush(s->bs, scsi_flush_complete, r);
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+ r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_flush_complete, r);
if (r->req.aiocb == NULL) {
scsi_flush_complete(r, -EIO);
}
@@ -1418,7 +1417,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
goto fail;
}
- rc = bdrv_discard(s->bs, r->req.cmd.lba * s->cluster_size,
+ rc = bdrv_discard(s->qdev.conf.bs, r->req.cmd.lba * s->cluster_size,
len * s->cluster_size);
if (rc < 0) {
/* XXX: better error code ?*/
@@ -1460,7 +1459,7 @@ static void scsi_disk_reset(DeviceState *dev)
scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
- bdrv_get_geometry(s->bs, &nb_sectors);
+ bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
nb_sectors /= s->cluster_size;
if (nb_sectors) {
nb_sectors--;
@@ -1530,16 +1529,15 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
error_report("scsi-disk: drive property not set");
return -1;
}
- s->bs = s->qdev.conf.bs;
- if (scsi_type == TYPE_DISK && !bdrv_is_inserted(s->bs)) {
+ if (scsi_type == TYPE_DISK && !bdrv_is_inserted(s->qdev.conf.bs)) {
error_report("Device needs media, but drive is empty");
return -1;
}
if (!s->serial) {
/* try to fall back to value set with legacy -drive serial=... */
- dinfo = drive_get_by_blockdev(s->bs);
+ dinfo = drive_get_by_blockdev(s->qdev.conf.bs);
if (*dinfo->serial) {
s->serial = g_strdup(dinfo->serial);
}
@@ -1549,13 +1547,13 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
s->version = g_strdup(QEMU_VERSION);
}
- if (bdrv_is_sg(s->bs)) {
+ if (bdrv_is_sg(s->qdev.conf.bs)) {
error_report("scsi-disk: unwanted /dev/sg*");
return -1;
}
if (scsi_type == TYPE_ROM) {
- bdrv_set_dev_ops(s->bs, &scsi_cd_block_ops, s);
+ bdrv_set_dev_ops(s->qdev.conf.bs, &scsi_cd_block_ops, s);
s->qdev.blocksize = 2048;
} else if (scsi_type == TYPE_DISK) {
s->qdev.blocksize = s->qdev.conf.logical_block_size;
@@ -1564,11 +1562,11 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
return -1;
}
s->cluster_size = s->qdev.blocksize / 512;
- bdrv_set_buffer_alignment(s->bs, s->qdev.blocksize);
+ bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
s->qdev.type = scsi_type;
qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
- bdrv_iostatus_enable(s->bs);
+ bdrv_iostatus_enable(s->qdev.conf.bs);
add_boot_device_path(s->qdev.conf.bootindex, &dev->qdev, ",0");
return 0;
}
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 45/55] scsi-disk: remove cluster_size
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
This field is redundant, and having it makes it more complicated
to share reqops between the upcoming scsi-block and scsi-generic.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-disk.c | 35 ++++++++++++++++-------------------
1 files changed, 16 insertions(+), 19 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 8a05031..f89e6c5 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -65,9 +65,6 @@ typedef struct SCSIDiskReq {
struct SCSIDiskState
{
SCSIDevice qdev;
- /* The qemu block layer uses a fixed 512 byte sector size.
- This is the number of 512 byte blocks in a single scsi sector. */
- int cluster_size;
uint32_t removable;
uint64_t max_lba;
bool media_changed;
@@ -854,7 +851,7 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf,
bdrv_get_geometry_hint(bdrv, &cylinders, &heads, &secs);
p[4] = heads & 0xff;
p[5] = secs & 0xff;
- p[6] = s->cluster_size * 2;
+ p[6] = s->qdev.blocksize >> 8;
p[8] = (cylinders >> 8) & 0xff;
p[9] = cylinders & 0xff;
/* Write precomp start cylinder, disabled */
@@ -983,7 +980,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
} else { /* MODE_SENSE_10 */
outbuf[7] = 8; /* Block descriptor length */
}
- nb_sectors /= s->cluster_size;
+ nb_sectors /= (s->qdev.blocksize / 512);
if (nb_sectors > 0xffffff) {
nb_sectors = 0;
}
@@ -993,7 +990,7 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
p[3] = nb_sectors & 0xff;
p[4] = 0; /* reserved */
p[5] = 0; /* bytes 5-7 are the sector size in bytes */
- p[6] = s->cluster_size * 2;
+ p[6] = s->qdev.blocksize >> 8;
p[7] = 0;
p += 8;
}
@@ -1044,7 +1041,7 @@ static int scsi_disk_emulate_read_toc(SCSIRequest *req, uint8_t *outbuf)
start_track = req->cmd.buf[6];
bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
- nb_sectors /= s->cluster_size;
+ nb_sectors /= s->qdev.blocksize / 512;
switch (format) {
case 0:
toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
@@ -1179,7 +1176,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
goto illegal_request;
}
- nb_sectors /= s->cluster_size;
+ nb_sectors /= s->qdev.blocksize / 512;
/* Returned value is the address of the last sector. */
nb_sectors--;
/* Remember the new size for read/write sanity checking. */
@@ -1194,7 +1191,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
outbuf[3] = nb_sectors & 0xff;
outbuf[4] = 0;
outbuf[5] = 0;
- outbuf[6] = s->cluster_size * 2;
+ outbuf[6] = s->qdev.blocksize >> 8;
outbuf[7] = 0;
buflen = 8;
break;
@@ -1234,7 +1231,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
goto illegal_request;
}
- nb_sectors /= s->cluster_size;
+ nb_sectors /= s->qdev.blocksize / 512;
/* Returned value is the address of the last sector. */
nb_sectors--;
/* Remember the new size for read/write sanity checking. */
@@ -1249,7 +1246,7 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
outbuf[7] = nb_sectors & 0xff;
outbuf[8] = 0;
outbuf[9] = 0;
- outbuf[10] = s->cluster_size * 2;
+ outbuf[10] = s->qdev.blocksize >> 8;
outbuf[11] = 0;
outbuf[12] = 0;
outbuf[13] = get_physical_block_exp(&s->qdev.conf);
@@ -1356,8 +1353,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
if (r->req.cmd.lba > s->max_lba) {
goto illegal_lba;
}
- r->sector = r->req.cmd.lba * s->cluster_size;
- r->sector_count = len * s->cluster_size;
+ r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
+ r->sector_count = len * (s->qdev.blocksize / 512);
break;
case WRITE_6:
case WRITE_10:
@@ -1373,8 +1370,8 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
if (r->req.cmd.lba > s->max_lba) {
goto illegal_lba;
}
- r->sector = r->req.cmd.lba * s->cluster_size;
- r->sector_count = len * s->cluster_size;
+ r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
+ r->sector_count = len * (s->qdev.blocksize / 512);
break;
case MODE_SELECT:
DPRINTF("Mode Select(6) (len %lu)\n", (long)r->req.cmd.xfer);
@@ -1417,8 +1414,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
goto fail;
}
- rc = bdrv_discard(s->qdev.conf.bs, r->req.cmd.lba * s->cluster_size,
- len * s->cluster_size);
+ rc = bdrv_discard(s->qdev.conf.bs,
+ r->req.cmd.lba * (s->qdev.blocksize / 512),
+ len * (s->qdev.blocksize / 512));
if (rc < 0) {
/* XXX: better error code ?*/
goto fail;
@@ -1460,7 +1458,7 @@ static void scsi_disk_reset(DeviceState *dev)
scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
- nb_sectors /= s->cluster_size;
+ nb_sectors /= s->qdev.blocksize / 512;
if (nb_sectors) {
nb_sectors--;
}
@@ -1561,7 +1559,6 @@ static int scsi_initfn(SCSIDevice *dev, uint8_t scsi_type)
error_report("scsi-disk: Unhandled SCSI type %02x", scsi_type);
return -1;
}
- s->cluster_size = s->qdev.blocksize / 512;
bdrv_set_buffer_alignment(s->qdev.conf.bs, s->qdev.blocksize);
s->qdev.type = scsi_type;
--
1.7.6.4
^ permalink raw reply related
* Lock in the ironlake_panel_vdd_work()
From: Konstantin Belousov @ 2011-10-31 13:01 UTC (permalink / raw)
To: Keith Packard; +Cc: intel-gfx
[-- Attachment #1.1: Type: text/plain, Size: 139 bytes --]
I have a question about ironlake_panel_vdd_work(). Should it use
the device struct_mutex, or need it to be the mode_config.mutex
instead ?
[-- Attachment #1.2: Type: application/pgp-signature, Size: 196 bytes --]
[-- Attachment #2: Type: text/plain, Size: 159 bytes --]
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [Qemu-devel] [PATCH 41/55] scsi-generic: check ioctl statuses when SG_IO succeeds
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
A succeeding ioctl does not imply that the SCSI command succeeded.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-generic.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 5ef4825..c313749 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -310,9 +310,9 @@ static int get_blocksize(BlockDriverState *bdrv)
io_header.timeout = 6000; /* XXX */
ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
- if (ret < 0)
+ if (ret < 0 || io_header.driver_status || io_header.host_status) {
return -1;
-
+ }
return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
}
@@ -341,9 +341,9 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
io_header.timeout = 6000; /* XXX */
ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
- if (ret < 0)
+ if (ret < 0 || io_header.driver_status || io_header.host_status) {
return -1;
-
+ }
return (buf[9] << 16) | (buf[10] << 8) | buf[11];
}
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 43/55] scsi-generic: snoop READ CAPACITY commands to get block size
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Instead of "guessing" the block size when there is no medium in the
drive, wait for the guest to send a READ CAPACITY command and snoop
it from there.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-generic.c | 66 ++++++++++++++++++++---------------------------------
1 files changed, 25 insertions(+), 41 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 5ad3d57..4d7ad82 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -155,6 +155,7 @@ static int execute_command(BlockDriverState *bdrv,
static void scsi_read_complete(void * opaque, int ret)
{
SCSIGenericReq *r = (SCSIGenericReq *)opaque;
+ SCSIDevice *s = r->req.dev;
int len;
r->req.aiocb = NULL;
@@ -170,6 +171,15 @@ static void scsi_read_complete(void * opaque, int ret)
if (len == 0) {
scsi_command_complete(r, 0);
} else {
+ /* Snoop READ CAPACITY output to set the blocksize. */
+ if (r->req.cmd.buf[0] == READ_CAPACITY_10) {
+ s->blocksize = ldl_be_p(&r->buf[4]);
+ } else if (r->req.cmd.buf[0] == SERVICE_ACTION_IN_16 &&
+ (r->req.cmd.buf[1] & 31) == SAI_READ_CAPACITY_16) {
+ s->blocksize = ldl_be_p(&r->buf[8]);
+ }
+ bdrv_set_buffer_alignment(s->conf.bs, s->blocksize);
+
scsi_req_data(&r->req, len);
}
}
@@ -298,36 +308,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
}
}
-static int get_blocksize(BlockDriverState *bdrv)
-{
- uint8_t cmd[10];
- uint8_t buf[8];
- uint8_t sensebuf[8];
- sg_io_hdr_t io_header;
- int ret;
-
- memset(cmd, 0, sizeof(cmd));
- memset(buf, 0, sizeof(buf));
- cmd[0] = READ_CAPACITY_10;
-
- memset(&io_header, 0, sizeof(io_header));
- io_header.interface_id = 'S';
- io_header.dxfer_direction = SG_DXFER_FROM_DEV;
- io_header.dxfer_len = sizeof(buf);
- io_header.dxferp = buf;
- io_header.cmdp = cmd;
- io_header.cmd_len = sizeof(cmd);
- io_header.mx_sb_len = sizeof(sensebuf);
- io_header.sbp = sensebuf;
- io_header.timeout = 6000; /* XXX */
-
- ret = bdrv_ioctl(bdrv, SG_IO, &io_header);
- if (ret < 0 || io_header.driver_status || io_header.host_status) {
- return -1;
- }
- return (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
-}
-
static int get_stream_blocksize(BlockDriverState *bdrv)
{
uint8_t cmd[6];
@@ -413,21 +393,25 @@ static int scsi_generic_initfn(SCSIDevice *s)
/* define device state */
s->type = scsiid.scsi_type;
DPRINTF("device type %d\n", s->type);
- if (s->type == TYPE_TAPE) {
+ switch (s->type) {
+ case TYPE_TAPE:
s->blocksize = get_stream_blocksize(s->conf.bs);
if (s->blocksize == -1) {
s->blocksize = 0;
}
- } else {
- s->blocksize = get_blocksize(s->conf.bs);
- /* removable media returns 0 if not present */
- if (s->blocksize <= 0) {
- if (s->type == TYPE_ROM || s->type == TYPE_WORM) {
- s->blocksize = 2048;
- } else {
- s->blocksize = 512;
- }
- }
+ break;
+
+ /* Make a guess for block devices, we'll fix it when the guest sends.
+ * READ CAPACITY. If they don't, they likely would assume these sizes
+ * anyway. (TODO: they could also send MODE SENSE).
+ */
+ case TYPE_ROM:
+ case TYPE_WORM:
+ s->blocksize = 2048;
+ break;
+ default:
+ s->blocksize = 512;
+ break;
}
DPRINTF("block size %d\n", s->blocksize);
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 42/55] scsi-generic: look at host status
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Pass down the host status so that failing transport can be detected
by the guest. Similar treatment of host status could be done in
virtio-blk, too.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-generic.c | 20 ++++++++++++++++----
1 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index c313749..5ad3d57 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -39,8 +39,13 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#define SCSI_SENSE_BUF_SIZE 96
-#define SG_ERR_DRIVER_TIMEOUT 0x06
-#define SG_ERR_DRIVER_SENSE 0x08
+#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
#ifndef MAX_UINT
#define MAX_UINT ((unsigned int)-1)
@@ -68,8 +73,9 @@ static void scsi_command_complete(void *opaque, int ret)
SCSIGenericReq *r = (SCSIGenericReq *)opaque;
r->req.aiocb = NULL;
- if (r->io_header.driver_status & SG_ERR_DRIVER_SENSE)
+ 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) {
@@ -86,9 +92,15 @@ static void scsi_command_complete(void *opaque, int ret)
break;
}
} else {
- if (r->io_header.driver_status & SG_ERR_DRIVER_TIMEOUT) {
+ 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) {
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 40/55] scsi-generic: remove scsi_req_fixup
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
This is not needed anymore, since asynchronous ioctls were introduced
by commit 221f715 (new scsi-generic abstraction, use SG_IO, 2009-03-28).
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-generic.c | 15 ---------------
1 files changed, 0 insertions(+), 15 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 4af0f24..5ef4825 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -232,19 +232,6 @@ static uint8_t *scsi_get_buf(SCSIRequest *req)
return r->buf;
}
-static void scsi_req_fixup(SCSIRequest *req)
-{
- switch(req->cmd.buf[0]) {
- case REWIND:
- case START_STOP:
- if (req->dev->type == TYPE_TAPE) {
- /* force IMMED, otherwise qemu waits end of command */
- req->cmd.buf[1] = 0x01;
- }
- break;
- }
-}
-
/* Execute a scsi command. Returns the length of the data expected by the
command. This will be Positive for data transfers from the device
(eg. disk reads), negative for transfers to the device (eg. disk writes),
@@ -256,8 +243,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
SCSIDevice *s = r->req.dev;
int ret;
- scsi_req_fixup(&r->req);
-
DPRINTF("Command: lun=%d tag=0x%x len %zd data=0x%02x", lun, tag,
r->req.cmd.xfer, cmd[0]);
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 36/55] scsi: add channel to addressing
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
This also requires little more than adding the new argument to
scsi_device_find, and the qdev property. All devices by default
end up on channel 0.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/esp.c | 4 ++--
hw/lsi53c895a.c | 4 ++--
hw/scsi-bus.c | 24 +++++++++++++++---------
hw/scsi.h | 5 +++--
hw/spapr_vscsi.c | 9 +++------
5 files changed, 25 insertions(+), 21 deletions(-)
diff --git a/hw/esp.c b/hw/esp.c
index 5742bb3..b698a43 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -217,7 +217,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
s->async_len = 0;
}
- s->current_dev = scsi_device_find(&s->bus, target, 0);
+ s->current_dev = scsi_device_find(&s->bus, 0, target, 0);
if (!s->current_dev) {
// No such drive
s->rregs[ESP_RSTAT] = 0;
@@ -237,7 +237,7 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
trace_esp_do_busid_cmd(busid);
lun = busid & 7;
- current_lun = scsi_device_find(&s->bus, s->current_dev->id, lun);
+ current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
s->current_req = scsi_req_new(current_lun, 0, lun, buf, NULL);
datalen = scsi_req_enqueue(s->current_req);
s->ti_size = datalen;
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index d26e442..2984cea 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -767,7 +767,7 @@ static void lsi_do_command(LSIState *s)
s->command_complete = 0;
id = (s->select_tag >> 8) & 0xf;
- dev = scsi_device_find(&s->bus, id, s->current_lun);
+ dev = scsi_device_find(&s->bus, 0, id, s->current_lun);
if (!dev) {
lsi_bad_selection(s, id);
return;
@@ -1198,7 +1198,7 @@ again:
}
s->sstat0 |= LSI_SSTAT0_WOA;
s->scntl1 &= ~LSI_SCNTL1_IARB;
- if (!scsi_device_find(&s->bus, id, 0)) {
+ if (!scsi_device_find(&s->bus, 0, id, 0)) {
lsi_bad_selection(s, id);
break;
}
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index cec06db..bdd6e94 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -16,6 +16,7 @@ static struct BusInfo scsi_bus_info = {
.size = sizeof(SCSIBus),
.get_fw_dev_path = scsibus_get_fw_dev_path,
.props = (Property[]) {
+ DEFINE_PROP_UINT32("channel", SCSIDevice, channel, 0),
DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
DEFINE_PROP_END_OF_LIST(),
@@ -40,6 +41,10 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
SCSIDevice *d;
int rc = -1;
+ if (dev->channel > bus->info->max_channel) {
+ error_report("bad scsi channel id: %d", dev->channel);
+ goto err;
+ }
if (dev->id != -1 && dev->id > bus->info->max_target) {
error_report("bad scsi device id: %d", dev->id);
goto err;
@@ -51,7 +56,7 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
dev->lun = 0;
}
do {
- d = scsi_device_find(bus, ++id, dev->lun);
+ d = scsi_device_find(bus, dev->channel, ++id, dev->lun);
} while (d && d->lun == dev->lun && id <= bus->info->max_target);
if (id > bus->info->max_target) {
error_report("no free target");
@@ -61,7 +66,7 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
} else if (dev->lun == -1) {
int lun = -1;
do {
- d = scsi_device_find(bus, dev->id, ++lun);
+ d = scsi_device_find(bus, dev->channel, dev->id, ++lun);
} while (d && d->lun == lun && lun < bus->info->max_lun);
if (lun > bus->info->max_lun) {
error_report("no free lun");
@@ -69,7 +74,7 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
}
dev->lun = lun;
} else {
- d = scsi_device_find(bus, dev->id, dev->lun);
+ d = scsi_device_find(bus, dev->channel, dev->id, dev->lun);
if (dev->lun == d->lun && dev != d) {
qdev_free(&d->qdev);
}
@@ -203,7 +208,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
{
DeviceState *qdev;
int i, len, n;
- int id;
+ int channel, id;
bool found_lun0;
if (r->req.cmd.xfer < 16) {
@@ -212,13 +217,14 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
if (r->req.cmd.buf[2] > 2) {
return false;
}
+ channel = r->req.dev->channel;
id = r->req.dev->id;
found_lun0 = false;
n = 0;
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
- if (dev->id == id) {
+ if (dev->channel == channel && dev->id == id) {
if (dev->lun == 0) {
found_lun0 = true;
}
@@ -240,7 +246,7 @@ static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
- if (dev->id == id) {
+ if (dev->channel == channel && dev->id == id) {
store_lun(&r->buf[i], dev->lun);
i += 8;
}
@@ -1203,12 +1209,12 @@ static char *scsibus_get_fw_dev_path(DeviceState *dev)
char path[100];
snprintf(path, sizeof(path), "%s@%d:%d:%d", qdev_fw_name(dev),
- 0, d->id, d->lun);
+ d->channel, d->id, d->lun);
return strdup(path);
}
-SCSIDevice *scsi_device_find(SCSIBus *bus, int id, int lun)
+SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun)
{
DeviceState *qdev;
SCSIDevice *target_dev = NULL;
@@ -1216,7 +1222,7 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int id, int lun)
QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
- if (dev->id == id) {
+ if (dev->channel == channel && dev->id == id) {
if (dev->lun == lun) {
return dev;
}
diff --git a/hw/scsi.h b/hw/scsi.h
index 401d8d3..c8649cf 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -66,6 +66,7 @@ struct SCSIDevice
uint8_t sense[SCSI_SENSE_BUF_SIZE];
uint32_t sense_len;
QTAILQ_HEAD(, SCSIRequest) requests;
+ uint32_t channel;
uint32_t lun;
int blocksize;
int type;
@@ -99,7 +100,7 @@ struct SCSIDeviceInfo {
struct SCSIBusInfo {
int tcq;
- int max_target, max_lun;
+ int max_channel, max_target, max_lun;
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
void (*complete)(SCSIRequest *req, uint32_t arg);
void (*cancel)(SCSIRequest *req);
@@ -194,6 +195,6 @@ void scsi_req_abort(SCSIRequest *req, int status);
void scsi_req_cancel(SCSIRequest *req);
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
-SCSIDevice *scsi_device_find(SCSIBus *bus, int target, int lun);
+SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int target, int lun);
#endif
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index e6c3581..00e2d2d 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -160,11 +160,7 @@ retry:
abort();
}
- if (channel) {
- *lun = -1;
- return NULL;
- }
- return scsi_device_find(bus, id, *lun);
+ return scsi_device_find(bus, channel, id, *lun);
}
static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
@@ -892,7 +888,8 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
static const struct SCSIBusInfo vscsi_scsi_info = {
.tcq = true,
- .max_target = 63, /* logical unit addressing format */
+ .max_channel = 7, /* logical unit addressing format */
+ .max_target = 63,
.max_lun = 31,
.transfer_data = vscsi_transfer_data,
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 39/55] scsi-generic: drop SCSIGenericState
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
It is not needed, because s->bs is already stored in SCSIDevice, and
can be reached from the conf.bs member.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-generic.c | 90 +++++++++++++++++++++++-----------------------------
1 files changed, 40 insertions(+), 50 deletions(-)
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 8f6b70d..4af0f24 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -46,8 +46,6 @@ do { fprintf(stderr, "scsi-generic: " fmt , ## __VA_ARGS__); } while (0)
#define MAX_UINT ((unsigned int)-1)
#endif
-typedef struct SCSIGenericState SCSIGenericState;
-
typedef struct SCSIGenericReq {
SCSIRequest req;
uint8_t *buf;
@@ -56,12 +54,6 @@ typedef struct SCSIGenericReq {
sg_io_hdr_t io_header;
} SCSIGenericReq;
-struct SCSIGenericState
-{
- SCSIDevice qdev;
- BlockDriverState *bs;
-};
-
static void scsi_free_request(SCSIRequest *req)
{
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
@@ -174,7 +166,7 @@ static void scsi_read_complete(void * opaque, int ret)
static void scsi_read_data(SCSIRequest *req)
{
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
+ SCSIDevice *s = r->req.dev;
int ret;
DPRINTF("scsi_read_data 0x%x\n", req->tag);
@@ -183,17 +175,16 @@ static void scsi_read_data(SCSIRequest *req)
return;
}
- ret = execute_command(s->bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
+ ret = execute_command(s->conf.bs, r, SG_DXFER_FROM_DEV, scsi_read_complete);
if (ret < 0) {
scsi_command_complete(r, ret);
- return;
}
}
static void scsi_write_complete(void * opaque, int ret)
{
SCSIGenericReq *r = (SCSIGenericReq *)opaque;
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
+ SCSIDevice *s = r->req.dev;
DPRINTF("scsi_write_complete() ret = %d\n", ret);
r->req.aiocb = NULL;
@@ -204,9 +195,9 @@ static void scsi_write_complete(void * opaque, int ret)
}
if (r->req.cmd.buf[0] == MODE_SELECT && r->req.cmd.buf[4] == 12 &&
- s->qdev.type == TYPE_TAPE) {
- s->qdev.blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
- DPRINTF("block size %d\n", s->qdev.blocksize);
+ s->type == TYPE_TAPE) {
+ s->blocksize = (r->buf[9] << 16) | (r->buf[10] << 8) | r->buf[11];
+ DPRINTF("block size %d\n", s->blocksize);
}
scsi_command_complete(r, ret);
@@ -216,8 +207,8 @@ static void scsi_write_complete(void * opaque, int ret)
The transfer may complete asynchronously. */
static void scsi_write_data(SCSIRequest *req)
{
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+ SCSIDevice *s = r->req.dev;
int ret;
DPRINTF("scsi_write_data 0x%x\n", req->tag);
@@ -227,7 +218,7 @@ static void scsi_write_data(SCSIRequest *req)
return;
}
- ret = execute_command(s->bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
+ ret = execute_command(s->conf.bs, r, SG_DXFER_TO_DEV, scsi_write_complete);
if (ret < 0) {
scsi_command_complete(r, ret);
}
@@ -261,8 +252,8 @@ static void scsi_req_fixup(SCSIRequest *req)
static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
{
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
+ SCSIDevice *s = r->req.dev;
int ret;
scsi_req_fixup(&r->req);
@@ -285,7 +276,7 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
g_free(r->buf);
r->buflen = 0;
r->buf = NULL;
- ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
+ ret = execute_command(s->conf.bs, r, SG_DXFER_NONE, scsi_command_complete);
if (ret < 0) {
scsi_command_complete(r, ret);
return 0;
@@ -373,77 +364,76 @@ static int get_stream_blocksize(BlockDriverState *bdrv)
static void scsi_generic_reset(DeviceState *dev)
{
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev.qdev, dev);
+ SCSIDevice *s = DO_UPCAST(SCSIDevice, qdev, dev);
- scsi_device_purge_requests(&s->qdev, SENSE_CODE(RESET));
+ scsi_device_purge_requests(s, SENSE_CODE(RESET));
}
-static void scsi_destroy(SCSIDevice *d)
+static void scsi_destroy(SCSIDevice *s)
{
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
-
- scsi_device_purge_requests(&s->qdev, SENSE_CODE(NO_SENSE));
- blockdev_mark_auto_del(s->qdev.conf.bs);
+ scsi_device_purge_requests(s, SENSE_CODE(NO_SENSE));
+ blockdev_mark_auto_del(s->conf.bs);
}
-static int scsi_generic_initfn(SCSIDevice *dev)
+static int scsi_generic_initfn(SCSIDevice *s)
{
- SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, dev);
int sg_version;
struct sg_scsi_id scsiid;
- if (!s->qdev.conf.bs) {
+ if (!s->conf.bs) {
error_report("scsi-generic: drive property not set");
return -1;
}
- s->bs = s->qdev.conf.bs;
/* check we are really using a /dev/sg* file */
- if (!bdrv_is_sg(s->bs)) {
+ if (!bdrv_is_sg(s->conf.bs)) {
error_report("scsi-generic: not /dev/sg*");
return -1;
}
- if (bdrv_get_on_error(s->bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
+ if (bdrv_get_on_error(s->conf.bs, 0) != BLOCK_ERR_STOP_ENOSPC) {
error_report("Device doesn't support drive option werror");
return -1;
}
- if (bdrv_get_on_error(s->bs, 1) != BLOCK_ERR_REPORT) {
+ if (bdrv_get_on_error(s->conf.bs, 1) != BLOCK_ERR_REPORT) {
error_report("Device doesn't support drive option rerror");
return -1;
}
/* check we are using a driver managing SG_IO (version 3 and after */
- if (bdrv_ioctl(s->bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
+ if (bdrv_ioctl(s->conf.bs, SG_GET_VERSION_NUM, &sg_version) < 0 ||
sg_version < 30000) {
error_report("scsi-generic: scsi generic interface too old");
return -1;
}
/* get LUN of the /dev/sg? */
- if (bdrv_ioctl(s->bs, SG_GET_SCSI_ID, &scsiid)) {
+ if (bdrv_ioctl(s->conf.bs, SG_GET_SCSI_ID, &scsiid)) {
error_report("scsi-generic: SG_GET_SCSI_ID ioctl failed");
return -1;
}
/* define device state */
- s->qdev.type = scsiid.scsi_type;
- DPRINTF("device type %d\n", s->qdev.type);
- if (s->qdev.type == TYPE_TAPE) {
- s->qdev.blocksize = get_stream_blocksize(s->bs);
- if (s->qdev.blocksize == -1)
- s->qdev.blocksize = 0;
+ s->type = scsiid.scsi_type;
+ DPRINTF("device type %d\n", s->type);
+ if (s->type == TYPE_TAPE) {
+ s->blocksize = get_stream_blocksize(s->conf.bs);
+ if (s->blocksize == -1) {
+ s->blocksize = 0;
+ }
} else {
- s->qdev.blocksize = get_blocksize(s->bs);
+ s->blocksize = get_blocksize(s->conf.bs);
/* removable media returns 0 if not present */
- if (s->qdev.blocksize <= 0) {
- if (s->qdev.type == TYPE_ROM || s->qdev.type == TYPE_WORM)
- s->qdev.blocksize = 2048;
- else
- s->qdev.blocksize = 512;
+ if (s->blocksize <= 0) {
+ if (s->type == TYPE_ROM || s->type == TYPE_WORM) {
+ s->blocksize = 2048;
+ } else {
+ s->blocksize = 512;
+ }
}
}
- DPRINTF("block size %d\n", s->qdev.blocksize);
+
+ DPRINTF("block size %d\n", s->blocksize);
return 0;
}
@@ -469,13 +459,13 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
static SCSIDeviceInfo scsi_generic_info = {
.qdev.name = "scsi-generic",
.qdev.desc = "pass through generic scsi device (/dev/sg*)",
- .qdev.size = sizeof(SCSIGenericState),
+ .qdev.size = sizeof(SCSIDevice),
.qdev.reset = scsi_generic_reset,
.init = scsi_generic_initfn,
.destroy = scsi_destroy,
.alloc_req = scsi_new_request,
.qdev.props = (Property[]) {
- DEFINE_BLOCK_PROPERTIES(SCSIGenericState, qdev.conf),
+ DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
DEFINE_PROP_END_OF_LIST(),
},
};
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 38/55] scsi-disk: fix retrying a flush
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Flush does not go anymore through scsi_disk_emulate_command.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-disk.c | 9 +++------
1 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 6b139ac..e800ab3 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -81,7 +81,7 @@ struct SCSIDiskState
};
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
-static int scsi_disk_emulate_command(SCSIDiskReq *r);
+static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf);
static void scsi_free_request(SCSIRequest *req)
{
@@ -325,7 +325,6 @@ static void scsi_dma_restart_bh(void *opaque)
r = DO_UPCAST(SCSIDiskReq, req, req);
if (r->status & SCSI_REQ_STATUS_RETRY) {
int status = r->status;
- int ret;
r->status &=
~(SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK);
@@ -338,10 +337,8 @@ static void scsi_dma_restart_bh(void *opaque)
scsi_write_data(&r->req);
break;
case SCSI_REQ_STATUS_RETRY_FLUSH:
- ret = scsi_disk_emulate_command(r);
- if (ret == 0) {
- scsi_req_complete(&r->req, GOOD);
- }
+ scsi_send_command(&r->req, r->req.cmd.buf);
+ break;
}
}
}
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 37/55] scsi-disk: fail READ CAPACITY if LBA != 0 but PMI == 0
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Tested by the Windows Logo Kit SCSI Compliance test. From SBC-3, paragraph
5.25: "The LOGICAL BLOCK ADDRESS field shall be set to zero if the PMI
bit is set to zero. If the PMI bit is set to zero and the LOGICAL BLOCK
ADDRESS field is not set to zero, then the device server shall terminate
the command with CHECK CONDITION status with the sense key set to ILLEGAL
REQUEST and the additional sense code set to INVALID FIELD IN CDB".
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-disk.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 50fc3d6..6b139ac 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1180,6 +1180,9 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
if (!nb_sectors) {
goto not_ready;
}
+ if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) {
+ goto illegal_request;
+ }
nb_sectors /= s->cluster_size;
/* Returned value is the address of the last sector. */
nb_sectors--;
@@ -1232,6 +1235,9 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
if (!nb_sectors) {
goto not_ready;
}
+ if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) {
+ goto illegal_request;
+ }
nb_sectors /= s->cluster_size;
/* Returned value is the address of the last sector. */
nb_sectors--;
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 33/55] scsi: remove devs array from SCSIBus
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Change the devs array into a linked list, and add a scsi_device_find
function to navigate the children list instead. This lets the SCSI
bus use more complex addressing, and HBAs can talk to the correct device
when there are multiple LUNs per target.
scsi_device_find may return another LUN on the same target if none is
found that matches exactly.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/esp.c | 8 +++++---
hw/lsi53c895a.c | 22 +++++++---------------
hw/qdev.h | 2 +-
hw/scsi-bus.c | 53 ++++++++++++++++++++++++++++++-----------------------
hw/scsi.h | 3 +--
hw/spapr_vscsi.c | 14 ++++++--------
6 files changed, 50 insertions(+), 52 deletions(-)
diff --git a/hw/esp.c b/hw/esp.c
index d3fb1c6..aad290f 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -217,7 +217,8 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
s->async_len = 0;
}
- if (target >= ESP_MAX_DEVS || !s->bus.devs[target]) {
+ s->current_dev = scsi_device_find(&s->bus, target, 0);
+ if (!s->current_dev) {
// No such drive
s->rregs[ESP_RSTAT] = 0;
s->rregs[ESP_RINTR] = INTR_DC;
@@ -225,7 +226,6 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
esp_raise_irq(s);
return 0;
}
- s->current_dev = s->bus.devs[target];
return dmalen;
}
@@ -233,10 +233,12 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
{
int32_t datalen;
int lun;
+ SCSIDevice *current_lun;
trace_esp_do_busid_cmd(busid);
lun = busid & 7;
- s->current_req = scsi_req_new(s->current_dev, 0, lun, buf, NULL);
+ current_lun = scsi_device_find(&s->bus, s->current_dev->id, lun);
+ s->current_req = scsi_req_new(current_lun, 0, lun, buf, NULL);
datalen = scsi_req_enqueue(s->current_req);
s->ti_size = datalen;
if (datalen != 0) {
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 4eeb496..c15f167 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -531,7 +531,7 @@ static void lsi_bad_selection(LSIState *s, uint32_t id)
/* Initiate a SCSI layer data transfer. */
static void lsi_do_dma(LSIState *s, int out)
{
- uint32_t count, id;
+ uint32_t count;
target_phys_addr_t addr;
SCSIDevice *dev;
@@ -542,12 +542,8 @@ static void lsi_do_dma(LSIState *s, int out)
return;
}
- id = (s->current->tag >> 8) & 0xf;
- dev = s->bus.devs[id];
- if (!dev) {
- lsi_bad_selection(s, id);
- return;
- }
+ dev = s->current->req->dev;
+ assert(dev);
count = s->dbc;
if (count > s->current->dma_len)
@@ -771,7 +767,7 @@ static void lsi_do_command(LSIState *s)
s->command_complete = 0;
id = (s->select_tag >> 8) & 0xf;
- dev = s->bus.devs[id];
+ dev = scsi_device_find(&s->bus, id, s->current_lun);
if (!dev) {
lsi_bad_selection(s, id);
return;
@@ -1202,7 +1198,7 @@ again:
}
s->sstat0 |= LSI_SSTAT0_WOA;
s->scntl1 &= ~LSI_SCNTL1_IARB;
- if (id >= LSI_MAX_DEVS || !s->bus.devs[id]) {
+ if (!scsi_device_find(&s->bus, id, 0)) {
lsi_bad_selection(s, id);
break;
}
@@ -1684,13 +1680,9 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
if (val & LSI_SCNTL1_RST) {
if (!(s->sstat0 & LSI_SSTAT0_RST)) {
DeviceState *dev;
- int id;
- for (id = 0; id < LSI_MAX_DEVS; id++) {
- if (s->bus.devs[id]) {
- dev = &s->bus.devs[id]->qdev;
- dev->info->reset(dev);
- }
+ QTAILQ_FOREACH(dev, &s->bus.qbus.children, sibling) {
+ dev->info->reset(dev);
}
s->sstat0 |= LSI_SSTAT0_RST;
lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
diff --git a/hw/qdev.h b/hw/qdev.h
index a7cc48b..36a4198 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -73,7 +73,7 @@ struct BusState {
const char *name;
int allow_hotplug;
int qdev_allocated;
- QTAILQ_HEAD(, DeviceState) children;
+ QTAILQ_HEAD(ChildrenHead, DeviceState) children;
QLIST_ENTRY(BusState) sibling;
};
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index d9d4e18..7104e98 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -37,12 +37,16 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
+ SCSIDevice *olddev;
int rc = -1;
if (dev->id == -1) {
- for (dev->id = 0; dev->id < bus->info->ndev; dev->id++) {
- if (bus->devs[dev->id] == NULL)
+ int id;
+ for (id = 0; id < bus->info->ndev; id++) {
+ if (!scsi_device_find(bus, id, 0)) {
+ dev->id = id;
break;
+ }
}
}
if (dev->id >= bus->info->ndev) {
@@ -50,17 +54,14 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
goto err;
}
- if (bus->devs[dev->id]) {
- qdev_free(&bus->devs[dev->id]->qdev);
+ olddev = scsi_device_find(bus, dev->id, dev->lun);
+ if (olddev && dev->lun == olddev->lun) {
+ qdev_free(&olddev->qdev);
}
- bus->devs[dev->id] = dev;
dev->info = info;
QTAILQ_INIT(&dev->requests);
rc = dev->info->init(dev);
- if (rc != 0) {
- bus->devs[dev->id] = NULL;
- }
err:
return rc;
@@ -69,13 +70,10 @@ err:
static int scsi_qdev_exit(DeviceState *qdev)
{
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
- SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
- assert(bus->devs[dev->id] != NULL);
- if (bus->devs[dev->id]->info->destroy) {
- bus->devs[dev->id]->info->destroy(bus->devs[dev->id]);
+ if (dev->info->destroy) {
+ dev->info->destroy(dev);
}
- bus->devs[dev->id] = NULL;
return 0;
}
@@ -1157,19 +1155,28 @@ void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense)
static char *scsibus_get_fw_dev_path(DeviceState *dev)
{
SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
- SCSIBus *bus = scsi_bus_from_device(d);
char path[100];
- int i;
- for (i = 0; i < bus->info->ndev; i++) {
- if (bus->devs[i] == d) {
- break;
- }
- }
+ snprintf(path, sizeof(path), "%s@%d:%d:%d", qdev_fw_name(dev),
+ 0, d->id, d->lun);
- assert(i != bus->info->ndev);
+ return strdup(path);
+}
+
+SCSIDevice *scsi_device_find(SCSIBus *bus, int id, int lun)
+{
+ DeviceState *qdev;
+ SCSIDevice *target_dev = NULL;
- snprintf(path, sizeof(path), "%s@%x", qdev_fw_name(dev), i);
+ QTAILQ_FOREACH_REVERSE(qdev, &bus->qbus.children, ChildrenHead, sibling) {
+ SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
- return strdup(path);
+ if (dev->id == id) {
+ if (dev->lun == lun) {
+ return dev;
+ }
+ target_dev = dev;
+ }
+ }
+ return target_dev;
}
diff --git a/hw/scsi.h b/hw/scsi.h
index b76c4ee..add3d2d 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -110,8 +110,6 @@ struct SCSIBus {
SCSISense unit_attention;
const SCSIBusInfo *info;
-
- SCSIDevice *devs[MAX_SCSI_DEVS];
};
void scsi_bus_new(SCSIBus *bus, DeviceState *host, const SCSIBusInfo *info);
@@ -195,5 +193,6 @@ void scsi_req_abort(SCSIRequest *req, int status);
void scsi_req_cancel(SCSIRequest *req);
void scsi_device_purge_requests(SCSIDevice *sdev, SCSISense sense);
int scsi_device_get_sense(SCSIDevice *dev, uint8_t *buf, int len, bool fixed);
+SCSIDevice *scsi_device_find(SCSIBus *bus, int target, int lun);
#endif
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index 33ae9b4..ea3bb08 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -129,11 +129,12 @@ static void vscsi_put_req(vscsi_req *req)
req->active = 0;
}
-static void vscsi_decode_id_lun(uint64_t srp_lun, int *id, int *lun)
+static SCSIDevice *vscsi_device_find(SCSIBus *bus, uint64_t srp_lun, int *lun)
{
/* XXX Figure that one out properly ! This is crackpot */
- *id = (srp_lun >> 56) & 0x7f;
+ int id = (srp_lun >> 56) & 0x7f;
*lun = (srp_lun >> 48) & 0xff;
+ return scsi_device_find(bus, id, *lun);
}
static int vscsi_send_iu(VSCSIState *s, vscsi_req *req,
@@ -582,14 +583,11 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
{
union srp_iu *srp = &req->iu.srp;
SCSIDevice *sdev;
- int n, id, lun;
+ int n, lun;
- vscsi_decode_id_lun(be64_to_cpu(srp->cmd.lun), &id, &lun);
-
- /* Qemu vs. linux issue with LUNs to be sorted out ... */
- sdev = (id < 8 && lun < 16) ? s->bus.devs[id] : NULL;
+ sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
if (!sdev) {
- dprintf("VSCSI: Command for id %d with no drive\n", id);
+ dprintf("VSCSI: Command for lun %08" PRIx64 " with no drive\n", be64_to_cpu(srp->cmd.lun));
if (srp->cmd.cdb[0] == INQUIRY) {
vscsi_inquiry_no_target(s, req);
} else {
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 35/55] scsi: allow arbitrary LUNs
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
This only requires changes in two places: in SCSIBus, we need to look
for a free LUN if somebody creates a device with a pre-existing scsi-id
but the default LUN (-1, meaning "search for a free spot"); in vSCSI,
we need to actually parse the LUN according to the SCSI spec.
For vSCSI, max_target/max_lun are set according to the logical unit
addressing format in SAM.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/esp.c | 3 ++-
hw/lsi53c895a.c | 3 ++-
hw/scsi-bus.c | 48 ++++++++++++++++++++++++++++++++----------------
hw/scsi.h | 3 ++-
hw/spapr_vscsi.c | 39 +++++++++++++++++++++++++++++++++++----
hw/usb-msd.c | 3 ++-
6 files changed, 75 insertions(+), 24 deletions(-)
diff --git a/hw/esp.c b/hw/esp.c
index aad290f..5742bb3 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -724,7 +724,8 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
static const struct SCSIBusInfo esp_scsi_info = {
.tcq = false,
- .ndev = ESP_MAX_DEVS,
+ .max_target = ESP_MAX_DEVS,
+ .max_lun = 7,
.transfer_data = esp_transfer_data,
.complete = esp_command_complete,
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index c15f167..d26e442 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2085,7 +2085,8 @@ static int lsi_scsi_uninit(PCIDevice *d)
static const struct SCSIBusInfo lsi_scsi_info = {
.tcq = true,
- .ndev = LSI_MAX_DEVS,
+ .max_target = LSI_MAX_DEVS,
+ .max_lun = 0, /* LUN support is buggy */
.transfer_data = lsi_transfer_data,
.complete = lsi_command_complete,
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index a2d57a7..cec06db 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -17,7 +17,7 @@ static struct BusInfo scsi_bus_info = {
.get_fw_dev_path = scsibus_get_fw_dev_path,
.props = (Property[]) {
DEFINE_PROP_UINT32("scsi-id", SCSIDevice, id, -1),
- DEFINE_PROP_UINT32("lun", SCSIDevice, lun, 0),
+ DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1),
DEFINE_PROP_END_OF_LIST(),
},
};
@@ -37,26 +37,42 @@ static int scsi_qdev_init(DeviceState *qdev, DeviceInfo *base)
SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
SCSIDeviceInfo *info = DO_UPCAST(SCSIDeviceInfo, qdev, base);
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
- SCSIDevice *olddev;
+ SCSIDevice *d;
int rc = -1;
- if (dev->id == -1) {
- int id;
- for (id = 0; id < bus->info->ndev; id++) {
- if (!scsi_device_find(bus, id, 0)) {
- dev->id = id;
- break;
- }
- }
- }
- if (dev->id >= bus->info->ndev) {
+ if (dev->id != -1 && dev->id > bus->info->max_target) {
error_report("bad scsi device id: %d", dev->id);
goto err;
}
- olddev = scsi_device_find(bus, dev->id, dev->lun);
- if (olddev && dev->lun == olddev->lun) {
- qdev_free(&olddev->qdev);
+ if (dev->id == -1) {
+ int id = -1;
+ if (dev->lun == -1) {
+ dev->lun = 0;
+ }
+ do {
+ d = scsi_device_find(bus, ++id, dev->lun);
+ } while (d && d->lun == dev->lun && id <= bus->info->max_target);
+ if (id > bus->info->max_target) {
+ error_report("no free target");
+ goto err;
+ }
+ dev->id = id;
+ } else if (dev->lun == -1) {
+ int lun = -1;
+ do {
+ d = scsi_device_find(bus, dev->id, ++lun);
+ } while (d && d->lun == lun && lun < bus->info->max_lun);
+ if (lun > bus->info->max_lun) {
+ error_report("no free lun");
+ goto err;
+ }
+ dev->lun = lun;
+ } else {
+ d = scsi_device_find(bus, dev->id, dev->lun);
+ if (dev->lun == d->lun && dev != d) {
+ qdev_free(&d->qdev);
+ }
}
dev->info = info;
@@ -115,7 +131,7 @@ int scsi_bus_legacy_handle_cmdline(SCSIBus *bus)
int res = 0, unit;
loc_push_none(&loc);
- for (unit = 0; unit < bus->info->ndev; unit++) {
+ for (unit = 0; unit < bus->info->max_target; unit++) {
dinfo = drive_get(IF_SCSI, bus->busnr, unit);
if (dinfo == NULL) {
continue;
diff --git a/hw/scsi.h b/hw/scsi.h
index add3d2d..401d8d3 100644
--- a/hw/scsi.h
+++ b/hw/scsi.h
@@ -98,7 +98,8 @@ struct SCSIDeviceInfo {
};
struct SCSIBusInfo {
- int tcq, ndev;
+ int tcq;
+ int max_target, max_lun;
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
void (*complete)(SCSIRequest *req, uint32_t arg);
void (*cancel)(SCSIRequest *req);
diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c
index ea3bb08..e6c3581 100644
--- a/hw/spapr_vscsi.c
+++ b/hw/spapr_vscsi.c
@@ -131,9 +131,39 @@ static void vscsi_put_req(vscsi_req *req)
static SCSIDevice *vscsi_device_find(SCSIBus *bus, uint64_t srp_lun, int *lun)
{
- /* XXX Figure that one out properly ! This is crackpot */
- int id = (srp_lun >> 56) & 0x7f;
- *lun = (srp_lun >> 48) & 0xff;
+ int channel = 0, id = 0;
+
+retry:
+ switch (srp_lun >> 62) {
+ case 0:
+ if ((srp_lun >> 56) != 0) {
+ channel = (srp_lun >> 56) & 0x3f;
+ id = (srp_lun >> 48) & 0xff;
+ srp_lun <<= 16;
+ goto retry;
+ }
+ *lun = (srp_lun >> 48) & 0xff;
+ break;
+
+ case 1:
+ *lun = (srp_lun >> 48) & 0x3fff;
+ break;
+ case 2:
+ channel = (srp_lun >> 53) & 0x7;
+ id = (srp_lun >> 56) & 0x3f;
+ *lun = (srp_lun >> 48) & 0x1f;
+ break;
+ case 3:
+ *lun = -1;
+ return NULL;
+ default:
+ abort();
+ }
+
+ if (channel) {
+ *lun = -1;
+ return NULL;
+ }
return scsi_device_find(bus, id, *lun);
}
@@ -862,7 +892,8 @@ static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
static const struct SCSIBusInfo vscsi_scsi_info = {
.tcq = true,
- .ndev = VSCSI_REQ_LIMIT,
+ .max_target = 63, /* logical unit addressing format */
+ .max_lun = 31,
.transfer_data = vscsi_transfer_data,
.complete = vscsi_command_complete,
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 2c047fa..1a0815a 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -497,7 +497,8 @@ static void usb_msd_password_cb(void *opaque, int err)
static const struct SCSIBusInfo usb_msd_scsi_info = {
.tcq = false,
- .ndev = 1,
+ .max_target = 0,
+ .max_lun = 0,
.transfer_data = usb_msd_transfer_data,
.complete = usb_msd_command_complete,
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 34/55] scsi: implement REPORT LUNS for arbitrary LUNs
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-bus.c | 49 +++++++++++++++++++++++++++++++++++++++----------
1 files changed, 39 insertions(+), 10 deletions(-)
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 7104e98..a2d57a7 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -170,7 +170,7 @@ typedef struct SCSITargetReq SCSITargetReq;
struct SCSITargetReq {
SCSIRequest req;
int len;
- uint8_t buf[64];
+ uint8_t buf[2056];
};
static void store_lun(uint8_t *outbuf, int lun)
@@ -185,23 +185,52 @@ static void store_lun(uint8_t *outbuf, int lun)
static bool scsi_target_emulate_report_luns(SCSITargetReq *r)
{
- int len;
+ DeviceState *qdev;
+ int i, len, n;
+ int id;
+ bool found_lun0;
+
if (r->req.cmd.xfer < 16) {
return false;
}
if (r->req.cmd.buf[2] > 2) {
return false;
}
- len = MIN(sizeof r->buf, r->req.cmd.xfer);
+ id = r->req.dev->id;
+ found_lun0 = false;
+ n = 0;
+ QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
+ SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+
+ if (dev->id == id) {
+ if (dev->lun == 0) {
+ found_lun0 = true;
+ }
+ n += 8;
+ }
+ }
+ if (!found_lun0) {
+ n += 8;
+ }
+ len = MIN(n + 8, r->req.cmd.xfer & ~7);
+ if (len > sizeof(r->buf)) {
+ /* TODO: > 256 LUNs? */
+ return false;
+ }
+
memset(r->buf, 0, len);
- if (r->req.dev->lun != 0) {
- r->buf[3] = 16;
- r->len = 24;
- store_lun(&r->buf[16], r->req.dev->lun);
- } else {
- r->buf[3] = 8;
- r->len = 16;
+ stl_be_p(&r->buf, n);
+ i = found_lun0 ? 8 : 16;
+ QTAILQ_FOREACH(qdev, &r->req.bus->qbus.children, sibling) {
+ SCSIDevice *dev = DO_UPCAST(SCSIDevice, qdev, qdev);
+
+ if (dev->id == id) {
+ store_lun(&r->buf[i], dev->lun);
+ i += 8;
+ }
}
+ assert(i == n + 8);
+ r->len = len;
return true;
}
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 32/55] qdev: switch children device list to QTAILQ
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
SCSI buses will need to read the children list first-to-last. This
requires using a QTAILQ, because hell breaks loose if you just try
inserting at the tail (thus reversing the order of all existing
visits from last-to-first to first-to-tail).
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/acpi_piix4.c | 4 ++--
hw/i2c.c | 2 +-
hw/intel-hda.c | 6 +++---
hw/qdev.c | 24 ++++++++++++------------
hw/qdev.h | 4 ++--
hw/s390-virtio-bus.c | 4 ++--
hw/spapr_vio.c | 6 +++---
hw/ssi.c | 6 +++---
8 files changed, 28 insertions(+), 28 deletions(-)
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index 29f0f76..d9075e6 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -276,7 +276,7 @@ static void piix4_update_hotplug(PIIX4PMState *s)
s->pci0_hotplug_enable = ~0;
- QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+ QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
PCIDeviceInfo *info = container_of(qdev->info, PCIDeviceInfo, qdev);
PCIDevice *pdev = DO_UPCAST(PCIDevice, qdev, qdev);
int slot = PCI_SLOT(pdev->devfn);
@@ -486,7 +486,7 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
PCIDeviceInfo *info;
int slot = ffs(val) - 1;
- QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+ QTAILQ_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
dev = DO_UPCAST(PCIDevice, qdev, qdev);
info = container_of(qdev->info, PCIDeviceInfo, qdev);
if (PCI_SLOT(dev->devfn) == slot && !info->no_hotplug) {
diff --git a/hw/i2c.c b/hw/i2c.c
index 49b9ecb..9bcf3e1 100644
--- a/hw/i2c.c
+++ b/hw/i2c.c
@@ -84,7 +84,7 @@ int i2c_start_transfer(i2c_bus *bus, uint8_t address, int recv)
DeviceState *qdev;
i2c_slave *slave = NULL;
- QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+ QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
i2c_slave *candidate = I2C_SLAVE_FROM_QDEV(qdev);
if (candidate->address == address) {
slave = candidate;
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index f97775c..675b659 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -86,7 +86,7 @@ HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
DeviceState *qdev;
HDACodecDevice *cdev;
- QLIST_FOREACH(qdev, &bus->qbus.children, sibling) {
+ QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) {
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
if (cdev->cad == cad) {
return cdev;
@@ -490,7 +490,7 @@ static void intel_hda_notify_codecs(IntelHDAState *d, uint32_t stream, bool runn
DeviceState *qdev;
HDACodecDevice *cdev;
- QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+ QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
if (cdev->info->stream) {
cdev->info->stream(cdev, stream, running, output);
@@ -1114,7 +1114,7 @@ static void intel_hda_reset(DeviceState *dev)
d->wall_base_ns = qemu_get_clock_ns(vm_clock);
/* reset codecs */
- QLIST_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
+ QTAILQ_FOREACH(qdev, &d->codecs.qbus.children, sibling) {
cdev = DO_UPCAST(HDACodecDevice, qdev, qdev);
if (qdev->info->reset) {
qdev->info->reset(qdev);
diff --git a/hw/qdev.c b/hw/qdev.c
index a223d41..50976dd 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -91,7 +91,7 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
qdev_prop_set_defaults(dev, dev->info->props);
qdev_prop_set_defaults(dev, dev->parent_bus->info->props);
qdev_prop_set_globals(dev);
- QLIST_INSERT_HEAD(&bus->children, dev, sibling);
+ QTAILQ_INSERT_HEAD(&bus->children, dev, sibling);
if (qdev_hotplug) {
assert(bus->allow_hotplug);
dev->hotplugged = 1;
@@ -408,7 +408,7 @@ void qdev_free(DeviceState *dev)
if (dev->opts)
qemu_opts_del(dev->opts);
}
- QLIST_REMOVE(dev, sibling);
+ QTAILQ_REMOVE(&dev->parent_bus->children, dev, sibling);
for (prop = dev->info->props; prop && prop->name; prop++) {
if (prop->info->free) {
prop->info->free(dev, prop);
@@ -510,7 +510,7 @@ int qbus_walk_children(BusState *bus, qdev_walkerfn *devfn,
}
}
- QLIST_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
err = qdev_walk_children(dev, devfn, busfn, opaque);
if (err < 0) {
return err;
@@ -560,7 +560,7 @@ static BusState *qbus_find_recursive(BusState *bus, const char *name,
return bus;
}
- QLIST_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
QLIST_FOREACH(child, &dev->child_bus, sibling) {
ret = qbus_find_recursive(child, name, info);
if (ret) {
@@ -576,7 +576,7 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
DeviceState *dev, *ret;
BusState *child;
- QLIST_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
if (dev->id && strcmp(dev->id, id) == 0)
return dev;
QLIST_FOREACH(child, &dev->child_bus, sibling) {
@@ -609,7 +609,7 @@ static void qbus_list_dev(BusState *bus)
const char *sep = " ";
error_printf("devices at \"%s\":", bus->name);
- QLIST_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
error_printf("%s\"%s\"", sep, dev->info->name);
if (dev->id)
error_printf("/\"%s\"", dev->id);
@@ -640,17 +640,17 @@ static DeviceState *qbus_find_dev(BusState *bus, char *elem)
* (2) driver name
* (3) driver alias, if present
*/
- QLIST_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
if (dev->id && strcmp(dev->id, elem) == 0) {
return dev;
}
}
- QLIST_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
if (strcmp(dev->info->name, elem) == 0) {
return dev;
}
}
- QLIST_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
if (dev->info->alias && strcmp(dev->info->alias, elem) == 0) {
return dev;
}
@@ -774,7 +774,7 @@ void qbus_create_inplace(BusState *bus, BusInfo *info,
bus->name = buf;
}
- QLIST_INIT(&bus->children);
+ QTAILQ_INIT(&bus->children);
if (parent) {
QLIST_INSERT_HEAD(&parent->child_bus, bus, sibling);
parent->num_child_bus++;
@@ -809,7 +809,7 @@ void qbus_free(BusState *bus)
{
DeviceState *dev;
- while ((dev = QLIST_FIRST(&bus->children)) != NULL) {
+ while ((dev = QTAILQ_FIRST(&bus->children)) != NULL) {
qdev_free(dev);
}
if (bus->parent) {
@@ -878,7 +878,7 @@ static void qbus_print(Monitor *mon, BusState *bus, int indent)
qdev_printf("bus: %s\n", bus->name);
indent += 2;
qdev_printf("type %s\n", bus->info->name);
- QLIST_FOREACH(dev, &bus->children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->children, sibling) {
qdev_print(mon, dev, indent);
}
}
diff --git a/hw/qdev.h b/hw/qdev.h
index aa7ae36..a7cc48b 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -42,7 +42,7 @@ struct DeviceState {
qemu_irq *gpio_in;
QLIST_HEAD(, BusState) child_bus;
int num_child_bus;
- QLIST_ENTRY(DeviceState) sibling;
+ QTAILQ_ENTRY(DeviceState) sibling;
int instance_id_alias;
int alias_required_for_version;
};
@@ -73,7 +73,7 @@ struct BusState {
const char *name;
int allow_hotplug;
int qdev_allocated;
- QLIST_HEAD(, DeviceState) children;
+ QTAILQ_HEAD(, DeviceState) children;
QLIST_ENTRY(BusState) sibling;
};
diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c
index e2f3e32..0ce6406 100644
--- a/hw/s390-virtio-bus.c
+++ b/hw/s390-virtio-bus.c
@@ -274,7 +274,7 @@ VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
DeviceState *dev;
int i;
- QLIST_FOREACH(dev, &bus->bus.children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
_dev = (VirtIOS390Device *)dev;
for(i = 0; i < VIRTIO_PCI_QUEUE_MAX; i++) {
if (!virtio_queue_get_addr(_dev->vdev, i))
@@ -297,7 +297,7 @@ VirtIOS390Device *s390_virtio_bus_find_mem(VirtIOS390Bus *bus, ram_addr_t mem)
VirtIOS390Device *_dev;
DeviceState *dev;
- QLIST_FOREACH(dev, &bus->bus.children, sibling) {
+ QTAILQ_FOREACH(dev, &bus->bus.children, sibling) {
_dev = (VirtIOS390Device *)dev;
if (_dev->dev_offs == mem) {
return _dev;
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 35818e1..977603f 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -63,7 +63,7 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
DeviceState *qdev;
VIOsPAPRDevice *dev = NULL;
- QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+ QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
dev = (VIOsPAPRDevice *)qdev;
if (dev->reg == reg) {
break;
@@ -588,7 +588,7 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
return;
}
- QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+ QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
dev = (VIOsPAPRDevice *)qdev;
spapr_vio_quiesce_one(dev);
}
@@ -726,7 +726,7 @@ int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt)
DeviceState *qdev;
int ret = 0;
- QLIST_FOREACH(qdev, &bus->bus.children, sibling) {
+ QTAILQ_FOREACH(qdev, &bus->bus.children, sibling) {
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
ret = vio_make_devnode(dev, fdt);
diff --git a/hw/ssi.c b/hw/ssi.c
index 3f4c5f9..9842fe7 100644
--- a/hw/ssi.c
+++ b/hw/ssi.c
@@ -25,8 +25,8 @@ static int ssi_slave_init(DeviceState *dev, DeviceInfo *base_info)
SSIBus *bus;
bus = FROM_QBUS(SSIBus, qdev_get_parent_bus(dev));
- if (QLIST_FIRST(&bus->qbus.children) != dev
- || QLIST_NEXT(dev, sibling) != NULL) {
+ if (QTAILQ_FIRST(&bus->qbus.children) != dev
+ || QTAILQ_NEXT(dev, sibling) != NULL) {
hw_error("Too many devices on SSI bus");
}
@@ -61,7 +61,7 @@ uint32_t ssi_transfer(SSIBus *bus, uint32_t val)
{
DeviceState *dev;
SSISlave *slave;
- dev = QLIST_FIRST(&bus->qbus.children);
+ dev = QTAILQ_FIRST(&bus->qbus.children);
if (!dev) {
return 0;
}
--
1.7.6.4
^ permalink raw reply related
* [Qemu-devel] [PATCH 30/55] scsi-disk: report media changed via GET EVENT STATUS NOTIFICATION
From: Kevin Wolf @ 2011-10-31 13:30 UTC (permalink / raw)
To: anthony; +Cc: kwolf, qemu-devel
In-Reply-To: <1320067830-12093-1-git-send-email-kwolf@redhat.com>
From: Paolo Bonzini <pbonzini@redhat.com>
This adds support for media change notification via the GET EVENT STATUS
NOTIFICATION command, used by Linux versions 2.6.38 and newer.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
hw/scsi-disk.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 8f8a94d..dd2b605 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -72,6 +72,7 @@ struct SCSIDiskState
uint32_t removable;
uint64_t max_lba;
bool media_changed;
+ bool media_event;
QEMUBH *bh;
char *version;
char *serial;
@@ -687,11 +688,58 @@ fail:
return -1;
}
-static int scsi_get_event_status_notification(SCSIDiskState *s,
- SCSIDiskReq *r, uint8_t *outbuf)
+static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
{
- scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
- return -1;
+ uint8_t event_code, media_status;
+
+ media_status = 0;
+ if (s->tray_open) {
+ media_status = MS_TRAY_OPEN;
+ } else if (bdrv_is_inserted(s->bs)) {
+ media_status = MS_MEDIA_PRESENT;
+ }
+
+ /* Event notification descriptor */
+ event_code = MEC_NO_CHANGE;
+ if (media_status != MS_TRAY_OPEN && s->media_event) {
+ event_code = MEC_NEW_MEDIA;
+ s->media_event = false;
+ }
+
+ outbuf[0] = event_code;
+ outbuf[1] = media_status;
+
+ /* These fields are reserved, just clear them. */
+ outbuf[2] = 0;
+ outbuf[3] = 0;
+ return 4;
+}
+
+static int scsi_get_event_status_notification(SCSIDiskState *s, SCSIDiskReq *r,
+ uint8_t *outbuf)
+{
+ int size;
+ uint8_t *buf = r->req.cmd.buf;
+ uint8_t notification_class_request = buf[4];
+ if (s->qdev.type != TYPE_ROM) {
+ return -1;
+ }
+ if ((buf[1] & 1) == 0) {
+ /* asynchronous */
+ return -1;
+ }
+
+ size = 4;
+ outbuf[0] = outbuf[1] = 0;
+ outbuf[3] = 1 << GESN_MEDIA; /* supported events */
+ if (notification_class_request & (1 << GESN_MEDIA)) {
+ outbuf[2] = GESN_MEDIA;
+ size += scsi_event_status_media(s, &outbuf[size]);
+ } else {
+ outbuf[2] = 0x80;
+ }
+ stw_be_p(outbuf, size - 4);
+ return size;
}
static int scsi_get_configuration(SCSIDiskState *s, uint8_t *outbuf)
@@ -1442,6 +1490,7 @@ static void scsi_cd_change_media_cb(void *opaque, bool load)
s->media_changed = load;
s->tray_open = !load;
s->qdev.unit_attention = SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM);
+ s->media_event = true;
}
static bool scsi_cd_is_tray_open(void *opaque)
--
1.7.6.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.