Blame 0001-Support-for-booting-from-LSI-Logic-LSI53C1030-SAS106.patch

Paolo Bonzini b13ac1
From 4d785f1227127d63ef412eaf482259cedd3ccf99 Mon Sep 17 00:00:00 2001
Paolo Bonzini b13ac1
From: Don Slutz <Don.Slutz@Gmail.com>
Paolo Bonzini b13ac1
Date: Thu, 24 Sep 2015 13:44:10 +0200
Paolo Bonzini b13ac1
Subject: [PATCH] Support for booting from LSI Logic LSI53C1030, SAS1068,
Paolo Bonzini b13ac1
 SAS1068e
Paolo Bonzini b13ac1
Paolo Bonzini b13ac1
Also known as Fusion MPT disk; this controller model is supported
Paolo Bonzini b13ac1
by VirtualBox and VMware, and QEMU support patches have been
Paolo Bonzini b13ac1
posted.
Paolo Bonzini b13ac1
Paolo Bonzini b13ac1
Signed-off-by: Don Slutz <Don.Slutz@Gmail.com>
Paolo Bonzini b13ac1
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Paolo Bonzini b13ac1
---
Paolo Bonzini b13ac1
 Makefile          |   2 +-
Paolo Bonzini b13ac1
 src/Kconfig       |   6 ++
Paolo Bonzini b13ac1
 src/block.c       |   3 +
Paolo Bonzini b13ac1
 src/block.h       |   1 +
Paolo Bonzini b13ac1
 src/hw/mpt-scsi.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
Paolo Bonzini b13ac1
 src/hw/mpt-scsi.h |   8 ++
Paolo Bonzini b13ac1
 src/post.c        |   2 +
Paolo Bonzini b13ac1
 7 files changed, 334 insertions(+), 1 deletion(-)
Paolo Bonzini b13ac1
 create mode 100644 src/hw/mpt-scsi.c
Paolo Bonzini b13ac1
 create mode 100644 src/hw/mpt-scsi.h
Paolo Bonzini b13ac1
Paolo Bonzini b13ac1
diff --git a/Makefile b/Makefile
Paolo Bonzini b13ac1
index 3a0d2e8..fcbd88a 100644
Paolo Bonzini b13ac1
--- a/Makefile
Paolo Bonzini b13ac1
+++ b/Makefile
Paolo Bonzini b13ac1
@@ -34,7 +34,7 @@ SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \
Paolo Bonzini b13ac1
     hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \
Paolo Bonzini b13ac1
     hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \
Paolo Bonzini b13ac1
     hw/blockcmd.c hw/floppy.c hw/ata.c hw/ramdisk.c \
Paolo Bonzini b13ac1
-    hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c
Paolo Bonzini b13ac1
+    hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c hw/mpt-scsi.c
Paolo Bonzini b13ac1
 SRC16=$(SRCBOTH)
Paolo Bonzini b13ac1
 SRC32FLAT=$(SRCBOTH) post.c e820map.c malloc.c romfile.c x86.c optionroms.c \
Paolo Bonzini b13ac1
     pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c tcgbios.c sha1.c \
Paolo Bonzini b13ac1
diff --git a/src/Kconfig b/src/Kconfig
Paolo Bonzini b13ac1
index b873cd3..8250702 100644
Paolo Bonzini b13ac1
--- a/src/Kconfig
Paolo Bonzini b13ac1
+++ b/src/Kconfig
Paolo Bonzini b13ac1
@@ -208,6 +208,12 @@ menu "Hardware support"
Paolo Bonzini b13ac1
         default y
Paolo Bonzini b13ac1
         help
Paolo Bonzini b13ac1
             Support boot from LSI MegaRAID SAS scsi storage.
Paolo Bonzini b13ac1
+    config MPT_SCSI
Paolo Bonzini b13ac1
+        depends on DRIVES
Paolo Bonzini b13ac1
+        bool "LSI MPT Fusion controllers"
Paolo Bonzini b13ac1
+        default y
Paolo Bonzini b13ac1
+        help
Paolo Bonzini b13ac1
+            Support boot from LSI MPT Fusion scsi storage.
Paolo Bonzini b13ac1
     config FLOPPY
