Add PowerPC power-management state check callback.
[qemu] / hw / scsi-disk.c
index decab1f..384c098 100644 (file)
@@ -7,6 +7,10 @@
  * Written by Paul Brook
  *
  * This code is licenced under the LGPL.
+ *
+ * Note that this file only handles the SCSI architecture model and device
+ * commands.  Emultion of interface/link layer protocols is handled by
+ * the host adapter emulation.
  */
 
 //#define DEBUG_SCSI
@@ -24,150 +28,245 @@ do { fprintf(stderr, "scsi-disk: " fmt , ##args); } while (0)
 #include "vl.h"
 
 #define SENSE_NO_SENSE        0
+#define SENSE_NOT_READY       2
+#define SENSE_HARDWARE_ERROR  4
 #define SENSE_ILLEGAL_REQUEST 5
 
-struct SCSIDevice
-{
-    int command;
+#define SCSI_DMA_BUF_SIZE    65536
+
+typedef struct SCSIRequest {
+    SCSIDevice *dev;
     uint32_t tag;
-    BlockDriverState *bdrv;
-    /* The qemu block layer uses a fixed 512 byte sector size.
-       This is the number of 512 byte blocks in a single scsi sector.  */
-    int cluster_size;
-    /* When transfering data buf_pos and buf_len contain a partially
-       transferred block of data (or response to a command), and
-       sector/sector_count identify any remaining sectors.
-       Both sector and sector_count are in terms of qemu 512 byte blocks.  */
     /* ??? 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.  */
+    /* Both sector and sector_count are in terms of qemu 512 byte blocks.  */
     int sector;
     int sector_count;
-    int buf_pos;
+    /* The amounnt of data in the buffer.  */
     int buf_len;
+    uint8_t dma_buf[SCSI_DMA_BUF_SIZE];
+    BlockDriverAIOCB *aiocb;
+    struct SCSIRequest *next;
+} SCSIRequest;
+
+struct SCSIDevice
+{
+    BlockDriverState *bdrv;
+    SCSIRequest *requests;
+    /* The qemu block layer uses a fixed 512 byte sector size.
+       This is the number of 512 byte blocks in a single scsi sector.  */
+    int cluster_size;
     int sense;
-    char buf[512];
+    int tcq;
+    /* Completion functions may be called from either scsi_{read,write}_data
+       or from the AIO completion routines.  */
     scsi_completionfn completion;
     void *opaque;
 };
 
-static void scsi_command_complete(SCSIDevice *s, int sense)
+/* Global pool of SCSIRequest structures.  */
+static SCSIRequest *free_requests = NULL;
+
+static SCSIRequest *scsi_new_request(SCSIDevice *s, uint32_t tag)
 {
-    s->sense = sense;
-    s->completion(s->opaque, s->tag, sense);
+    SCSIRequest *r;
+
+    if (free_requests) {
+        r = free_requests;
+        free_requests = r->next;
+    } else {
+        r = qemu_malloc(sizeof(SCSIRequest));
+    }
+    r->dev = s;
+    r->tag = tag;
+    r->sector_count = 0;
+    r->buf_len = 0;
+    r->aiocb = NULL;
+
+    r->next = s->requests;
+    s->requests = r;
+    return r;
 }
 
-/* Read data from a scsi device.  Returns nonzero on failure.  */
-int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len)
+static void scsi_remove_request(SCSIRequest *r)
 {
-    uint32_t n;
-
-    DPRINTF("Read %d (%d/%d)\n", len, s->buf_len, s->sector_count);
-    if (s->buf_len == 0 && s->sector_count == 0)
-        return 1;
+    SCSIRequest *last;
+    SCSIDevice *s = r->dev;
 
-    if (s->buf_len) {
-        n = s->buf_len;
-        if (n > len)
-            n = len;
-        memcpy(data, s->buf + s->buf_pos, n);
-        s->buf_pos += n;
-        s->buf_len -= n;
-        data += n;
-        len -= n;
-        if (s->buf_len == 0)
-            s->buf_pos = 0;
+    if (s->requests == r) {
+        s->requests = r->next;
+    } else {
+        last = s->requests;
+        while (last && last->next != r)
+            last = last->next;
+        if (last) {
+            last->next = r->next;
+        } else {
+            BADF("Orphaned request\n");
+        }
     }
+    r->next = free_requests;
+    free_requests = r;
+}
+
+static SCSIRequest *scsi_find_request(SCSIDevice *s, uint32_t tag)
+{
+    SCSIRequest *r;
 
-    n = len / 512;
-    if (n > s->sector_count)
-      n = s->sector_count;
+    r = s->requests;
+    while (r && r->tag != tag)
+        r = r->next;
 
-    if (n != 0) {
-        bdrv_read(s->bdrv, s->sector, data, n);
-        data += n * 512;
-        len -= n * 512;
-        s->sector += n;
-        s->sector_count -= n;
-    }
+    return r;
+}
 
-    if (len && s->sector_count) {
-        bdrv_read(s->bdrv, s->sector, s->buf, 1);
-        s->sector++;
-        s->sector_count--;
-        s->buf_pos = 0;
-        s->buf_len = 512;
-        /* Recurse to complete the partial read.  */
-        return scsi_read_data(s, data, len);
+/* Helper function for command completion.  */
+static void scsi_command_complete(SCSIRequest *r, int sense)
+{
+    SCSIDevice *s = r->dev;
+    uint32_t tag;
+    DPRINTF("Command complete tag=0x%x sense=%d\n", r->tag, sense);
+    s->sense = sense;
+    tag = r->tag;
+    scsi_remove_request(r);
+    s->completion(s->opaque, SCSI_REASON_DONE, tag, sense);
+}
+
+/* Cancel a pending data transfer.  */
+void scsi_cancel_io(SCSIDevice *s, uint32_t tag)
+{
+    SCSIRequest *r;
+    DPRINTF("Cancel tag=0x%x\n", tag);
+    r = scsi_find_request(s, tag);
+    if (r) {
+        if (r->aiocb)
+            bdrv_aio_cancel(r->aiocb);
+        r->aiocb = NULL;
+        scsi_remove_request(r);
     }
+}
 
-    if (len != 0)
-        return 1;
+static void scsi_read_complete(void * opaque, int ret)
+{
+    SCSIRequest *r = (SCSIRequest *)opaque;
+    SCSIDevice *s = r->dev;
 
-    if (s->buf_len == 0 && s->sector_count == 0)
-        scsi_command_complete(s, SENSE_NO_SENSE);
+    if (ret) {
+        DPRINTF("IO error\n");
+        scsi_command_complete(r, SENSE_HARDWARE_ERROR);
+        return;
+    }
+    DPRINTF("Data ready tag=0x%x len=%d\n", r->tag, r->buf_len);
 
-    return 0;
+    s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len);
 }
 
-/* Read data to a scsi device.  Returns nonzero on failure.  */
-int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len)
+/* Read more data from scsi device into buffer.  */
+void scsi_read_data(SCSIDevice *s, uint32_t tag)
 {
+    SCSIRequest *r;
     uint32_t n;
 
-    DPRINTF("Write %d (%d/%d)\n", len, s->buf_len, s->sector_count);
-    if (s->buf_pos != 0) {
-        BADF("Bad state on write\n");
-        return 1;
+    r = scsi_find_request(s, tag);
+    if (!r) {
+        BADF("Bad read tag 0x%x\n", tag);
+        /* ??? This is the wrong error.  */
+        scsi_command_complete(r, SENSE_HARDWARE_ERROR);
+        return;
+    }
+    if (r->sector_count == (uint32_t)-1) {
+        DPRINTF("Read buf_len=%d\n", r->buf_len);
+        r->sector_count = 0;
+        s->completion(s->opaque, SCSI_REASON_DATA, r->tag, r->buf_len);
+        return;
+    }
+    DPRINTF("Read sector_count=%d\n", r->sector_count);
+    if (r->sector_count == 0) {
+        scsi_command_complete(r, SENSE_NO_SENSE);
+        return;
     }
 
-    if (s->sector_count == 0)
-        return 1;
+    n = r->sector_count;
+    if (n > SCSI_DMA_BUF_SIZE / 512)
+        n = SCSI_DMA_BUF_SIZE / 512;
+
+    r->buf_len = n * 512;
+    r->aiocb = bdrv_aio_read(s->bdrv, r->sector, r->dma_buf, n,
+                             scsi_read_complete, r);
+    if (r->aiocb == NULL)
+        scsi_command_complete(r, SENSE_HARDWARE_ERROR);
+    r->sector += n;
+    r->sector_count -= n;
+}
 
-    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;
-        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--;
-        }
-    }
+static void scsi_write_complete(void * opaque, int ret)
+{
+    SCSIRequest *r = (SCSIRequest *)opaque;
+    SCSIDevice *s = r->dev;
+    uint32_t len;
 
-    n = len / 512;
-    if (n > s->sector_count)
-        n = s->sector_count;
+    if (ret) {
+        fprintf(stderr, "scsi-disc: IO write error\n");
+        exit(1);
+    }
 
-    if (n != 0) {
-        bdrv_write(s->bdrv, s->sector, data, n);
-        data += n * 512;
-        len -= n * 512;
-        s->sector += n;
-        s->sector_count -= n;
+    r->aiocb = NULL;
+    if (r->sector_count == 0) {
+        scsi_command_complete(r, SENSE_NO_SENSE);
+    } else {
+        len = r->sector_count * 512;
+        if (len > SCSI_DMA_BUF_SIZE) {
+            len = SCSI_DMA_BUF_SIZE;
+        }
+        r->buf_len = len;
+        DPRINTF("Write complete tag=0x%x more=%d\n", r->tag, len);
+        s->completion(s->opaque, SCSI_REASON_DATA, r->tag, len);
     }
+}
 
-    if (len >= 512)
-        return 1;
+/* Write data to a scsi device.  Returns nonzero on failure.
+   The transfer may complete asynchronously.  */
+int scsi_write_data(SCSIDevice *s, uint32_t tag)
+{
+    SCSIRequest *r;
+    uint32_t n;
 
-    if (len && s->sector_count) {
-        /* Recurse to complete the partial write.  */
-        return scsi_write_data(s, data, len);
+    DPRINTF("Write data tag=0x%x\n", tag);
+    r = scsi_find_request(s, tag);
+    if (!r) {
+        BADF("Bad write tag 0x%x\n", tag);
+        scsi_command_complete(r, SENSE_HARDWARE_ERROR);
+        return 1;
+    }
+    if (r->aiocb)
+        BADF("Data transfer already in progress\n");
+    n = r->buf_len / 512;
+    if (n) {
+        r->aiocb = bdrv_aio_write(s->bdrv, r->sector, r->dma_buf, n,
+                                  scsi_write_complete, r);
+        if (r->aiocb == NULL)
+            scsi_command_complete(r, SENSE_HARDWARE_ERROR);
+        r->sector += n;
+        r->sector_count -= n;
+    } else {
+        /* Invoke completion routine to fetch data from host.  */
+        scsi_write_complete(r, 0);
     }
 
-    if (len != 0)
-        return 1;
+    return 0;
+}
 
-    if (s->sector_count == 0)
-        scsi_command_complete(s, SENSE_NO_SENSE);
+/* Return a pointer to the data buffer.  */
+uint8_t *scsi_get_buf(SCSIDevice *s, uint32_t tag)
+{
+    SCSIRequest *r;
 
-    return 0;
+    r = scsi_find_request(s, tag);
+    if (!r) {
+        BADF("Bad buffer tag 0x%x\n", tag);
+        return NULL;
+    }
+    return r->dma_buf;
 }
 
 /* Execute a scsi command.  Returns the length of the data expected by the
@@ -182,15 +281,23 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
     uint32_t len;
     int cmdlen;
     int is_write;
-
-    s->command = buf[0];
-    s->tag = tag;
-    s->sector_count = 0;
-    s->buf_pos = 0;
-    s->buf_len = 0;
+    uint8_t command;
+    uint8_t *outbuf;
+    SCSIRequest *r;
+
+    command = buf[0];
+    r = scsi_find_request(s, tag);
+    if (r) {
+        BADF("Tag 0x%x already in use\n", tag);
+        scsi_cancel_io(s, tag);
+    }
+    /* ??? Tags are not unique for different luns.  We only implement a
+       single lun, so this should not matter.  */
+    r = scsi_new_request(s, tag);
+    outbuf = r->dma_buf;
     is_write = 0;
-    DPRINTF("Command: 0x%02x", buf[0]);
-    switch (s->command >> 5) {
+    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
+    switch (command >> 5) {
     case 0:
         lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
         len = buf[4];
@@ -213,7 +320,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
         cmdlen = 12;
         break;
     default:
-        BADF("Unsupported command length, command %x\n", s->command);
+        BADF("Unsupported command length, command %x\n", command);
         goto fail;
     }
 #ifdef DEBUG_SCSI
@@ -230,7 +337,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
         DPRINTF("Unimplemented LUN %d\n", lun ? lun : buf[1] >> 5);
         goto fail;
     }
-    switch (s->command) {
+    switch (command) {
     case 0x0:
        DPRINTF("Test Unit Ready\n");
        break;
@@ -238,34 +345,36 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
         DPRINTF("Request Sense (len %d)\n", len);
         if (len < 4)
             goto fail;
-        memset(buf, 0, 4);
-        s->buf[0] = 0xf0;
-        s->buf[1] = 0;
-        s->buf[2] = s->sense;
-        s->buf_len = 4;
+        memset(outbuf, 0, 4);
+        outbuf[0] = 0xf0;
+        outbuf[1] = 0;
+        outbuf[2] = s->sense;
+        r->buf_len = 4;
         break;
     case 0x12:
         DPRINTF("Inquiry (len %d)\n", len);
         if (len < 36) {
             BADF("Inquiry buffer too small (%d)\n", len);
         }
-       memset(s->buf, 0, 36);
+       memset(outbuf, 0, 36);
        if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
-           s->buf[0] = 5;
-            s->buf[1] = 0x80;
-           memcpy(&s->buf[16], "QEMU CD-ROM    ", 16);
+           outbuf[0] = 5;
+            outbuf[1] = 0x80;
+           memcpy(&outbuf[16], "QEMU CD-ROM    ", 16);
        } else {
-           s->buf[0] = 0;
-           memcpy(&s->buf[16], "QEMU HARDDISK  ", 16);
+           outbuf[0] = 0;
+           memcpy(&outbuf[16], "QEMU HARDDISK  ", 16);
        }
-       memcpy(&s->buf[8], "QEMU   ", 8);
-        memcpy(&s->buf[32], QEMU_VERSION, 4);
+       memcpy(&outbuf[8], "QEMU   ", 8);
+        memcpy(&outbuf[32], QEMU_VERSION, 4);
         /* Identify device as SCSI-3 rev 1.
            Some later commands are also implemented. */
-       s->buf[2] = 3;
-       s->buf[3] = 2; /* Format 2 */
-       s->buf[4] = 32;
-       s->buf_len = 36;
+       outbuf[2] = 3;
+       outbuf[3] = 2; /* Format 2 */
+       outbuf[4] = 31;
+        /* Sync data transfer and TCQ.  */
+        outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0);
+       r->buf_len = 36;
        break;
     case 0x16:
         DPRINTF("Reserve(6)\n");
@@ -280,25 +389,26 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
     case 0x1a:
     case 0x5a:
         {
-            char *p;
+            uint8_t *p;
             int page;
 
             page = buf[2] & 0x3f;
             DPRINTF("Mode Sense (page %d, len %d)\n", page, len);
-            p = s->buf;
+            p = outbuf;
             memset(p, 0, 4);
-            s->buf[1] = 0; /* Default media type.  */
-            s->buf[3] = 0; /* Block descriptor length.  */
+            outbuf[1] = 0; /* Default media type.  */
+            outbuf[3] = 0; /* Block descriptor length.  */
             if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {
-                s->buf[2] = 0x80; /* Readonly.  */
+                outbuf[2] = 0x80; /* Readonly.  */
             }
             p += 4;
             if ((page == 8 || page == 0x3f)) {
                 /* Caching page.  */
+                memset(p,0,20);
                 p[0] = 8;
                 p[1] = 0x12;
                 p[2] = 4; /* WCE */
-                p += 19;
+                p += 20;
             }
             if ((page == 0x3f || page == 0x2a)
                     && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) {
@@ -328,12 +438,12 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
                 p[19] = (16 * 176) & 0xff;
                 p[20] = (16 * 176) >> 8; // 16x write speed current
                 p[21] = (16 * 176) & 0xff;
-                p += 21;
+                p += 22;
             }
-            s->buf_len = p - s->buf;
-            s->buf[0] = s->buf_len - 4;
-            if (s->buf_len > len)
-                s->buf_len = len;
+            r->buf_len = p - outbuf;
+            outbuf[0] = r->buf_len - 4;
+            if (r->buf_len > len)
+                r->buf_len = len;
         }
         break;
     case 0x1b:
@@ -346,33 +456,40 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
     case 0x25:
        DPRINTF("Read Capacity\n");
         /* The normal LEN field for this command is zero.  */
-       memset(s->buf, 0, 8);
+       memset(outbuf, 0, 8);
        bdrv_get_geometry(s->bdrv, &nb_sectors);
-       s->buf[0] = (nb_sectors >> 24) & 0xff;
-       s->buf[1] = (nb_sectors >> 16) & 0xff;
-       s->buf[2] = (nb_sectors >> 8) & 0xff;
-       s->buf[3] = nb_sectors & 0xff;
-       s->buf[4] = 0;
-       s->buf[5] = 0;
-        s->buf[6] = s->cluster_size * 2;
-       s->buf[7] = 0;
-       s->buf_len = 8;
+        /* Returned value is the address of the last sector.  */
+        if (nb_sectors) {
+            nb_sectors--;
+            outbuf[0] = (nb_sectors >> 24) & 0xff;
+            outbuf[1] = (nb_sectors >> 16) & 0xff;
+            outbuf[2] = (nb_sectors >> 8) & 0xff;
+            outbuf[3] = nb_sectors & 0xff;
+            outbuf[4] = 0;
+            outbuf[5] = 0;
+            outbuf[6] = s->cluster_size * 2;
+            outbuf[7] = 0;
+            r->buf_len = 8;
+        } else {
+            scsi_command_complete(r, SENSE_NOT_READY);
+            return 0;
+        }
        break;
     case 0x08:
     case 0x28:
         DPRINTF("Read (sector %d, count %d)\n", lba, len);
-        s->sector = lba * s->cluster_size;
-        s->sector_count = len * s->cluster_size;
+        r->sector = lba * s->cluster_size;
+        r->sector_count = len * s->cluster_size;
         break;
     case 0x0a:
     case 0x2a:
         DPRINTF("Write (sector %d, count %d)\n", lba, len);
-        s->sector = lba * s->cluster_size;
-        s->sector_count = len * s->cluster_size;
+        r->sector = lba * s->cluster_size;
+        r->sector_count = len * s->cluster_size;
         is_write = 1;
         break;
     case 0x35:
-        DPRINTF("Syncronise cache (sector %d, count %d)\n", lba, len);
+        DPRINTF("Synchronise cache (sector %d, count %d)\n", lba, len);
         bdrv_flush(s->bdrv);
         break;
     case 0x43:
@@ -386,18 +503,18 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
             DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
             switch(format) {
             case 0:
-                toclen = cdrom_read_toc(nb_sectors, s->buf, msf, start_track);
+                toclen = cdrom_read_toc(nb_sectors, outbuf, msf, start_track);
                 break;
             case 1:
                 /* multi session : only a single session defined */
                 toclen = 12;
-                memset(s->buf, 0, 12);
-                s->buf[1] = 0x0a;
-                s->buf[2] = 0x01;
-                s->buf[3] = 0x01;
+                memset(outbuf, 0, 12);
+                outbuf[1] = 0x0a;
+                outbuf[2] = 0x01;
+                outbuf[3] = 0x01;
                 break;
             case 2:
-                toclen = cdrom_read_toc_raw(nb_sectors, s->buf, msf, start_track);
+                toclen = cdrom_read_toc_raw(nb_sectors, outbuf, msf, start_track);
                 break;
             default:
                 goto error_cmd;
@@ -405,7 +522,7 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
             if (toclen > 0) {
                 if (len > toclen)
                   len = toclen;
-                s->buf_len = len;
+                r->buf_len = len;
                 break;
             }
         error_cmd:
@@ -414,11 +531,11 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
         }
     case 0x46:
         DPRINTF("Get Configuration (rt %d, maxlen %d)\n", buf[1] & 3, len);
-        memset(s->buf, 0, 8);
+        memset(outbuf, 0, 8);
         /* ??? This shoud probably return much more information.  For now
            just return the basic header indicating the CD-ROM profile.  */
-        s->buf[7] = 8; // CD-ROM
-        s->buf_len = 8;
+        outbuf[7] = 8; // CD-ROM
+        r->buf_len = 8;
         break;
     case 0x56:
         DPRINTF("Reserve(10)\n");
@@ -434,30 +551,36 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun)
         DPRINTF("Report LUNs (len %d)\n", len);
         if (len < 16)
             goto fail;
-        memset(s->buf, 0, 16);
-        s->buf[3] = 8;
-        s->buf_len = 16;
+        memset(outbuf, 0, 16);
+        outbuf[3] = 8;
+        r->buf_len = 16;
         break;
     default:
        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]);
     fail:
