From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LPzgh-0005oK-3J for qemu-devel@nongnu.org; Thu, 22 Jan 2009 08:33:39 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LPzgf-0005o3-0E for qemu-devel@nongnu.org; Thu, 22 Jan 2009 08:33:37 -0500 Received: from [199.232.76.173] (port=39180 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LPzgd-0005ny-85 for qemu-devel@nongnu.org; Thu, 22 Jan 2009 08:33:35 -0500 Received: from mx2.redhat.com ([66.187.237.31]:48936) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LPzgc-0003J2-Md for qemu-devel@nongnu.org; Thu, 22 Jan 2009 08:33:34 -0500 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n0MDXXZT013660 for ; Thu, 22 Jan 2009 08:33:33 -0500 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n0MDXXBp022740 for ; Thu, 22 Jan 2009 08:33:34 -0500 Received: from dhcp-1-237.tlv.redhat.com (dhcp-1-237.tlv.redhat.com [10.35.1.237]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n0MDXXeC027383 for ; Thu, 22 Jan 2009 08:33:33 -0500 Received: from dhcp-1-237.tlv.redhat.com (localhost [127.0.0.1]) by dhcp-1-237.tlv.redhat.com (Postfix) with ESMTP id D4A7A18D407 for ; Thu, 22 Jan 2009 15:31:42 +0200 (IST) From: Gleb Natapov Date: Thu, 22 Jan 2009 15:31:42 +0200 Message-ID: <20090122133142.16090.9308.stgit@dhcp-1-237.tlv.redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Subject: [Qemu-devel] [PATCH 1/2] Stop VM on error in scsi-disk Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Signed-off-by: Gleb Natapov --- hw/scsi-disk.c | 86 +++++++++++++++++++++++++++++++++++++++++++++----------- vl.c | 4 +-- 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 744573e..9eda2f6 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -42,6 +42,8 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0) #define SCSI_DMA_BUF_SIZE 131072 #define SCSI_MAX_INQUIRY_LEN 256 +#define SCSI_REQ_STATUS_RETRY 0x01 + typedef struct SCSIRequest { SCSIDeviceState *dev; uint32_t tag; @@ -55,6 +57,7 @@ typedef struct SCSIRequest { uint8_t *dma_buf; BlockDriverAIOCB *aiocb; struct SCSIRequest *next; + uint32_t status; } SCSIRequest; struct SCSIDeviceState @@ -92,6 +95,7 @@ static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag) r->sector_count = 0; r->buf_len = 0; r->aiocb = NULL; + r->status = 0; r->next = s->requests; s->requests = r; @@ -212,18 +216,42 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) r->sector_count -= n; } +static int scsi_handle_write_error(SCSIRequest *r, int error) +{ + BlockInterfaceErrorAction action = drive_get_onerror(r->dev->bdrv); + + if (action == BLOCK_ERR_IGNORE) + return 0; + + if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC) + || action == BLOCK_ERR_STOP_ANY) { + r->status |= SCSI_REQ_STATUS_RETRY; + vm_stop(0); + } else { + scsi_command_complete(r, STATUS_CHECK_CONDITION, + SENSE_HARDWARE_ERROR); + } + + return 1; +} + static void scsi_write_complete(void * opaque, int ret) { SCSIRequest *r = (SCSIRequest *)opaque; SCSIDeviceState *s = r->dev; uint32_t len; + uint32_t n; + + r->aiocb = NULL; if (ret) { - fprintf(stderr, "scsi-disc: IO write error\n"); - exit(1); + if (scsi_handle_write_error(r, -ret)) + return; } - r->aiocb = NULL; + n = r->buf_len / 512; + r->sector += n; + r->sector_count -= n; if (r->sector_count == 0) { scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); } else { @@ -237,13 +265,30 @@ static void scsi_write_complete(void * opaque, int ret) } } +static void scsi_write_request(SCSIRequest *r) +{ + SCSIDeviceState *s = r->dev; + uint32_t n; + + n = r->buf_len / 512; + if (n) { + r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n, + scsi_write_complete, r); + if (r->aiocb == NULL) + scsi_command_complete(r, STATUS_CHECK_CONDITION, + SENSE_HARDWARE_ERROR); + } else { + /* Invoke completion routine to fetch data from host. */ + 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) { SCSIDeviceState *s = d->state; SCSIRequest *r; - uint32_t n; DPRINTF("Write data tag=0x%x\n", tag); r = scsi_find_request(s, tag); @@ -252,25 +297,31 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); return 1; } + if (r->aiocb) BADF("Data transfer already in progress\n"); - n = r->buf_len / 512; - if (n) { - r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n, - scsi_write_complete, r); - if (r->aiocb == NULL) - scsi_command_complete(r, STATUS_CHECK_CONDITION, - SENSE_HARDWARE_ERROR); - r->sector += n; - r->sector_count -= n; - } else { - /* Invoke completion routine to fetch data from host. */ - scsi_write_complete(r, 0); - } + + scsi_write_request(r); return 0; } +static void scsi_dma_restart_cb(void *opaque, int running) +{ + SCSIDeviceState *s = opaque; + SCSIRequest *r = s->requests; + if (!running) + return; + + while (r) { + if (r->status & SCSI_REQ_STATUS_RETRY) { + r->status &= ~SCSI_REQ_STATUS_RETRY; + scsi_write_request(r); + } + r = r->next; + } +} + /* Return a pointer to the data buffer. */ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) { @@ -822,6 +873,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, sizeof(s->drive_serial_str)); if (strlen(s->drive_serial_str) == 0) pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0"); + qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s); d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); d->state = s; d->destroy = scsi_destroy; diff --git a/vl.c b/vl.c index 045b09f..a325c81 100644 --- a/vl.c +++ b/vl.c @@ -2432,8 +2432,8 @@ static int drive_init(struct drive_opt *arg, int snapshot, onerror = BLOCK_ERR_REPORT; if (get_param_value(buf, sizeof(serial), "werror", str)) { - if (type != IF_IDE) { - fprintf(stderr, "werror is supported only by IDE\n"); + if (type != IF_IDE && type != IF_SCSI) { + fprintf(stderr, "werror is no supported by this format\n"); return -1; } if (!strcmp(buf, "ignore"))