From b13ac1d2a36049b4332d9e14fead72e2cc09caea Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mar 24 2016 14:32:37 +0000 Subject: Add MPT Fusion driver (will miss QEMU 2.6), include all drivers in 128k ROM --- diff --git a/0001-Support-for-booting-from-LSI-Logic-LSI53C1030-SAS106.patch b/0001-Support-for-booting-from-LSI-Logic-LSI53C1030-SAS106.patch new file mode 100644 index 0000000..2826a56 --- /dev/null +++ b/0001-Support-for-booting-from-LSI-Logic-LSI53C1030-SAS106.patch @@ -0,0 +1,443 @@ +From 4d785f1227127d63ef412eaf482259cedd3ccf99 Mon Sep 17 00:00:00 2001 +From: Don Slutz +Date: Thu, 24 Sep 2015 13:44:10 +0200 +Subject: [PATCH] Support for booting from LSI Logic LSI53C1030, SAS1068, + SAS1068e + +Also known as Fusion MPT disk; this controller model is supported +by VirtualBox and VMware, and QEMU support patches have been +posted. + +Signed-off-by: Don Slutz +Signed-off-by: Paolo Bonzini +--- + Makefile | 2 +- + src/Kconfig | 6 ++ + src/block.c | 3 + + src/block.h | 1 + + src/hw/mpt-scsi.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ + src/hw/mpt-scsi.h | 8 ++ + src/post.c | 2 + + 7 files changed, 334 insertions(+), 1 deletion(-) + create mode 100644 src/hw/mpt-scsi.c + create mode 100644 src/hw/mpt-scsi.h + +diff --git a/Makefile b/Makefile +index 3a0d2e8..fcbd88a 100644 +--- a/Makefile ++++ b/Makefile +@@ -34,7 +34,7 @@ SRCBOTH=misc.c stacks.c output.c string.c block.c cdrom.c disk.c mouse.c kbd.c \ + hw/usb.c hw/usb-uhci.c hw/usb-ohci.c hw/usb-ehci.c \ + hw/usb-hid.c hw/usb-msc.c hw/usb-uas.c \ + hw/blockcmd.c hw/floppy.c hw/ata.c hw/ramdisk.c \ +- hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c ++ hw/lsi-scsi.c hw/esp-scsi.c hw/megasas.c hw/mpt-scsi.c + SRC16=$(SRCBOTH) + SRC32FLAT=$(SRCBOTH) post.c e820map.c malloc.c romfile.c x86.c optionroms.c \ + pmm.c font.c boot.c bootsplash.c jpeg.c bmp.c tcgbios.c sha1.c \ +diff --git a/src/Kconfig b/src/Kconfig +index b873cd3..8250702 100644 +--- a/src/Kconfig ++++ b/src/Kconfig +@@ -208,6 +208,12 @@ menu "Hardware support" + default y + help + Support boot from LSI MegaRAID SAS scsi storage. ++ config MPT_SCSI ++ depends on DRIVES ++ bool "LSI MPT Fusion controllers" ++ default y ++ help ++ Support boot from LSI MPT Fusion scsi storage. + config FLOPPY + depends on DRIVES && HARDWARE_IRQ + bool "Floppy controller" +diff --git a/src/block.c b/src/block.c +index 97e05fa..ef1cd9f 100644 +--- a/src/block.c ++++ b/src/block.c +@@ -13,6 +13,7 @@ + #include "hw/esp-scsi.h" // esp_scsi_process_op + #include "hw/lsi-scsi.h" // lsi_scsi_process_op + #include "hw/megasas.h" // megasas_process_op ++#include "hw/mpt-scsi.h" // mpt_scsi_process_op + #include "hw/pci.h" // pci_bdf_to_bus + #include "hw/pvscsi.h" // pvscsi_process_op + #include "hw/rtc.h" // rtc_read +@@ -521,6 +522,8 @@ process_op_both(struct disk_op_s *op) + return esp_scsi_process_op(op); + case DTYPE_MEGASAS: + return megasas_process_op(op); ++ case DTYPE_MPT_SCSI: ++ return mpt_scsi_process_op(op); + default: + if (!MODESEGMENT) + return DISK_RET_EPARAM; +diff --git a/src/block.h b/src/block.h +index 2ff359f..7de6f54 100644 +--- a/src/block.h ++++ b/src/block.h +@@ -80,6 +80,7 @@ struct drive_s { + #define DTYPE_ESP_SCSI 0x81 + #define DTYPE_MEGASAS 0x82 + #define DTYPE_PVSCSI 0x83 ++#define DTYPE_MPT_SCSI 0x84 + #define DTYPE_SDCARD 0x90 + + #define MAXDESCSIZE 80 +diff --git a/src/hw/mpt-scsi.c b/src/hw/mpt-scsi.c +new file mode 100644 +index 0000000..44f5446 +--- /dev/null ++++ b/src/hw/mpt-scsi.c +@@ -0,0 +1,313 @@ ++// MPT Fusion boot support. ++// ++// This file may be distributed under the terms of the GNU LGPLv3 license. ++ ++#include "biosvar.h" // GET_GLOBALFLAT ++#include "block.h" // struct drive_s ++#include "blockcmd.h" // scsi_drive_setup ++#include "config.h" // CONFIG_* ++#include "malloc.h" // free ++#include "output.h" // dprintf ++#include "pci.h" // foreachpci ++#include "pci_ids.h" // PCI_DEVICE_ID ++#include "pci_regs.h" // PCI_VENDOR_ID ++#include "std/disk.h" // DISK_RET_SUCCESS ++#include "string.h" // memset ++#include "util.h" // usleep ++ ++#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_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[4] __attribute((aligned(4))) VARLOW; ++ ++#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 = { ++ .WhoInit = 2, ++ .Function = MPT_MESSAGE_HDR_FUNCTION_IOC_INIT, ++ .MaxDevices = 8, ++ .MaxBuses = 1, ++ .ReplyFrameSize = sizeof(reply_msg), ++ .HostMfaHighAddr = 0, ++ .SenseBufferHighAddr = 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. */ ++}; ++ ++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. */ ++} __attribute__((packed)) MptSCSIIORequest_t; ++ ++#define MPT_POLL_TIMEOUT 60000 ++ ++typedef struct MptSGEntrySimple32 { ++ u32 FlagsLength; ++ u32 DataBufferAddressLow; ++} __attribute__((packed)) MptSGEntrySimple32_t; ++ ++static int ++mpt_scsi_cmd(u32 iobase, struct disk_op_s *op, ++ u8 *cdb, u16 target, u16 lun, u16 blocksize) ++{ ++ if (lun != 0) ++ return DISK_RET_ENOTREADY; ++ ++ u32 end = timer_calc(MPT_POLL_TIMEOUT); ++ ++ u8 sense_buf[18]; ++ struct scsi_req { ++ MptSCSIIORequest_t scsi_io; ++ MptSGEntrySimple32_t sge; ++ } __attribute__((packed, aligned(4))) req = { ++ .scsi_io = { ++ .TargetID = target, ++ .Bus = 0, ++ .Function = MPT_MESSAGE_HDR_FUNCTION_SCSI_IO_REQUEST, ++ .CDBLength = 16, ++ .SenseBufferLength = 18, ++ .MessageContext = end & 0x7fffffff, ++ .DataLength = op->count * blocksize, ++ .SenseBufferLowAddr = (u32)MAKE_FLATPTR(GET_SEG(SS), &sense_buf[0]), ++ }, ++ .sge = { ++ /* end of list, simple entry, end of buffer, last element */ ++ .FlagsLength = (op->count * blocksize) | 0xD1000000, ++ .DataBufferAddressLow = (u32)op->buf_fl, ++ } ++ }; ++ ++ req.scsi_io.LUN[1] = lun; ++ memcpy(req.scsi_io.CDB, cdb, 16); ++ if (blocksize) { ++ if (scsi_is_read(op)) { ++ req.scsi_io.Control = 2 << 24; ++ } else { ++ req.scsi_io.Control = 1 << 24; ++ req.sge.FlagsLength |= 0x04000000; ++ } ++ } ++ ++ outl((u32)MAKE_FLATPTR(GET_SEG(SS), &req), iobase + MPT_REG_REQ_Q); ++ ++ for (;;) { ++ if (timer_check(end)) { ++ return DISK_RET_ETIMEOUT; ++ } ++ ++ u32 istatus = inl(iobase + MPT_REG_ISTATUS); ++ if (istatus & MPT_IMASK_REPLY) { ++ u32 resp = inl(iobase + MPT_REG_REP_Q); ++ /* another read to turn interrupt off */ ++ inl(iobase + MPT_REG_REP_Q); ++ if (resp == req.scsi_io.MessageContext) { ++ return DISK_RET_SUCCESS; ++ } else if (resp & 0x80000000) { ++ outl((u32)&reply_msg[0], iobase + MPT_REG_REP_Q); ++ return DISK_RET_EBADTRACK; ++ } ++ } ++ usleep(50); ++ } ++} ++ ++int ++mpt_scsi_process_op(struct disk_op_s *op) ++{ ++ if (!CONFIG_MPT_SCSI) ++ return DISK_RET_EBADTRACK; ++ ++ u8 cdbcmd[16]; ++ int blocksize = scsi_fill_cmd(op, cdbcmd, sizeof(cdbcmd)); ++ if (blocksize < 0) ++ return default_process_op(op); ++ ++ struct mpt_lun_s *llun_gf = ++ container_of(op->drive_gf, struct mpt_lun_s, drive); ++ u16 target = GET_GLOBALFLAT(llun_gf->target); ++ u16 lun = GET_GLOBALFLAT(llun_gf->lun); ++ u32 iobase = GET_GLOBALFLAT(llun_gf->iobase); ++ return mpt_scsi_cmd(iobase, op, cdbcmd, target, 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_drive_setup(&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 inline void ++mpt_out_doorbell(u8 func, u8 arg, u16 iobase) ++{ ++ outl((func << 24) | (arg << 16), iobase + MPT_REG_DOORBELL); ++} ++ ++static void ++init_mpt_scsi(struct pci_device *pci, const char *dev_name) ++{ ++ 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; ++ ++ pci_config_maskw(bdf, PCI_COMMAND, 0, ++ PCI_COMMAND_IO | PCI_COMMAND_MASTER); ++ ++ 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 ++ mpt_out_doorbell(MPT_DOORBELL_MSG_RESET, 0, iobase); ++ outl(MPT_IMASK_DOORBELL|MPT_IMASK_REPLY , iobase + MPT_REG_IMASK); ++ outl(0, iobase + MPT_REG_ISTATUS); ++ ++ // send IOC Init message through the doorbell ++ mpt_out_doorbell(MPT_DOORBELL_HANDSHAKE, ++ sizeof(MptIOCInitRequest)/sizeof(u32), ++ iobase); ++ ++ outsl(iobase + MPT_REG_DOORBELL, ++ (u32 *)&MptIOCInitRequest, ++ sizeof(MptIOCInitRequest)/sizeof(u32)); ++ ++ // Read the reply 16 bits at a time. Cannot use insl ++ // because the port is 32 bits wide. ++ msg_in_p = (u16 *)&MptIOCInitReply; ++ while(msg_in_p != (u16 *)(&MptIOCInitReply + 1)) ++ *msg_in_p++ = (u16)inl(iobase + MPT_REG_DOORBELL); ++ ++ // Eat doorbell interrupt ++ outl(0, iobase + MPT_REG_ISTATUS); ++ ++ // Post reply message used for SCSI errors ++ outl((u32)&reply_msg[0], iobase + MPT_REG_REP_Q); ++ ++ for (int 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/hw/mpt-scsi.h b/src/hw/mpt-scsi.h +new file mode 100644 +index 0000000..6535dd8 +--- /dev/null ++++ b/src/hw/mpt-scsi.h +@@ -0,0 +1,8 @@ ++#ifndef __MPT_SCSI_H ++#define __MPT_SCSI_H ++ ++struct disk_op_s; ++int mpt_scsi_process_op(struct disk_op_s *op); ++void mpt_scsi_setup(void); ++ ++#endif /* __MPT_SCSI_H */ +diff --git a/src/post.c b/src/post.c +index 6803585..1dd075e 100644 +--- a/src/post.c ++++ b/src/post.c +@@ -14,6 +14,7 @@ + #include "hw/ata.h" // ata_setup + #include "hw/esp-scsi.h" // esp_scsi_setup + #include "hw/lsi-scsi.h" // lsi_scsi_setup ++#include "hw/mpt-scsi.h" // lsi_scsi_setup + #include "hw/megasas.h" // megasas_setup + #include "hw/pvscsi.h" // pvscsi_setup + #include "hw/pic.h" // pic_setup +@@ -153,6 +154,7 @@ device_hardware_setup(void) + esp_scsi_setup(); + megasas_setup(); + pvscsi_setup(); ++ mpt_scsi_setup(); + } + + static void +-- +2.5.0 + diff --git a/config.seabios-128k b/config.seabios-128k index 155741b..29495c1 100644 --- a/config.seabios-128k +++ b/config.seabios-128k @@ -1,10 +1,15 @@ # for qemu machine types 1.7 + older -# need to turn off features (xhci) to make it fit into 128k +# need to turn off features (bootsplash) to make it fit into 128k CONFIG_QEMU=y CONFIG_ROM_SIZE=128 CONFIG_XEN=n -CONFIG_USB_XHCI=n -CONFIG_USB_UAS=n +CONFIG_BOOTSPLASH=n +CONFIG_FLASH_FLOPPY=n CONFIG_USB_OHCI=n -CONFIG_SDCARD=n CONFIG_TCGBIOS=n + +# Right now all drivers fit in the ROM, but these could +# easily go... +#CONFIG_ESP_SCSI=n +#CONFIG_USB_UAS=n +#CONFIG_SDCARD=n diff --git a/seabios.spec b/seabios.spec index a9a5900..aff92c3 100644 --- a/seabios.spec +++ b/seabios.spec @@ -1,6 +1,6 @@ Name: seabios Version: 1.9.1 -Release: 1%{?dist} +Release: 2%{?dist} Summary: Open-source legacy BIOS implementation Group: Applications/Emulators @@ -8,6 +8,7 @@ License: LGPLv3 URL: http://www.coreboot.org/SeaBIOS Source0: http://code.coreboot.org/p/seabios/downloads/get/%{name}-%{version}.tar.gz +Patch1: 0001-Support-for-booting-from-LSI-Logic-LSI53C1030-SAS106.patch Source10: config.vga.cirrus Source11: config.vga.isavga @@ -71,6 +72,7 @@ SeaVGABIOS is an open-source VGABIOS implementation. %prep %setup -q +%patch1 -p1 %build @@ -137,6 +139,10 @@ install -m 0644 binaries/vgabios*.bin $RPM_BUILD_ROOT%{_datadir}/seavgabios %changelog +* Thu Mar 24 2016 Paolo Bonzini - 1.9.1-2 +- Include MPT Fusion driver, in preparation for QEMU 2.6 +- Include XHCI and UAS drivers in 128k ROM, sacrifice bootsplash instead + * Thu Mar 17 2016 Cole Robinson - 1.9.1-1 - Rebased to version 1.9.1 - Fix incorrect UUID format in boot output (bz #1284259)