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