Paolo Bonzini b13ac1
         depends on DRIVES && HARDWARE_IRQ
Paolo Bonzini b13ac1
         bool "Floppy controller"
Paolo Bonzini b13ac1
diff --git a/src/block.c b/src/block.c
Paolo Bonzini b13ac1
index 97e05fa..ef1cd9f 100644
Paolo Bonzini b13ac1
--- a/src/block.c
Paolo Bonzini b13ac1
+++ b/src/block.c
Paolo Bonzini b13ac1
@@ -13,6 +13,7 @@
Paolo Bonzini b13ac1
 #include "hw/esp-scsi.h" // esp_scsi_process_op
Paolo Bonzini b13ac1
 #include "hw/lsi-scsi.h" // lsi_scsi_process_op
Paolo Bonzini b13ac1
 #include "hw/megasas.h" // megasas_process_op
Paolo Bonzini b13ac1
+#include "hw/mpt-scsi.h" // mpt_scsi_process_op
Paolo Bonzini b13ac1
 #include "hw/pci.h" // pci_bdf_to_bus
Paolo Bonzini b13ac1
 #include "hw/pvscsi.h" // pvscsi_process_op
Paolo Bonzini b13ac1
 #include "hw/rtc.h" // rtc_read
Paolo Bonzini b13ac1
@@ -521,6 +522,8 @@ process_op_both(struct disk_op_s *op)
Paolo Bonzini b13ac1
         return esp_scsi_process_op(op);
Paolo Bonzini b13ac1
     case DTYPE_MEGASAS:
Paolo Bonzini b13ac1
         return megasas_process_op(op);
Paolo Bonzini b13ac1
+    case DTYPE_MPT_SCSI:
Paolo Bonzini b13ac1
+        return mpt_scsi_process_op(op);
Paolo Bonzini b13ac1
     default:
Paolo Bonzini b13ac1
         if (!MODESEGMENT)
Paolo Bonzini b13ac1
             return DISK_RET_EPARAM;
