Merge remote-tracking branch 'bonzini/scsi-next' into staging

* bonzini/scsi-next:
  scsi: add support for ATA_PASSTHROUGH_xx scsi command
  esp: add missing const on TypeInfo structures
  esp: enable for all PCI machines
  Revert "megasas: disable due to build breakage"
  megasas: static SAS addresses
  scsi-disk: fix compilation with DEBUG_SCSI
  megasas: Update function megasys_scsi_uninit
  SCSI: STARTSTOPUNIT only eject/load media if powercondition is 0
  SCSI: Update the sense code for PREVENT REMOVAL errors
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index fee8cde..2c78175 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -25,4 +25,3 @@
 CONFIG_APPLESMC=y
 CONFIG_I8259=y
 CONFIG_PFLASH_CFI01=y
-CONFIG_ESP=y
diff --git a/default-configs/pci.mak b/default-configs/pci.mak
index 9d3e1db..9febb47 100644
--- a/default-configs/pci.mak
+++ b/default-configs/pci.mak
@@ -10,9 +10,11 @@
 CONFIG_PCNET_PCI=y
 CONFIG_PCNET_COMMON=y
 CONFIG_LSI_SCSI_PCI=y
+CONFIG_MEGASAS_SCSI_PCI=y
 CONFIG_RTL8139_PCI=y
 CONFIG_E1000_PCI=y
 CONFIG_IDE_CORE=y
 CONFIG_IDE_QDEV=y
 CONFIG_IDE_PCI=y
 CONFIG_AHCI=y
+CONFIG_ESP=y
diff --git a/hw/esp.c b/hw/esp.c
index a011347..77f5707 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -816,7 +816,7 @@
     dc->vmsd = &vmstate_sysbus_esp_scsi;
 }
 
-static TypeInfo sysbus_esp_info = {
+static const TypeInfo sysbus_esp_info = {
     .name          = "esp",
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(SysBusESPState),
@@ -1176,7 +1176,7 @@
     dc->vmsd = &vmstate_esp_pci_scsi;
 }
 
-static TypeInfo esp_pci_info = {
+static const TypeInfo esp_pci_info = {
     .name = "am53c974",
     .parent = TYPE_PCI_DEVICE,
     .instance_size = sizeof(PCIESPState),
diff --git a/hw/megasas.c b/hw/megasas.c
index 9a0eab1..c35a15d 100644
--- a/hw/megasas.c
+++ b/hw/megasas.c
@@ -38,6 +38,9 @@
 #define MEGASAS_MAX_SECTORS 0xFFFF      /* No real limit */
 #define MEGASAS_MAX_ARRAYS 128
 
+#define NAA_LOCALLY_ASSIGNED_ID 0x3ULL
+#define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400
+
 #define MEGASAS_FLAG_USE_JBOD      0
 #define MEGASAS_MASK_USE_JBOD      (1 << MEGASAS_FLAG_USE_JBOD)
 #define MEGASAS_FLAG_USE_MSIX      1
@@ -89,6 +92,8 @@
     int shutdown_event;
     int boot_event;
 
+    uint64_t sas_addr;
+
     uint64_t reply_queue_pa;
     void *reply_queue;
     int reply_queue_len;
@@ -372,14 +377,16 @@
     return bcd_time;
 }
 
-static uint64_t megasas_gen_sas_addr(uint64_t id)
+/*
+ * Default disk sata address
+ * 0x1221 is the magic number as
+ * present in real hardware,
+ * so use it here, too.
+ */
+static uint64_t megasas_get_sata_addr(uint16_t id)
 {
-    uint64_t addr;
-
-    addr = 0x5001a4aULL << 36;
-    addr |= id & 0xfffffffff;
-
-    return addr;
+    uint64_t addr = (0x1221ULL << 48);
+    return addr & (id << 24);
 }
 
 /*
@@ -652,10 +659,7 @@
     size_t dcmd_size = sizeof(info);
     BusChild *kid;
     int num_ld_disks = 0;
-
-    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
-        num_ld_disks++;
-    }
+    uint16_t sdev_id;
 
     memset(&info, 0x0, cmd->iov_size);
     if (cmd->iov_size < dcmd_size) {
@@ -669,10 +673,29 @@
     info.pci.subvendor = cpu_to_le16(PCI_VENDOR_ID_LSI_LOGIC);
     info.pci.subdevice = cpu_to_le16(0x1013);
 
-    info.host.type = MFI_INFO_HOST_PCIX;
+    /*
+     * For some reason the firmware supports
+     * only up to 8 device ports.
+     * Despite supporting a far larger number
+     * of devices for the physical devices.
+     * So just display the first 8 devices
+     * in the device port list, independent
+     * of how many logical devices are actually
+     * present.
+     */
+    info.host.type = MFI_INFO_HOST_PCIE;
     info.device.type = MFI_INFO_DEV_SAS3G;
-    info.device.port_count = 2;
-    info.device.port_addr[0] = cpu_to_le64(megasas_gen_sas_addr((uint64_t)s));
+    info.device.port_count = 8;
+    QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+        SCSIDevice *sdev = DO_UPCAST(SCSIDevice, qdev, kid->child);
+
+        if (num_ld_disks < 8) {
+            sdev_id = ((sdev->id & 0xFF) >> 8) | (sdev->lun & 0xFF);
+            info.device.port_addr[num_ld_disks] =
+                cpu_to_le64(megasas_get_sata_addr(sdev_id));
+        }
+        num_ld_disks++;
+    }
 
     memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
     snprintf(info.serial_number, 32, "QEMU%08lx",
@@ -761,7 +784,7 @@
         return MFI_STAT_INVALID_PARAMETER;
     }
 
-    info.sas_addr = cpu_to_le64(megasas_gen_sas_addr((uint64_t)s));
+    info.sas_addr = cpu_to_le64(s->sas_addr);
     info.stripe_size = 3;
     info.flush_time = 4;
     info.background_rate = 30;
@@ -891,7 +914,7 @@
         info.addr[num_pd_disks].scsi_dev_type = sdev->type;
         info.addr[num_pd_disks].connect_port_bitmap = 0x1;
         info.addr[num_pd_disks].sas_addr[0] =
-            cpu_to_le64(megasas_gen_sas_addr((uint64_t)sdev));
+            cpu_to_le64(megasas_get_sata_addr(sdev_id));
         num_pd_disks++;
         offset += sizeof(struct mfi_pd_address);
     }
