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")) | ... | ... |