Commit ea8a5d7f1f49f9bd38f4f1b32f4d9c413e6cf0bd

Authored by aliguori
1 parent 7e739a58

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

Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6409 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 71 additions and 19 deletions
hw/scsi-disk.c
@@ -42,6 +42,8 @@ do { fprintf(stderr, &quot;scsi-disk: &quot; fmt , ##args); } while (0) @@ -42,6 +42,8 @@ do { fprintf(stderr, &quot;scsi-disk: &quot; fmt , ##args); } while (0)
42 #define SCSI_DMA_BUF_SIZE 131072 42 #define SCSI_DMA_BUF_SIZE 131072
43 #define SCSI_MAX_INQUIRY_LEN 256 43 #define SCSI_MAX_INQUIRY_LEN 256
44 44
  45 +#define SCSI_REQ_STATUS_RETRY 0x01
  46 +
45 typedef struct SCSIRequest { 47 typedef struct SCSIRequest {
46 SCSIDeviceState *dev; 48 SCSIDeviceState *dev;
47 uint32_t tag; 49 uint32_t tag;
@@ -55,6 +57,7 @@ typedef struct SCSIRequest { @@ -55,6 +57,7 @@ typedef struct SCSIRequest {
55 uint8_t *dma_buf; 57 uint8_t *dma_buf;
56 BlockDriverAIOCB *aiocb; 58 BlockDriverAIOCB *aiocb;
57 struct SCSIRequest *next; 59 struct SCSIRequest *next;
  60 + uint32_t status;
58 } SCSIRequest; 61 } SCSIRequest;
59 62
60 struct SCSIDeviceState 63 struct SCSIDeviceState
@@ -92,6 +95,7 @@ static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag) @@ -92,6 +95,7 @@ static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
92 r->sector_count = 0; 95 r->sector_count = 0;
93 r->buf_len = 0; 96 r->buf_len = 0;
94 r->aiocb = NULL; 97 r->aiocb = NULL;
  98 + r->status = 0;
95 99
96 r->next = s->requests; 100 r->next = s->requests;
97 s->requests = r; 101 s->requests = r;
@@ -212,18 +216,42 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag) @@ -212,18 +216,42 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
212 r->sector_count -= n; 216 r->sector_count -= n;
213 } 217 }
214 218
  219 +static int scsi_handle_write_error(SCSIRequest *r, int error)
  220 +{
  221 + BlockInterfaceErrorAction action = drive_get_onerror(r->dev->bdrv);
  222 +
  223 + if (action == BLOCK_ERR_IGNORE)
  224 + return 0;
  225 +
  226 + if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
  227 + || action == BLOCK_ERR_STOP_ANY) {
  228 + r->status |= SCSI_REQ_STATUS_RETRY;
  229 + vm_stop(0);
  230 + } else {
  231 + scsi_command_complete(r, STATUS_CHECK_CONDITION,
  232 + SENSE_HARDWARE_ERROR);
  233 + }
  234 +
  235 + return 1;
  236 +}
  237 +
215 static void scsi_write_complete(void * opaque, int ret) 238 static void scsi_write_complete(void * opaque, int ret)
216 { 239 {
217 SCSIRequest *r = (SCSIRequest *)opaque; 240 SCSIRequest *r = (SCSIRequest *)opaque;
218 SCSIDeviceState *s = r->dev; 241 SCSIDeviceState *s = r->dev;
219 uint32_t len; 242 uint32_t len;
  243 + uint32_t n;
  244 +
  245 + r->aiocb = NULL;
220 246
221 if (ret) { 247 if (ret) {
222 - fprintf(stderr, "scsi-disc: IO write error\n");  
223 - exit(1); 248 + if (scsi_handle_write_error(r, -ret))
  249 + return;
224 } 250 }
225 251
226 - r->aiocb = NULL; 252 + n = r->buf_len / 512;
  253 + r->sector += n;
  254 + r->sector_count -= n;
227 if (r->sector_count == 0) { 255 if (r->sector_count == 0) {
228 scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE); 256 scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
229 } else { 257 } else {
@@ -237,13 +265,30 @@ static void scsi_write_complete(void * opaque, int ret) @@ -237,13 +265,30 @@ static void scsi_write_complete(void * opaque, int ret)
237 } 265 }
238 } 266 }
239 267
  268 +static void scsi_write_request(SCSIRequest *r)
  269 +{
  270 + SCSIDeviceState *s = r->dev;
  271 + uint32_t n;
  272 +
  273 + n = r->buf_len / 512;
  274 + if (n) {
  275 + r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n,
  276 + scsi_write_complete, r);
  277 + if (r->aiocb == NULL)
  278 + scsi_command_complete(r, STATUS_CHECK_CONDITION,
  279 + SENSE_HARDWARE_ERROR);
  280 + } else {
  281 + /* Invoke completion routine to fetch data from host. */
  282 + scsi_write_complete(r, 0);
  283 + }
  284 +}
  285 +
