qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [6409] Stop VM on error in scsi-disk (Gleb Natapov)


From: Anthony Liguori
Subject: [Qemu-devel] [6409] Stop VM on error in scsi-disk (Gleb Natapov)
Date: Thu, 22 Jan 2009 19:52:22 +0000

Revision: 6409
          http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=6409
Author:   aliguori
Date:     2009-01-22 19:52:21 +0000 (Thu, 22 Jan 2009)

Log Message:
-----------
Stop VM on error in scsi-disk (Gleb Natapov)

Signed-off-by: Gleb Natapov <address@hidden>
Signed-off-by: Anthony Liguori <address@hidden>

Modified Paths:
--------------
    trunk/hw/scsi-disk.c
    trunk/vl.c

Modified: trunk/hw/scsi-disk.c
===================================================================
--- trunk/hw/scsi-disk.c        2009-01-22 18:57:38 UTC (rev 6408)
+++ trunk/hw/scsi-disk.c        2009-01-22 19:52:21 UTC (rev 6409)
@@ -42,6 +42,8 @@
 #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 @@
     uint8_t *dma_buf;
     BlockDriverAIOCB *aiocb;
     struct SCSIRequest *next;
+    uint32_t status;
 } SCSIRequest;
 
 struct SCSIDeviceState
@@ -92,6 +95,7 @@
     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 @@
     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_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 @@
         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, int reason)
+{
+    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 @@
             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;

Modified: trunk/vl.c
===================================================================
--- trunk/vl.c  2009-01-22 18:57:38 UTC (rev 6408)
+++ trunk/vl.c  2009-01-22 19:52:21 UTC (rev 6409)
@@ -2432,8 +2432,8 @@
 
     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"))






reply via email to

[Prev in Thread] Current Thread [Next in Thread]