mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-09 05:38:34 +00:00
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:
parent
cf6d911814
commit
8ccc2ace56
16
hw/esp.c
16
hw/esp.c
@ -165,7 +165,7 @@ static int get_cmd(ESPState *s, uint8_t *buf)
|
||||
|
||||
if (s->current_dev) {
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@ -188,7 +188,7 @@ static void do_cmd(ESPState *s, uint8_t *buf)
|
||||
|
||||
DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
|
||||
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;
|
||||
if (datalen != 0) {
|
||||
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;
|
||||
if (datalen > 0) {
|
||||
s->rregs[ESP_RSTAT] |= STAT_DI;
|
||||
scsi_read_data(s->current_dev, 0);
|
||||
s->current_dev->read_data(s->current_dev, 0);
|
||||
} else {
|
||||
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;
|
||||
@ -298,9 +298,9 @@ static void esp_do_dma(ESPState *s)
|
||||
if (s->async_len == 0) {
|
||||
if (to_device) {
|
||||
// ti_size is negative
|
||||
scsi_write_data(s->current_dev, 0);
|
||||
s->current_dev->write_data(s->current_dev, 0);
|
||||
} 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
|
||||
complete the DMA operation immeriately. Otherwise defer
|
||||
until the scsi layer has completed. */
|
||||
@ -335,7 +335,7 @@ static void esp_command_complete(void *opaque, int reason, uint32_t tag,
|
||||
} else {
|
||||
DPRINTF("transfer %d/%d\n", s->dma_left, s->ti_size);
|
||||
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) {
|
||||
esp_do_dma(s);
|
||||
} 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]) {
|
||||
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);
|
||||
/* Command queueing is not implemented. */
|
||||
|
@ -187,6 +187,7 @@ typedef struct {
|
||||
/* The tag is a combination of the device ID and the SCSI tag. */
|
||||
uint32_t current_tag;
|
||||
uint32_t current_dma_len;
|
||||
int command_complete;
|
||||
uint8_t *dma_buf;
|
||||
lsi_queue *queue;
|
||||
int queue_len;
|
||||
@ -465,7 +466,8 @@ static void lsi_do_dma(LSIState *s, int out)
|
||||
s->dbc -= count;
|
||||
|
||||
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. */
|
||||
@ -479,10 +481,10 @@ static void lsi_do_dma(LSIState *s, int out)
|
||||
s->dma_buf = NULL;
|
||||
if (out) {
|
||||
/* Write the data. */
|
||||
scsi_write_data(s->current_dev, s->current_tag);
|
||||
s->current_dev->write_data(s->current_dev, s->current_tag);
|
||||
} else {
|
||||
/* 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 {
|
||||
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) {
|
||||
DPRINTF("Command complete sense=%d\n", (int)arg);
|
||||
s->sense = arg;
|
||||
s->command_complete = 2;
|
||||
if (s->waiting && s->dbc != 0) {
|
||||
/* Raise phase mismatch for short transfers. */
|
||||
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);
|
||||
s->current_dma_len = arg;
|
||||
s->command_complete = 1;
|
||||
if (!s->waiting)
|
||||
return;
|
||||
if (s->waiting == 1 || s->dbc == 0) {
|
||||
@ -631,21 +635,30 @@ static void lsi_do_command(LSIState *s)
|
||||
s->dbc = 16;
|
||||
cpu_physical_memory_read(s->dnad, buf, s->dbc);
|
||||
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) {
|
||||
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) {
|
||||
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. */
|
||||
lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
|
||||
lsi_add_msg_byte(s, 4); /* DISCONNECT */
|
||||
lsi_set_phase(s, PHASE_MI);
|
||||
s->msg_action = 1;
|
||||
lsi_queue_command(s);
|
||||
|
||||
if (!s->command_complete) {
|
||||
if (n) {
|
||||
/* Command did not complete immediately so disconnect. */
|
||||
lsi_add_msg_byte(s, 2); /* SAVE DATA POINTER */
|
||||
lsi_add_msg_byte(s, 4); /* DISCONNECT */
|
||||
/* 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]) {
|
||||
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);
|
||||
s->scsi_dev[id] = scsi_disk_init(bd, 1, lsi_command_complete, s);
|
||||
|
@ -37,7 +37,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
|
||||
#define SCSI_DMA_BUF_SIZE 65536
|
||||
|
||||
typedef struct SCSIRequest {
|
||||
SCSIDevice *dev;
|
||||
SCSIDeviceState *dev;
|
||||
uint32_t tag;
|
||||
/* ??? 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. */
|
||||
@ -51,7 +51,7 @@ typedef struct SCSIRequest {
|
||||
struct SCSIRequest *next;
|
||||
} SCSIRequest;
|
||||
|
||||
struct SCSIDevice
|
||||
struct SCSIDeviceState
|
||||
{
|
||||
BlockDriverState *bdrv;
|
||||
SCSIRequest *requests;
|
||||
@ -69,7 +69,7 @@ struct SCSIDevice
|
||||
/* Global pool of SCSIRequest structures. */
|
||||
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;
|
||||
|
||||
@ -93,7 +93,7 @@ static SCSIRequest *scsi_new_request(SCSIDevice *s, uint32_t tag)
|
||||
static void scsi_remove_request(SCSIRequest *r)
|
||||
{
|
||||
SCSIRequest *last;
|
||||
SCSIDevice *s = r->dev;
|
||||
SCSIDeviceState *s = r->dev;
|
||||
|
||||
if (s->requests == r) {
|
||||
s->requests = r->next;
|
||||
@ -111,7 +111,7 @@ static void scsi_remove_request(SCSIRequest *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;
|
||||
|
||||
@ -125,7 +125,7 @@ static SCSIRequest *scsi_find_request(SCSIDevice *s, uint32_t tag)
|
||||
/* Helper function for command completion. */
|
||||
static void scsi_command_complete(SCSIRequest *r, int sense)
|
||||
{
|
||||
SCSIDevice *s = r->dev;
|
||||
SCSIDeviceState *s = r->dev;
|
||||
uint32_t tag;
|
||||
DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense);
|
||||
s->sense = sense;
|
||||
@ -135,8 +135,9 @@ static void scsi_command_complete(SCSIRequest *r, int sense)
|
||||
}
|
||||
|
||||
/* 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;
|
||||
DPRINTF("Cancel tag=0x%x\n", 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)
|
||||
{
|
||||
SCSIRequest *r = (SCSIRequest *)opaque;
|
||||
SCSIDevice *s = r->dev;
|
||||
SCSIDeviceState *s = r->dev;
|
||||
|
||||
if (ret) {
|
||||
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. */
|
||||
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;
|
||||
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)
|
||||
{
|
||||
SCSIRequest *r = (SCSIRequest *)opaque;
|
||||
SCSIDevice *s = r->dev;
|
||||
SCSIDeviceState *s = r->dev;
|
||||
uint32_t len;
|
||||
|
||||
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.
|
||||
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;
|
||||
uint32_t n;
|
||||
|
||||
@ -259,8 +262,9 @@ int scsi_write_data(SCSIDevice *s, uint32_t tag)
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
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),
|
||||
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;
|
||||
uint32_t lba;
|
||||
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);
|
||||
if (r) {
|
||||
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
|
||||
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,
|
||||
int tcq,
|
||||
scsi_completionfn completion,
|
||||
void *opaque)
|
||||
SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
|
||||
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->tcq = tcq;
|
||||
s->completion = completion;
|
||||
@ -599,6 +605,14 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
|
||||
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;
|
||||
}
|
||||
|
@ -7,24 +7,25 @@ enum scsi_reason {
|
||||
SCSI_REASON_DATA /* Transfer complete, more data required. */
|
||||
};
|
||||
|
||||
typedef struct SCSIDeviceState SCSIDeviceState;
|
||||
typedef struct SCSIDevice SCSIDevice;
|
||||
typedef void (*scsi_completionfn)(void *opaque, int reason, uint32_t tag,
|
||||
uint32_t arg);
|
||||
|
||||
SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
|
||||
int tcq,
|
||||
scsi_completionfn completion,
|
||||
void *opaque);
|
||||
void scsi_disk_destroy(SCSIDevice *s);
|
||||
struct SCSIDevice
|
||||
{
|
||||
SCSIDeviceState *state;
|
||||
void (*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);
|
||||
/* SCSI data transfers are asynchrnonous. However, unlike the block IO
|
||||
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);
|
||||
SCSIDevice *scsi_disk_init(BlockDriverState *bdrv, int tcq,
|
||||
scsi_completionfn completion, void *opaque);
|
||||
|
||||
/* cdrom.c */
|
||||
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
|
||||
|
16
hw/usb-msd.c
16
hw/usb-msd.c
@ -149,9 +149,9 @@ static void usb_msd_copy_data(MSDState *s)
|
||||
s->data_len -= len;
|
||||
if (s->scsi_len == 0) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
usb_msd_copy_data(s);
|
||||
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)
|
||||
{
|
||||
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->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",
|
||||
s->tag, cbw.flags, cbw.cmd_len, s->data_len);
|
||||
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
|
||||
directions match. */
|
||||
if (s->residue == 0) {
|
||||
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) {
|
||||
scsi_write_data(s->scsi_dev, s->tag);
|
||||
s->scsi_dev->write_data(s->scsi_dev, s->tag);
|
||||
}
|
||||
}
|
||||
ret = len;
|
||||
@ -508,7 +508,7 @@ static void usb_msd_handle_destroy(USBDevice *dev)
|
||||
{
|
||||
MSDState *s = (MSDState *)dev;
|
||||
|
||||
scsi_disk_destroy(s->scsi_dev);
|
||||
s->scsi_dev->destroy(s->scsi_dev);
|
||||
bdrv_delete(s->bs);
|
||||
qemu_free(s);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user