Paolo Bonzini b13ac1
diff --git a/src/block.h b/src/block.h
Paolo Bonzini b13ac1
index 2ff359f..7de6f54 100644
Paolo Bonzini b13ac1
--- a/src/block.h
Paolo Bonzini b13ac1
+++ b/src/block.h
Paolo Bonzini b13ac1
@@ -80,6 +80,7 @@ struct drive_s {
Paolo Bonzini b13ac1
 #define DTYPE_ESP_SCSI     0x81
Paolo Bonzini b13ac1
 #define DTYPE_MEGASAS      0x82
Paolo Bonzini b13ac1
 #define DTYPE_PVSCSI       0x83
Paolo Bonzini b13ac1
+#define DTYPE_MPT_SCSI     0x84
Paolo Bonzini b13ac1
 #define DTYPE_SDCARD       0x90
Paolo Bonzini b13ac1
 
Paolo Bonzini b13ac1
 #define MAXDESCSIZE 80
Paolo Bonzini b13ac1
diff --git a/src/hw/mpt-scsi.c b/src/hw/mpt-scsi.c
Paolo Bonzini b13ac1
new file mode 100644
Paolo Bonzini b13ac1
index 0000000..44f5446
Paolo Bonzini b13ac1
--- /dev/null
Paolo Bonzini b13ac1
+++ b/src/hw/mpt-scsi.c
Paolo Bonzini b13ac1
@@ -0,0 +1,313 @@
Paolo Bonzini b13ac1
+// MPT Fusion boot support.
Paolo Bonzini b13ac1
+//
Paolo Bonzini b13ac1
+// This file may be distributed under the terms of the GNU LGPLv3 license.
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+#include "biosvar.h" // GET_GLOBALFLAT
Paolo Bonzini b13ac1
+#include "block.h" // struct drive_s
Paolo Bonzini b13ac1
+#include "blockcmd.h" // scsi_drive_setup
Paolo Bonzini b13ac1
+#include "config.h" // CONFIG_*
Paolo Bonzini b13ac1
+#include "malloc.h" // free
Paolo Bonzini b13ac1
+#include "output.h" // dprintf
Paolo Bonzini b13ac1
+#include "pci.h" // foreachpci
Paolo Bonzini b13ac1
+#include "pci_ids.h" // PCI_DEVICE_ID
Paolo Bonzini b13ac1
+#include "pci_regs.h" // PCI_VENDOR_ID
Paolo Bonzini b13ac1
+#include "std/disk.h" // DISK_RET_SUCCESS
Paolo Bonzini b13ac1
+#include "string.h" // memset
Paolo Bonzini b13ac1
+#include "util.h" // usleep
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+#define MPT_REG_DOORBELL  0x00
Paolo Bonzini b13ac1
+#define MPT_REG_WRITE_SEQ 0x04
Paolo Bonzini b13ac1
+#define MPT_REG_HOST_DIAG 0x08
Paolo Bonzini b13ac1
+#define MPT_REG_TEST      0x0c
Paolo Bonzini b13ac1
+#define MPT_REG_DIAG_DATA 0x10
Paolo Bonzini b13ac1
+#define MPT_REG_DIAG_ADDR 0x14
Paolo Bonzini b13ac1
+#define MPT_REG_ISTATUS   0x30
Paolo Bonzini b13ac1
+#define MPT_REG_IMASK     0x34
Paolo Bonzini b13ac1
+#define MPT_REG_REQ_Q     0x40
Paolo Bonzini b13ac1
+#define MPT_REG_REP_Q     0x44
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+#define MPT_DOORBELL_MSG_RESET 0x40
Paolo Bonzini b13ac1
+#define MPT_DOORBELL_HANDSHAKE 0x42
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+#define MPT_IMASK_DOORBELL 0x01
Paolo Bonzini b13ac1
+#define MPT_IMASK_REPLY    0x08
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+struct mpt_lun_s {
Paolo Bonzini b13ac1
+    struct drive_s drive;
Paolo Bonzini b13ac1
+    struct pci_device *pci;
Paolo Bonzini b13ac1
+    u32 iobase;
Paolo Bonzini b13ac1
+    u8 target;
Paolo Bonzini b13ac1
+    u8 lun;
Paolo Bonzini b13ac1
+};
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+u8 reply_msg[4] __attribute((aligned(4))) VARLOW;
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+#define MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST        (0x00)
Paolo Bonzini b13ac1
+#define MPT_MESSAGE_HDR_FUNCTION_IOC_INIT               (0x02)
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+static struct MptIOCInitRequest
Paolo Bonzini b13ac1
+{
Paolo Bonzini b13ac1
+    u8     WhoInit;             /* Which system sent this init request. */
Paolo Bonzini b13ac1
+    u8     Reserved1;           /* Reserved */
Paolo Bonzini b13ac1
+    u8     ChainOffset;         /* Chain offset in the SG list. */
Paolo Bonzini b13ac1
+    u8     Function;            /* Function to execute. */
Paolo Bonzini b13ac1
+    u8     Flags;               /* Flags */
Paolo Bonzini b13ac1
+    u8     MaxDevices;          /* Max devices the driver can handle. */
Paolo Bonzini b13ac1
+    u8     MaxBuses;            /* Max buses the driver can handle. */
Paolo Bonzini b13ac1
+    u8     MessageFlags;        /* Message flags. */
Paolo Bonzini b13ac1
+    u32    MessageContext;      /* Message context ID. */
Paolo Bonzini b13ac1
+    u16    ReplyFrameSize;      /* Reply frame size. */
Paolo Bonzini b13ac1
+    u16    Reserved2;           /* Reserved */
Paolo Bonzini b13ac1
+    u32    HostMfaHighAddr;     /* Upper 32bit of the message frames. */
Paolo Bonzini b13ac1
+    u32    SenseBufferHighAddr; /* Upper 32bit of the sense buffer. */
Paolo Bonzini b13ac1
+} MptIOCInitRequest = {
Paolo Bonzini b13ac1
+    .WhoInit = 2,
Paolo Bonzini b13ac1
+    .Function = MPT_MESSAGE_HDR_FUNCTION_IOC_INIT,
Paolo Bonzini b13ac1
+    .MaxDevices = 8,
Paolo Bonzini b13ac1
+    .MaxBuses = 1,
Paolo Bonzini b13ac1
+    .ReplyFrameSize = sizeof(reply_msg),
Paolo Bonzini b13ac1
+    .HostMfaHighAddr = 0,
Paolo Bonzini b13ac1
+    .SenseBufferHighAddr = 0
Paolo Bonzini b13ac1
+};
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+struct MptIOCInitReply {
Paolo Bonzini b13ac1
+    u8     WhoInit;     /* Which subsystem sent this init request. */
Paolo Bonzini b13ac1
+    u8     Reserved1;   /* Reserved */
Paolo Bonzini b13ac1
+    u8     MessageLength; /* Message length */
Paolo Bonzini b13ac1
+    u8     Function;    /* Function. */
Paolo Bonzini b13ac1
+    u8     Flags;       /* Flags */
Paolo Bonzini b13ac1
+    u8     MaxDevices;  /* Maximum number of devices the driver can handle. */
Paolo Bonzini b13ac1
+    u8     MaxBuses;    /* Maximum number of busses the driver can handle. */
Paolo Bonzini b13ac1
+    u8     MessageFlags; /* Message flags. */
Paolo Bonzini b13ac1
+    u32    MessageContext; /* Message context ID */
Paolo Bonzini b13ac1
+    u16    Reserved2;   /* Reserved */
Paolo Bonzini b13ac1
+    u16    IOCStatus;   /* IO controller status. */
Paolo Bonzini b13ac1
+    u32    IOCLogInfo;  /* IO controller log information. */
Paolo Bonzini b13ac1
+};
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+typedef struct MptSCSIIORequest {
Paolo Bonzini b13ac1
+    u8     TargetID;            /* Target ID */
Paolo Bonzini b13ac1
+    u8     Bus;                 /* Bus number */
Paolo Bonzini b13ac1
+    u8     ChainOffset;         /* Chain offset */
Paolo Bonzini b13ac1
+    u8     Function;            /* Function number. */
Paolo Bonzini b13ac1
+    u8     CDBLength;           /* CDB length. */
Paolo Bonzini b13ac1
+    u8     SenseBufferLength;   /* Sense buffer length. */
Paolo Bonzini b13ac1
+    u8     Reserved;            /* Reserved */
Paolo Bonzini b13ac1
+    u8     MessageFlags;        /* Message flags. */
Paolo Bonzini b13ac1
+    u32    MessageContext;      /* Message context ID. */
Paolo Bonzini b13ac1
+    u8     LUN[8];              /* LUN */
Paolo Bonzini b13ac1
+    u32    Control;             /* Control values. */
Paolo Bonzini b13ac1
+    u8     CDB[16];             /* The CDB. */
Paolo Bonzini b13ac1
+    u32    DataLength;          /* Data length. */
Paolo Bonzini b13ac1
+    u32    SenseBufferLowAddr;  /* Sense buffer low 32bit address. */
Paolo Bonzini b13ac1
+} __attribute__((packed)) MptSCSIIORequest_t;
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+#define MPT_POLL_TIMEOUT  60000
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+typedef struct MptSGEntrySimple32 {
Paolo Bonzini b13ac1
+    u32 FlagsLength;
Paolo Bonzini b13ac1
+    u32 DataBufferAddressLow;
Paolo Bonzini b13ac1
+} __attribute__((packed)) MptSGEntrySimple32_t;
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+static int
Paolo Bonzini b13ac1
+mpt_scsi_cmd(u32 iobase, struct disk_op_s *op,
Paolo Bonzini b13ac1
+             u8 *cdb, u16 target, u16 lun, u16 blocksize)
Paolo Bonzini b13ac1
+{
Paolo Bonzini b13ac1
+    if (lun != 0)
Paolo Bonzini b13ac1
+        return DISK_RET_ENOTREADY;
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    u32 end = timer_calc(MPT_POLL_TIMEOUT);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    u8 sense_buf[18];
Paolo Bonzini b13ac1
+    struct scsi_req {
Paolo Bonzini b13ac1
+        MptSCSIIORequest_t      scsi_io;
Paolo Bonzini b13ac1
+        MptSGEntrySimple32_t    sge;
Paolo Bonzini b13ac1
+    } __attribute__((packed, aligned(4))) req = {
Paolo Bonzini b13ac1
+        .scsi_io = {
Paolo Bonzini b13ac1
+            .TargetID = target,
Paolo Bonzini b13ac1
+            .Bus = 0,
Paolo Bonzini b13ac1
+            .Function = MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST,
Paolo Bonzini b13ac1
+            .CDBLength = 16,
Paolo Bonzini b13ac1
+            .SenseBufferLength = 18,
Paolo Bonzini b13ac1
+            .MessageContext = end & 0x7fffffff,
Paolo Bonzini b13ac1
+            .DataLength = op->count * blocksize,
Paolo Bonzini b13ac1
+            .SenseBufferLowAddr = (u32)MAKE_FLATPTR(GET_SEG(SS), &sense_buf[0]),
Paolo Bonzini b13ac1
+        },
Paolo Bonzini b13ac1
+        .sge = {
Paolo Bonzini b13ac1
+            /* end of list, simple entry, end of buffer, last element */
Paolo Bonzini b13ac1
+            .FlagsLength = (op->count * blocksize) | 0xD1000000,
Paolo Bonzini b13ac1
+            .DataBufferAddressLow = (u32)op->buf_fl,
Paolo Bonzini b13ac1
+        }
Paolo Bonzini b13ac1
+    };
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    req.scsi_io.LUN[1] = lun;
Paolo Bonzini b13ac1
+    memcpy(req.scsi_io.CDB, cdb, 16);
Paolo Bonzini b13ac1
+    if (blocksize) {
Paolo Bonzini b13ac1
+        if (scsi_is_read(op)) {
Paolo Bonzini b13ac1
+            req.scsi_io.Control = 2 << 24;
Paolo Bonzini b13ac1
+        } else {
Paolo Bonzini b13ac1
+            req.scsi_io.Control = 1 << 24;
Paolo Bonzini b13ac1
+            req.sge.FlagsLength |= 0x04000000;
Paolo Bonzini b13ac1
+        }
Paolo Bonzini b13ac1
+    }
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    outl((u32)MAKE_FLATPTR(GET_SEG(SS), &req), iobase + MPT_REG_REQ_Q);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    for (;;) {
Paolo Bonzini b13ac1
+        if (timer_check(end)) {
Paolo Bonzini b13ac1
+            return DISK_RET_ETIMEOUT;
Paolo Bonzini b13ac1
+        }
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+        u32 istatus = inl(iobase + MPT_REG_ISTATUS);
Paolo Bonzini b13ac1
+        if (istatus & MPT_IMASK_REPLY) {
Paolo Bonzini b13ac1
+            u32 resp = inl(iobase + MPT_REG_REP_Q);
Paolo Bonzini b13ac1
+            /* another read to turn interrupt off */
Paolo Bonzini b13ac1
+            inl(iobase + MPT_REG_REP_Q);
Paolo Bonzini b13ac1
+            if (resp == req.scsi_io.MessageContext) {
Paolo Bonzini b13ac1
+                return DISK_RET_SUCCESS;
Paolo Bonzini b13ac1
+            } else if (resp & 0x80000000) {
Paolo Bonzini b13ac1
+                outl((u32)&reply_msg[0], iobase + MPT_REG_REP_Q);
Paolo Bonzini b13ac1
+                return DISK_RET_EBADTRACK;
Paolo Bonzini b13ac1
+            }
Paolo Bonzini b13ac1
+        }
Paolo Bonzini b13ac1
+        usleep(50);
Paolo Bonzini b13ac1
+    }
Paolo Bonzini b13ac1
+}
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+int
Paolo Bonzini b13ac1
+mpt_scsi_process_op(struct disk_op_s *op)
Paolo Bonzini b13ac1
+{
Paolo Bonzini b13ac1
+    if (!CONFIG_MPT_SCSI)
Paolo Bonzini b13ac1
+        return DISK_RET_EBADTRACK;
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    u8 cdbcmd[16];
Paolo Bonzini b13ac1
+    int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd));
Paolo Bonzini b13ac1
+    if (blocksize < 0)
Paolo Bonzini b13ac1
+        return default_process_op(op);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    struct mpt_lun_s *llun_gf =
Paolo Bonzini b13ac1
+        container_of(op->drive_gf, struct mpt_lun_s, drive);
Paolo Bonzini b13ac1
+    u16 target = GET_GLOBALFLAT(llun_gf->target);
Paolo Bonzini b13ac1
+    u16 lun = GET_GLOBALFLAT(llun_gf->lun);
Paolo Bonzini b13ac1
+    u32 iobase = GET_GLOBALFLAT(llun_gf->iobase);
Paolo Bonzini b13ac1
+    return mpt_scsi_cmd(iobase, op, cdbcmd, target, lun, blocksize);
Paolo Bonzini b13ac1
+}
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+static int
Paolo Bonzini b13ac1
+mpt_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun)
Paolo Bonzini b13ac1
+{
Paolo Bonzini b13ac1
+    struct mpt_lun_s *llun = malloc_fseg(sizeof(*llun));
Paolo Bonzini b13ac1
+    if (!llun) {
Paolo Bonzini b13ac1
+        warn_noalloc();
Paolo Bonzini b13ac1
+        return -1;
Paolo Bonzini b13ac1
+    }
Paolo Bonzini b13ac1
+    memset(llun, 0, sizeof(*llun));
Paolo Bonzini b13ac1
+    llun->drive.type = DTYPE_MPT_SCSI;
Paolo Bonzini b13ac1
+    llun->drive.cntl_id = pci->bdf;
Paolo Bonzini b13ac1
+    llun->pci = pci;
Paolo Bonzini b13ac1
+    llun->target = target;
Paolo Bonzini b13ac1
+    llun->lun = lun;
Paolo Bonzini b13ac1
+    llun->iobase = iobase;
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    char *name = znprintf(16, "mpt %02x:%02x.%x %d:%d",
Paolo Bonzini b13ac1
+                          pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
Paolo Bonzini b13ac1
+                          pci_bdf_to_fn(pci->bdf), target, lun);
Paolo Bonzini b13ac1
+    int prio = bootprio_find_scsi_device(pci, target, lun);
Paolo Bonzini b13ac1
+    int ret = scsi_drive_setup(&llun->drive, name, prio);
Paolo Bonzini b13ac1
+    free(name);
Paolo Bonzini b13ac1
+    if (ret) {
Paolo Bonzini b13ac1
+        goto fail;
Paolo Bonzini b13ac1
+    }
Paolo Bonzini b13ac1
+    return 0;
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+fail:
Paolo Bonzini b13ac1
+    free(llun);
Paolo Bonzini b13ac1
+    return -1;
Paolo Bonzini b13ac1
+}
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+static void
Paolo Bonzini b13ac1
+mpt_scsi_scan_target(struct pci_device *pci, u32 iobase, u8 target)
Paolo Bonzini b13ac1
+{
Paolo Bonzini b13ac1
+    /* TODO: send REPORT LUNS.  For now, only LUN 0 is recognized.  */
Paolo Bonzini b13ac1
+    mpt_scsi_add_lun(pci, iobase, target, 0);
Paolo Bonzini b13ac1
+}
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+static inline void
Paolo Bonzini b13ac1
+mpt_out_doorbell(u8 func, u8 arg, u16 iobase)
Paolo Bonzini b13ac1
+{
Paolo Bonzini b13ac1
+    outl((func << 24) | (arg << 16), iobase + MPT_REG_DOORBELL);
Paolo Bonzini b13ac1
+}
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+static void
Paolo Bonzini b13ac1
+init_mpt_scsi(struct pci_device *pci, const char *dev_name)
Paolo Bonzini b13ac1
+{
Paolo Bonzini b13ac1
+    u16 *msg_in_p;
Paolo Bonzini b13ac1
+    u16 bdf = pci->bdf;
Paolo Bonzini b13ac1
+    u32 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
Paolo Bonzini b13ac1
+        & PCI_BASE_ADDRESS_IO_MASK;
Paolo Bonzini b13ac1
+    struct MptIOCInitReply MptIOCInitReply;
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    pci_config_maskw(bdf, PCI_COMMAND, 0,
Paolo Bonzini b13ac1
+                     PCI_COMMAND_IO | PCI_COMMAND_MASTER);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    dprintf(1, "found %s at %02x:%02x.%x, io @ %x\n", dev_name,
Paolo Bonzini b13ac1
+            pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
Paolo Bonzini b13ac1
+            pci_bdf_to_fn(bdf), iobase);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    // reset
Paolo Bonzini b13ac1
+    mpt_out_doorbell(MPT_DOORBELL_MSG_RESET, 0, iobase);
Paolo Bonzini b13ac1
+    outl(MPT_IMASK_DOORBELL|MPT_IMASK_REPLY , iobase + MPT_REG_IMASK);
Paolo Bonzini b13ac1
+    outl(0, iobase + MPT_REG_ISTATUS);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    // send IOC Init message through the doorbell
Paolo Bonzini b13ac1
+    mpt_out_doorbell(MPT_DOORBELL_HANDSHAKE,
Paolo Bonzini b13ac1
+		     sizeof(MptIOCInitRequest)/sizeof(u32),
Paolo Bonzini b13ac1
+		     iobase);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    outsl(iobase + MPT_REG_DOORBELL,
Paolo Bonzini b13ac1
+	  (u32 *)&MptIOCInitRequest,
Paolo Bonzini b13ac1
+	  sizeof(MptIOCInitRequest)/sizeof(u32));
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    // Read the reply 16 bits at a time.  Cannot use insl
Paolo Bonzini b13ac1
+    // because the port is 32 bits wide.
Paolo Bonzini b13ac1
+    msg_in_p = (u16 *)&MptIOCInitReply;
Paolo Bonzini b13ac1
+    while(msg_in_p != (u16 *)(&MptIOCInitReply + 1))
Paolo Bonzini b13ac1
+        *msg_in_p++ = (u16)inl(iobase + MPT_REG_DOORBELL);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    // Eat doorbell interrupt
Paolo Bonzini b13ac1
+    outl(0, iobase + MPT_REG_ISTATUS);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    // Post reply message used for SCSI errors
Paolo Bonzini b13ac1
+    outl((u32)&reply_msg[0], iobase + MPT_REG_REP_Q);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    for (int i = 0; i < 7; i++)
Paolo Bonzini b13ac1
+        mpt_scsi_scan_target(pci, iobase, i);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    return;
Paolo Bonzini b13ac1
+}
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+void
Paolo Bonzini b13ac1
+mpt_scsi_setup(void)
Paolo Bonzini b13ac1
+{
Paolo Bonzini b13ac1
+    ASSERT32FLAT();
Paolo Bonzini b13ac1
+    if (!CONFIG_MPT_SCSI) {
Paolo Bonzini b13ac1
+        return;
Paolo Bonzini b13ac1
+    }
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    dprintf(3, "init MPT\n");
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+    struct pci_device *pci;
Paolo Bonzini b13ac1
+    foreachpci(pci) {
Paolo Bonzini b13ac1
+        if (pci->vendor == PCI_VENDOR_ID_LSI_LOGIC) {
Paolo Bonzini b13ac1
+            if (pci->device == PCI_DEVICE_ID_LSI_53C1030) {
Paolo Bonzini b13ac1
+                init_mpt_scsi(pci, "lsi53c1030");
Paolo Bonzini b13ac1
+            }
Paolo Bonzini b13ac1
+            if (pci->device == PCI_DEVICE_ID_LSI_SAS1068) {
Paolo Bonzini b13ac1
+                init_mpt_scsi(pci, "sas1068");
Paolo Bonzini b13ac1
+            }
Paolo Bonzini b13ac1
+            if (pci->device == PCI_DEVICE_ID_LSI_SAS1068E) {
Paolo Bonzini b13ac1
+                init_mpt_scsi(pci, "sas1068e");
Paolo Bonzini b13ac1
+            }
Paolo Bonzini b13ac1
+        }
Paolo Bonzini b13ac1
+    }
Paolo Bonzini b13ac1
+}
Paolo Bonzini b13ac1
diff --git a/src/hw/mpt-scsi.h b/src/hw/mpt-scsi.h
Paolo Bonzini b13ac1
new file mode 100644
Paolo Bonzini b13ac1
index 0000000..6535dd8
Paolo Bonzini b13ac1
--- /dev/null
Paolo Bonzini b13ac1
+++ b/src/hw/mpt-scsi.h
Paolo Bonzini b13ac1
@@ -0,0 +1,8 @@
Paolo Bonzini b13ac1
+#ifndef __MPT_SCSI_H
Paolo Bonzini b13ac1
+#define __MPT_SCSI_H
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+struct disk_op_s;
Paolo Bonzini b13ac1
+int mpt_scsi_process_op(struct disk_op_s *op);
Paolo Bonzini b13ac1
+void mpt_scsi_setup(void);
Paolo Bonzini b13ac1
+
Paolo Bonzini b13ac1
+#endif /* __MPT_SCSI_H */
Paolo Bonzini b13ac1
diff --git a/src/post.c b/src/post.c
Paolo Bonzini b13ac1
index 6803585..1dd075e 100644
Paolo Bonzini b13ac1
--- a/src/post.c
Paolo Bonzini b13ac1
+++ b/src/post.c
Paolo Bonzini b13ac1
@@ -14,6 +14,7 @@
Paolo Bonzini b13ac1
 #include "hw/ata.h" // ata_setup
Paolo Bonzini b13ac1
 #include "hw/esp-scsi.h" // esp_scsi_setup
Paolo Bonzini b13ac1
 #include "hw/lsi-scsi.h" // lsi_scsi_setup
Paolo Bonzini b13ac1
+#include "hw/mpt-scsi.h" // lsi_scsi_setup
Paolo Bonzini b13ac1
 #include "hw/megasas.h" // megasas_setup
Paolo Bonzini b13ac1
 #include "hw/pvscsi.h" // pvscsi_setup
Paolo Bonzini b13ac1
 #include "hw/pic.h" // pic_setup
Paolo Bonzini b13ac1
@@ -153,6 +154,7 @@ device_hardware_setup(void)
Paolo Bonzini b13ac1
     esp_scsi_setup();
Paolo Bonzini b13ac1
     megasas_setup();
Paolo Bonzini b13ac1
     pvscsi_setup();
Paolo Bonzini b13ac1
+    mpt_scsi_setup();
Paolo Bonzini b13ac1
 }
Paolo Bonzini b13ac1
 
Paolo Bonzini b13ac1
 static void
Paolo Bonzini b13ac1
-- 
Paolo Bonzini b13ac1
2.5.0
Paolo Bonzini b13ac1