aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/megasas.c65
-rw-r--r--hw/mfi.h1
2 files changed, 49 insertions, 17 deletions
diff --git a/hw/megasas.c b/hw/megasas.c
index 8a4960f8a1..c35a15db4f 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 @@ typedef struct MegasasState {
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 @@ static uint64_t megasas_fw_time(void)
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 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
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 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
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 @@ static int megasas_mfc_get_defaults(MegasasState *s, MegasasCmd *cmd)
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 @@ static int megasas_dcmd_pd_get_list(MegasasState *s, MegasasCmd *cmd)
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 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
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;
@@ -2102,6 +2125,13 @@ static int megasas_scsi_init(PCIDevice *dev)
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) {
@@ -2136,6 +2166,7 @@ static Property megasas_properties[] = {
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 3045d4eb6e..436b6906b1 100644
--- a/hw/mfi.h
+++ b/hw/mfi.h
@@ -656,6 +656,7 @@ struct mfi_info_device {
#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];