@@ -994,7 +1017,7 @@
     info->slot_number = (sdev->id & 0xFF);
     info->path_info.count = 1;
     info->path_info.sas_addr[0] =
-        cpu_to_le64(megasas_gen_sas_addr((uint64_t)sdev));
+        cpu_to_le64(megasas_get_sata_addr(sdev_id));
     info->connected_port_bitmap = 0x1;
     info->device_speed = 1;
     info->link_speed = 1;
@@ -2040,7 +2063,7 @@
     }
 };
 
-static int megasas_scsi_uninit(PCIDevice *d)
+static void megasas_scsi_uninit(PCIDevice *d)
 {
     MegasasState *s = DO_UPCAST(MegasasState, dev, d);
 
@@ -2050,7 +2073,6 @@
     memory_region_destroy(&s->mmio_io);
     memory_region_destroy(&s->port_io);
     memory_region_destroy(&s->queue_io);
-    return 0;
 }
 
 static const struct SCSIBusInfo megasas_scsi_info = {
@@ -2103,6 +2125,13 @@
         msix_vector_use(&s->dev, 0);
     }
 
+    if (!s->sas_addr) {
+        s->sas_addr = ((NAA_LOCALLY_ASSIGNED_ID << 24) |
+                       IEEE_COMPANY_LOCALLY_ASSIGNED) << 36;
+        s->sas_addr |= (pci_bus_num(dev->bus) << 16);
+        s->sas_addr |= (PCI_SLOT(dev->devfn) << 8);
+        s->sas_addr |= PCI_FUNC(dev->devfn);
+    }
     if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
         s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
     } else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) {
@@ -2137,6 +2166,7 @@
                        MEGASAS_DEFAULT_SGE),
     DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
                        MEGASAS_DEFAULT_FRAMES),
+    DEFINE_PROP_HEX64("sas_address", MegasasState, sas_addr, 0),
 #ifdef USE_MSIX
     DEFINE_PROP_BIT("use_msix", MegasasState, flags,
                     MEGASAS_FLAG_USE_MSIX, false),
diff --git a/hw/mfi.h b/hw/mfi.h
index 3045d4e..436b690 100644
--- a/hw/mfi.h
+++ b/hw/mfi.h
@@ -656,6 +656,7 @@
 #define MFI_INFO_DEV_SAS3G      0x02
 #define MFI_INFO_DEV_SATA1      0x04
 #define MFI_INFO_DEV_SATA3G     0x08
