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,6 +42,8 @@ do { fprintf(stderr, "scsi-disk: " 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; |
vl.c
| @@ -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")) |