]> git.proxmox.com Git - qemu.git/commitdiff
SCSI cleanup, by Laurent Vivier.
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 10 Dec 2007 02:58:34 +0000 (02:58 +0000)
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
Mon, 10 Dec 2007 02:58:34 +0000 (02:58 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3797 c046a42c-6fe2-441c-8c8c-71466251a162

hw/esp.c
hw/lsi53c895a.c
hw/scsi-disk.c
hw/scsi-disk.h
hw/usb-msd.c

index d6af3f61f0e89c18224947a941a0f8ed648ee2d3..df7a5e16680ec6326b2a39a35962715f703fe1f9 100644 (file)
--- a/hw/esp.c
+++ b/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.  */
index dbf67cb0c16836d2b7b135ca57d9d60e45c4a0e7..3a4ddf7f63a7f867e3ce068f23f01a1955f5d3c8 100644 (file)
@@ -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);
index 700b91446e663e3cda534ddd3fe0fe26d9ffd74e..d281b8cbba23b47eb65652d433f90e0c19453aed 100644 (file)
@@ -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;
+}
index 9071cec4904e60b63f9ab4bb57c4bd80cb7a4190..ffe894b767ffa384635cff33ed037addd622fcf6 100644 (file)
@@ -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);
index 7ee9cc1da5405b69b2dc406ddcc498b478078885..01d492d42de0bb43fc755a843de8caaaa9341c22 100644 (file)
@@ -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);
 }