+#define MFI_INFO_DEV_PCIE       0x10
     uint8_t reserved[6];
     uint8_t port_count;
     uint64_t port_addr[8];
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index e4ec19e..6120cc8 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -733,6 +733,72 @@
     }
 }
 
+static int ata_passthrough_xfer_unit(SCSIDevice *dev, uint8_t *buf)
+{
+    int byte_block = (buf[2] >> 2) & 0x1;
+    int type = (buf[2] >> 4) & 0x1;
+    int xfer_unit;
+
+    if (byte_block) {
+        if (type) {
+            xfer_unit = dev->blocksize;
+        } else {
+            xfer_unit = 512;
+        }
+    } else {
+        xfer_unit = 1;
+    }
+
+    return xfer_unit;
+}
+
+static int ata_passthrough_12_xfer_size(SCSIDevice *dev, uint8_t *buf)
+{
+    int length = buf[2] & 0x3;
+    int xfer;
+    int unit = ata_passthrough_xfer_unit(dev, buf);
+
+    switch (length) {
+    case 0:
+    case 3: /* USB-specific.  */
+        xfer = 0;
+        break;
+    case 1:
+        xfer = buf[3];
+        break;
+    case 2:
+        xfer = buf[4];
+        break;
+    }
+
+    return xfer * unit;
+}
+
+static int ata_passthrough_16_xfer_size(SCSIDevice *dev, uint8_t *buf)
+{
+    int extend = buf[1] & 0x1;
+    int length = buf[2] & 0x3;
+    int xfer;
+    int unit = ata_passthrough_xfer_unit(dev, buf);
+
+    switch (length) {
+    case 0:
+    case 3: /* USB-specific.  */
+        xfer = 0;
+        break;
+    case 1:
+        xfer = buf[4];
+        xfer |= (extend ? buf[3] << 8 : 0);
+        break;
+    case 2:
+        xfer = buf[6];
+        xfer |= (extend ? buf[5] << 8 : 0);
+        break;
+    }
+
+    return xfer * unit;
+}
+
 static int scsi_req_length(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf)
 {
     switch (buf[0] >> 5) {
@@ -867,6 +933,17 @@
             cmd->xfer = buf[9] | (buf[8] << 8);
         }
         break;
+    case ATA_PASSTHROUGH_12:
+        if (dev->type == TYPE_ROM) {
+            /* BLANK command of MMC */
+            cmd->xfer = 0;
+        } else {
+            cmd->xfer = ata_passthrough_12_xfer_size(dev, buf);
+        }
+        break;
+    case ATA_PASSTHROUGH_16:
+        cmd->xfer = ata_passthrough_16_xfer_size(dev, buf);
+        break;
     }
     return 0;
 }
@@ -996,9 +1073,14 @@
     case SEND_DVD_STRUCTURE:
     case PERSISTENT_RESERVE_OUT:
     case MAINTENANCE_OUT:
-    case ATA_PASSTHROUGH:
         cmd->mode = SCSI_XFER_TO_DEV;
         break;
+    case ATA_PASSTHROUGH_12:
+    case ATA_PASSTHROUGH_16:
+        /* T_DIR */
+        cmd->mode = (cmd->buf[2] & 0x8) ?
+                   SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV;
+        break;
     default:
         cmd->mode = SCSI_XFER_FROM_DEV;
         break;
@@ -1103,7 +1185,7 @@
 
 /* LUN not ready, medium removal prevented */
 const struct SCSISense sense_code_NOT_READY_REMOVAL_PREVENTED = {
-    .key = NOT_READY, .asc = 0x53, .ascq = 0x00
+    .key = NOT_READY, .asc = 0x53, .ascq = 0x02
 };
 
 /* Hardware error, internal target failure */
@@ -1153,7 +1235,7 @@
 
 /* Illegal request, medium removal prevented */
 const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = {
-    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x00
+    .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02
 };
 
 /* Command aborted, I/O process terminated */
@@ -1335,7 +1417,7 @@
         [ PERSISTENT_RESERVE_OUT   ] = "PERSISTENT_RESERVE_OUT",
         [ WRITE_FILEMARKS_16       ] = "WRITE_FILEMARKS_16",
         [ EXTENDED_COPY            ] = "EXTENDED_COPY",
