Commit ea8a5d7f1f49f9bd38f4f1b32f4d9c413e6cf0bd
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, "scsi-disk: " 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; | ... | ... |
vl.c
| ... | ... | @@ -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")) | ... | ... |