Revision ea8a5d7f hw/scsi-disk.c

b/hw/scsi-disk.c
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 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 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 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 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 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 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;

Also available in: Unified diff