-        [ ATA_PASSTHROUGH          ] = "ATA_PASSTHROUGH",
+        [ ATA_PASSTHROUGH_16       ] = "ATA_PASSTHROUGH_16",
         [ ACCESS_CONTROL_IN        ] = "ACCESS_CONTROL_IN",
         [ ACCESS_CONTROL_OUT       ] = "ACCESS_CONTROL_OUT",
         [ READ_16                  ] = "READ_16",
@@ -1352,7 +1434,7 @@
         [ SERVICE_ACTION_IN_16     ] = "SERVICE_ACTION_IN_16",
         [ WRITE_LONG_16            ] = "WRITE_LONG_16",
         [ REPORT_LUNS              ] = "REPORT_LUNS",
-        [ BLANK                    ] = "BLANK",
+        [ ATA_PASSTHROUGH_12       ] = "BLANK/ATA_PASSTHROUGH_12",
         [ MOVE_MEDIUM              ] = "MOVE_MEDIUM",
         [ EXCHANGE_MEDIUM          ] = "EXCHANGE MEDIUM",
         [ LOAD_UNLOAD              ] = "LOAD_UNLOAD",
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index 8a73f74..d7a4019 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -100,7 +100,7 @@
 #define READ_REVERSE_16       0x81
 #define ALLOW_OVERWRITE       0x82
 #define EXTENDED_COPY         0x83
-#define ATA_PASSTHROUGH       0x85
+#define ATA_PASSTHROUGH_16    0x85
 #define ACCESS_CONTROL_IN     0x86
 #define ACCESS_CONTROL_OUT    0x87
 #define READ_16               0x88
@@ -117,7 +117,7 @@
 #define SERVICE_ACTION_IN_16  0x9e
 #define WRITE_LONG_16         0x9f
 #define REPORT_LUNS           0xa0
-#define BLANK                 0xa1
+#define ATA_PASSTHROUGH_12    0xa1
 #define MAINTENANCE_IN        0xa3
 #define MAINTENANCE_OUT       0xa4
 #define MOVE_MEDIUM           0xa5
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 84b63ff..a9c7279 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -447,7 +447,7 @@
         return;
     } else {
         scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
-        DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
+        DPRINTF("Write complete tag=0x%x more=%zd\n", r->req.tag, r->qiov.size);
         scsi_req_data(&r->req, r->qiov.size);
     }
 
@@ -1247,6 +1247,12 @@
     SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
     bool start = req->cmd.buf[4] & 1;
     bool loej = req->cmd.buf[4] & 2; /* load on start, eject on !start */
+    int pwrcnd = req->cmd.buf[4] & 0xf0;
+
+    if (pwrcnd) {
+        /* eject/load only happens for power condition == 0 */
+        return 0;
+    }
 
     if ((s->features & (1 << SCSI_DISK_F_REMOVABLE)) && loej) {
         if (!start && !s->tray_open && s->tray_locked) {
@@ -1271,7 +1277,7 @@
     int buflen = r->iov.iov_len;
 
     if (buflen) {
-        DPRINTF("Read buf_len=%zd\n", buflen);
+        DPRINTF("Read buf_len=%d\n", buflen);
         r->iov.iov_len = 0;
         r->started = true;
         scsi_req_data(&r->req, buflen);
@@ -1449,7 +1455,7 @@
 
     if (r->iov.iov_len) {
         int buflen = r->iov.iov_len;
-        DPRINTF("Write buf_len=%zd\n", buflen);
+        DPRINTF("Write buf_len=%d\n", buflen);
         r->iov.iov_len = 0;
         scsi_req_data(&r->req, buflen);
         return;
@@ -2087,23 +2093,24 @@
     const SCSIReqOps *ops;
     uint8_t command;
 
-#ifdef DEBUG_SCSI
-    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, buf[0]);
-    {
-        int i;
-        for (i = 1; i < r->req.cmd.len; i++) {
-            printf(" 0x%02x", buf[i]);
-        }
-        printf("\n");
-    }
-#endif
-
     command = buf[0];
     ops = scsi_disk_reqops_dispatch[command];
     if (!ops) {
         ops = &scsi_disk_emulate_reqops;
     }
     req = scsi_req_alloc(ops, &s->qdev, tag, lun, hba_private);
+
+#ifdef DEBUG_SCSI
+    DPRINTF("Command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]);
+    {
+        int i;
+        for (i = 1; i < req->cmd.len; i++) {
+            printf(" 0x%02x", buf[i]);
+        }
+        printf("\n");
+    }
+#endif
+
     return req;
 }