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 42 #define SCSI_DMA_BUF_SIZE 131072
43 43 #define SCSI_MAX_INQUIRY_LEN 256
44 44  
  45 +#define SCSI_REQ_STATUS_RETRY 0x01
  46 +
45 47 typedef struct SCSIRequest {
46 48 SCSIDeviceState *dev;
47 49 uint32_t tag;
... ... @@ -55,6 +57,7 @@ typedef struct SCSIRequest {
55 57 uint8_t *dma_buf;
56 58 BlockDriverAIOCB *aiocb;
57 59 struct SCSIRequest *next;
  60 + uint32_t status;
58 61 } SCSIRequest;
59 62  
60 63 struct SCSIDeviceState
... ... @@ -92,6 +95,7 @@ static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
92 95 r->sector_count = 0;
93 96 r->buf_len = 0;
94 97 r->aiocb = NULL;
  98 + r->status = 0;
95 99  
96 100 r->next = s->requests;
97 101 s->requests = r;
... ... @@ -212,18 +216,42 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
212 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 238 static void scsi_write_complete(void * opaque, int ret)
216 239 {
217 240 SCSIRequest *r = (SCSIRequest *)opaque;
218 241 SCSIDeviceState *s = r->dev;
219 242 uint32_t len;
  243 + uint32_t n;
  244 +
  245 + r->aiocb = NULL;
220 246  
221 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 255 if (r->sector_count == 0) {
228 256 scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
229 257 } else {
... ... @@ -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 286 /* Write data to a scsi device. Returns nonzero on failure.
241 287 The transfer may complete asynchronously. */
242 288 static int scsi_write_data(SCSIDevice *d, uint32_t tag)
243 289 {
244 290 SCSIDeviceState *s = d->state;
245 291 SCSIRequest *r;
246   - uint32_t n;
247 292  
248 293 DPRINTF("Write data tag=0x%x\n", tag);
249 294 r = scsi_find_request(s, tag);
... ... @@ -252,25 +297,31 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
252 297 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
253 298 return 1;
254 299 }
  300 +
255 301 if (r->aiocb)
256 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 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 325 /* Return a pointer to the data buffer. */
275 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 873 sizeof(s->drive_serial_str));
823 874 if (strlen(s->drive_serial_str) == 0)
824 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 877 d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
826 878 d->state = s;
827 879 d->destroy = scsi_destroy;
... ...
... ... @@ -2432,8 +2432,8 @@ static int drive_init(struct drive_opt *arg, int snapshot,
2432 2432  
2433 2433 onerror = BLOCK_ERR_REPORT;
2434 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 2437 return -1;
2438 2438 }
2439 2439 if (!strcmp(buf, "ignore"))
... ...