-        scsi_command_complete(s, SENSE_ILLEGAL_REQUEST);
+        scsi_command_complete(r, SENSE_ILLEGAL_REQUEST);
        return 0;
     }
-    if (s->sector_count == 0 && s->buf_len == 0) {
-        scsi_command_complete(s, SENSE_NO_SENSE);
+    if (r->sector_count == 0 && r->buf_len == 0) {
+        scsi_command_complete(r, SENSE_NO_SENSE);
+    }
+    len = r->sector_count * 512 + r->buf_len;
+    if (is_write) {
+        return -len;
+    } else {
+        if (!r->sector_count)
+            r->sector_count = -1;
+        return len;
     }
-    len = s->sector_count * 512 + s->buf_len;
-    return is_write ? -len : len;
 }
 
 void scsi_disk_destroy(SCSIDevice *s)
 {
-    bdrv_close(s->bdrv);
     qemu_free(s);
 }
 
 SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
+                           int tcq,
                            scsi_completionfn completion,
                            void *opaque)
 {
@@ -465,6 +588,7 @@ SCSIDevice *scsi_disk_init(BlockDriverState *bdrv,
 
     s = (SCSIDevice *)qemu_mallocz(sizeof(SCSIDevice));
     s->bdrv = bdrv;
+    s->tcq = tcq;
     s->completion = completion;
     s->opaque = opaque;
     if (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM) {