提交 5c6c0e51 编写于 作者: H Hannes Reinecke 提交者: Paolo Bonzini

scsi: Use 'SCSIRequest' directly

Currently the SCSIRequest structure is abstracted away and cannot accessed
directly from the driver. This requires the handler to do a lookup on
an abstract 'tag' which identifies the SCSIRequest structure.

With this patch the SCSIRequest structure is exposed to the driver. This
allows use to use it directly as an argument to the SCSIDeviceInfo
callback functions and remove the lookup.

A new callback function 'alloc_req' is introduced matching 'free
req'; unref'ing to free up resources after use is moved into the
scsi_command_complete callbacks.

This temporarily introduces a leak of requests that are cancelled,
when they are removed from the queue and not from the driver.  This
is fixed later by introducing scsi_req_cancel.  That patch in turn
depends on this one, because the argument to scsi_req_cancel is a
SCSIRequest.
Signed-off-by: NHannes Reinecke <hare@suse.de>
Signed-off-by: NPaolo Bonzini <pbonzini@redhat.com>
Reviewed-by: NChristoph Hellwig <hch@lst.de>
上级 11257187
...@@ -65,6 +65,7 @@ struct ESPState { ...@@ -65,6 +65,7 @@ struct ESPState {
uint32_t dma; uint32_t dma;
SCSIBus bus; SCSIBus bus;
SCSIDevice *current_dev; SCSIDevice *current_dev;
SCSIRequest *current_req;
uint8_t cmdbuf[TI_BUFSZ]; uint8_t cmdbuf[TI_BUFSZ];
uint32_t cmdlen; uint32_t cmdlen;
uint32_t do_cmd; uint32_t do_cmd;
...@@ -209,7 +210,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf) ...@@ -209,7 +210,7 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
if (s->current_dev) { if (s->current_dev) {
/* Started a new command before the old one finished. Cancel it. */ /* Started a new command before the old one finished. Cancel it. */
s->current_dev->info->cancel_io(s->current_dev, 0); s->current_dev->info->cancel_io(s->current_req);
s->async_len = 0; s->async_len = 0;
} }
...@@ -232,7 +233,8 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) ...@@ -232,7 +233,8 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
DPRINTF("do_busid_cmd: busid 0x%x\n", busid); DPRINTF("do_busid_cmd: busid 0x%x\n", busid);
lun = busid & 7; lun = busid & 7;
datalen = s->current_dev->info->send_command(s->current_dev, 0, buf, lun); s->current_req = s->current_dev->info->alloc_req(s->current_dev, 0, lun);
datalen = s->current_dev->info->send_command(s->current_req, buf);
s->ti_size = datalen; s->ti_size = datalen;
if (datalen != 0) { if (datalen != 0) {
s->rregs[ESP_RSTAT] = STAT_TC; s->rregs[ESP_RSTAT] = STAT_TC;
...@@ -240,10 +242,10 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) ...@@ -240,10 +242,10 @@ static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
s->dma_counter = 0; s->dma_counter = 0;
if (datalen > 0) { if (datalen > 0) {
s->rregs[ESP_RSTAT] |= STAT_DI; s->rregs[ESP_RSTAT] |= STAT_DI;
s->current_dev->info->read_data(s->current_dev, 0); s->current_dev->info->read_data(s->current_req);
} else { } else {
s->rregs[ESP_RSTAT] |= STAT_DO; s->rregs[ESP_RSTAT] |= STAT_DO;
s->current_dev->info->write_data(s->current_dev, 0); s->current_dev->info->write_data(s->current_req);
} }
} }
s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
...@@ -372,9 +374,9 @@ static void esp_do_dma(ESPState *s) ...@@ -372,9 +374,9 @@ static void esp_do_dma(ESPState *s)
if (s->async_len == 0) { if (s->async_len == 0) {
if (to_device) { if (to_device) {
// ti_size is negative // ti_size is negative
s->current_dev->info->write_data(s->current_dev, 0); s->current_dev->info->write_data(s->current_req);
} else { } else {
s->current_dev->info->read_data(s->current_dev, 0); s->current_dev->info->read_data(s->current_req);
/* If there is still data to be read from the device then /* If there is still data to be read from the device then
complete the DMA operation immediately. Otherwise defer complete the DMA operation immediately. Otherwise defer
until the scsi layer has completed. */ until the scsi layer has completed. */
...@@ -388,10 +390,9 @@ static void esp_do_dma(ESPState *s) ...@@ -388,10 +390,9 @@ static void esp_do_dma(ESPState *s)
} }
} }
static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag, static void esp_command_complete(SCSIRequest *req, int reason, uint32_t arg)
uint32_t arg)
{ {
ESPState *s = DO_UPCAST(ESPState, busdev.qdev, bus->qbus.parent); ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent);
if (reason == SCSI_REASON_DONE) { if (reason == SCSI_REASON_DONE) {
DPRINTF("SCSI Command complete\n"); DPRINTF("SCSI Command complete\n");
...@@ -405,11 +406,15 @@ static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag, ...@@ -405,11 +406,15 @@ static void esp_command_complete(SCSIBus *bus, int reason, uint32_t tag,
s->sense = arg; s->sense = arg;
s->rregs[ESP_RSTAT] = STAT_ST; s->rregs[ESP_RSTAT] = STAT_ST;
esp_dma_done(s); esp_dma_done(s);
s->current_dev = NULL; if (s->current_req) {
scsi_req_unref(s->current_req);
s->current_req = NULL;
s->current_dev = NULL;
}
} else { } else {
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
s->async_len = arg; s->async_len = arg;
s->async_buf = s->current_dev->info->get_buf(s->current_dev, 0); s->async_buf = s->current_dev->info->get_buf(req);
if (s->dma_left) { if (s->dma_left) {
esp_do_dma(s); esp_do_dma(s);
} else if (s->dma_counter != 0 && s->ti_size <= 0) { } else if (s->dma_counter != 0 && s->ti_size <= 0) {
......
...@@ -174,6 +174,7 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) ...@@ -174,6 +174,7 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
#define LSI_TAG_VALID (1 << 16) #define LSI_TAG_VALID (1 << 16)
typedef struct lsi_request { typedef struct lsi_request {
SCSIRequest *req;
uint32_t tag; uint32_t tag;
uint32_t dma_len; uint32_t dma_len;
uint8_t *dma_buf; uint8_t *dma_buf;
...@@ -567,11 +568,9 @@ static void lsi_do_dma(LSIState *s, int out) ...@@ -567,11 +568,9 @@ static void lsi_do_dma(LSIState *s, int out)
s->csbc += count; s->csbc += count;
s->dnad += count; s->dnad += count;
s->dbc -= count; s->dbc -= count;
if (s->current->dma_buf == NULL) {
if (s->current->dma_buf == NULL) { s->current->dma_buf = dev->info->get_buf(s->current->req);
s->current->dma_buf = dev->info->get_buf(dev, s->current->tag);
} }
/* ??? Set SFBR to first data byte. */ /* ??? Set SFBR to first data byte. */
if (out) { if (out) {
cpu_physical_memory_read(addr, s->current->dma_buf, count); cpu_physical_memory_read(addr, s->current->dma_buf, count);
...@@ -583,10 +582,10 @@ static void lsi_do_dma(LSIState *s, int out) ...@@ -583,10 +582,10 @@ static void lsi_do_dma(LSIState *s, int out)
s->current->dma_buf = NULL; s->current->dma_buf = NULL;
if (out) { if (out) {
/* Write the data. */ /* Write the data. */
dev->info->write_data(dev, s->current->tag); dev->info->write_data(s->current->req);
} else { } else {
/* Request any remaining data. */ /* Request any remaining data. */
dev->info->read_data(dev, s->current->tag); dev->info->read_data(s->current->req);
} }
} else { } else {
s->current->dma_buf += count; s->current->dma_buf += count;
...@@ -698,12 +697,10 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) ...@@ -698,12 +697,10 @@ static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg)
return 1; return 1;
} }
} }
/* Callback to indicate that the SCSI layer has completed a transfer. */
/* Callback to indicate that the SCSI layer has completed a transfer. */ static void lsi_command_complete(SCSIRequest *req, int reason, uint32_t arg)
static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
uint32_t arg)
{ {
LSIState *s = DO_UPCAST(LSIState, dev.qdev, bus->qbus.parent); LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent);
int out; int out;
out = (s->sstat1 & PHASE_MASK) == PHASE_DO; out = (s->sstat1 & PHASE_MASK) == PHASE_DO;
...@@ -718,21 +715,24 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, ...@@ -718,21 +715,24 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
lsi_set_phase(s, PHASE_ST); lsi_set_phase(s, PHASE_ST);
} }
qemu_free(s->current); if (s->current && req == s->current->req) {
s->current = NULL; scsi_req_unref(s->current->req);
qemu_free(s->current);
s->current = NULL;
}
lsi_resume_script(s); lsi_resume_script(s);
return; return;
} }
if (s->waiting == 1 || !s->current || tag != s->current->tag || if (s->waiting == 1 || !s->current || req->tag != s->current->tag ||
(lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) { (lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON))) {
if (lsi_queue_tag(s, tag, arg)) if (lsi_queue_tag(s, req->tag, arg)) {
return; return;
}
} }
/* host adapter (re)connected */ /* host adapter (re)connected */
DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg); DPRINTF("Data ready tag=0x%x len=%d\n", req->tag, arg);
s->current->dma_len = arg; s->current->dma_len = arg;
s->command_complete = 1; s->command_complete = 1;
if (!s->waiting) if (!s->waiting)
...@@ -768,14 +768,16 @@ static void lsi_do_command(LSIState *s) ...@@ -768,14 +768,16 @@ static void lsi_do_command(LSIState *s)
assert(s->current == NULL); assert(s->current == NULL);
s->current = qemu_mallocz(sizeof(lsi_request)); s->current = qemu_mallocz(sizeof(lsi_request));
s->current->tag = s->select_tag; s->current->tag = s->select_tag;
s->current->req = dev->info->alloc_req(dev, s->current->tag,
s->current_lun);
n = dev->info->send_command(dev, s->current->tag, buf, s->current_lun); n = dev->info->send_command(s->current->req, buf);
if (n > 0) { if (n > 0) {
lsi_set_phase(s, PHASE_DI); lsi_set_phase(s, PHASE_DI);
dev->info->read_data(dev, s->current->tag); dev->info->read_data(s->current->req);
} else if (n < 0) { } else if (n < 0) {
lsi_set_phase(s, PHASE_DO); lsi_set_phase(s, PHASE_DO);
dev->info->write_data(dev, s->current->tag); dev->info->write_data(s->current->req);
} }
if (!s->command_complete) { if (!s->command_complete) {
...@@ -868,13 +870,15 @@ static void lsi_do_msgout(LSIState *s) ...@@ -868,13 +870,15 @@ static void lsi_do_msgout(LSIState *s)
int len; int len;
uint32_t current_tag; uint32_t current_tag;
SCSIDevice *current_dev; SCSIDevice *current_dev;
lsi_request *p, *p_next; lsi_request *current_req, *p, *p_next;
int id; int id;
if (s->current) { if (s->current) {
current_tag = s->current->tag; current_tag = s->current->tag;
current_req = s->current;
} else { } else {
current_tag = s->select_tag; current_tag = s->select_tag;
current_req = lsi_find_by_tag(s, current_tag);
} }
id = (current_tag >> 8) & 0xf; id = (current_tag >> 8) & 0xf;
current_dev = s->bus.devs[id]; current_dev = s->bus.devs[id];
...@@ -926,7 +930,9 @@ static void lsi_do_msgout(LSIState *s) ...@@ -926,7 +930,9 @@ static void lsi_do_msgout(LSIState *s)
case 0x0d: case 0x0d:
/* The ABORT TAG message clears the current I/O process only. */ /* The ABORT TAG message clears the current I/O process only. */
DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag); DPRINTF("MSG: ABORT TAG tag=0x%x\n", current_tag);
current_dev->info->cancel_io(current_dev, current_tag); if (current_req) {
current_dev->info->cancel_io(current_req->req);
}
lsi_disconnect(s); lsi_disconnect(s);
break; break;
case 0x06: case 0x06:
...@@ -949,7 +955,9 @@ static void lsi_do_msgout(LSIState *s) ...@@ -949,7 +955,9 @@ static void lsi_do_msgout(LSIState *s)
} }
/* clear the current I/O process */ /* clear the current I/O process */
current_dev->info->cancel_io(current_dev, current_tag); if (s->current) {
current_dev->info->cancel_io(s->current->req);
}
/* As the current implemented devices scsi_disk and scsi_generic /* As the current implemented devices scsi_disk and scsi_generic
only support one LUN, we don't need to keep track of LUNs. only support one LUN, we don't need to keep track of LUNs.
...@@ -961,7 +969,7 @@ static void lsi_do_msgout(LSIState *s) ...@@ -961,7 +969,7 @@ static void lsi_do_msgout(LSIState *s)
id = current_tag & 0x0000ff00; id = current_tag & 0x0000ff00;
QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) { QTAILQ_FOREACH_SAFE(p, &s->queue, next, p_next) {
if ((p->tag & 0x0000ff00) == id) { if ((p->tag & 0x0000ff00) == id) {
current_dev->info->cancel_io(current_dev, p->tag); current_dev->info->cancel_io(p->req);
QTAILQ_REMOVE(&s->queue, p, next); QTAILQ_REMOVE(&s->queue, p, next);
} }
} }
......
...@@ -136,29 +136,22 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l ...@@ -136,29 +136,22 @@ SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t l
SCSIRequest *req; SCSIRequest *req;
req = qemu_mallocz(size); req = qemu_mallocz(size);
/* Two references: one is passed back to the HBA, one is in d->requests. */ req->refcount = 1;
req->refcount = 2;
req->bus = scsi_bus_from_device(d); req->bus = scsi_bus_from_device(d);
req->dev = d; req->dev = d;
req->tag = tag; req->tag = tag;
req->lun = lun; req->lun = lun;
req->status = -1; req->status = -1;
req->enqueued = true;
trace_scsi_req_alloc(req->dev->id, req->lun, req->tag); trace_scsi_req_alloc(req->dev->id, req->lun, req->tag);
QTAILQ_INSERT_TAIL(&d->requests, req, next);
return req; return req;
} }
SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag) void scsi_req_enqueue(SCSIRequest *req)
{ {
SCSIRequest *req; assert(!req->enqueued);
scsi_req_ref(req);
QTAILQ_FOREACH(req, &d->requests, next) { req->enqueued = true;
if (req->tag == tag) { QTAILQ_INSERT_TAIL(&req->dev->requests, req, next);
return req;
}
}
return NULL;
} }
void scsi_req_dequeue(SCSIRequest *req) void scsi_req_dequeue(SCSIRequest *req)
...@@ -516,7 +509,7 @@ void scsi_req_unref(SCSIRequest *req) ...@@ -516,7 +509,7 @@ void scsi_req_unref(SCSIRequest *req)
void scsi_req_data(SCSIRequest *req, int len) void scsi_req_data(SCSIRequest *req, int len)
{ {
trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); trace_scsi_req_data(req->dev->id, req->lun, req->tag, len);
req->bus->ops->complete(req->bus, SCSI_REASON_DATA, req->tag, len); req->bus->ops->complete(req, SCSI_REASON_DATA, len);
} }
void scsi_req_print(SCSIRequest *req) void scsi_req_print(SCSIRequest *req)
...@@ -552,9 +545,7 @@ void scsi_req_complete(SCSIRequest *req) ...@@ -552,9 +545,7 @@ void scsi_req_complete(SCSIRequest *req)
assert(req->status != -1); assert(req->status != -1);
scsi_req_ref(req); scsi_req_ref(req);
scsi_req_dequeue(req); scsi_req_dequeue(req);
req->bus->ops->complete(req->bus, SCSI_REASON_DONE, req->bus->ops->complete(req, SCSI_REASON_DONE, req->status);
req->tag,
req->status);
scsi_req_unref(req); scsi_req_unref(req);
} }
......
...@@ -86,16 +86,17 @@ struct SCSIDiskState ...@@ -86,16 +86,17 @@ struct SCSIDiskState
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type); static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type);
static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf); static int scsi_disk_emulate_command(SCSIDiskReq *r, uint8_t *outbuf);
static SCSIDiskReq *scsi_new_request(SCSIDiskState *s, uint32_t tag, static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag,
uint32_t lun) uint32_t lun)
{ {
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIRequest *req; SCSIRequest *req;
SCSIDiskReq *r; SCSIDiskReq *r;
req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun); req = scsi_req_alloc(sizeof(SCSIDiskReq), &s->qdev, tag, lun);
r = DO_UPCAST(SCSIDiskReq, req, req); r = DO_UPCAST(SCSIDiskReq, req, req);
r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE); r->iov.iov_base = qemu_blockalign(s->bs, SCSI_DMA_BUF_SIZE);
return r; return req;
} }
static void scsi_free_request(SCSIRequest *req) static void scsi_free_request(SCSIRequest *req)
...@@ -105,11 +106,6 @@ static void scsi_free_request(SCSIRequest *req) ...@@ -105,11 +106,6 @@ static void scsi_free_request(SCSIRequest *req)
qemu_vfree(r->iov.iov_base); qemu_vfree(r->iov.iov_base);
} }
static SCSIDiskReq *scsi_find_request(SCSIDiskState *s, uint32_t tag)
{
return DO_UPCAST(SCSIDiskReq, req, scsi_req_find(&s->qdev, tag));
}
static void scsi_disk_clear_sense(SCSIDiskState *s) static void scsi_disk_clear_sense(SCSIDiskState *s)
{ {
memset(&s->sense, 0, sizeof(s->sense)); memset(&s->sense, 0, sizeof(s->sense));
...@@ -138,18 +134,16 @@ static void scsi_command_complete(SCSIDiskReq *r, int status, int sense) ...@@ -138,18 +134,16 @@ static void scsi_command_complete(SCSIDiskReq *r, int status, int sense)
} }
/* Cancel a pending data transfer. */ /* Cancel a pending data transfer. */
static void scsi_cancel_io(SCSIDevice *d, uint32_t tag) static void scsi_cancel_io(SCSIRequest *req)
{ {
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
SCSIDiskReq *r;
DPRINTF("Cancel tag=0x%x\n", tag); DPRINTF("Cancel tag=0x%x\n", req->tag);
r = scsi_find_request(s, tag); if (r->req.aiocb) {
if (r) { bdrv_aio_cancel(r->req.aiocb);
if (r->req.aiocb)
bdrv_aio_cancel(r->req.aiocb);
r->req.aiocb = NULL;
scsi_req_dequeue(&r->req);
} }
r->req.aiocb = NULL;
scsi_req_dequeue(&r->req);
} }
static void scsi_read_complete(void * opaque, int ret) static void scsi_read_complete(void * opaque, int ret)
...@@ -174,8 +168,10 @@ static void scsi_read_complete(void * opaque, int ret) ...@@ -174,8 +168,10 @@ static void scsi_read_complete(void * opaque, int ret)
} }
static void scsi_read_request(SCSIDiskReq *r) /* Read more data from scsi device into buffer. */
static void scsi_read_data(SCSIRequest *req)
{ {
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n; uint32_t n;
...@@ -207,23 +203,6 @@ static void scsi_read_request(SCSIDiskReq *r) ...@@ -207,23 +203,6 @@ static void scsi_read_request(SCSIDiskReq *r)
} }
} }
/* Read more data from scsi device into buffer. */
static void scsi_read_data(SCSIDevice *d, uint32_t tag)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIDiskReq *r;
r = scsi_find_request(s, tag);
if (!r) {
BADF("Bad read tag 0x%x\n", tag);
/* ??? This is the wrong error. */
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
return;
}
scsi_read_request(r);
}
static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type) static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type)
{ {
int is_read = (type == SCSI_REQ_STATUS_RETRY_READ); int is_read = (type == SCSI_REQ_STATUS_RETRY_READ);
...@@ -285,8 +264,9 @@ static void scsi_write_complete(void * opaque, int ret) ...@@ -285,8 +264,9 @@ static void scsi_write_complete(void * opaque, int ret)
} }
} }
static void scsi_write_request(SCSIDiskReq *r) static int scsi_write_data(SCSIRequest *req)
{ {
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint32_t n; uint32_t n;
...@@ -305,24 +285,6 @@ static void scsi_write_request(SCSIDiskReq *r) ...@@ -305,24 +285,6 @@ static void scsi_write_request(SCSIDiskReq *r)
/* Invoke completion routine to fetch data from host. */ /* Invoke completion routine to fetch data from host. */
scsi_write_complete(r, 0); scsi_write_complete(r, 0);
} }
}
/* Write data to a scsi device. Returns nonzero on failure.
The transfer may complete asynchronously. */
static int scsi_write_data(SCSIDevice *d, uint32_t tag)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
SCSIDiskReq *r;
DPRINTF("Write data tag=0x%x\n", tag);
r = scsi_find_request(s, tag);
if (!r) {
BADF("Bad write tag 0x%x\n", tag);
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
return 1;
}
scsi_write_request(r);
return 0; return 0;
} }
...@@ -347,10 +309,10 @@ static void scsi_dma_restart_bh(void *opaque) ...@@ -347,10 +309,10 @@ static void scsi_dma_restart_bh(void *opaque)
switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) { switch (status & SCSI_REQ_STATUS_RETRY_TYPE_MASK) {
case SCSI_REQ_STATUS_RETRY_READ: case SCSI_REQ_STATUS_RETRY_READ:
scsi_read_request(r); scsi_read_data(&r->req);
break; break;
case SCSI_REQ_STATUS_RETRY_WRITE: case SCSI_REQ_STATUS_RETRY_WRITE:
scsi_write_request(r); scsi_write_data(&r->req);
break; break;
case SCSI_REQ_STATUS_RETRY_FLUSH: case SCSI_REQ_STATUS_RETRY_FLUSH:
ret = scsi_disk_emulate_command(r, r->iov.iov_base); ret = scsi_disk_emulate_command(r, r->iov.iov_base);
...@@ -376,16 +338,10 @@ static void scsi_dma_restart_cb(void *opaque, int running, int reason) ...@@ -376,16 +338,10 @@ static void scsi_dma_restart_cb(void *opaque, int running, int reason)
} }
/* Return a pointer to the data buffer. */ /* Return a pointer to the data buffer. */
static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) static uint8_t *scsi_get_buf(SCSIRequest *req)
{ {
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
SCSIDiskReq *r;
r = scsi_find_request(s, tag);
if (!r) {
BADF("Bad buffer tag 0x%x\n", tag);
return NULL;
}
return (uint8_t *)r->iov.iov_base; return (uint8_t *)r->iov.iov_base;
} }
...@@ -1029,26 +985,18 @@ illegal_request: ...@@ -1029,26 +985,18 @@ illegal_request:
(eg. disk reads), negative for transfers to the device (eg. disk writes), (eg. disk reads), negative for transfers to the device (eg. disk writes),
and zero if the command does not transfer any data. */ and zero if the command does not transfer any data. */
static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
uint8_t *buf, int lun)
{ {
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d); SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
int32_t len; int32_t len;
int is_write; int is_write;
uint8_t command; uint8_t command;
uint8_t *outbuf; uint8_t *outbuf;
SCSIDiskReq *r;
int rc; int rc;
scsi_req_enqueue(req);
command = buf[0]; command = buf[0];
r = scsi_find_request(s, tag);
if (r) {
BADF("Tag 0x%x already in use\n", tag);
scsi_cancel_io(d, tag);
}
/* ??? Tags are not unique for different luns. We only implement a
single lun, so this should not matter. */
r = scsi_new_request(s, tag, lun);
outbuf = (uint8_t *)r->iov.iov_base; outbuf = (uint8_t *)r->iov.iov_base;
is_write = 0; is_write = 0;
DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]); DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
...@@ -1067,9 +1015,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, ...@@ -1067,9 +1015,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
} }
#endif #endif
if (lun || buf[1] >> 5) { if (req->lun || buf[1] >> 5) {
/* Only LUN 0 supported. */ /* Only LUN 0 supported. */
DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5); DPRINTF("Unimplemented LUN %d\n", req->lun ? req->lun : buf[1] >> 5);
if (command != REQUEST_SENSE && command != INQUIRY) if (command != REQUEST_SENSE && command != INQUIRY)
goto fail; goto fail;
} }
...@@ -1095,7 +1043,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, ...@@ -1095,7 +1043,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case REZERO_UNIT: case REZERO_UNIT:
rc = scsi_disk_emulate_command(r, outbuf); rc = scsi_disk_emulate_command(r, outbuf);
if (rc < 0) { if (rc < 0) {
scsi_req_unref(&r->req);
return 0; return 0;
} }
...@@ -1105,7 +1052,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, ...@@ -1105,7 +1052,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case READ_10: case READ_10:
case READ_12: case READ_12:
case READ_16: case READ_16:
len = r->req.cmd.xfer / d->blocksize; len = r->req.cmd.xfer / s->qdev.blocksize;
DPRINTF("Read (sector %" PRId64 ", count %d)\n", r->req.cmd.lba, len); 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->max_lba)
goto illegal_lba; goto illegal_lba;
...@@ -1119,7 +1066,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, ...@@ -1119,7 +1066,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
case WRITE_VERIFY: case WRITE_VERIFY:
case WRITE_VERIFY_12: case WRITE_VERIFY_12:
case WRITE_VERIFY_16: case WRITE_VERIFY_16:
len = r->req.cmd.xfer / d->blocksize; len = r->req.cmd.xfer / s->qdev.blocksize;
DPRINTF("Write %s(sector %" PRId64 ", count %d)\n", DPRINTF("Write %s(sector %" PRId64 ", count %d)\n",
(command & 0xe) == 0xe ? "And Verify " : "", (command & 0xe) == 0xe ? "And Verify " : "",
r->req.cmd.lba, len); r->req.cmd.lba, len);
...@@ -1154,7 +1101,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, ...@@ -1154,7 +1101,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
} }
break; break;
case WRITE_SAME_16: case WRITE_SAME_16:
len = r->req.cmd.xfer / d->blocksize; len = r->req.cmd.xfer / s->qdev.blocksize;
DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n", DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
r->req.cmd.lba, len); r->req.cmd.lba, len);
...@@ -1182,11 +1129,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, ...@@ -1182,11 +1129,9 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
fail: fail:
scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST); scsi_command_complete(r, CHECK_CONDITION, ILLEGAL_REQUEST);
scsi_req_unref(&r->req);
return 0; return 0;
illegal_lba: illegal_lba:
scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR); scsi_command_complete(r, CHECK_CONDITION, HARDWARE_ERROR);
scsi_req_unref(&r->req);
return 0; return 0;
} }
if (r->sector_count == 0 && r->iov.iov_len == 0) { if (r->sector_count == 0 && r->iov.iov_len == 0) {
...@@ -1199,7 +1144,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, ...@@ -1199,7 +1144,6 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
if (!r->sector_count) if (!r->sector_count)
r->sector_count = -1; r->sector_count = -1;
} }
scsi_req_unref(&r->req);
return len; return len;
} }
...@@ -1213,6 +1157,7 @@ static void scsi_disk_purge_requests(SCSIDiskState *s) ...@@ -1213,6 +1157,7 @@ static void scsi_disk_purge_requests(SCSIDiskState *s)
bdrv_aio_cancel(r->req.aiocb); bdrv_aio_cancel(r->req.aiocb);
} }
scsi_req_dequeue(&r->req); scsi_req_dequeue(&r->req);
scsi_req_unref(&r->req);
} }
} }
...@@ -1325,6 +1270,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { ...@@ -1325,6 +1270,7 @@ static SCSIDeviceInfo scsi_disk_info[] = {
.qdev.reset = scsi_disk_reset, .qdev.reset = scsi_disk_reset,
.init = scsi_hd_initfn, .init = scsi_hd_initfn,
.destroy = scsi_destroy, .destroy = scsi_destroy,
.alloc_req = scsi_new_request,
.free_req = scsi_free_request, .free_req = scsi_free_request,
.send_command = scsi_send_command, .send_command = scsi_send_command,
.read_data = scsi_read_data, .read_data = scsi_read_data,
...@@ -1344,6 +1290,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { ...@@ -1344,6 +1290,7 @@ static SCSIDeviceInfo scsi_disk_info[] = {
.qdev.reset = scsi_disk_reset, .qdev.reset = scsi_disk_reset,
.init = scsi_cd_initfn, .init = scsi_cd_initfn,
.destroy = scsi_destroy, .destroy = scsi_destroy,
.alloc_req = scsi_new_request,
.free_req = scsi_free_request, .free_req = scsi_free_request,
.send_command = scsi_send_command, .send_command = scsi_send_command,
.read_data = scsi_read_data, .read_data = scsi_read_data,
...@@ -1362,6 +1309,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { ...@@ -1362,6 +1309,7 @@ static SCSIDeviceInfo scsi_disk_info[] = {
.qdev.reset = scsi_disk_reset, .qdev.reset = scsi_disk_reset,
.init = scsi_disk_initfn, .init = scsi_disk_initfn,
.destroy = scsi_destroy, .destroy = scsi_destroy,
.alloc_req = scsi_new_request,
.free_req = scsi_free_request, .free_req = scsi_free_request,
.send_command = scsi_send_command, .send_command = scsi_send_command,
.read_data = scsi_read_data, .read_data = scsi_read_data,
......
...@@ -66,12 +66,12 @@ struct SCSIGenericState ...@@ -66,12 +66,12 @@ struct SCSIGenericState
uint8_t senselen; uint8_t senselen;
}; };
static SCSIGenericReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun) static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
{ {
SCSIRequest *req; SCSIRequest *req;
req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun); req = scsi_req_alloc(sizeof(SCSIGenericReq), d, tag, lun);
return DO_UPCAST(SCSIGenericReq, req, req); return req;
} }
static void scsi_free_request(SCSIRequest *req) static void scsi_free_request(SCSIRequest *req)
...@@ -81,11 +81,6 @@ static void scsi_free_request(SCSIRequest *req) ...@@ -81,11 +81,6 @@ static void scsi_free_request(SCSIRequest *req)
qemu_free(r->buf); qemu_free(r->buf);
} }
static SCSIGenericReq *scsi_find_request(SCSIGenericState *s, uint32_t tag)
{
return DO_UPCAST(SCSIGenericReq, req, scsi_req_find(&s->qdev, tag));
}
/* Helper function for command completion. */ /* Helper function for command completion. */
static void scsi_command_complete(void *opaque, int ret) static void scsi_command_complete(void *opaque, int ret)
{ {
...@@ -117,19 +112,16 @@ static void scsi_command_complete(void *opaque, int ret) ...@@ -117,19 +112,16 @@ static void scsi_command_complete(void *opaque, int ret)
} }
/* Cancel a pending data transfer. */ /* Cancel a pending data transfer. */
static void scsi_cancel_io(SCSIDevice *d, uint32_t tag) static void scsi_cancel_io(SCSIRequest *req)
{ {
DPRINTF("scsi_cancel_io 0x%x\n", tag); SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d);
SCSIGenericReq *r; DPRINTF("Cancel tag=0x%x\n", req->tag);
DPRINTF("Cancel tag=0x%x\n", tag); if (r->req.aiocb) {
r = scsi_find_request(s, tag); bdrv_aio_cancel(r->req.aiocb);
if (r) {
if (r->req.aiocb)
bdrv_aio_cancel(r->req.aiocb);
r->req.aiocb = NULL;
scsi_req_dequeue(&r->req);
} }
r->req.aiocb = NULL;
scsi_req_dequeue(&r->req);
} }
static int execute_command(BlockDriverState *bdrv, static int execute_command(BlockDriverState *bdrv,
...@@ -182,21 +174,13 @@ static void scsi_read_complete(void * opaque, int ret) ...@@ -182,21 +174,13 @@ static void scsi_read_complete(void * opaque, int ret)
} }
/* Read more data from scsi device into buffer. */ /* Read more data from scsi device into buffer. */
static void scsi_read_data(SCSIDevice *d, uint32_t tag) static void scsi_read_data(SCSIRequest *req)
{ {
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
SCSIGenericReq *r; SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, r->req.dev);
int ret; int ret;
DPRINTF("scsi_read_data 0x%x\n", tag); DPRINTF("scsi_read_data 0x%x\n", req->tag);
r = scsi_find_request(s, tag);
if (!r) {
BADF("Bad read tag 0x%x\n", tag);
/* ??? This is the wrong error. */
scsi_command_complete(r, -EINVAL);
return;
}
if (r->len == -1) { if (r->len == -1) {
scsi_command_complete(r, 0); scsi_command_complete(r, 0);
return; return;
...@@ -249,21 +233,13 @@ static void scsi_write_complete(void * opaque, int ret) ...@@ -249,21 +233,13 @@ static void scsi_write_complete(void * opaque, int ret)
/* Write data to a scsi device. Returns nonzero on failure. /* Write data to a scsi device. Returns nonzero on failure.
The transfer may complete asynchronously. */ The transfer may complete asynchronously. */
static int scsi_write_data(SCSIDevice *d, uint32_t tag) static int scsi_write_data(SCSIRequest *req)
{ {
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
SCSIGenericReq *r; SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
int ret; int ret;
DPRINTF("scsi_write_data 0x%x\n", tag); DPRINTF("scsi_write_data 0x%x\n", req->tag);
r = scsi_find_request(s, tag);
if (!r) {
BADF("Bad write tag 0x%x\n", tag);
/* ??? This is the wrong error. */
scsi_command_complete(r, -EINVAL);
return 0;
}
if (r->len == 0) { if (r->len == 0) {
r->len = r->buflen; r->len = r->buflen;
scsi_req_data(&r->req, r->len); scsi_req_data(&r->req, r->len);
...@@ -280,15 +256,10 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) ...@@ -280,15 +256,10 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
} }
/* Return a pointer to the data buffer. */ /* Return a pointer to the data buffer. */
static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) static uint8_t *scsi_get_buf(SCSIRequest *req)
{ {
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
SCSIGenericReq *r;
r = scsi_find_request(s, tag);
if (!r) {
BADF("Bad buffer tag 0x%x\n", tag);
return NULL;
}
return r->buf; return r->buf;
} }
...@@ -316,18 +287,17 @@ static void scsi_req_fixup(SCSIRequest *req) ...@@ -316,18 +287,17 @@ static void scsi_req_fixup(SCSIRequest *req)
(eg. disk reads), negative for transfers to the device (eg. disk writes), (eg. disk reads), negative for transfers to the device (eg. disk writes),
and zero if the command does not transfer any data. */ and zero if the command does not transfer any data. */
static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, static int32_t scsi_send_command(SCSIRequest *req, uint8_t *cmd)
uint8_t *cmd, int lun)
{ {
SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, d); SCSIGenericState *s = DO_UPCAST(SCSIGenericState, qdev, req->dev);
SCSIGenericReq *r; SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req);
SCSIBus *bus; SCSIBus *bus;
int ret; int ret;
int32_t len;
scsi_req_enqueue(req);
if (cmd[0] != REQUEST_SENSE && if (cmd[0] != REQUEST_SENSE &&
(lun != s->lun || (cmd[1] >> 5) != s->lun)) { (req->lun != s->lun || (cmd[1] >> 5) != s->lun)) {
DPRINTF("Unimplemented LUN %d\n", lun ? lun : cmd[1] >> 5); DPRINTF("Unimplemented LUN %d\n", req->lun ? req->lun : cmd[1] >> 5);
s->sensebuf[0] = 0x70; s->sensebuf[0] = 0x70;
s->sensebuf[1] = 0x00; s->sensebuf[1] = 0x00;
...@@ -338,18 +308,11 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, ...@@ -338,18 +308,11 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
s->sensebuf[6] = 0x00; s->sensebuf[6] = 0x00;
s->senselen = 7; s->senselen = 7;
s->driver_status = SG_ERR_DRIVER_SENSE; s->driver_status = SG_ERR_DRIVER_SENSE;
bus = scsi_bus_from_device(d); bus = scsi_bus_from_device(&s->qdev);
bus->ops->complete(bus, SCSI_REASON_DONE, tag, CHECK_CONDITION); bus->ops->complete(req, SCSI_REASON_DONE, CHECK_CONDITION);
return 0; return 0;
} }
r = scsi_find_request(s, tag);
if (r) {
BADF("Tag 0x%x already in use %p\n", tag, r);
scsi_cancel_io(d, tag);
}
r = scsi_new_request(d, tag, lun);
if (-1 == scsi_req_parse(&r->req, cmd)) { if (-1 == scsi_req_parse(&r->req, cmd)) {
BADF("Unsupported command length, command %x\n", cmd[0]); BADF("Unsupported command length, command %x\n", cmd[0]);
scsi_req_dequeue(&r->req); scsi_req_dequeue(&r->req);
...@@ -379,10 +342,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, ...@@ -379,10 +342,7 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete); ret = execute_command(s->bs, r, SG_DXFER_NONE, scsi_command_complete);
if (ret == -1) { if (ret == -1) {
scsi_command_complete(r, -EINVAL); scsi_command_complete(r, -EINVAL);
scsi_req_unref(&r->req);
return 0;
} }
scsi_req_unref(&r->req);
return 0; return 0;
} }
...@@ -397,13 +357,10 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag, ...@@ -397,13 +357,10 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
r->len = r->req.cmd.xfer; r->len = r->req.cmd.xfer;
if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
r->len = 0; r->len = 0;
len = -r->req.cmd.xfer; return -r->req.cmd.xfer;
} else { } else {
len = r->req.cmd.xfer; return r->req.cmd.xfer;
} }
scsi_req_unref(&r->req);
return len;
} }
static int get_blocksize(BlockDriverState *bdrv) static int get_blocksize(BlockDriverState *bdrv)
...@@ -477,6 +434,7 @@ static void scsi_generic_purge_requests(SCSIGenericState *s) ...@@ -477,6 +434,7 @@ static void scsi_generic_purge_requests(SCSIGenericState *s)
bdrv_aio_cancel(r->req.aiocb); bdrv_aio_cancel(r->req.aiocb);
} }
scsi_req_dequeue(&r->req); scsi_req_dequeue(&r->req);
scsi_req_unref(&r->req);
} }
} }
...@@ -568,6 +526,7 @@ static SCSIDeviceInfo scsi_generic_info = { ...@@ -568,6 +526,7 @@ static SCSIDeviceInfo scsi_generic_info = {
.qdev.reset = scsi_generic_reset, .qdev.reset = scsi_generic_reset,
.init = scsi_generic_initfn, .init = scsi_generic_initfn,
.destroy = scsi_destroy, .destroy = scsi_destroy,
.alloc_req = scsi_new_request,
.free_req = scsi_free_request, .free_req = scsi_free_request,
.send_command = scsi_send_command, .send_command = scsi_send_command,
.read_data = scsi_read_data, .read_data = scsi_read_data,
......
...@@ -19,6 +19,7 @@ typedef struct SCSIBus SCSIBus; ...@@ -19,6 +19,7 @@ typedef struct SCSIBus SCSIBus;
typedef struct SCSIBusOps SCSIBusOps; typedef struct SCSIBusOps SCSIBusOps;
typedef struct SCSIDevice SCSIDevice; typedef struct SCSIDevice SCSIDevice;
typedef struct SCSIDeviceInfo SCSIDeviceInfo; typedef struct SCSIDeviceInfo SCSIDeviceInfo;
typedef struct SCSIRequest SCSIRequest;
enum SCSIXferMode { enum SCSIXferMode {
SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */ SCSI_XFER_NONE, /* TEST_UNIT_READY, ... */
...@@ -26,7 +27,7 @@ enum SCSIXferMode { ...@@ -26,7 +27,7 @@ enum SCSIXferMode {
SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */ SCSI_XFER_TO_DEV, /* WRITE, MODE_SELECT, ... */
}; };
typedef struct SCSIRequest { struct SCSIRequest {
SCSIBus *bus; SCSIBus *bus;
SCSIDevice *dev; SCSIDevice *dev;
uint32_t refcount; uint32_t refcount;
...@@ -43,7 +44,7 @@ typedef struct SCSIRequest { ...@@ -43,7 +44,7 @@ typedef struct SCSIRequest {
BlockDriverAIOCB *aiocb; BlockDriverAIOCB *aiocb;
bool enqueued; bool enqueued;
QTAILQ_ENTRY(SCSIRequest) next; QTAILQ_ENTRY(SCSIRequest) next;
} SCSIRequest; };
struct SCSIDevice struct SCSIDevice
{ {
...@@ -66,17 +67,17 @@ struct SCSIDeviceInfo { ...@@ -66,17 +67,17 @@ struct SCSIDeviceInfo {
DeviceInfo qdev; DeviceInfo qdev;
scsi_qdev_initfn init; scsi_qdev_initfn init;
void (*destroy)(SCSIDevice *s); void (*destroy)(SCSIDevice *s);
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun);
void (*free_req)(SCSIRequest *req); void (*free_req)(SCSIRequest *req);
int32_t (*send_command)(SCSIDevice *s, uint32_t tag, uint8_t *buf, int32_t (*send_command)(SCSIRequest *req, uint8_t *buf);
int lun); void (*read_data)(SCSIRequest *req);
void (*read_data)(SCSIDevice *s, uint32_t tag); int (*write_data)(SCSIRequest *req);
int (*write_data)(SCSIDevice *s, uint32_t tag); void (*cancel_io)(SCSIRequest *req);
void (*cancel_io)(SCSIDevice *s, uint32_t tag); uint8_t *(*get_buf)(SCSIRequest *req);
uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag);
}; };
struct SCSIBusOps { struct SCSIBusOps {
void (*complete)(SCSIBus *bus, int reason, uint32_t tag, uint32_t arg); void (*complete)(SCSIRequest *req, int reason, uint32_t arg);
}; };
struct SCSIBus { struct SCSIBus {
...@@ -103,7 +104,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv, ...@@ -103,7 +104,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockDriverState *bdrv,
int scsi_bus_legacy_handle_cmdline(SCSIBus *bus); int scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun); SCSIRequest *scsi_req_alloc(size_t size, SCSIDevice *d, uint32_t tag, uint32_t lun);
SCSIRequest *scsi_req_find(SCSIDevice *d, uint32_t tag); void scsi_req_enqueue(SCSIRequest *req);
void scsi_req_free(SCSIRequest *req); void scsi_req_free(SCSIRequest *req);
void scsi_req_dequeue(SCSIRequest *req); void scsi_req_dequeue(SCSIRequest *req);
SCSIRequest *scsi_req_ref(SCSIRequest *req); SCSIRequest *scsi_req_ref(SCSIRequest *req);
......
...@@ -75,6 +75,7 @@ typedef struct vscsi_req { ...@@ -75,6 +75,7 @@ typedef struct vscsi_req {
/* SCSI request tracking */ /* SCSI request tracking */
SCSIDevice *sdev; SCSIDevice *sdev;
SCSIRequest *sreq;
uint32_t qtag; /* qemu tag != srp tag */ uint32_t qtag; /* qemu tag != srp tag */
int lun; int lun;
int active; int active;
...@@ -123,11 +124,16 @@ static struct vscsi_req *vscsi_get_req(VSCSIState *s) ...@@ -123,11 +124,16 @@ static struct vscsi_req *vscsi_get_req(VSCSIState *s)
static void vscsi_put_req(VSCSIState *s, vscsi_req *req) static void vscsi_put_req(VSCSIState *s, vscsi_req *req)
{ {
if (req->sreq != NULL) {
scsi_req_unref(req->sreq);
}
req->sreq = NULL;
req->active = 0; req->active = 0;
} }
static vscsi_req *vscsi_find_req(VSCSIState *s, uint32_t tag) static vscsi_req *vscsi_find_req(VSCSIState *s, SCSIRequest *req)
{ {
uint32_t tag = req->tag;
if (tag >= VSCSI_REQ_LIMIT || !s->reqs[tag].active) { if (tag >= VSCSI_REQ_LIMIT || !s->reqs[tag].active) {
return NULL; return NULL;
} }
...@@ -453,11 +459,11 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) ...@@ -453,11 +459,11 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
cdb[4] = 96; cdb[4] = 96;
cdb[5] = 0; cdb[5] = 0;
req->sensing = 1; req->sensing = 1;
n = sdev->info->send_command(sdev, req->qtag, cdb, req->lun); n = sdev->info->send_command(req->sreq, cdb);
dprintf("VSCSI: Queued request sense tag 0x%x\n", req->qtag); dprintf("VSCSI: Queued request sense tag 0x%x\n", req->qtag);
if (n < 0) { if (n < 0) {
fprintf(stderr, "VSCSI: REQUEST_SENSE wants write data !?!?!?\n"); fprintf(stderr, "VSCSI: REQUEST_SENSE wants write data !?!?!?\n");
sdev->info->cancel_io(sdev, req->qtag); sdev->info->cancel_io(req->sreq);
vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
vscsi_put_req(s, req); vscsi_put_req(s, req);
...@@ -465,24 +471,23 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req) ...@@ -465,24 +471,23 @@ static void vscsi_send_request_sense(VSCSIState *s, vscsi_req *req)
} else if (n == 0) { } else if (n == 0) {
return; return;
} }
sdev->info->read_data(sdev, req->qtag); sdev->info->read_data(req->sreq);
} }
/* Callback to indicate that the SCSI layer has completed a transfer. */ /* Callback to indicate that the SCSI layer has completed a transfer. */
static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, static void vscsi_command_complete(SCSIRequest *sreq, int reason, uint32_t arg)
uint32_t arg)
{ {
VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, bus->qbus.parent); VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent);
vscsi_req *req = vscsi_find_req(s, tag); vscsi_req *req = vscsi_find_req(s, sreq);
SCSIDevice *sdev; SCSIDevice *sdev;
uint8_t *buf; uint8_t *buf;
int32_t res_in = 0, res_out = 0; int32_t res_in = 0, res_out = 0;
int len, rc = 0; int len, rc = 0;
dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x arg=0x%x, req=%p\n", dprintf("VSCSI: SCSI cmd complete, r=0x%x tag=0x%x arg=0x%x, req=%p\n",
reason, tag, arg, req); reason, sreq->tag, arg, req);
if (req == NULL) { if (req == NULL) {
fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", tag); fprintf(stderr, "VSCSI: Can't find request for tag 0x%x\n", sreq->tag);
return; return;
} }
sdev = req->sdev; sdev = req->sdev;
...@@ -493,7 +498,7 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, ...@@ -493,7 +498,7 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
vscsi_put_req(s, req); vscsi_put_req(s, req);
} else { } else {
uint8_t *buf = sdev->info->get_buf(sdev, tag); uint8_t *buf = sdev->info->get_buf(sreq);
len = MIN(arg, SCSI_SENSE_BUF_SIZE); len = MIN(arg, SCSI_SENSE_BUF_SIZE);
dprintf("VSCSI: Sense data, %d bytes:\n", len); dprintf("VSCSI: Sense data, %d bytes:\n", len);
...@@ -505,7 +510,7 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, ...@@ -505,7 +510,7 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
buf[12], buf[13], buf[14], buf[15]); buf[12], buf[13], buf[14], buf[15]);
memcpy(req->sense, buf, len); memcpy(req->sense, buf, len);
req->senselen = len; req->senselen = len;
sdev->info->read_data(sdev, req->qtag); sdev->info->read_data(sreq);
} }
return; return;
} }
...@@ -537,12 +542,12 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, ...@@ -537,12 +542,12 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
* to write for writes (ie, how much is to be DMA'd) * to write for writes (ie, how much is to be DMA'd)
*/ */
if (arg) { if (arg) {
buf = sdev->info->get_buf(sdev, tag); buf = sdev->info->get_buf(sreq);
rc = vscsi_srp_transfer_data(s, req, req->writing, buf, arg); rc = vscsi_srp_transfer_data(s, req, req->writing, buf, arg);
} }
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc); fprintf(stderr, "VSCSI: RDMA error rc=%d!\n", rc);
sdev->info->cancel_io(sdev, req->qtag); sdev->info->cancel_io(sreq);
vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0); vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0); vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
vscsi_put_req(s, req); vscsi_put_req(s, req);
...@@ -552,9 +557,9 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, ...@@ -552,9 +557,9 @@ static void vscsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
/* Start next chunk */ /* Start next chunk */
req->data_len -= rc; req->data_len -= rc;
if (req->writing) { if (req->writing) {
sdev->info->write_data(sdev, req->qtag); sdev->info->write_data(sreq);
} else { } else {
sdev->info->read_data(sdev, req->qtag); sdev->info->read_data(sreq);
} }
} }
...@@ -644,7 +649,8 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) ...@@ -644,7 +649,8 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
req->sdev = sdev; req->sdev = sdev;
req->lun = lun; req->lun = lun;
n = sdev->info->send_command(sdev, req->qtag, srp->cmd.cdb, lun); req->sreq = sdev->info->alloc_req(sdev, req->qtag, lun);
n = sdev->info->send_command(req->sreq, srp->cmd.cdb);
dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n", dprintf("VSCSI: Queued command tag 0x%x CMD 0x%x ID %d LUN %d ret: %d\n",
req->qtag, srp->cmd.cdb[0], id, lun, n); req->qtag, srp->cmd.cdb[0], id, lun, n);
...@@ -662,10 +668,10 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req) ...@@ -662,10 +668,10 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
/* Get transfer direction and initiate transfer */ /* Get transfer direction and initiate transfer */
if (n > 0) { if (n > 0) {
req->data_len = n; req->data_len = n;
sdev->info->read_data(sdev, req->qtag); sdev->info->read_data(req->sreq);
} else if (n < 0) { } else if (n < 0) {
req->data_len = -n; req->data_len = -n;
sdev->info->write_data(sdev, req->qtag); sdev->info->write_data(req->sreq);
} }
/* Don't touch req here, it may have been recycled already */ /* Don't touch req here, it may have been recycled already */
......
...@@ -48,6 +48,7 @@ typedef struct { ...@@ -48,6 +48,7 @@ typedef struct {
uint32_t data_len; uint32_t data_len;
uint32_t residue; uint32_t residue;
uint32_t tag; uint32_t tag;
SCSIRequest *req;
SCSIBus bus; SCSIBus bus;
BlockConf conf; BlockConf conf;
SCSIDevice *scsi_dev; SCSIDevice *scsi_dev;
...@@ -190,9 +191,9 @@ static void usb_msd_copy_data(MSDState *s) ...@@ -190,9 +191,9 @@ static void usb_msd_copy_data(MSDState *s)
s->data_len -= len; s->data_len -= len;
if (s->scsi_len == 0 || s->data_len == 0) { if (s->scsi_len == 0 || s->data_len == 0) {
if (s->mode == USB_MSDM_DATAIN) { if (s->mode == USB_MSDM_DATAIN) {
s->scsi_dev->info->read_data(s->scsi_dev, s->tag); s->scsi_dev->info->read_data(s->req);
} else if (s->mode == USB_MSDM_DATAOUT) { } else if (s->mode == USB_MSDM_DATAOUT) {
s->scsi_dev->info->write_data(s->scsi_dev, s->tag); s->scsi_dev->info->write_data(s->req);
} }
} }
} }
...@@ -211,14 +212,13 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p) ...@@ -211,14 +212,13 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p)
memcpy(p->data, &csw, len); memcpy(p->data, &csw, len);
} }
static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, static void usb_msd_command_complete(SCSIRequest *req, int reason, uint32_t arg)
uint32_t arg)
{ {
MSDState *s = DO_UPCAST(MSDState, dev.qdev, bus->qbus.parent); MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
USBPacket *p = s->packet; USBPacket *p = s->packet;
if (tag != s->tag) { if (req->tag != s->tag) {
fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", tag); fprintf(stderr, "usb-msd: Unexpected SCSI Tag 0x%x\n", req->tag);
} }
if (reason == SCSI_REASON_DONE) { if (reason == SCSI_REASON_DONE) {
DPRINTF("Command complete %d\n", arg); DPRINTF("Command complete %d\n", arg);
...@@ -245,10 +245,12 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag, ...@@ -245,10 +245,12 @@ static void usb_msd_command_complete(SCSIBus *bus, int reason, uint32_t tag,
} else if (s->data_len == 0) { } else if (s->data_len == 0) {
s->mode = USB_MSDM_CSW; s->mode = USB_MSDM_CSW;
} }
scsi_req_unref(req);
s->req = NULL;
return; return;
} }
s->scsi_len = arg; s->scsi_len = arg;
s->scsi_buf = s->scsi_dev->info->get_buf(s->scsi_dev, tag); s->scsi_buf = s->scsi_dev->info->get_buf(req);
if (p) { if (p) {
usb_msd_copy_data(s); usb_msd_copy_data(s);
if (s->usb_len == 0) { if (s->usb_len == 0) {
...@@ -316,7 +318,7 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value, ...@@ -316,7 +318,7 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value,
static void usb_msd_cancel_io(USBPacket *p, void *opaque) static void usb_msd_cancel_io(USBPacket *p, void *opaque)
{ {
MSDState *s = opaque; MSDState *s = opaque;
s->scsi_dev->info->cancel_io(s->scsi_dev, s->tag); s->scsi_dev->info->cancel_io(s->req);
s->packet = NULL; s->packet = NULL;
s->scsi_len = 0; s->scsi_len = 0;
} }
...@@ -365,14 +367,15 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p) ...@@ -365,14 +367,15 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
s->tag, cbw.flags, cbw.cmd_len, s->data_len); s->tag, cbw.flags, cbw.cmd_len, s->data_len);
s->residue = 0; s->residue = 0;
s->scsi_len = 0; s->scsi_len = 0;
s->scsi_dev->info->send_command(s->scsi_dev, s->tag, cbw.cmd, 0); s->req = s->scsi_dev->info->alloc_req(s->scsi_dev, s->tag, 0);
s->scsi_dev->info->send_command(s->req, cbw.cmd);
/* ??? Should check that USB and SCSI data transfer /* ??? Should check that USB and SCSI data transfer
directions match. */ directions match. */
if (s->residue == 0) { if (s->residue == 0) {
if (s->mode == USB_MSDM_DATAIN) { if (s->mode == USB_MSDM_DATAIN) {
s->scsi_dev->info->read_data(s->scsi_dev, s->tag); s->scsi_dev->info->read_data(s->req);
} else if (s->mode == USB_MSDM_DATAOUT) { } else if (s->mode == USB_MSDM_DATAOUT) {
s->scsi_dev->info->write_data(s->scsi_dev, s->tag); s->scsi_dev->info->write_data(s->req);
} }
} }
ret = len; ret = len;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册