mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-05 08:43:55 -06:00
SCSI and USB async IO support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2107 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
4ca9c76f36
commit
4d611c9a2f
14 changed files with 745 additions and 292 deletions
152
hw/scsi-disk.c
152
hw/scsi-disk.c
|
@ -25,6 +25,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
|
|||
|
||||
#define SENSE_NO_SENSE 0
|
||||
#define SENSE_NOT_READY 2
|
||||
#define SENSE_HARDWARE_ERROR 4
|
||||
#define SENSE_ILLEGAL_REQUEST 5
|
||||
|
||||
struct SCSIDevice
|
||||
|
@ -46,7 +47,13 @@ struct SCSIDevice
|
|||
int buf_pos;
|
||||
int buf_len;
|
||||
int sense;
|
||||
BlockDriverAIOCB *aiocb;
|
||||
/* Data still to be transfered after this request completes. */
|
||||
uint8_t *aiodata;
|
||||
uint32_t aiolen;
|
||||
char buf[512];
|
||||
/* Completion functions may be called from either scsi_{read,write}_data
|
||||
or from the AIO completion routines. */
|
||||
scsi_completionfn completion;
|
||||
void *opaque;
|
||||
};
|
||||
|
@ -54,10 +61,49 @@ struct SCSIDevice
|
|||
static void scsi_command_complete(SCSIDevice *s, int sense)
|
||||
{
|
||||
s->sense = sense;
|
||||
s->completion(s->opaque, s->tag, sense);
|
||||
s->completion(s->opaque, SCSI_REASON_DONE, sense);
|
||||
}
|
||||
|
||||
/* Read data from a scsi device. Returns nonzero on failure. */
|
||||
static void scsi_transfer_complete(SCSIDevice *s)
|
||||
{
|
||||
s->completion(s->opaque, SCSI_REASON_DATA, 0);
|
||||
s->aiocb = NULL;
|
||||
}
|
||||
|
||||
static void scsi_read_complete(void * opaque, int ret)
|
||||
{
|
||||
SCSIDevice *s = (SCSIDevice *)opaque;
|
||||
|
||||
if (ret) {
|
||||
DPRINTF("IO error\n");
|
||||
scsi_command_complete(s, SENSE_HARDWARE_ERROR);
|
||||
}
|
||||
|
||||
if (s->aiolen) {
|
||||
/* Read the remaining data. Full and partial sectors are transferred
|
||||
separately. */
|
||||
scsi_read_data(s, s->aiodata, s->aiolen);
|
||||
} else {
|
||||
if (s->buf_len == 0 && s->sector_count == 0)
|
||||
scsi_command_complete(s, SENSE_NO_SENSE);
|
||||
else
|
||||
scsi_transfer_complete(s);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cancel a pending data transfer. */
|
||||
void scsi_cancel_io(SCSIDevice *s)
|
||||
{
|
||||
if (!s->aiocb) {
|
||||
BADF("Cancel with no pending IO\n");
|
||||
return;
|
||||
}
|
||||
bdrv_aio_cancel(s->aiocb);
|
||||
s->aiocb = NULL;
|
||||
}
|
||||
|
||||
/* Read data from a scsi device. Returns nonzero on failure.
|
||||
The transfer may complete asynchronously. */
|
||||
int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint32_t n;
|
||||
|
@ -84,14 +130,19 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len)
|
|||
n = s->sector_count;
|
||||
|
||||
if (n != 0) {
|
||||
bdrv_read(s->bdrv, s->sector, data, n);
|
||||
data += n * 512;
|
||||
len -= n * 512;
|
||||
s->aiolen = len - n * 512;
|
||||
s->aiodata = data + n * 512;
|
||||
s->aiocb = bdrv_aio_read(s->bdrv, s->sector, data, n,
|
||||
scsi_read_complete, s);
|
||||
if (s->aiocb == NULL)
|
||||
scsi_command_complete(s, SENSE_HARDWARE_ERROR);
|
||||
s->sector += n;
|
||||
s->sector_count -= n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (len && s->sector_count) {
|
||||
/* TODO: Make this use AIO. */
|
||||
bdrv_read(s->bdrv, s->sector, s->buf, 1);
|
||||
s->sector++;
|
||||
s->sector_count--;
|
||||
|
@ -106,11 +157,53 @@ int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len)
|
|||
|
||||
if (s->buf_len == 0 && s->sector_count == 0)
|
||||
scsi_command_complete(s, SENSE_NO_SENSE);
|
||||
else
|
||||
scsi_transfer_complete(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read data to a scsi device. Returns nonzero on failure. */
|
||||
static void scsi_write_complete(void * opaque, int ret)
|
||||
{
|
||||
SCSIDevice *s = (SCSIDevice *)opaque;
|
||||
|
||||
if (ret) {
|
||||
fprintf(stderr, "scsi-disc: IO write error\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (s->sector_count == 0)
|
||||
scsi_command_complete(s, SENSE_NO_SENSE);
|
||||
else
|
||||
scsi_transfer_complete(s);
|
||||
}
|
||||
|
||||
static uint32_t scsi_write_partial_sector(SCSIDevice *s, uint8_t *data,
|
||||
uint32_t len)
|
||||
{
|
||||
int n;
|
||||
|
||||
n = 512 - s->buf_len;
|
||||
if (n > len)
|
||||
n = len;
|
||||
|
||||
memcpy(s->buf + s->buf_len, data, n);
|
||||
data += n;
|
||||
s->buf_len += n;
|
||||
len -= n;
|
||||
if (s->buf_len == 512) {
|
||||
/* A full sector has been accumulated. Write it to disk. */
|
||||
/* TODO: Make this use async IO. */
|
||||
bdrv_write(s->bdrv, s->sector, s->buf, 1);
|
||||
s->buf_len = 0;
|
||||
s->sector++;
|
||||
s->sector_count--;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Write data to a scsi device. Returns nonzero on failure.
|
||||
The transfer may complete asynchronously. */
|
||||
int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint32_t n;
|
||||
|
@ -125,48 +218,39 @@ int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
|
|||
return 1;
|
||||
|
||||
if (s->buf_len != 0 || len < 512) {
|
||||
n = 512 - s->buf_len;
|
||||
if (n > len)
|
||||
n = len;
|
||||
|
||||
memcpy(s->buf + s->buf_len, data, n);
|
||||
data += n;
|
||||
s->buf_len += n;
|
||||
n = scsi_write_partial_sector(s, data, len);
|
||||
len -= n;
|
||||
if (s->buf_len == 512) {
|
||||
/* A full sector has been accumulated. Write it to disk. */
|
||||
bdrv_write(s->bdrv, s->sector, s->buf, 1);
|
||||
s->buf_len = 0;
|
||||
s->sector++;
|
||||
s->sector_count--;
|
||||
}
|
||||
data += n;
|
||||
}
|
||||
|
||||
n = len / 512;
|
||||
if (n > s->sector_count)
|
||||
n = s->sector_count;
|
||||
return 1;
|
||||
|
||||
if (n != 0) {
|
||||
bdrv_write(s->bdrv, s->sector, data, n);
|
||||
s->aiocb = bdrv_aio_write(s->bdrv, s->sector, data, n,
|
||||
scsi_write_complete, s);
|
||||
if (s->aiocb == NULL)
|
||||
scsi_command_complete(s, SENSE_HARDWARE_ERROR);
|
||||
data += n * 512;
|
||||
len -= n * 512;
|
||||
s->sector += n;
|
||||
s->sector_count -= n;
|
||||
}
|
||||
|
||||
if (len >= 512)
|
||||
return 1;
|
||||
|
||||
if (len && s->sector_count) {
|
||||
/* Recurse to complete the partial write. */
|
||||
return scsi_write_data(s, data, len);
|
||||
if (len) {
|
||||
if (s->sector_count == 0)
|
||||
return 1;
|
||||
/* Complete a partial write. */
|
||||
scsi_write_partial_sector(s, data, len);
|
||||
}
|
||||
if (n == 0) {
|
||||
/* Transfer completes immediately. */
|
||||
if (s->sector_count == 0)
|
||||
scsi_command_complete(s, SENSE_NO_SENSE);
|
||||
else
|
||||
scsi_transfer_complete(s);
|
||||
}
|
||||
|
||||
if (len != 0)
|
||||
return 1;
|
||||
|
||||
if (s->sector_count == 0)
|
||||
scsi_command_complete(s, SENSE_NO_SENSE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue