[SeaBIOS] [PATCH] Support for booting from QEMU emulated LSI Logic LSI53C1030, SAS1068, SAS1068e.

Don Slutz Don at CloudSwitch.com
Tue Sep 11 20:11:23 CEST 2012


Also known as Fusion MPT disk.

This needs the patch (for the QEMU emulation):

http://lists.gnu.org/archive/html/qemu-devel/2012-09/msg01608.html

Signed-off-by: Don Slutz <Don at CloudSwitch.com>
---
 Makefile       |    2 +-
 src/Kconfig    |    6 +
 src/block.c    |    1 +
 src/blockcmd.c |    3 +
 src/disk.h     |    1 +
 src/mpt-scsi.c |  340 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/mpt-scsi.h |    8 ++
 src/post.c     |    2 +
 8 files changed, 362 insertions(+), 1 deletions(-)
 create mode 100644 src/mpt-scsi.c
 create mode 100644 src/mpt-scsi.h

diff --git a/Makefile b/Makefile
index 5486f88..d42d998 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ SRCBOTH=misc.c stacks.c pmm.c output.c util.c block.c floppy.c ata.c mouse.c \
     pnpbios.c pirtable.c vgahooks.c ramdisk.c pcibios.c blockcmd.c \
     usb.c usb-uhci.c usb-ohci.c usb-ehci.c usb-hid.c usb-msc.c \
     virtio-ring.c virtio-pci.c virtio-blk.c virtio-scsi.c apm.c ahci.c \
-    usb-uas.c lsi-scsi.c esp-scsi.c
+    usb-uas.c lsi-scsi.c esp-scsi.c mpt-scsi.c
 SRC16=$(SRCBOTH) system.c disk.c font.c
 SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \
     acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \
diff --git a/src/Kconfig b/src/Kconfig
index b5dd63b..4243a05 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -131,6 +131,12 @@ menu "Hardware support"
         default y
         help
             Support boot from qemu-emulated lsi53c895a scsi storage.
+    config MPT_SCSI
+        depends on DRIVES && !COREBOOT
+        bool "lsi50c1030 scsi & lsi1068 sas controllers"
+        default y
+        help
+            Support boot from qemu-emulated lsi53c1030 scsi and lsi1068 sas storage.
     config FLOPPY
         depends on DRIVES
         bool "Floppy controller"
diff --git a/src/block.c b/src/block.c
index 243428e..4985bc1 100644
--- a/src/block.c
+++ b/src/block.c
@@ -336,6 +336,7 @@ process_op(struct disk_op_s *op)
     case DTYPE_VIRTIO_SCSI:
     case DTYPE_LSI_SCSI:
     case DTYPE_ESP_SCSI:
+    case DTYPE_MPT_SCSI:
         return process_scsi_op(op);
     default:
         op->count = 0;
diff --git a/src/blockcmd.c b/src/blockcmd.c
index 77c690f..233a501 100644
--- a/src/blockcmd.c
+++ b/src/blockcmd.c
@@ -17,6 +17,7 @@
 #include "virtio-scsi.h" // virtio_scsi_cmd_data
 #include "lsi-scsi.h" // lsi_scsi_cmd_data
 #include "esp-scsi.h" // esp_scsi_cmd_data
+#include "mpt-scsi.h" // esp_scsi_cmd_data
 #include "boot.h" // boot_add_hd
 
 // Route command to low-level handler.
@@ -39,6 +40,8 @@ cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
         return lsi_scsi_cmd_data(op, cdbcmd, blocksize);
     case DTYPE_ESP_SCSI:
         return esp_scsi_cmd_data(op, cdbcmd, blocksize);
+    case DTYPE_MPT_SCSI:
+        return mpt_scsi_cmd_data(op, cdbcmd, blocksize);
     default:
         op->count = 0;
         return DISK_RET_EPARAM;
