diff options
Diffstat (limited to 'hw/scsi/scsi-disk.c')
-rw-r--r-- | hw/scsi/scsi-disk.c | 47 |
1 files changed, 42 insertions, 5 deletions
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index a5a58d7db3..ceaf78b423 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -77,7 +77,6 @@ typedef struct SCSIDiskReq { struct iovec iov; QEMUIOVector qiov; BlockAcctCookie acct; - unsigned char *status; } SCSIDiskReq; #define SCSI_DISK_F_REMOVABLE 0 @@ -261,8 +260,6 @@ static bool scsi_disk_req_check_error(SCSIDiskReq *r, int ret, bool acct_failed) if (ret < 0) { return scsi_handle_rw_error(r, ret, acct_failed); - } else if (r->status && *r->status) { - return scsi_handle_rw_error(r, *r->status, acct_failed); } return false; @@ -2697,8 +2694,47 @@ typedef struct SCSIBlockReq { /* CDB passed to SG_IO. */ uint8_t cdb[16]; + BlockCompletionFunc *cb; + void *cb_opaque; } SCSIBlockReq; +static void scsi_block_sgio_complete(void *opaque, int ret) +{ + SCSIBlockReq *req = (SCSIBlockReq *)opaque; + SCSIDiskReq *r = &req->req; + SCSIDevice *s = r->req.dev; + sg_io_hdr_t *io_hdr = &req->io_header; + SCSISense sense; + + if (ret == 0) { + if (io_hdr->host_status != SCSI_HOST_OK) { + ret = scsi_sense_from_host_status(io_hdr->host_status, &sense); + if (ret == CHECK_CONDITION) { + scsi_req_build_sense(&r->req, sense); + } + } else if (io_hdr->driver_status & SG_ERR_DRIVER_TIMEOUT) { + ret = BUSY; + } else { + ret = io_hdr->status; + } + + if (ret > 0) { + aio_context_acquire(blk_get_aio_context(s->conf.blk)); + if (scsi_handle_rw_error(r, ret, true)) { + aio_context_release(blk_get_aio_context(s->conf.blk)); + scsi_req_unref(&r->req); + return; + } + aio_context_release(blk_get_aio_context(s->conf.blk)); + + /* Ignore error. */ + ret = 0; + } + } + + req->cb(req->cb_opaque, ret); +} + static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req, int64_t offset, QEMUIOVector *iov, int direction, @@ -2777,9 +2813,11 @@ static BlockAIOCB *scsi_block_do_sgio(SCSIBlockReq *req, io_header->timeout = s->qdev.io_timeout * 1000; io_header->usr_ptr = r; io_header->flags |= SG_FLAG_DIRECT_IO; + req->cb = cb; + req->cb_opaque = opaque; trace_scsi_disk_aio_sgio_command(r->req.tag, req->cdb[0], lba, nb_logical_blocks, io_header->timeout); - aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, cb, opaque); + aiocb = blk_aio_ioctl(s->qdev.conf.blk, SG_IO, io_header, scsi_block_sgio_complete, req); assert(aiocb != NULL); return aiocb; } @@ -2893,7 +2931,6 @@ static int32_t scsi_block_dma_command(SCSIRequest *req, uint8_t *buf) return 0; } - r->req.status = &r->io_header.status; return scsi_disk_dma_command(req, buf); } |