240 /* Write data to a scsi device. Returns nonzero on failure. 286 /* Write data to a scsi device. Returns nonzero on failure.
241 The transfer may complete asynchronously. */ 287 The transfer may complete asynchronously. */
242 static int scsi_write_data(SCSIDevice *d, uint32_t tag) 288 static int scsi_write_data(SCSIDevice *d, uint32_t tag)
243 { 289 {
244 SCSIDeviceState *s = d->state; 290 SCSIDeviceState *s = d->state;
245 SCSIRequest *r; 291 SCSIRequest *r;
246 - uint32_t n;  
247 292
248 DPRINTF("Write data tag=0x%x\n", tag); 293 DPRINTF("Write data tag=0x%x\n", tag);
249 r = scsi_find_request(s, tag); 294 r = scsi_find_request(s, tag);
@@ -252,25 +297,31 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) @@ -252,25 +297,31 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
252 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR); 297 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
253 return 1; 298 return 1;
254 } 299 }
  300 +
255 if (r->aiocb) 301 if (r->aiocb)
256 BADF("Data transfer already in progress\n"); 302 BADF("Data transfer already in progress\n");
257 - n = r->buf_len / 512;  
258 - if (n) {  
259 - r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n,  
260 - scsi_write_complete, r);  
261 - if (r->aiocb == NULL)  
262 - scsi_command_complete(r, STATUS_CHECK_CONDITION,  
263 - SENSE_HARDWARE_ERROR);  
264 - r->sector += n;  
265 - r->sector_count -= n;  
266 - } else {  
267 - /* Invoke completion routine to fetch data from host. */  
268 - scsi_write_complete(r, 0);  
269 - } 303 +
  304 + scsi_write_request(r);
270 305
271 return 0; 306 return 0;
272 } 307 }
273 308
  309 +static void scsi_dma_restart_cb(void *opaque, int running, int reason)
  310 +{
  311 + SCSIDeviceState *s = opaque;
  312 + SCSIRequest *r = s->requests;
  313 + if (!running)
  314 + return;
  315 +
  316 + while (r) {
  317 + if (r->status & SCSI_REQ_STATUS_RETRY) {
  318 + r->status &= ~SCSI_REQ_STATUS_RETRY;
  319 + scsi_write_request(r);
  320 + }
  321 + r = r->next;
  322 + }
  323 +}
  324 +
274 /* Return a pointer to the data buffer. */ 325 /* Return a pointer to the data buffer. */
275 static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) 326 static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
276 { 327 {
@@ -822,6 +873,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq, @@ -822,6 +873,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
822 sizeof(s->drive_serial_str)); 873 sizeof(s->drive_serial_str));
823 if (strlen(s->drive_serial_str) == 0) 874 if (strlen(s->drive_serial_str) == 0)
824 pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0"); 875 pstrcpy(s->drive_serial_str, sizeof(s->drive_serial_str), "0");
  876 + qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
825 d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); 877 d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
826 d->state = s; 878 d->state = s;
827 d->destroy = scsi_destroy; 879 d->destroy = scsi_destroy;
@@ -2432,8 +2432,8 @@ static int drive_init(struct drive_opt *arg, int snapshot, @@ -2432,8 +2432,8 @@ static int drive_init(struct drive_opt *arg, int snapshot,
2432 2432
2433 onerror = BLOCK_ERR_REPORT; 2433 onerror = BLOCK_ERR_REPORT;
2434 if (get_param_value(buf, sizeof(serial), "werror", str)) { 2434 if (get_param_value(buf, sizeof(serial), "werror", str)) {
2435 - if (type != IF_IDE) {  
2436 - fprintf(stderr, "werror is supported only by IDE\n"); 2435 + if (type != IF_IDE && type != IF_SCSI) {
  2436 + fprintf(stderr, "werror is no supported by this format\n");
2437 return -1; 2437 return -1;
2438 } 2438 }
2439 if (!strcmp(buf, "ignore")) 2439 if (!strcmp(buf, "ignore"))