]> Git Repo - qemu.git/blobdiff - hw/scsi-disk.c
lsi: Adjust some register reset values
[qemu.git] / hw / scsi-disk.c
index d510da4aad505647d27dc5f8be2fb143a9beb94f..4d209197ce4e7e1142a89533118104fb1135aa9f 100644 (file)
@@ -19,8 +19,6 @@
  * the host adapter emulator.
  */
 
-#include <qemu-common.h>
-#include <sysemu.h>
 //#define DEBUG_SCSI
 
 #ifdef DEBUG_SCSI
@@ -34,6 +32,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
 
 #include "qemu-common.h"
+#include "qemu-error.h"
 #include "block.h"
 #include "scsi.h"
 #include "scsi-defs.h"
@@ -126,6 +125,8 @@ static void scsi_read_complete(void * opaque, int ret)
 {
     SCSIDiskReq *r = (SCSIDiskReq *)opaque;
 
+    r->req.aiocb = NULL;
+
     if (ret) {
         DPRINTF("IO error\n");
         r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0);
@@ -190,8 +191,8 @@ static int scsi_handle_write_error(SCSIDiskReq *r, int error)
     if ((error == ENOSPC && action == BLOCK_ERR_STOP_ENOSPC)
             || action == BLOCK_ERR_STOP_ANY) {
         r->status |= SCSI_REQ_STATUS_RETRY;
-        vm_stop(0);
         bdrv_mon_event(s->bs, BDRV_ACTION_STOP, 0);
+        vm_stop(0);
     } else {
         scsi_command_complete(r, CHECK_CONDITION,
                 HARDWARE_ERROR);
@@ -349,10 +350,11 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
         case 0x00: /* Supported page codes, mandatory */
             DPRINTF("Inquiry EVPD[Supported pages] "
                     "buffer size %zd\n", req->cmd.xfer);
-            outbuf[buflen++] = 3;    // number of pages
+            outbuf[buflen++] = 4;    // number of pages
             outbuf[buflen++] = 0x00; // list of supported pages (this page)
             outbuf[buflen++] = 0x80; // unit serial number
             outbuf[buflen++] = 0x83; // device identification
+            outbuf[buflen++] = 0xb0; // block device characteristics
             break;
 
         case 0x80: /* Device serial number, optional */
@@ -394,6 +396,29 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
             buflen += id_len;
             break;
         }
+        case 0xb0: /* block device characteristics */
+        {
+            unsigned int min_io_size =
+                    s->qdev.conf.min_io_size / s->qdev.blocksize;
+            unsigned int opt_io_size =
+                    s->qdev.conf.opt_io_size / s->qdev.blocksize;
+
+            /* required VPD size with unmap support */
+            outbuf[3] = buflen = 0x3c;
+
+            memset(outbuf + 4, 0, buflen - 4);
+
+            /* optimal transfer length granularity */
+            outbuf[6] = (min_io_size >> 8) & 0xff;
+            outbuf[7] = min_io_size & 0xff;
+
+            /* optimal transfer length */
+            outbuf[12] = (opt_io_size >> 24) & 0xff;
+            outbuf[13] = (opt_io_size >> 16) & 0xff;
+            outbuf[14] = (opt_io_size >> 8) & 0xff;
+            outbuf[15] = opt_io_size & 0xff;
+            break;
+        }
         default:
             BADF("Error: unsupported Inquiry (EVPD[%02X]) "
                  "buffer size %zd\n", page_code, req->cmd.xfer);
@@ -437,10 +462,16 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
         memcpy(&outbuf[16], "QEMU HARDDISK   ", 16);
     }
     memcpy(&outbuf[8], "QEMU    ", 8);
