SCSI cleanup, by Laurent Vivier.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3797 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
ths 2007-12-10 02:58:34 +00:00
parent cf6d911814
commit 8ccc2ace56
5 changed files with 95 additions and 67 deletions

View File

@ -165,7 +165,7 @@ static int get_cmd(ESPState *s, uint8_t *buf)
if (s->current_dev) { if (s->current_dev) {
/* Started a new command before the old one finished. Cancel it. */ /* Started a new command before the old one finished. Cancel it. */
scsi_cancel_io(s->current_dev, 0); s->current_dev->cancel_io(s->current_dev, 0);
s->async_len = 0; s->async_len = 0;
} }
@ -188,7 +188,7 @@ static void do_cmd(ESPState *s, uint8_t *buf)
DPRINTF("do_cmd: busid 0x%x\n", buf[0]); DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
lun = buf[0] & 7; lun = buf[0] & 7;
datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun); datalen = s->current_dev->send_command(s->current_dev, 0, &buf[1], lun);
s->ti_size = datalen; s->ti_size = datalen;
if (datalen != 0) { if (datalen != 0) {
s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC; s->rregs[ESP_RSTAT] = STAT_IN | STAT_TC;
@ -196,10 +196,10 @@ static void do_cmd(ESPState *s, uint8_t *buf)
s->dma_counter = 0; s->dma_counter = 0;
if (datalen > 0) { if (datalen > 0) {
s->rregs[ESP_RSTAT] |= STAT_DI; s->rregs[ESP_RSTAT] |= STAT_DI;
scsi_read_data(s->current_dev, 0); s->current_dev->read_data(s->current_dev, 0);
} else { } else {
s->rregs[ESP_RSTAT] |= STAT_DO; s->rregs[ESP_RSTAT] |= STAT_DO;
scsi_write_data(s->current_dev, 0); s->current_dev->write_data(s->current_dev, 0);
} }
} }
s->rregs[ESP_RINTR] = INTR_BS | INTR_FC; s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
@ -298,9 +298,9 @@ static void esp_do_dma(ESPState *s)
if (s->async_len == 0) { if (s->async_len == 0) {
if (to_device) { if (to_device) {
// ti_size is negative // ti_size is negative
scsi_write_data(s->current_dev, 0); s->current_dev->write_data(s->current_dev, 0);
} else { } else {
scsi_read_data(s->current_dev, 0); s->current_dev->read_data(s->current_dev, 0);
/* If there is still data to be read from the device then /* If there is still data to be read from the device then
complete the DMA operation immeriately. Otherwise defer complete the DMA operation immeriately. Otherwise defer
until the scsi layer has completed. */ until the scsi layer has completed. */
@ -335,7 +335,7 @@ static void esp_command_complete(void *opaque, int reason, uint32_t tag,
} else { } else {
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size); DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
s->async_len = arg; s->async_len = arg;
s->async_buf = scsi_get_buf(s->current_dev, 0); s->async_buf = s->current_dev->get_buf(s->current_dev, 0);
if (s->dma_left) { if (s->dma_left) {
esp_do_dma(s); esp_do_dma(s);
} else if (s->dma_counter != 0 && s->ti_size <= 0) { } else if (s->dma_counter != 0 && s->ti_size <= 0) {
@ -611,7 +611,7 @@ void esp_scsi_attach(void *opaque, BlockDriverState *bd, int id)
} }
if (s->scsi_dev[id]) { if (s->scsi_dev[id]) {
DPRINTF("Destroying device %d\n", id); DPRINTF("Destroying device %d\n", id);
scsi_disk_destroy(s->scsi_dev[id]); s->scsi_dev[id]->destroy(s->scsi_dev[id]);
} }
DPRINTF("Attaching block device %d\n", id); DPRINTF("Attaching block device %d\n", id);
/* Command queueing is not implemented. */ /* Command queueing is not implemented. */

View File

@ -187,6 +187,7 @@ typedef struct {
/* The tag is a combination of the device ID and the SCSI tag. */ /* The tag is a combination of the device ID and the SCSI tag. */
uint32_t current_tag; uint32_t current_tag;
uint32_t current_dma_len; uint32_t current_dma_len;
int command_complete;
uint8_t *dma_buf; uint8_t *dma_buf;
lsi_queue *queue; lsi_queue *queue;
int queue_len; int queue_len;
@ -465,7 +466,8 @@ static void lsi_do_dma(LSIState *s, int out)
s->dbc -= count; s->dbc -= count;
if (s->dma_buf == NULL) { if (s->dma_buf == NULL) {
s->dma_buf = scsi_get_buf(s->current_dev, s->current_tag); s->dma_buf = s->current_dev->get_buf(s->current_dev,
s->current_tag);
} }
/* ??? Set SFBR to first data byte. */ /* ??? Set SFBR to first data byte. */
@ -479,10 +481,10 @@ static void lsi_do_dma(LSIState *s, int out)
s->dma_buf = NULL; s->dma_buf = NULL;
if (out) { if (out) {
/* Write the data. */ /* Write the data. */
scsi_write_data(s->current_dev, s->current_tag); s->current_dev->write_data(s->current_dev, s->current_tag);
} else { } else {
/* Request any remaining data. */ /* Request any remaining data. */
scsi_read_data(s->current_dev, s->current_tag); s->current_dev->read_data(s->current_dev, s->current_tag);
} }
} else { } else {
s->dma_buf += count; s->dma_buf += count;
@ -596,6 +598,7 @@ static void lsi_command_complete(void *opaque, int reason, uint32_t tag,
if (reason == SCSI_REASON_DONE) { if (reason == SCSI_REASON_DONE) {
DPRINTF("Command complete sense=%d\n", (int)arg); DPRINTF("Command complete sense=%d\n", (int)arg);
s->sense = arg; s->sense = arg;
s->command_complete = 2;
if (s->waiting && s->dbc != 0) { if (s->waiting && s->dbc != 0) {
/* Raise phase mismatch for short transfers. */ /* Raise phase mismatch for short transfers. */
lsi_bad_phase(s, out, PHASE_ST); lsi_bad_phase(s, out, PHASE_ST);
@ -612,6 +615,7 @@ static void lsi_command_complete(void *opaque, int reason, uint32_t tag,
} }
DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg); DPRINTF("Data ready tag=0x%x len=%d\n", tag, arg);
s->current_dma_len = arg; s->current_dma_len = arg;
s->command_complete = 1;
if (!s->waiting) if (!s->waiting)
return; return;
if (s->waiting == 1 || s->dbc == 0) { if (s->waiting == 1 || s->dbc == 0) {
@ -631,21 +635,30 @@ static void lsi_do_command(LSIState *s)
s->dbc = 16; s->dbc = 16;
cpu_physical_memory_read(s->dnad, buf, s->dbc); cpu_physical_memory_read(s->dnad, buf, s->dbc);
s->sfbr = buf[0]; s->sfbr = buf[0];
n = scsi_send_command(s->current_dev, s->current_tag, buf, s->current_lun); s->command_complete = 0;
n = s->current_dev->send_command(s->current_dev, s->current_tag, buf,
s->current_lun);
if (n > 0) { if (n > 0) {
lsi_set_phase(s, PHASE_DI); lsi_set_phase(s, PHASE_DI);
scsi_read_data(s->current_dev, s->current_tag); s->current_dev->read_data(s->current_dev, s->current_tag);
} else if (n < 0) { } else if (n < 0) {
lsi_set_phase(s, PHASE_DO); lsi_set_phase(s, PHASE_DO);
scsi_write_data(s->current_dev, s->current_tag); s->current_dev->write_data(s->current_dev, s->current_tag);
} }
if (n && s->current_dma_len == 0) {
/* Command did not complete immediately so disconnect. */ if (!s->command_complete) {
lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */ if (n) {
lsi_add_msg_byte(s, 4); /* DISCONNECT */ /* Command did not complete immediately so disconnect. */
lsi_set_phase(s, PHASE_MI); lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
s->msg_action = 1; lsi_add_msg_byte(s, 4); /* DISCONNECT */
lsi_queue_command(s); /* wait data */
lsi_set_phase(s, PHASE_MI);
s->msg_action = 1;
lsi_queue_command(s);
} else {
/* wait command complete */
lsi_set_phase(s, PHASE_DI);
}
} }
} }
@ -1822,7 +1835,7 @@ void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id)
} }
if (s->scsi_dev[id]) { if (s->scsi_dev[id]) {
DPRINTF("Destroying device %d\n", id); DPRINTF("Destroying device %d\n", id);
scsi_disk_destroy(s->scsi_dev[id]); s->scsi_dev[id]->destroy(s->scsi_dev[id]);
} }
DPRINTF("Attaching block device %d\n", id); DPRINTF("Attaching block device %d\n", id);
s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s); s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s);

View File

@ -37,7 +37,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
#define SCSI_DMA_BUF_SIZE 65536 #define SCSI_DMA_BUF_SIZE 65536
typedef struct SCSIRequest { typedef struct SCSIRequest {
SCSIDevice *dev; SCSIDeviceState *dev;
uint32_t tag; uint32_t tag;
/* ??? We should probably keep track of whether the data trasfer is /* ??? We should probably keep track of whether the data trasfer is
a read or a write. Currently we rely on the host getting it right. */ a read or a write. Currently we rely on the host getting it right. */
@ -51,7 +51,7 @@ typedef struct SCSIRequest {
struct SCSIRequest *next; struct SCSIRequest *next;
} SCSIRequest; } SCSIRequest;
struct SCSIDevice struct SCSIDeviceState
{ {
BlockDriverState *bdrv; BlockDriverState *bdrv;
SCSIRequest *requests; SCSIRequest *requests;
@ -69,7 +69,7 @@ struct SCSIDevice
/* Global pool of SCSIRequest structures. */ /* Global pool of SCSIRequest structures. */
static SCSIRequest *free_requests = NULL; static SCSIRequest *free_requests = NULL;
static SCSIRequest *scsi_new_request(SCSIDevice *s, uint32_t tag) static SCSIRequest *scsi_new_request(SCSIDeviceState *s, uint32_t tag)
{ {
SCSIRequest *r; SCSIRequest *r;
@ -93,7 +93,7 @@ static SCSIRequest *scsi_new_request(SCSIDevice *s, uint32_t tag)
static void scsi_remove_request(SCSIRequest *r) static void scsi_remove_request(SCSIRequest *r)
{ {
SCSIRequest *last; SCSIRequest *last;
SCSIDevice *s = r->dev; SCSIDeviceState *s = r->dev;
if (s->requests == r) { if (s->requests == r) {
s->requests = r->next; s->requests = r->next;
@ -111,7 +111,7 @@ static void scsi_remove_request(SCSIRequest *r)
free_requests = r; free_requests = r;
} }
static SCSIRequest *scsi_find_request(SCSIDevice *s, uint32_t tag) static SCSIRequest *scsi_find_request(SCSIDeviceState *s, uint32_t tag)
{ {
SCSIRequest *r; SCSIRequest *r;
@ -125,7 +125,7 @@ static SCSIRequest *scsi_find_request(SCSIDevice *s, uint32_t tag)
/* Helper function for command completion. */ /* Helper function for command completion. */
static void scsi_command_complete(SCSIRequest *r, int sense) static void scsi_command_complete(SCSIRequest *r, int sense)
{ {
SCSIDevice *s = r->dev; SCSIDeviceState *s = r->dev;
uint32_t tag; uint32_t tag;
DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense); DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense);
s->sense = sense; s->sense = sense;
@ -135,8 +135,9 @@ static void scsi_command_complete(SCSIRequest *r, int sense)
} }
/* Cancel a pending data transfer. */ /* Cancel a pending data transfer. */
void scsi_cancel_io(SCSIDevice *s, uint32_t tag) static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
{ {
SCSIDeviceState *s = d->state;
SCSIRequest *r; SCSIRequest *r;
DPRINTF("Cancel tag=0x%x\n", tag); DPRINTF("Cancel tag=0x%x\n", tag);
r = scsi_find_request(s, tag); r = scsi_find_request(s, tag);
@ -151,7 +152,7 @@ void scsi_cancel_io(SCSIDevice *s, uint32_t tag)
static void scsi_read_complete(void * opaque, int ret) static void scsi_read_complete(void * opaque, int ret)
{ {
SCSIRequest *r = (SCSIRequest *)opaque; SCSIRequest *r = (SCSIRequest *)opaque;
SCSIDevice *s = r->dev; SCSIDeviceState *s = r->dev;
if (ret) { if (ret) {
DPRINTF("IO error\n"); DPRINTF("IO error\n");
@ -164,8 +165,9 @@ static void scsi_read_complete(void * opaque, int ret)
} }
/* Read more data from scsi device into buffer. */ /* Read more data from scsi device into buffer. */
void scsi_read_data(SCSIDevice *s, uint32_t tag) static void scsi_read_data(SCSIDevice *d, uint32_t tag)
{ {
SCSIDeviceState *s = d->state;
SCSIRequest *r; SCSIRequest *r;
uint32_t n; uint32_t n;
@ -204,7 +206,7 @@ void scsi_read_data(SCSIDevice *s, uint32_t tag)
static void scsi_write_complete(void * opaque, int ret) static void scsi_write_complete(void * opaque, int ret)
{ {
SCSIRequest *r = (SCSIRequest *)opaque; SCSIRequest *r = (SCSIRequest *)opaque;
SCSIDevice *s = r->dev; SCSIDeviceState *s = r->dev;
uint32_t len; uint32_t len;
if (ret) { if (ret) {
@ -228,8 +230,9 @@ static void scsi_write_complete(void * opaque, int ret)
/* Write data to a scsi device. Returns nonzero on failure. /* Write data to a scsi device. Returns nonzero on failure.
The transfer may complete asynchronously. */ The transfer may complete asynchronously. */
int scsi_write_data(SCSIDevice *s, uint32_t tag) static int scsi_write_data(SCSIDevice *d, uint32_t tag)
{ {
SCSIDeviceState *s = d->state;
SCSIRequest *r; SCSIRequest *r;
uint32_t n; uint32_t n;
@ -259,8 +262,9 @@ int scsi_write_data(SCSIDevice *s, uint32_t tag)
} }
/* Return a pointer to the data buffer. */ /* Return a pointer to the data buffer. */
uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag) static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
{ {
SCSIDeviceState *s = d->state;
SCSIRequest *r; SCSIRequest *r;
r = scsi_find_request(s, tag); r = scsi_find_request(s, tag);
@ -276,8 +280,10 @@ uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag)
(eg. disk reads), negative for transfers to the device (eg. disk writes), (eg. disk reads), negative for transfers to the device (eg. disk writes),
and zero if the command does not transfer any data. */ and zero if the command does not transfer any data. */
int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun) static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
uint8_t *buf, int lun)
{ {
SCSIDeviceState *s = d->state;
int64_t nb_sectors; int64_t nb_sectors;
uint32_t lba; uint32_t lba;
uint32_t len; uint32_t len;
@ -291,7 +297,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
r = scsi_find_request(s, tag); r = scsi_find_request(s, tag);
if (r) { if (r) {
BADF("Tag 0x%x already in use\n", tag); BADF("Tag 0x%x already in use\n", tag);
scsi_cancel_io(s, tag); scsi_cancel_io(d, tag);
} }
/* ??? Tags are not unique for different luns. We only implement a /* ??? Tags are not unique for different luns. We only implement a
single lun, so this should not matter. */ single lun, so this should not matter. */
@ -576,19 +582,19 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
} }
} }
void scsi_disk_destroy(SCSIDevice *s) static void scsi_destroy(SCSIDevice *d)
{ {
qemu_free(s); qemu_free(d->state);
qemu_free(d);
} }
SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
int tcq, scsi_completionfn completion, void *opaque)
scsi_completionfn completion,
void *opaque)
{ {
SCSIDevice *s; SCSIDevice *d;
SCSIDeviceState *s;
s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice)); s = (SCSIDeviceState *)qemu_mallocz(sizeof(SCSIDeviceState));
s->bdrv = bdrv; s->bdrv = bdrv;
s->tcq = tcq; s->tcq = tcq;
s->completion = completion; s->completion = completion;
@ -599,6 +605,14 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
s->cluster_size = 1; s->cluster_size = 1;
} }
return s; d = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
} d->state = s;
d->destroy = scsi_destroy;
d->send_command = scsi_send_command;
d->read_data = scsi_read_data;
d->write_data = scsi_write_data;
d->cancel_io = scsi_cancel_io;
d->get_buf = scsi_get_buf;
return d;
}

View File

@ -7,24 +7,25 @@ enum scsi_reason {
SCSI_REASON_DATA /* Transfer complete, more data required. */ SCSI_REASON_DATA /* Transfer complete, more data required. */
}; };
typedef struct SCSIDeviceState SCSIDeviceState;
typedef struct SCSIDevice SCSIDevice; typedef struct SCSIDevice SCSIDevice;
typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag, typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag,
uint32_t arg); uint32_t arg);
SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, struct SCSIDevice
int tcq, {
scsi_completionfn completion, SCSIDeviceState *state;
void *opaque); void (*destroy)(SCSIDevice *s);
void scsi_disk_destroy(SCSIDevice *s); int32_t (*send_command)(SCSIDevice *s, uint32_t tag, uint8_t *buf,
int lun);
void (*read_data)(SCSIDevice *s, uint32_t tag);
int (*write_data)(SCSIDevice *s, uint32_t tag);
void (*cancel_io)(SCSIDevice *s, uint32_t tag);
uint8_t *(*get_buf)(SCSIDevice *s, uint32_t tag);
};
int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun); SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
/* SCSI data transfers are asynchrnonous. However, unlike the block IO scsi_completionfn completion, void *opaque);
layer the completion routine may be called directly by
scsi_{read,write}_data. */
void scsi_read_data(SCSIDevice *s, uint32_t tag);
int scsi_write_data(SCSIDevice *s, uint32_t tag);
void scsi_cancel_io(SCSIDevice *s, uint32_t tag);
uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag);
/* cdrom.c */ /* cdrom.c */
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);

View File

@ -149,9 +149,9 @@ static void usb_msd_copy_data(MSDState *s)
s->data_len -= len; s->data_len -= len;
if (s->scsi_len == 0) { if (s->scsi_len == 0) {
if (s->mode == USB_MSDM_DATAIN) { if (s->mode == USB_MSDM_DATAIN) {
scsi_read_data(s->scsi_dev, s->tag); s->scsi_dev->read_data(s->scsi_dev, s->tag);
} else if (s->mode == USB_MSDM_DATAOUT) { } else if (s->mode == USB_MSDM_DATAOUT) {
scsi_write_data(s->scsi_dev, s->tag); s->scsi_dev->write_data(s->scsi_dev, s->tag);
} }
} }
} }
@ -204,7 +204,7 @@ static void usb_msd_command_complete(void *opaque, int reason, uint32_t tag,
return; return;
} }
s->scsi_len = arg; s->scsi_len = arg;
s->scsi_buf = scsi_get_buf(s->scsi_dev, tag); s->scsi_buf = s->scsi_dev->get_buf(s->scsi_dev, tag);
if (p) { if (p) {
usb_msd_copy_data(s); usb_msd_copy_data(s);
if (s->usb_len == 0) { if (s->usb_len == 0) {
@ -342,7 +342,7 @@ static int usb_msd_handle_control(USBDevice *dev, int request, int value,
static void usb_msd_cancel_io(USBPacket *p, void *opaque) static void usb_msd_cancel_io(USBPacket *p, void *opaque)
{ {
MSDState *s = opaque; MSDState *s = opaque;
scsi_cancel_io(s->scsi_dev, s->tag); s->scsi_dev->cancel_io(s->scsi_dev, s->tag);
s->packet = NULL; s->packet = NULL;
s->scsi_len = 0; s->scsi_len = 0;
} }
@ -390,14 +390,14 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
s->tag, cbw.flags, cbw.cmd_len, s->data_len); s->tag, cbw.flags, cbw.cmd_len, s->data_len);
s->residue = 0; s->residue = 0;
scsi_send_command(s->scsi_dev, s->tag, cbw.cmd, 0); s->scsi_dev->send_command(s->scsi_dev, s->tag, cbw.cmd, 0);
/* ??? Should check that USB and SCSI data transfer /* ??? Should check that USB and SCSI data transfer
directions match. */ directions match. */
if (s->residue == 0) { if (s->residue == 0) {
if (s->mode == USB_MSDM_DATAIN) { if (s->mode == USB_MSDM_DATAIN) {
scsi_read_data(s->scsi_dev, s->tag); s->scsi_dev->read_data(s->scsi_dev, s->tag);
} else if (s->mode == USB_MSDM_DATAOUT) { } else if (s->mode == USB_MSDM_DATAOUT) {
scsi_write_data(s->scsi_dev, s->tag); s->scsi_dev->write_data(s->scsi_dev, s->tag);
} }
} }
ret = len; ret = len;
@ -508,7 +508,7 @@ static void usb_msd_handle_destroy(USBDevice *dev)
{ {
MSDState *s = (MSDState *)dev; MSDState *s = (MSDState *)dev;
scsi_disk_destroy(s->scsi_dev); s->scsi_dev->destroy(s->scsi_dev);
bdrv_delete(s->bs); bdrv_delete(s->bs);
qemu_free(s); qemu_free(s);
} }