diff --git a/src/disk.h b/src/disk.h
index 3d07372..f8d37cf 100644
--- a/src/disk.h
+++ b/src/disk.h
@@ -235,6 +235,7 @@ struct drive_s {
 #define DTYPE_UAS          0x0b
 #define DTYPE_LSI_SCSI     0x0c
 #define DTYPE_ESP_SCSI     0x0d
+#define DTYPE_MPT_SCSI     0x0e
 
 #define MAXDESCSIZE 80
 
diff --git a/src/mpt-scsi.c b/src/mpt-scsi.c
new file mode 100644
index 0000000..da351e4
--- /dev/null
+++ b/src/mpt-scsi.c
@@ -0,0 +1,340 @@
+// (qemu-emulated) Fusion MPT boot support.
+//
+// Copyright (C) 2012 Red Hat Inc.
+//
+// Authors:
+//  Gerd Hoffmann <kraxel at redhat.com>
+//
+// based on virtio-scsi.c which is written by:
+//  Paolo Bonzini <pbonzini at redhat.com>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "pci.h" // foreachpci
+#include "config.h" // CONFIG_*
+#include "biosvar.h" // GET_GLOBAL
+#include "pci_ids.h" // PCI_DEVICE_ID_VIRTIO_BLK
+#include "pci_regs.h" // PCI_VENDOR_ID
+#include "boot.h" // bootprio_find_scsi_device
+#include "blockcmd.h" // scsi_init_drive
+#include "disk.h"
+
+#define MPT_REG_DOORBELL  0x00
+#define MPT_REG_WRITE_SEQ 0x04
+#define MPT_REG_HOST_DIAG 0x08
+#define MPT_REG_TEST      0x0c
+#define MPT_REG_DIAG_DATA 0x10
+#define MPT_REG_DIAG_ADDR 0x14
+#define MPT_REG_ISTATUS   0x30
+#define MPT_REG_IMASK     0x34
+#define MPT_REG_REQ_Q     0x40
+#define MPT_REG_REP_Q     0x44
+
+#define MPT_DOORBELL_MSG_RESET 0x40
+#define MPT_DOORBELL_HANDSHAKE 0x42
+#define MPT_DOORBELL_REG_FUNC(f, s) ((((f)&0xff)<<24)|(((s)&0xff)<<16))
+
+#define MPT_IMASK_DOORBELL 0x01
+#define MPT_IMASK_REPLY    0x08
+
+struct mpt_lun_s {
+    struct drive_s drive;
+    struct pci_device *pci;
+    u32 iobase;
+    u8 target;
+    u8 lun;
+};
+
+u8 reply_msg[128] VAR16VISIBLE;
+
+#define MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST        (0x00)
+#define MPT_MESSAGE_HDR_FUNCTION_IOC_INIT               (0x02)
+
+static struct MptIOCInitRequest
+{
+    u8     WhoInit;             /* Which system sent this init request. */
+    u8     Reserved1;           /* Reserved */
+    u8     ChainOffset;         /* Chain offset in the SG list. */
+    u8     Function;            /* Function to execute. */
+    u8     Flags;               /* Flags */
+    u8     MaxDevices;          /* Max devices the driver can handle. */
+    u8     MaxBuses;            /* Max buses the driver can handle. */
+    u8     MessageFlags;        /* Message flags. */
+    u32    MessageContext;      /* Message context ID. */
+    u16    ReplyFrameSize;      /* Reply frame size. */
+    u16    Reserved2;           /* Reserved */
+    u32    HostMfaHighAddr;     /* Upper 32bit of the message frames. */
+    u32    SenseBufferHighAddr; /* Upper 32bit of the sense buffer. */
+} MptIOCInitRequest = {
+        2,
+        0,
+        0,
+        MPT_MESSAGE_HDR_FUNCTION_IOC_INIT,
+        0,
+        8,
+        1,
+        0,
+        0,
+        sizeof(reply_msg),
+        0,
+        0,
+        0
+};
+
+struct MptIOCInitReply {
+    u8     WhoInit;     /* Which subsystem sent this init request. */
+    u8     Reserved1;   /* Reserved */
+    u8     MessageLength; /* Message length */
+    u8     Function;    /* Function. */
+    u8     Flags;       /* Flags */
+    u8     MaxDevices;  /* Maximum number of devices the driver can handle. */
+    u8     MaxBuses;    /* Maximum number of busses the driver can handle. */
+    u8     MessageFlags; /* Message flags. */
+    u32    MessageContext; /* Message context ID */
+    u16    Reserved2;   /* Reserved */
+    u16    IOCStatus;   /* IO controller status. */
+    u32    IOCLogInfo;  /* IO controller log information. */
+};
+
+#pragma pack(1)
+typedef struct MptSCSIIORequest {
+    u8     TargetID;            /* Target ID */
+    u8     Bus;                 /* Bus number */
+    u8     ChainOffset;         /* Chain offset */
+    u8     Function;            /* Function number. */
+    u8     CDBLength;           /* CDB length. */
+    u8     SenseBufferLength;   /* Sense buffer length. */
+    u8     Reserved;            /* Reserved */
+    u8     MessageFlags;        /* Message flags. */
+    u32    MessageContext;      /* Message context ID. */
+    u8     LUN[8];              /* LUN */
+    u32    Control;             /* Control values. */
+    u8     CDB[16];             /* The CDB. */
+    u32    DataLength;          /* Data length. */
+    u32    SenseBufferLowAddr;  /* Sense buffer low 32bit address. */
+} MptSCSIIORequest_t;
+
+#define MPT_CONTEXT_MAGIC 0xaaaa5555
+
+typedef struct MptSGEntrySimple32 {
+    unsigned u24Length:24;
+    unsigned fEndOfList:1;
+    unsigned f64BitAddress:1;
+    unsigned fBufferContainsData:1;
+    unsigned fLocalAddress:1;
+    unsigned u2ElementType:2;
+    unsigned fEndOfBuffer:1;
+    unsigned fLastElement:1;
+    u32 DataBufferAddressLow;
+} MptSGEntrySimple32_t;
+#pragma pack(0)
+
+static int
+mpt_scsi_cmd(struct mpt_lun_s *llun, struct disk_op_s *op,
+             void *cdbcmd, u16 target, u16 lun, u16 blocksize)
+{
+    u32 iobase = GET_GLOBAL(llun->iobase);
+    int i;
+    u8 sense_buf[32];
+    int retry = 0;
+
+    struct scsi_req {
+        MptSCSIIORequest_t      scsi_io;
+        MptSGEntrySimple32_t    sge;
+    } req = {
+        {
+        target,
+        0,
+        0,
+        MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST,
+        16,
+        32,
+        0,
+        0,
+        MPT_CONTEXT_MAGIC,
+        {0, lun, 0, 0, 0, 0, 0, 0},
+        0,
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+        (op->count * blocksize),
+        (u32)MAKE_FLATPTR(GET_SEG(SS), &sense_buf[0])
+        },
+        {
+        op->count * blocksize,
+        1,
+        0,
+        0,
+        0,
+        1,
+        1,
+        1,
+        (u32)op->buf_fl
+        }
+    };
+
+    if (lun != 0) {
+        return DISK_RET_ENOTREADY;
+    }
+
+    if (blocksize == 0) {
+        req.scsi_io.Control = 0;
+    } else if (cdb_is_read(cdbcmd, blocksize)) {
+        req.scsi_io.Control = 2 << 24;
+    } else {
+        req.scsi_io.Control = 1 << 24;
+        req.sge.fBufferContainsData = 1;
+    }
+
+    u8 *cdb = (u8 *)cdbcmd;
+    for (i = 0; i < 16; i++) {
+        req.scsi_io.CDB[i] = cdb[i];
+    }
+
+try_again:
+    outl((u32)MAKE_FLATPTR(GET_SEG(SS), &req), iobase + MPT_REG_REQ_Q);
+
+    for (;;) {
+        u32 istatus = inl(iobase + MPT_REG_ISTATUS);
+        u32 resp;
+        if (istatus & MPT_IMASK_REPLY) {
+            do {
+                resp = inl(iobase + MPT_REG_REP_Q);
+                if (resp == MPT_CONTEXT_MAGIC) {
+                    return DISK_RET_SUCCESS;
+                } else if ((resp << 1) == (u32)&reply_msg[0]) {
+                    if (retry == 0) {
+                        retry = 1;
+                        goto try_again;
+                    }
+                    return DISK_RET_EBADTRACK;
+                }
+            } while (resp != 0xffffffff);
+        }
+        usleep(50);
+    }
+}
+
+int
+mpt_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+    if (!CONFIG_MPT_SCSI) {
+        return DISK_RET_EBADTRACK;
+    }
+
+    struct mpt_lun_s *llun =
+        container_of(op->drive_g, struct mpt_lun_s, drive);
+
+    return mpt_scsi_cmd(llun, op, cdbcmd,
+                        GET_GLOBAL(llun->target), GET_GLOBAL(llun->lun),
+                        blocksize);
+}
+
+static int
+mpt_scsi_add_lun(struct pci_device *pci, u32 iobase, u8 target, u8 lun)
+{
+    struct mpt_lun_s *llun = malloc_fseg(sizeof(*llun));
+    if (!llun) {
+        warn_noalloc();
+        return -1;
+    }
+    memset(llun, 0, sizeof(*llun));
+    llun->drive.type = DTYPE_MPT_SCSI;
+    llun->drive.cntl_id = pci->bdf;
+    llun->pci = pci;
+    llun->target = target;
+    llun->lun = lun;
+    llun->iobase = iobase;
+
+    char *name = znprintf(16, "mpt %02x:%02x.%x %d:%d",
+                          pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+                          pci_bdf_to_fn(pci->bdf), target, lun);
+    int prio = bootprio_find_scsi_device(pci, target, lun);
+    int ret = scsi_init_drive(&llun->drive, name, prio);
+    free(name);
+    if (ret) {
+        goto fail;
+    }
+    return 0;
+
+fail:
+    free(llun);
+    return -1;
+}
+
+static void
+mpt_scsi_scan_target(struct pci_device *pci, u32 iobase, u8 target)
+{
+    /* TODO: send REPORT LUNS.  For now, only LUN 0 is recognized.  */
+    mpt_scsi_add_lun(pci, iobase, target, 0);
+}
+
+static void
+init_mpt_scsi(struct pci_device *pci, const char *dev_name)
+{
+    u32 *msg_out_p;
+    u16 *msg_in_p;
+    u16 bdf = pci->bdf;
+    u32 iobase = pci_config_readl(pci->bdf, PCI_BASE_ADDRESS_0)
+        & PCI_BASE_ADDRESS_IO_MASK;
+    struct MptIOCInitReply MptIOCInitReply;
+
+    dprintf(1, "found %s at %02x:%02x.%x, io @ %x\n", dev_name,
+            pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf),
+            pci_bdf_to_fn(bdf), iobase);
+
+    // reset
+    outl(MPT_DOORBELL_REG_FUNC(MPT_DOORBELL_MSG_RESET, 0),
+        iobase + MPT_REG_DOORBELL);
+    outl(MPT_IMASK_DOORBELL|MPT_IMASK_REPLY , iobase + MPT_REG_IMASK);
+    outl(0, iobase + MPT_REG_ISTATUS);
+
+    outl(MPT_DOORBELL_REG_FUNC(MPT_DOORBELL_HANDSHAKE,
+        sizeof(MptIOCInitRequest)/sizeof(u32)), iobase + MPT_REG_DOORBELL);
+    msg_out_p = (u32 *)&MptIOCInitRequest;
+    int i;
+    for (i = 0; i < sizeof(MptIOCInitRequest)/sizeof(u32); i++) {
+        outl(*msg_out_p++, iobase + MPT_REG_DOORBELL);
+    }
+
+    msg_in_p = (u16 *)&MptIOCInitReply;
+    for (i = 0; i < sizeof(MptIOCInitReply)/sizeof(u16); i++)
+        /* Lower 16 bits has the message */
+        *msg_in_p++ = (u16)inl(iobase + MPT_REG_DOORBELL);
+    /* TODO: Should make sure reply message looks good */
+
+    outl(0, iobase + MPT_REG_ISTATUS);
+
+    outl((u32)&reply_msg[0], iobase + MPT_REG_REP_Q);
+
+    for (i = 0; i < 7; i++) {
+        mpt_scsi_scan_target(pci, iobase, i);
+    }
+
+    return;
+}
+
+void
+mpt_scsi_setup(void)
+{
+    ASSERT32FLAT();
+    if (!CONFIG_MPT_SCSI) {
+        return;
+    }
+
+    dprintf(3, "init MPT\n");
+
+    struct pci_device *pci;
+    foreachpci(pci) {
+        if (pci->vendor == PCI_VENDOR_ID_LSI_LOGIC) {
+            if (pci->device == PCI_DEVICE_ID_LSI_53C1030) {
+                init_mpt_scsi(pci, "lsi53c1030");
+            }
+            if (pci->device == PCI_DEVICE_ID_LSI_SAS1068) {
+                init_mpt_scsi(pci, "sas1068");
+            }
+            if (pci->device == PCI_DEVICE_ID_LSI_SAS1068E) {
+                init_mpt_scsi(pci, "sas1068e");
+            }
+        }
+    }
+}
diff --git a/src/mpt-scsi.h b/src/mpt-scsi.h
new file mode 100644
index 0000000..938ac2b
--- /dev/null
+++ b/src/mpt-scsi.h
@@ -0,0 +1,8 @@
+#ifndef __MPT_SCSI_H
+#define __MPT_SCSI_H
+
+struct disk_op_s;
+int mpt_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+void mpt_scsi_setup(void);
+
+#endif /* __MPT_SCSI_H */
diff --git a/src/post.c b/src/post.c
index 924b311..d56b6a6 100644
--- a/src/post.c
+++ b/src/post.c
@@ -29,6 +29,7 @@
 #include "virtio-scsi.h" // virtio_scsi_setup
 #include "lsi-scsi.h" // lsi_scsi_setup
 #include "esp-scsi.h" // esp_scsi_setup
+#include "mpt-scsi.h" // mpt_scsi_setup
 
 
 /****************************************************************
@@ -198,6 +199,7 @@ init_hw(void)
     virtio_scsi_setup();
     lsi_scsi_setup();
     esp_scsi_setup();
+    mpt_scsi_setup();
 }
 
 // Begin the boot process by invoking an int0x19 in 16bit mode.
-- 
1.7.1




More information about the SeaBIOS mailing list