-    memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION, 4);
-    /* Identify device as SCSI-3 rev 1.
-       Some later commands are also implemented. */
-    outbuf[2] = 3;
+    memset(&outbuf[32], 0, 4);
+    memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION,
+           MIN(4, strlen(s->version ? s->version : QEMU_VERSION)));
+    /*
+     * We claim conformance to SPC-3, which is required for guests
+     * to ask for modern features like READ CAPACITY(16) or the
+     * block characteristics VPD page by default.  Not all of SPC-3
+     * is actually implemented, but we're good enough.
+     */
+    outbuf[2] = 5;
     outbuf[3] = 2; /* Format 2 */
 
     if (buflen > 36) {
@@ -586,8 +617,7 @@ static int scsi_disk_emulate_mode_sense(SCSIRequest *req, uint8_t *outbuf)
 
     p[1] = 0; /* Default media type.  */
     p[3] = 0; /* Block descriptor length.  */
-    if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM ||
-        bdrv_is_read_only(s->bs)) {
+    if (bdrv_is_read_only(s->bs)) {
         p[2] = 0x80; /* Readonly.  */
     }
     p += 4;
@@ -794,6 +824,8 @@ static int scsi_disk_emulate_command(SCSIRequest *req, uint8_t *outbuf)
             outbuf[9] = 0;
             outbuf[10] = s->cluster_size * 2;
             outbuf[11] = 0;
+            outbuf[12] = 0;
+            outbuf[13] = get_physical_block_exp(&s->qdev.conf);
             /* Protection, exponent and lowest lba field left blank. */
             buflen = req->cmd.xfer;
             break;
@@ -980,41 +1012,65 @@ static int32_t scsi_send_command(SCSIDevice *d, uint32_t tag,
     }
 }
 
-static void scsi_destroy(SCSIDevice *dev)
+static void scsi_disk_purge_requests(SCSIDiskState *s)
 {
-    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
     SCSIDiskReq *r;
 
     while (!QTAILQ_EMPTY(&s->qdev.requests)) {
         r = DO_UPCAST(SCSIDiskReq, req, QTAILQ_FIRST(&s->qdev.requests));
+        if (r->req.aiocb) {
+            bdrv_aio_cancel(r->req.aiocb);
+        }
         scsi_remove_request(r);
     }
+}
+
+static void scsi_disk_reset(DeviceState *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev.qdev, dev);
+    uint64_t nb_sectors;
+
+    scsi_disk_purge_requests(s);
+
+    bdrv_get_geometry(s->bs, &nb_sectors);
+    nb_sectors /= s->cluster_size;
+    if (nb_sectors) {
+        nb_sectors--;
+    }
+    s->max_lba = nb_sectors;
+}
+
+static void scsi_destroy(SCSIDevice *dev)
+{
+    SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+
+    scsi_disk_purge_requests(s);
     drive_uninit(s->qdev.conf.dinfo);
 }
 
 static int scsi_disk_initfn(SCSIDevice *dev)
 {
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
-    uint64_t nb_sectors;
 
     if (!s->qdev.conf.dinfo || !s->qdev.conf.dinfo->bdrv) {
-        qemu_error("scsi-disk: drive property not set\n");
+        error_report("scsi-disk: drive property not set");
         return -1;
     }
     s->bs = s->qdev.conf.dinfo->bdrv;
 
+    if (bdrv_is_sg(s->bs)) {
+        error_report("scsi-disk: unwanted /dev/sg*");
+        return -1;
+    }
+
     if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
-        s->cluster_size = 4;
+        s->qdev.blocksize = 2048;
     } else {
-        s->cluster_size = 1;
+        s->qdev.blocksize = s->qdev.conf.logical_block_size;
     }
-    s->qdev.blocksize = 512 * s->cluster_size;
+    s->cluster_size = s->qdev.blocksize / 512;
+
     s->qdev.type = TYPE_DISK;
-    bdrv_get_geometry(s->bs, &nb_sectors);
-    nb_sectors /= s->cluster_size;
-    if (nb_sectors)
-        nb_sectors--;
-    s->max_lba = nb_sectors;
     qemu_add_vm_change_state_handler(scsi_dma_restart_cb, s);
     return 0;
 }
@@ -1023,6 +1079,7 @@ static SCSIDeviceInfo scsi_disk_info = {
     .qdev.name    = "scsi-disk",
     .qdev.desc    = "virtual scsi disk or cdrom",
     .qdev.size    = sizeof(SCSIDiskState),
+    .qdev.reset   = scsi_disk_reset,
     .init         = scsi_disk_initfn,
     .destroy      = scsi_destroy,
     .send_command = scsi_send_command,
This page took 0.031944 seconds and 4 git commands to generate.