From 67b1f390e7df755904e78d4b1ed76b7f1dcc9e94 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: May 28 2012 20:56:40 +0000 Subject: Rebased to version 1.7.0 Support for virtio-scsi Improved USB drive support Several USB controller bug fixes and improvements --- diff --git a/.gitignore b/.gitignore index 0b098a5..69db142 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ seabios-0.5.1.tar.gz seabios-0.6.0.tar.gz /seabios-0.6.2.tar.gz /seabios-1.6.3.tar.gz +/seabios-1.7.0.tar.gz diff --git a/seabios-do-not-advertise-S4-S3-in-DSDT.patch b/seabios-do-not-advertise-S4-S3-in-DSDT.patch index 469c46a..b5da2d0 100644 --- a/seabios-do-not-advertise-S4-S3-in-DSDT.patch +++ b/seabios-do-not-advertise-S4-S3-in-DSDT.patch @@ -1,58 +1,27 @@ -From 526d703a74752b66fd54ac4a9133a3de31c90549 Mon Sep 17 00:00:00 2001 -From: Gleb Natapov -Date: Sun, 11 Sep 2011 09:05:50 +0200 -Subject: [PATCH] do not advertise S4/S3 in DSDT - -RH-Author: Gleb Natapov -Message-id: <20110911090550.GF21417@redhat.com> -Patchwork-id: 32631 -O-Subject: [PATCHv2 RHEL6.2 SEABIOS] do not advertise S4/S3 in DSDT -Bugzilla: 736522 -RH-Acked-by: Gerd Hoffmann -RH-Acked-by: Marcelo Tosatti -RH-Acked-by: Markus Armbruster - -To compile Seabios with PM support run make "DSDT_CPP_FLAGS=-DDSDT_PM" - -BZ: 736522 -Upstream: local patch - -Signed-off-by: Gleb Natapov --- - Gleb. - -Signed-off-by: Michal Novotny ---- - Makefile | 2 +- - src/acpi-dsdt.dsl | 2 ++ - 2 files changed, 3 insertions(+), 1 deletions(-) - -diff --git a/Makefile b/Makefile -index b185ac8..f5c7104 100644 ---- a/Makefile -+++ b/Makefile -@@ -186,7 +186,7 @@ $(OUT)vgabios.bin: $(OUT)vgabios.bin.raw tools/buildrom.py - ####### dsdt build rules - src/%.hex: src/%.dsl - @echo "Compiling DSDT" -- $(Q)cpp -P $< > $(OUT)$*.dsl.i -+ $(Q)cpp $(DSDT_CPP_FLAGS) -P $< > $(OUT)$*.dsl.i - $(Q)iasl -tc -p $(OUT)$* $(OUT)$*.dsl.i - $(Q)cp $(OUT)$*.hex $@ +diff -rup seabios-1.7.0/Makefile mysea/Makefile +--- seabios-1.7.0/Makefile 2012-05-28 16:53:27.898842738 -0400 ++++ mysea/Makefile 2012-05-28 16:50:37.307644939 -0400 +@@ -221,7 +221,7 @@ $(OUT)vgabios.bin: $(OUT)vgabios.bin.raw -diff --git a/src/acpi-dsdt.dsl b/src/acpi-dsdt.dsl -index b54c558..1db5ae9 100644 ---- a/src/acpi-dsdt.dsl -+++ b/src/acpi-dsdt.dsl -@@ -722,6 +722,7 @@ DefinitionBlock ( - } - } + src/%.hex: src/%.dsl ./tools/acpi_extract_preprocess.py ./tools/acpi_extract.py + @echo "Compiling DSDT" +- $(Q)cpp -P $< > $(OUT)$*.dsl.i.orig ++ $(Q)cpp $(DSDT_CPP_FLAGS) -P $< > $(OUT)$*.dsl.i.orig + $(Q)$(PYTHON) ./tools/acpi_extract_preprocess.py $(OUT)$*.dsl.i.orig > $(OUT)$*.dsl.i + $(Q)iasl -l -tc -p $(OUT)$* $(OUT)$*.dsl.i + $(Q)$(PYTHON) ./tools/acpi_extract.py $(OUT)$*.lst > $(OUT)$*.off +diff -rup seabios-1.7.0/src/acpi-dsdt.dsl mysea/src/acpi-dsdt.dsl +--- seabios-1.7.0/src/acpi-dsdt.dsl 2012-04-14 22:27:40.000000000 -0400 ++++ mysea/src/acpi-dsdt.dsl 2012-05-28 16:52:11.745575415 -0400 +@@ -609,6 +609,7 @@ DefinitionBlock ( + * Suspend + ****************************************************************/ +#ifdef DSDT_PM /* * S3 (suspend-to-ram), S4 (suspend-to-disk) and S5 (power-off) type codes: * must match piix4 emulation. -@@ -740,6 +741,7 @@ DefinitionBlock ( +@@ -627,6 +628,7 @@ DefinitionBlock ( Zero, /* reserved */ Zero /* reserved */ }) @@ -60,6 +29,3 @@ index b54c558..1db5ae9 100644 Name (\_S5, Package (0x04) { Zero, /* PM1a_CNT.SLP_TYP */ --- -1.7.4.4 - diff --git a/seabios-usb-boot.patch b/seabios-usb-boot.patch deleted file mode 100644 index 06dcd54..0000000 --- a/seabios-usb-boot.patch +++ /dev/null @@ -1,275 +0,0 @@ -From 5c244dfbfcc8b610eac30ffa39c009724843695b Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 5 Mar 2012 12:29:12 +0100 -Subject: [PATCH 1/4] scsi: do not send MODE SENSE except to QEMU disks - -This is the simplest way to avoid breaking boot on USB sticks that -stall when asked for the MODE SENSE page 4. Some old sticks do -not support the MODE SENSE command at all and just return a -"medium may have changed" unit attention condition when SeaBIOS -sends it! - -Reported-by: Dave Frodin -Signed-off-by: Paolo Bonzini -(cherry-picked from commit cb721714570520c02ae48efc26d3c04b8548d973) ---- - src/blockcmd.c | 37 +++++++++++++++++++++++-------------- - 1 files changed, 23 insertions(+), 14 deletions(-) - -diff --git a/src/blockcmd.c b/src/blockcmd.c -index 9919acb..4f3131c 100644 ---- a/src/blockcmd.c -+++ b/src/blockcmd.c -@@ -131,20 +131,29 @@ scsi_init_drive(struct drive_s *drive, const char *s, int *pdt, char **desc) - dprintf(1, "%s blksize=%d sectors=%d\n" - , s, drive->blksize, (unsigned)drive->sectors); - -- struct cdbres_mode_sense_geom geomdata; -- ret = cdb_mode_sense_geom(&dop, &geomdata); -- if (ret == 0) { -- u32 cylinders; -- cylinders = geomdata.cyl[0] << 16; -- cylinders |= geomdata.cyl[1] << 8; -- cylinders |= geomdata.cyl[2]; -- if (cylinders && geomdata.heads && -- drive->sectors <= 0xFFFFFFFFULL && -- ((u32)drive->sectors % (geomdata.heads * cylinders) == 0)) { -- drive->pchs.cylinders = cylinders; -- drive->pchs.heads = geomdata.heads; -- drive->pchs.spt = (u32)drive->sectors -- / (geomdata.heads * cylinders); -+ // We do not recover from USB stalls, so try to be safe and avoid -+ // sending the command if the (obsolete, but still provided by QEMU) -+ // fixed disk geometry page may not be supported. -+ // -+ // We could also send the command only to small disks (e.g. <504MiB) -+ // but some old USB keys only support a very small subset of SCSI which -+ // does not even include the MODE SENSE command! -+ // -+ if (! CONFIG_COREBOOT && memcmp(vendor, "QEMU ", 8) == 0) { -+ struct cdbres_mode_sense_geom geomdata; -+ ret = cdb_mode_sense_geom(&dop, &geomdata); -+ if (ret == 0) { -+ u32 cylinders; -+ cylinders = geomdata.cyl[0] << 16; -+ cylinders |= geomdata.cyl[1] << 8; -+ cylinders |= geomdata.cyl[2]; -+ if (cylinders && geomdata.heads && -+ drive->sectors <= 0xFFFFFFFFULL && -+ ((u32)drive->sectors % (geomdata.heads * cylinders) == 0)) { -+ drive->pchs.cylinders = cylinders; -+ drive->pchs.heads = geomdata.heads; -+ drive->pchs.spt = (u32)drive->sectors / (geomdata.heads * cylinders); -+ } - } - } - --- -1.7.9.1 - - -From 04b3f8876a82eac4f06c8e89d6ca0e2c35f632a6 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Thu, 15 Mar 2012 16:10:53 +0100 -Subject: [PATCH 2/4] Use OUT mode for all zero byte "scsi" transfers. - -Upstream status: posted at - http://permalink.gmane.org/gmane.comp.bios.coreboot.seabios/3466 - -Some devices can get confused if asked to "read" data during a zero -byte transfer, so consider these transfers as "writes". (Reported by -Steve Goodrich.) - -Also, extract out the code to determine the transfer direction into -cdb_is_read(). - -Signed-off-by: Kevin O'Connor -Signed-off-by: Paolo Bonzini -(cherry-picked from commit 1fd9a89082b807a4bb4ab6ce1285df474cb75746) ---- - src/blockcmd.c | 7 +++++++ - src/blockcmd.h | 1 + - src/usb-msc.c | 4 ++-- - src/virtio-scsi.c | 7 ++++--- - 4 files changed, 14 insertions(+), 5 deletions(-) - -diff --git a/src/blockcmd.c b/src/blockcmd.c -index 4f3131c..f77f3af 100644 ---- a/src/blockcmd.c -+++ b/src/blockcmd.c -@@ -31,6 +31,13 @@ cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) - } - } - -+// Determine if the command is a request to pull data from the device -+int -+cdb_is_read(u8 *cdbcmd, u16 blocksize) -+{ -+ return blocksize && cdbcmd[0] != CDB_CMD_WRITE_10; -+} -+ - int - scsi_is_ready(struct disk_op_s *op) - { -diff --git a/src/blockcmd.h b/src/blockcmd.h -index bace649..4442ae1 100644 ---- a/src/blockcmd.h -+++ b/src/blockcmd.h -@@ -100,6 +100,7 @@ struct cdbres_mode_sense_geom { - } PACKED; - - // blockcmd.c -+int cdb_is_read(u8 *cdbcmd, u16 blocksize); - int cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data); - int cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data); - int cdb_test_unit_ready(struct disk_op_s *op); -diff --git a/src/usb-msc.c b/src/usb-msc.c -index cde08ce..8210a15 100644 ---- a/src/usb-msc.c -+++ b/src/usb-msc.c -@@ -74,13 +74,13 @@ usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) - cbw.dCBWSignature = CBW_SIGNATURE; - cbw.dCBWTag = 999; // XXX - cbw.dCBWDataTransferLength = bytes; -- cbw.bmCBWFlags = (cbw.CBWCB[0] == CDB_CMD_WRITE_10) ? USB_DIR_OUT : USB_DIR_IN; -+ cbw.bmCBWFlags = cdb_is_read(cdbcmd, blocksize) ? USB_DIR_IN : USB_DIR_OUT; - cbw.bCBWLUN = 0; // XXX - cbw.bCBWCBLength = USB_CDB_SIZE; - - // Transfer cbw to device. - int ret = usb_msc_send(udrive_g, USB_DIR_OUT -- , MAKE_FLATPTR(GET_SEG(SS), &cbw), sizeof(cbw)); -+ , MAKE_FLATPTR(GET_SEG(SS), &cbw), sizeof(cbw)); - if (ret) - goto fail; - -diff --git a/src/virtio-scsi.c b/src/virtio-scsi.c -index 9437116..76c5f29 100644 ---- a/src/virtio-scsi.c -+++ b/src/virtio-scsi.c -@@ -31,7 +31,7 @@ struct virtio_lun_s { - - static int - virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op, -- void *cdbcmd, u16 target, u16 lun, u32 len) -+ void *cdbcmd, u16 target, u16 lun, u16 blocksize) - { - struct virtio_scsi_req_cmd req; - struct virtio_scsi_resp_cmd resp; -@@ -44,7 +44,8 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op, - req.lun[3] = (lun & 0xff); - memcpy(req.cdb, cdbcmd, 16); - -- int datain = (req.cdb[0] != CDB_CMD_WRITE_10); -+ u32 len = op->count * blocksize; -+ int datain = cdb_is_read(cdbcmd, blocksize); - int data_idx = (datain ? 2 : 1); - int out_num = (datain ? 1 : 2); - int in_num = (len ? 3 : 2) - out_num; -@@ -89,7 +90,7 @@ virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) - return virtio_scsi_cmd(GET_GLOBAL(vlun->ioaddr), - GET_GLOBAL(vlun->vq), op, cdbcmd, - GET_GLOBAL(vlun->target), GET_GLOBAL(vlun->lun), -- blocksize * op->count); -+ blocksize); - } - - static int --- -1.7.9.1 - - -From ff5cb1672acf63e2a82a765f04f4044ce5c19d6f Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 19 Mar 2012 11:44:05 +0100 -Subject: [PATCH 3/4] virtio-scsi: Fix virtio-scsi after cdb_is_read changes. - -The previous patch changes the way TEST_UNIT_READY is composed in the - buffers and breaks virtio-scsi. - -Signed-off-by: Paolo Bonzini -(cherry-picked from commit 8c313078917099a002d45f58d58ae2f4eb9a657f) ---- - src/virtio-scsi.c | 12 +++++++----- - 1 files changed, 7 insertions(+), 5 deletions(-) - -diff --git a/src/virtio-scsi.c b/src/virtio-scsi.c -index 76c5f29..0aa3388 100644 ---- a/src/virtio-scsi.c -+++ b/src/virtio-scsi.c -@@ -46,9 +46,8 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op, - - u32 len = op->count * blocksize; - int datain = cdb_is_read(cdbcmd, blocksize); -- int data_idx = (datain ? 2 : 1); -- int out_num = (datain ? 1 : 2); -- int in_num = (len ? 3 : 2) - out_num; -+ int in_num = (datain ? 2 : 1); -+ int out_num = (len ? 3 : 2) - in_num; - - sg[0].addr = MAKE_FLATPTR(GET_SEG(SS), &req); - sg[0].length = sizeof(req); -@@ -56,8 +55,11 @@ virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op, - sg[out_num].addr = MAKE_FLATPTR(GET_SEG(SS), &resp); - sg[out_num].length = sizeof(resp); - -- sg[data_idx].addr = op->buf_fl; -- sg[data_idx].length = len; -+ if (len) { -+ int data_idx = (datain ? 2 : 1); -+ sg[data_idx].addr = op->buf_fl; -+ sg[data_idx].length = len; -+ } - - /* Add to virtqueue and kick host */ - vring_add_buf(vq, sg, out_num, in_num, 0, 0); --- -1.7.9.1 - - -From 9c70fa372c60e1195bc407fcd0064efc24f440a5 Mon Sep 17 00:00:00 2001 -From: Paolo Bonzini -Date: Mon, 19 Mar 2012 11:37:30 +0100 -Subject: [PATCH 4/4] ata: send TEST UNIT READY correctly - -The ATAPI driver does not need to support writes, but it does needs to -avoid the PIO transfer and DRQ check when TEST UNIT READY is sent. -Since TEST UNIT READY has no payload, checking for not busy is enough. - -This fixes a timeout when booting from CD/DVD, which fellaw@gmx.net -reported to cause boot failures. - -Signed-off-by: Paolo Bonzini ---- - src/ata.c | 14 ++++++++------ - 1 files changed, 8 insertions(+), 6 deletions(-) - -diff --git a/src/ata.c b/src/ata.c -index b33dcb6..752db4a 100644 ---- a/src/ata.c -+++ b/src/ata.c -@@ -642,13 +642,15 @@ atapi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) - ret = -2; - goto fail; - } -- if (!(status & ATA_CB_STAT_DRQ)) { -- dprintf(6, "send_atapi_cmd : DRQ not set (status %02x)\n", status); -- ret = -3; -- goto fail; -- } -+ if (blocksize) { -+ if (!(status & ATA_CB_STAT_DRQ)) { -+ dprintf(6, "send_atapi_cmd : DRQ not set (status %02x)\n", status); -+ ret = -3; -+ goto fail; -+ } - -- ret = ata_pio_transfer(op, 0, blocksize); -+ ret = ata_pio_transfer(op, 0, blocksize); -+ } - - fail: - // Enable interrupts --- -1.7.9.1 - diff --git a/seabios-usb_fix_boot_paths.patch b/seabios-usb_fix_boot_paths.patch deleted file mode 100644 index d5104b5..0000000 --- a/seabios-usb_fix_boot_paths.patch +++ /dev/null @@ -1,27 +0,0 @@ -commit a3fea015398d7c41db5b5d348fe3f6d76236b6be -Author: Paolo Bonzini -Date: Fri Nov 18 15:59:24 2011 +0100 - - usb: fix boot paths - - The fw paths for USB devices that SeaBIOS computes are off-by-one, - because QEMU builds those paths with a numbering that starts from one - (see usb_fill_port and usb_hub_initfn in QEMU). Fix that so that - the numbering agrees. - -diff --git a/src/boot.c b/src/boot.c -index 119f290..93928d3 100644 ---- a/src/boot.c -+++ b/src/boot.c -@@ -191,9 +191,9 @@ int bootprio_find_usb(struct pci_device *pci, u64 path) - for (i=56; i>0; i-=8) { - int port = (path >> i) & 0xff; - if (port != 0xff) -- p += snprintf(p, desc+sizeof(desc)-p, "/hub@%x", port); -+ p += snprintf(p, desc+sizeof(desc)-p, "/hub@%x", port+1); - } -- snprintf(p, desc+sizeof(desc)-p, "/*@%x", (u32)(path & 0xff)); -+ snprintf(p, desc+sizeof(desc)-p, "/*@%x", (u32)(path & 0xff)+1); - return find_prio(desc); - } - diff --git a/seabios-virtio-scsi.patch b/seabios-virtio-scsi.patch deleted file mode 100644 index 47a4527..0000000 --- a/seabios-virtio-scsi.patch +++ /dev/null @@ -1,1557 +0,0 @@ -diff --git a/Makefile b/Makefile -index 7d511e8..fb9bfaf 100644 ---- a/Makefile -+++ b/Makefile -@@ -12,10 +12,10 @@ OUT=out/ - - # Source files - SRCBOTH=misc.c stacks.c pmm.c output.c util.c block.c floppy.c ata.c mouse.c \ -- kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.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 apm.c ahci.c -+ kbd.c pci.c serial.c clock.c pic.c cdrom.c ps2port.c smp.c resume.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 - 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 338f51a..8de3503 100644 ---- a/src/Kconfig -+++ b/src/Kconfig -@@ -109,10 +109,16 @@ menu "Hardware support" - Support for AHCI disk code. - config VIRTIO_BLK - depends on DRIVES && !COREBOOT -- bool "VirtIO controllers" -+ bool "virtio-blk controllers" - default y - help -- Support boot from virtio storage. -+ Support boot from virtio-blk storage. -+ config VIRTIO_SCSI -+ depends on DRIVES && !COREBOOT -+ bool "virtio-scsi controllers" -+ default y -+ help -+ Support boot from virtio-scsi storage. - config FLOPPY - depends on DRIVES - bool "Floppy controller" -diff --git a/src/block.c b/src/block.c -index f7e7851..e607d67 100644 ---- a/src/block.c -+++ b/src/block.c -@@ -11,8 +11,8 @@ - #include "util.h" // dprintf - #include "ata.h" // process_ata_op - #include "ahci.h" // process_ahci_op --#include "usb-msc.h" // process_usb_op --#include "virtio-blk.h" // process_virtio_op -+#include "virtio-blk.h" // process_virtio_blk_op -+#include "blockcmd.h" // cdb_* - - u8 FloppyCount VAR16VISIBLE; - u8 CDCount; -@@ -276,6 +276,28 @@ map_floppy_drive(struct drive_s *drive_g) - * 16bit calling interface - ****************************************************************/ - -+int -+process_scsi_op(struct disk_op_s *op) -+{ -+ if (!CONFIG_VIRTIO_SCSI && !CONFIG_USB_MSC) -+ return 0; -+ switch (op->command) { -+ case CMD_READ: -+ return cdb_read(op); -+ case CMD_WRITE: -+ return cdb_write(op); -+ case CMD_FORMAT: -+ case CMD_RESET: -+ case CMD_ISREADY: -+ case CMD_VERIFY: -+ case CMD_SEEK: -+ return DISK_RET_SUCCESS; -+ default: -+ op->count = 0; -+ return DISK_RET_EPARAM; -+ } -+} -+ - // Execute a disk_op request. - int - process_op(struct disk_op_s *op) -@@ -293,12 +315,13 @@ process_op(struct disk_op_s *op) - return process_ramdisk_op(op); - case DTYPE_CDEMU: - return process_cdemu_op(op); -- case DTYPE_USB: -- return process_usb_op(op); -- case DTYPE_VIRTIO: -- return process_virtio_op(op); -+ case DTYPE_VIRTIO_BLK: -+ return process_virtio_blk_op(op); - case DTYPE_AHCI: - return process_ahci_op(op); -+ case DTYPE_USB: -+ case DTYPE_VIRTIO_SCSI: -+ return process_scsi_op(op); - default: - op->count = 0; - return DISK_RET_EPARAM; -diff --git a/src/blockcmd.c b/src/blockcmd.c -index c9c6845..b2a8d71 100644 ---- a/src/blockcmd.c -+++ b/src/blockcmd.c -@@ -12,6 +12,7 @@ - #include "ata.h" // atapi_cmd_data - #include "ahci.h" // atapi_cmd_data - #include "usb-msc.h" // usb_cmd_data -+#include "virtio-scsi.h" // virtio_scsi_cmd_data - - // Route command to low-level handler. - static int -@@ -25,6 +26,8 @@ cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) - return usb_cmd_data(op, cdbcmd, blocksize); - case DTYPE_AHCI: - return ahci_cmd_data(op, cdbcmd, blocksize); -+ case DTYPE_VIRTIO_SCSI: -+ return virtio_scsi_cmd_data(op, cdbcmd, blocksize); - default: - op->count = 0; - return DISK_RET_EPARAM; -@@ -32,6 +35,128 @@ cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) - } - - int -+scsi_is_ready(struct disk_op_s *op) -+{ -+ dprintf(6, "scsi_is_ready (drive=%p)\n", op->drive_g); -+ -+ /* Retry TEST UNIT READY for 5 seconds unless MEDIUM NOT PRESENT is -+ * reported by the device. If the device reports "IN PROGRESS", -+ * 30 seconds is added. */ -+ int in_progress = 0; -+ u64 end = calc_future_tsc(5000); -+ for (;;) { -+ if (check_tsc(end)) { -+ dprintf(1, "test unit ready failed\n"); -+ return -1; -+ } -+ -+ int ret = cdb_test_unit_ready(op); -+ if (!ret) -+ // Success -+ break; -+ -+ struct cdbres_request_sense sense; -+ ret = cdb_get_sense(op, &sense); -+ if (ret) -+ // Error - retry. -+ continue; -+ -+ // Sense succeeded. -+ if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */ -+ dprintf(1, "Device reports MEDIUM NOT PRESENT\n"); -+ return -1; -+ } -+ -+ if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) { -+ /* IN PROGRESS OF BECOMING READY */ -+ printf("Waiting for device to detect medium... "); -+ /* Allow 30 seconds more */ -+ end = calc_future_tsc(30000); -+ in_progress = 1; -+ } -+ } -+ return 0; -+} -+ -+// Validate drive and find block size and sector count. -+int -+scsi_init_drive(struct drive_s *drive, const char *s, int *pdt, char **desc) -+{ -+ if (!CONFIG_USB_MSC && !CONFIG_VIRTIO_SCSI) -+ return 0; -+ -+ struct disk_op_s dop; -+ memset(&dop, 0, sizeof(dop)); -+ dop.drive_g = drive; -+ struct cdbres_inquiry data; -+ int ret = cdb_get_inquiry(&dop, &data); -+ if (ret) -+ return ret; -+ char vendor[sizeof(data.vendor)+1], product[sizeof(data.product)+1]; -+ char rev[sizeof(data.rev)+1]; -+ strtcpy(vendor, data.vendor, sizeof(vendor)); -+ nullTrailingSpace(vendor); -+ strtcpy(product, data.product, sizeof(product)); -+ nullTrailingSpace(product); -+ strtcpy(rev, data.rev, sizeof(rev)); -+ nullTrailingSpace(rev); -+ *pdt = data.pdt & 0x1f; -+ int removable = !!(data.removable & 0x80); -+ dprintf(1, "%s vendor='%s' product='%s' rev='%s' type=%d removable=%d\n" -+ , s, vendor, product, rev, *pdt, removable); -+ drive->removable = removable; -+ -+ if (*pdt == SCSI_TYPE_CDROM) { -+ drive->blksize = CDROM_SECTOR_SIZE; -+ drive->sectors = (u64)-1; -+ -+ *desc = znprintf(MAXDESCSIZE, "DVD/CD [%s Drive %s %s %s]" -+ , s, vendor, product, rev); -+ return 0; -+ } -+ -+ ret = scsi_is_ready(&dop); -+ if (ret) { -+ dprintf(1, "scsi_is_ready returned %d\n", ret); -+ return ret; -+ } -+ -+ struct cdbres_read_capacity capdata; -+ ret = cdb_read_capacity(&dop, &capdata); -+ if (ret) -+ return ret; -+ -+ // READ CAPACITY returns the address of the last block. -+ // We do not bother with READ CAPACITY(16) because BIOS does not support -+ // 64-bit LBA anyway. -+ drive->blksize = ntohl(capdata.blksize); -+ drive->sectors = (u64)ntohl(capdata.sectors) + 1; -+ dprintf(1, "%s blksize=%d sectors=%d\n" -+ , s, drive->blksize, (unsigned)drive->sectors); -+ -+ struct cdbres_mode_sense_geom geomdata; -+ ret = cdb_mode_sense_geom(&dop, &geomdata); -+ if (ret == 0) { -+ u32 cylinders; -+ cylinders = geomdata.cyl[0] << 16; -+ cylinders |= geomdata.cyl[1] << 8; -+ cylinders |= geomdata.cyl[2]; -+ if (cylinders && geomdata.heads && -+ drive->sectors <= 0xFFFFFFFFULL && -+ ((u32)drive->sectors % (geomdata.heads * cylinders) == 0)) { -+ drive->pchs.cylinders = cylinders; -+ drive->pchs.heads = geomdata.heads; -+ drive->pchs.spt = (u32)drive->sectors -+ / (geomdata.heads * cylinders); -+ } -+ } -+ -+ *desc = znprintf(MAXDESCSIZE, "%s Drive %s %s %s" -+ , s, vendor, product, rev); -+ return 0; -+} -+ -+int - cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data) - { - struct cdb_request_sense cmd; -@@ -56,6 +181,18 @@ cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data) - return cdb_cmd_data(op, &cmd, sizeof(*data)); - } - -+// Test unit ready -+int -+cdb_test_unit_ready(struct disk_op_s *op) -+{ -+ struct cdb_request_sense cmd; -+ memset(&cmd, 0, sizeof(cmd)); -+ cmd.command = CDB_CMD_TEST_UNIT_READY; -+ op->count = 0; -+ op->buf_fl = NULL; -+ return cdb_cmd_data(op, &cmd, 0); -+} -+ - // Request capacity - int - cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data) -@@ -68,6 +205,21 @@ cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data) - return cdb_cmd_data(op, &cmd, sizeof(*data)); - } - -+// Mode sense, geometry page. -+int -+cdb_mode_sense_geom(struct disk_op_s *op, struct cdbres_mode_sense_geom *data) -+{ -+ struct cdb_mode_sense cmd; -+ memset(&cmd, 0, sizeof(cmd)); -+ cmd.command = CDB_CMD_MODE_SENSE; -+ cmd.flags = 8; /* DBD */ -+ cmd.page = MODE_PAGE_HD_GEOMETRY; -+ cmd.count = htons(sizeof(*data)); -+ op->count = 1; -+ op->buf_fl = data; -+ return cdb_cmd_data(op, &cmd, sizeof(*data)); -+} -+ - // Read sectors. - int - cdb_read(struct disk_op_s *op) -@@ -79,3 +231,15 @@ cdb_read(struct disk_op_s *op) - cmd.count = htons(op->count); - return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize)); - } -+ -+// Write sectors. -+int -+cdb_write(struct disk_op_s *op) -+{ -+ struct cdb_rwdata_10 cmd; -+ memset(&cmd, 0, sizeof(cmd)); -+ cmd.command = CDB_CMD_WRITE_10; -+ cmd.lba = htonl(op->lba); -+ cmd.count = htons(op->count); -+ return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize)); -+} -diff --git a/src/blockcmd.h b/src/blockcmd.h -index 903c435..bace649 100644 ---- a/src/blockcmd.h -+++ b/src/blockcmd.h -@@ -32,8 +32,9 @@ struct cdbres_read_capacity { - u32 blksize; - } PACKED; - --#define CDB_CMD_INQUIRY 0x12 --#define CDB_CMD_REQUEST_SENSE 0x03 -+#define CDB_CMD_TEST_UNIT_READY 0x00 -+#define CDB_CMD_INQUIRY 0x12 -+#define CDB_CMD_REQUEST_SENSE 0x03 - - struct cdb_request_sense { - u8 command; -@@ -56,6 +57,9 @@ struct cdbres_request_sense { - u32 reserved_0e; - } PACKED; - -+#define SCSI_TYPE_DISK 0x00 -+#define SCSI_TYPE_CDROM 0x05 -+ - struct cdbres_inquiry { - u8 pdt; - u8 removable; -@@ -67,11 +71,45 @@ struct cdbres_inquiry { - char rev[4]; - } PACKED; - -+#define CDB_CMD_MODE_SENSE 0x5A -+#define MODE_PAGE_HD_GEOMETRY 0x04 -+ -+struct cdb_mode_sense { -+ u8 command; -+ u8 flags; -+ u8 page; -+ u32 reserved_03; -+ u16 count; -+ u8 reserved_09; -+ u8 pad[6]; -+} PACKED; -+ -+struct cdbres_mode_sense_geom { -+ u8 unused_00[3]; -+ u8 read_only; -+ u32 unused_04; -+ u8 page; -+ u8 length; -+ u8 cyl[3]; -+ u8 heads; -+ u8 precomp[3]; -+ u8 reduced[3]; -+ u16 step_rate; -+ u8 landing[3]; -+ u16 rpm; -+} PACKED; -+ - // blockcmd.c - int cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data); - int cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data); -+int cdb_test_unit_ready(struct disk_op_s *op); - int cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data); -+int cdb_mode_sense_geom(struct disk_op_s *op, struct cdbres_mode_sense_geom *data); - int cdb_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data); - int cdb_read(struct disk_op_s *op); -+int cdb_write(struct disk_op_s *op); -+ -+int scsi_is_ready(struct disk_op_s *op); -+int scsi_init_drive(struct drive_s *drive, const char *s, int *pdt, char **desc); - - #endif // blockcmd.h -diff --git a/src/boot.c b/src/boot.c -index 93928d3..c0991cd 100644 ---- a/src/boot.c -+++ b/src/boot.c -@@ -128,6 +128,20 @@ int bootprio_find_pci_device(struct pci_device *pci) - return find_prio(desc); - } - -+int bootprio_find_scsi_device(struct pci_device *pci, int target, int lun) -+{ -+ if (!CONFIG_BOOTORDER) -+ return -1; -+ if (!pci) -+ // support only pci machine for now -+ return -1; -+ // Find scsi drive - for example: /pci@i0cf8/scsi@5/channel@0/disk@1,0 -+ char desc[256], *p; -+ p = build_pci_path(desc, sizeof(desc), "*", pci); -+ snprintf(p, desc+sizeof(desc)-p, "/*@0/*@%d,%d", target, lun); -+ return find_prio(desc); -+} -+ - int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave) - { - if (!CONFIG_BOOTORDER) -diff --git a/src/boot.h b/src/boot.h -index d776aa1..686f04d 100644 ---- a/src/boot.h -+++ b/src/boot.h -@@ -14,6 +14,7 @@ void boot_add_cbfs(void *data, const char *desc, int prio); - void boot_prep(void); - struct pci_device; - int bootprio_find_pci_device(struct pci_device *pci); -+int bootprio_find_scsi_device(struct pci_device *pci, int target, int lun); - int bootprio_find_ata_device(struct pci_device *pci, int chanid, int slave); - int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid); - int bootprio_find_pci_rom(struct pci_device *pci, int instance); -diff --git a/src/cdrom.c b/src/cdrom.c -index 6351fec..170ffc4 100644 ---- a/src/cdrom.c -+++ b/src/cdrom.c -@@ -184,60 +184,6 @@ cdemu_134b(struct bregs *regs) - * CD booting - ****************************************************************/ - --static int --atapi_is_ready(struct disk_op_s *op) --{ -- dprintf(6, "atapi_is_ready (drive=%p)\n", op->drive_g); -- -- /* Retry READ CAPACITY for 5 seconds unless MEDIUM NOT PRESENT is -- * reported by the device. If the device reports "IN PROGRESS", -- * 30 seconds is added. */ -- struct cdbres_read_capacity info; -- int in_progress = 0; -- u64 end = calc_future_tsc(5000); -- for (;;) { -- if (check_tsc(end)) { -- dprintf(1, "read capacity failed\n"); -- return -1; -- } -- -- int ret = cdb_read_capacity(op, &info); -- if (!ret) -- // Success -- break; -- -- struct cdbres_request_sense sense; -- ret = cdb_get_sense(op, &sense); -- if (ret) -- // Error - retry. -- continue; -- -- // Sense succeeded. -- if (sense.asc == 0x3a) { /* MEDIUM NOT PRESENT */ -- dprintf(1, "Device reports MEDIUM NOT PRESENT\n"); -- return -1; -- } -- -- if (sense.asc == 0x04 && sense.ascq == 0x01 && !in_progress) { -- /* IN PROGRESS OF BECOMING READY */ -- printf("Waiting for device to detect medium... "); -- /* Allow 30 seconds more */ -- end = calc_future_tsc(30000); -- in_progress = 1; -- } -- } -- -- u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors); -- if (blksize != GET_GLOBAL(op->drive_g->blksize)) { -- printf("Unsupported sector size %u\n", blksize); -- return -1; -- } -- -- dprintf(6, "sectors=%u\n", sectors); -- printf("%dMB medium detected\n", sectors>>(20-11)); -- return 0; --} -- - int - cdrom_boot(struct drive_s *drive_g) - { -@@ -248,9 +194,9 @@ cdrom_boot(struct drive_s *drive_g) - if (!dop.drive_g || cdid < 0) - return 1; - -- int ret = atapi_is_ready(&dop); -+ int ret = scsi_is_ready(&dop); - if (ret) -- dprintf(1, "atapi_is_ready returned %d\n", ret); -+ dprintf(1, "scsi_is_ready returned %d\n", ret); - - // Read the Boot Record Volume Descriptor - u8 buffer[2048]; -diff --git a/src/disk.c b/src/disk.c -index 8f7c61f..6a170fd 100644 ---- a/src/disk.c -+++ b/src/disk.c -@@ -546,7 +546,8 @@ disk_1348(struct bregs *regs, struct drive_s *drive_g) - SET_INT13DPT(regs, blksize, blksize); - - if (size < 30 || -- (type != DTYPE_ATA && type != DTYPE_ATAPI && type != DTYPE_VIRTIO)) { -+ (type != DTYPE_ATA && type != DTYPE_ATAPI && -+ type != DTYPE_VIRTIO_BLK && type != DTYPE_VIRTIO_SCSI)) { - disk_ret(regs, DISK_RET_SUCCESS); - return; - } -@@ -651,7 +652,7 @@ disk_1348(struct bregs *regs, struct drive_s *drive_g) - SET_INT13DPT(regs, iface_path, iobase1); - } - -- if (type != DTYPE_VIRTIO) { -+ if (type != DTYPE_VIRTIO_BLK) { - SET_INT13DPT(regs, iface_type[0], 'A'); - SET_INT13DPT(regs, iface_type[1], 'T'); - SET_INT13DPT(regs, iface_type[2], 'A'); -diff --git a/src/disk.h b/src/disk.h -index ac33518..d344399 100644 ---- a/src/disk.h -+++ b/src/disk.h -@@ -198,15 +198,16 @@ struct drive_s { - #define DISK_SECTOR_SIZE 512 - #define CDROM_SECTOR_SIZE 2048 - --#define DTYPE_NONE 0x00 --#define DTYPE_FLOPPY 0x01 --#define DTYPE_ATA 0x02 --#define DTYPE_ATAPI 0x03 --#define DTYPE_RAMDISK 0x04 --#define DTYPE_CDEMU 0x05 --#define DTYPE_USB 0x06 --#define DTYPE_VIRTIO 0x07 --#define DTYPE_AHCI 0x08 -+#define DTYPE_NONE 0x00 -+#define DTYPE_FLOPPY 0x01 -+#define DTYPE_ATA 0x02 -+#define DTYPE_ATAPI 0x03 -+#define DTYPE_RAMDISK 0x04 -+#define DTYPE_CDEMU 0x05 -+#define DTYPE_USB 0x06 -+#define DTYPE_VIRTIO_BLK 0x07 -+#define DTYPE_AHCI 0x08 -+#define DTYPE_VIRTIO_SCSI 0x09 - - #define MAXDESCSIZE 80 - -diff --git a/src/pci_ids.h b/src/pci_ids.h -index e1cded2..4b59585 100644 ---- a/src/pci_ids.h -+++ b/src/pci_ids.h -@@ -2608,3 +2608,4 @@ - - #define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 - #define PCI_DEVICE_ID_VIRTIO_BLK 0x1001 -+#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 -diff --git a/src/post.c b/src/post.c -index b4ad1fa..d7bbcdd 100644 ---- a/src/post.c -+++ b/src/post.c -@@ -26,6 +26,7 @@ - #include "xen.h" // xen_probe_hvm_info - #include "ps2port.h" // ps2port_setup - #include "virtio-blk.h" // virtio_blk_setup -+#include "virtio-scsi.h" // virtio_scsi_setup - - - /**************************************************************** -@@ -190,6 +191,7 @@ init_hw(void) - cbfs_payload_setup(); - ramdisk_setup(); - virtio_blk_setup(); -+ virtio_scsi_setup(); - } - - // Begin the boot process by invoking an int0x19 in 16bit mode. -diff --git a/src/usb-ehci.c b/src/usb-ehci.c -index a60c607..9bdd638 100644 ---- a/src/usb-ehci.c -+++ b/src/usb-ehci.c -@@ -303,22 +303,12 @@ ehci_init(struct pci_device *pci, int busid, struct pci_device *comppci) - * End point communication - ****************************************************************/ - --static int --ehci_wait_qh(struct usb_ehci_s *cntl, struct ehci_qh *qh) --{ -- // XXX - 500ms just a guess -- u64 end = calc_future_tsc(500); -- for (;;) { -- if (qh->qtd_next & EHCI_PTR_TERM) -- // XXX - confirm -- return 0; -- if (check_tsc(end)) { -- warn_timeout(); -- return -1; -- } -- yield(); -- } --} -+struct ehci_pipe { -+ struct ehci_qh qh; -+ struct ehci_qtd *next_td, *tds; -+ void *data; -+ struct usb_pipe pipe; -+}; - - // Wait for next USB async frame to start - for ensuring safe memory release. - static void -@@ -362,12 +352,46 @@ ehci_waittick(struct usb_ehci_s *cntl) - writel(&cntl->regs->usbsts, STS_IAA); - } - --struct ehci_pipe { -- struct ehci_qh qh; -- struct ehci_qtd *next_td, *tds; -- void *data; -- struct usb_pipe pipe; --}; -+static void -+ehci_reset_pipe(struct ehci_pipe *pipe) -+{ -+ SET_FLATPTR(pipe->qh.qtd_next, EHCI_PTR_TERM); -+ SET_FLATPTR(pipe->qh.alt_next, EHCI_PTR_TERM); -+ barrier(); -+ SET_FLATPTR(pipe->qh.token, GET_FLATPTR(pipe->qh.token) & QTD_TOGGLE); -+} -+ -+static int -+ehci_wait_td(struct ehci_pipe *pipe, struct ehci_qtd *td, int timeout) -+{ -+ u64 end = calc_future_tsc(timeout); -+ u32 status; -+ for (;;) { -+ status = td->token; -+ if (!(status & QTD_STS_ACTIVE)) -+ break; -+ if (check_tsc(end)) { -+ u32 cur = GET_FLATPTR(pipe->qh.current); -+ u32 tok = GET_FLATPTR(pipe->qh.token); -+ u32 next = GET_FLATPTR(pipe->qh.qtd_next); -+ warn_timeout(); -+ dprintf(1, "ehci pipe=%p cur=%08x tok=%08x next=%x td=%p status=%x\n" -+ , pipe, cur, tok, next, td, status); -+ ehci_reset_pipe(pipe); -+ struct usb_ehci_s *cntl = container_of( -+ GET_FLATPTR(pipe->pipe.cntl), struct usb_ehci_s, usb); -+ ehci_waittick(cntl); -+ return -1; -+ } -+ yield(); -+ } -+ if (status & QTD_STS_HALT) { -+ dprintf(1, "ehci_wait_td error - status=%x\n", status); -+ ehci_reset_pipe(pipe); -+ return -2; -+ } -+ return 0; -+} - - void - ehci_free_pipe(struct usb_pipe *p) -@@ -416,7 +440,6 @@ ehci_alloc_control_pipe(struct usb_pipe *dummy) - memset(pipe, 0, sizeof(*pipe)); - memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe)); - pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM; -- pipe->qh.token = QTD_STS_HALT; - - // Add queue head to controller list. - struct ehci_qh *async_qh = cntl->async_qh; -@@ -455,15 +478,14 @@ ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - ASSERT32FLAT(); - if (! CONFIG_USB_EHCI) - return -1; -- dprintf(5, "ehci_control %p\n", p); -+ dprintf(5, "ehci_control %p (dir=%d cmd=%d data=%d)\n" -+ , p, dir, cmdsize, datasize); - if (datasize > 4*4096 || cmdsize > 4*4096) { - // XXX - should support larger sizes. - warn_noalloc(); - return -1; - } - struct ehci_pipe *pipe = container_of(p, struct ehci_pipe, pipe); -- struct usb_ehci_s *cntl = container_of( -- pipe->pipe.cntl, struct usb_ehci_s, usb); - - u16 maxpacket = pipe->pipe.maxpacket; - int speed = pipe->pipe.speed; -@@ -513,14 +535,12 @@ ehci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - // Transfer data - barrier(); - pipe->qh.qtd_next = (u32)tds; -- barrier(); -- pipe->qh.token = 0; -- int ret = ehci_wait_qh(cntl, &pipe->qh); -- pipe->qh.token = QTD_STS_HALT; -- if (ret) { -- pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM; -- // XXX - halt qh? -- ehci_waittick(cntl); -+ int i, ret=0; -+ for (i=0; i<3; i++) { -+ struct ehci_qtd *td = &tds[i]; -+ ret = ehci_wait_td(pipe, td, 500); -+ if (ret) -+ break; - } - free(tds); - return ret; -@@ -545,7 +565,6 @@ ehci_alloc_bulk_pipe(struct usb_pipe *dummy) - memset(pipe, 0, sizeof(*pipe)); - memcpy(&pipe->pipe, dummy, sizeof(pipe->pipe)); - pipe->qh.qtd_next = pipe->qh.alt_next = EHCI_PTR_TERM; -- pipe->qh.token = QTD_STS_HALT; - - // Add queue head to controller list. - struct ehci_qh *async_qh = cntl->async_qh; -@@ -555,28 +574,6 @@ ehci_alloc_bulk_pipe(struct usb_pipe *dummy) - return &pipe->pipe; - } - --static int --ehci_wait_td(struct ehci_qtd *td) --{ -- u64 end = calc_future_tsc(5000); // XXX - lookup real time. -- u32 status; -- for (;;) { -- status = td->token; -- if (!(status & QTD_STS_ACTIVE)) -- break; -- if (check_tsc(end)) { -- warn_timeout(); -- return -1; -- } -- yield(); -- } -- if (status & QTD_STS_HALT) { -- dprintf(1, "ehci_wait_td error - status=%x\n", status); -- return -2; -- } -- return 0; --} -- - #define STACKQTDS 4 - - int -@@ -607,15 +604,13 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) - | (GET_FLATPTR(pipe->pipe.tt_devaddr) << QH_HUBADDR_SHIFT))); - barrier(); - SET_FLATPTR(pipe->qh.qtd_next, (u32)MAKE_FLATPTR(GET_SEG(SS), tds)); -- barrier(); -- SET_FLATPTR(pipe->qh.token, GET_FLATPTR(pipe->qh.token) & QTD_TOGGLE); - - int tdpos = 0; - while (datasize) { - struct ehci_qtd *td = &tds[tdpos++ % STACKQTDS]; -- int ret = ehci_wait_td(td); -+ int ret = ehci_wait_td(pipe, td, 5000); - if (ret) -- goto fail; -+ return -1; - - struct ehci_qtd *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS) - , &tds[tdpos % STACKQTDS]); -@@ -633,21 +628,12 @@ ehci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) - int i; - for (i=0; iqh.qtd_next, EHCI_PTR_TERM); -- SET_FLATPTR(pipe->qh.alt_next, EHCI_PTR_TERM); -- // XXX - halt qh? -- struct usb_ehci_s *cntl = container_of( -- GET_FLATPTR(pipe->pipe.cntl), struct usb_ehci_s, usb); -- ehci_waittick(cntl); -- return -1; - } - - struct usb_pipe * -diff --git a/src/usb-msc.c b/src/usb-msc.c -index 13ef93e..4a09972 100644 ---- a/src/usb-msc.c -+++ b/src/usb-msc.c -@@ -46,6 +46,17 @@ struct csw_s { - u8 bCSWStatus; - } PACKED; - -+static int -+usb_msc_send(struct usbdrive_s *udrive_g, int dir, void *buf, u32 bytes) -+{ -+ struct usb_pipe *pipe; -+ if (dir == USB_DIR_OUT) -+ pipe = GET_GLOBAL(udrive_g->bulkout); -+ else -+ pipe = GET_GLOBAL(udrive_g->bulkin); -+ return usb_send_bulk(pipe, dir, buf, bytes); -+} -+ - // Low-level usb command transmit function. - int - usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) -@@ -57,35 +68,35 @@ usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) - , op->drive_g, 0, op->count, blocksize, op->buf_fl); - struct usbdrive_s *udrive_g = container_of( - op->drive_g, struct usbdrive_s, drive); -- struct usb_pipe *bulkin = GET_GLOBAL(udrive_g->bulkin); -- struct usb_pipe *bulkout = GET_GLOBAL(udrive_g->bulkout); - - // Setup command block wrapper. - u32 bytes = blocksize * op->count; - struct cbw_s cbw; - memset(&cbw, 0, sizeof(cbw)); -+ memcpy(cbw.CBWCB, cdbcmd, USB_CDB_SIZE); - cbw.dCBWSignature = CBW_SIGNATURE; - cbw.dCBWTag = 999; // XXX - cbw.dCBWDataTransferLength = bytes; -- cbw.bmCBWFlags = USB_DIR_IN; // XXX -+ cbw.bmCBWFlags = (cbw.CBWCB[0] == CDB_CMD_WRITE_10) ? USB_DIR_OUT : USB_DIR_IN; - cbw.bCBWLUN = 0; // XXX - cbw.bCBWCBLength = USB_CDB_SIZE; -- memcpy(cbw.CBWCB, cdbcmd, USB_CDB_SIZE); - - // Transfer cbw to device. -- int ret = usb_send_bulk(bulkout, USB_DIR_OUT -+ int ret = usb_msc_send(udrive_g, USB_DIR_OUT - , MAKE_FLATPTR(GET_SEG(SS), &cbw), sizeof(cbw)); - if (ret) - goto fail; - -- // Transfer data from device. -- ret = usb_send_bulk(bulkin, USB_DIR_IN, op->buf_fl, bytes); -- if (ret) -- goto fail; -+ // Transfer data to/from device. -+ if (bytes) { -+ ret = usb_msc_send(udrive_g, cbw.bmCBWFlags, op->buf_fl, bytes); -+ if (ret) -+ goto fail; -+ } - - // Transfer csw info. - struct csw_s csw; -- ret = usb_send_bulk(bulkin, USB_DIR_IN -+ ret = usb_msc_send(udrive_g, USB_DIR_IN - , MAKE_FLATPTR(GET_SEG(SS), &csw), sizeof(csw)); - if (ret) - goto fail; -@@ -95,7 +106,8 @@ usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) - if (csw.bCSWStatus == 2) - goto fail; - -- op->count -= csw.dCSWDataResidue / blocksize; -+ if (blocksize) -+ op->count -= csw.dCSWDataResidue / blocksize; - return DISK_RET_EBADTRACK; - - fail: -@@ -107,75 +119,33 @@ fail: - - - /**************************************************************** -- * Drive ops -- ****************************************************************/ -- --// 16bit command demuxer for ATAPI cdroms. --int --process_usb_op(struct disk_op_s *op) --{ -- if (!CONFIG_USB_MSC) -- return 0; -- switch (op->command) { -- case CMD_READ: -- return cdb_read(op); -- case CMD_FORMAT: -- case CMD_WRITE: -- return DISK_RET_EWRITEPROTECT; -- case CMD_RESET: -- case CMD_ISREADY: -- case CMD_VERIFY: -- case CMD_SEEK: -- return DISK_RET_SUCCESS; -- default: -- op->count = 0; -- return DISK_RET_EPARAM; -- } --} -- -- --/**************************************************************** - * Setup - ****************************************************************/ - - static int --setup_drive_cdrom(struct disk_op_s *op, char *desc) -+setup_drive_cdrom(struct drive_s *drive, char *desc) - { -- op->drive_g->blksize = CDROM_SECTOR_SIZE; -- op->drive_g->sectors = (u64)-1; -+ drive->sectors = (u64)-1; - struct usb_pipe *pipe = container_of( -- op->drive_g, struct usbdrive_s, drive)->bulkout; -+ drive, struct usbdrive_s, drive)->bulkout; - int prio = bootprio_find_usb(pipe->cntl->pci, pipe->path); -- boot_add_cd(op->drive_g, desc, prio); -+ boot_add_cd(drive, desc, prio); - return 0; - } - - static int --setup_drive_hd(struct disk_op_s *op, char *desc) -+setup_drive_hd(struct drive_s *drive, char *desc) - { -- struct cdbres_read_capacity info; -- int ret = cdb_read_capacity(op, &info); -- if (ret) -- return ret; -- // XXX - retry for some timeout? -- -- u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors); -- if (blksize != DISK_SECTOR_SIZE) { -- if (blksize == CDROM_SECTOR_SIZE) -- return setup_drive_cdrom(op, desc); -- dprintf(1, "Unsupported USB MSC block size %d\n", blksize); -+ if (drive->blksize != DISK_SECTOR_SIZE) { -+ dprintf(1, "Unsupported USB MSC block size %d\n", drive->blksize); - return -1; - } -- op->drive_g->blksize = blksize; -- op->drive_g->sectors = sectors; -- dprintf(1, "USB MSC blksize=%d sectors=%d\n", blksize, sectors); - - // Register with bcv system. - struct usb_pipe *pipe = container_of( -- op->drive_g, struct usbdrive_s, drive)->bulkout; -+ drive, struct usbdrive_s, drive)->bulkout; - int prio = bootprio_find_usb(pipe->cntl->pci, pipe->path); -- boot_add_hd(op->drive_g, desc, prio); -- -+ boot_add_hd(drive, desc, prio); - return 0; - } - -@@ -218,37 +188,17 @@ usb_msc_init(struct usb_pipe *pipe - if (!udrive_g->bulkin || !udrive_g->bulkout) - goto fail; - -- // Validate drive and find block size and sector count. -- struct disk_op_s dop; -- memset(&dop, 0, sizeof(dop)); -- dop.drive_g = &udrive_g->drive; -- struct cdbres_inquiry data; -- int ret = cdb_get_inquiry(&dop, &data); -+ int ret, pdt; -+ char *desc = NULL; -+ ret = scsi_init_drive(&udrive_g->drive, "USB MSC", &pdt, &desc); - if (ret) - goto fail; -- char vendor[sizeof(data.vendor)+1], product[sizeof(data.product)+1]; -- char rev[sizeof(data.rev)+1]; -- strtcpy(vendor, data.vendor, sizeof(vendor)); -- nullTrailingSpace(vendor); -- strtcpy(product, data.product, sizeof(product)); -- nullTrailingSpace(product); -- strtcpy(rev, data.rev, sizeof(rev)); -- nullTrailingSpace(rev); -- int pdt = data.pdt & 0x1f; -- int removable = !!(data.removable & 0x80); -- dprintf(1, "USB MSC vendor='%s' product='%s' rev='%s' type=%d removable=%d\n" -- , vendor, product, rev, pdt, removable); -- udrive_g->drive.removable = removable; -- -- if (pdt == USB_MSC_TYPE_CDROM) { -- char *desc = znprintf(MAXDESCSIZE, "DVD/CD [USB Drive %s %s %s]" -- , vendor, product, rev); -- ret = setup_drive_cdrom(&dop, desc); -- } else { -- char *desc = znprintf(MAXDESCSIZE, "USB Drive %s %s %s" -- , vendor, product, rev); -- ret = setup_drive_hd(&dop, desc); -- } -+ -+ if (pdt == SCSI_TYPE_CDROM) -+ ret = setup_drive_cdrom(&udrive_g->drive, desc); -+ else -+ ret = setup_drive_hd(&udrive_g->drive, desc); -+ - if (ret) - goto fail; - -diff --git a/src/usb-msc.h b/src/usb-msc.h -index 71adb20..a8686a3 100644 ---- a/src/usb-msc.h -+++ b/src/usb-msc.h -@@ -21,7 +21,4 @@ int process_usb_op(struct disk_op_s *op); - - #define US_PR_BULK 0x50 - --#define USB_MSC_TYPE_DISK 0x00 --#define USB_MSC_TYPE_CDROM 0x05 -- - #endif // ush-msc.h -diff --git a/src/usb-uhci.c b/src/usb-uhci.c -index f3680d3..a78dbca 100644 ---- a/src/usb-uhci.c -+++ b/src/usb-uhci.c -@@ -212,26 +212,13 @@ uhci_init(struct pci_device *pci, int busid) - * End point communication - ****************************************************************/ - --static int --wait_qh(struct usb_uhci_s *cntl, struct uhci_qh *qh) --{ -- // XXX - 500ms just a guess -- u64 end = calc_future_tsc(500); -- for (;;) { -- if (qh->element & UHCI_PTR_TERM) -- return 0; -- if (check_tsc(end)) { -- warn_timeout(); -- struct uhci_td *td = (void*)(qh->element & ~UHCI_PTR_BITS); -- dprintf(1, "Timeout on wait_qh %p (td=%p s=%x c=%x/%x)\n" -- , qh, td, td->status -- , inw(cntl->iobase + USBCMD) -- , inw(cntl->iobase + USBSTS)); -- return -1; -- } -- yield(); -- } --} -+struct uhci_pipe { -+ struct uhci_qh qh; -+ struct uhci_td *next_td; -+ struct usb_pipe pipe; -+ u16 iobase; -+ u8 toggle; -+}; - - // Wait for next USB frame to start - for ensuring safe memory release. - static void -@@ -251,13 +238,29 @@ uhci_waittick(u16 iobase) - } - } - --struct uhci_pipe { -- struct uhci_qh qh; -- struct uhci_td *next_td; -- struct usb_pipe pipe; -- u16 iobase; -- u8 toggle; --}; -+static int -+wait_pipe(struct uhci_pipe *pipe, int timeout) -+{ -+ u64 end = calc_future_tsc(timeout); -+ for (;;) { -+ u32 el_link = GET_FLATPTR(pipe->qh.element); -+ if (el_link & UHCI_PTR_TERM) -+ return 0; -+ if (check_tsc(end)) { -+ warn_timeout(); -+ u16 iobase = GET_FLATPTR(pipe->iobase); -+ struct uhci_td *td = (void*)(el_link & ~UHCI_PTR_BITS); -+ dprintf(1, "Timeout on wait_pipe %p (td=%p s=%x c=%x/%x)\n" -+ , pipe, (void*)el_link, GET_FLATPTR(td->status) -+ , inw(iobase + USBCMD) -+ , inw(iobase + USBSTS)); -+ SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM); -+ uhci_waittick(iobase); -+ return -1; -+ } -+ yield(); -+ } -+} - - void - uhci_free_pipe(struct usb_pipe *p) -@@ -331,8 +334,6 @@ uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - return -1; - dprintf(5, "uhci_control %p\n", p); - struct uhci_pipe *pipe = container_of(p, struct uhci_pipe, pipe); -- struct usb_uhci_s *cntl = container_of( -- pipe->pipe.cntl, struct usb_uhci_s, usb); - - int maxpacket = pipe->pipe.maxpacket; - int lowspeed = pipe->pipe.speed; -@@ -376,11 +377,7 @@ uhci_control(struct usb_pipe *p, int dir, const void *cmd, int cmdsize - // Transfer data - barrier(); - pipe->qh.element = (u32)&tds[0]; -- int ret = wait_qh(cntl, &pipe->qh); -- if (ret) { -- pipe->qh.element = UHCI_PTR_TERM; -- uhci_waittick(pipe->iobase); -- } -+ int ret = wait_pipe(pipe, 500); - free(tds); - return ret; - } -@@ -487,16 +484,8 @@ uhci_send_bulk(struct usb_pipe *p, int dir, void *data, int datasize) - data += transfer; - datasize -= transfer; - } -- int i; -- for (i=0; itoggle, !!toggle); -- return 0; -+ return wait_pipe(pipe, 5000); - fail: - dprintf(1, "uhci_send_bulk failed\n"); - SET_FLATPTR(pipe->qh.element, UHCI_PTR_TERM); -diff --git a/src/virtio-blk.c b/src/virtio-blk.c -index b1274fc..b869189 100644 ---- a/src/virtio-blk.c -+++ b/src/virtio-blk.c -@@ -75,7 +75,7 @@ virtio_blk_op(struct disk_op_s *op, int write) - } - - int --process_virtio_op(struct disk_op_s *op) -+process_virtio_blk_op(struct disk_op_s *op) - { - if (! CONFIG_VIRTIO_BLK || CONFIG_COREBOOT) - return 0; -@@ -103,27 +103,17 @@ init_virtio_blk(struct pci_device *pci) - dprintf(1, "found virtio-blk at %x:%x\n", pci_bdf_to_bus(bdf), - pci_bdf_to_dev(bdf)); - struct virtiodrive_s *vdrive_g = malloc_fseg(sizeof(*vdrive_g)); -- struct vring_virtqueue *vq = memalign_low(PAGE_SIZE, sizeof(*vq)); -- if (!vdrive_g || !vq) { -+ if (!vdrive_g) { - warn_noalloc(); -- goto fail; -+ return; - } - memset(vdrive_g, 0, sizeof(*vdrive_g)); -- memset(vq, 0, sizeof(*vq)); -- vdrive_g->drive.type = DTYPE_VIRTIO; -+ vdrive_g->drive.type = DTYPE_VIRTIO_BLK; - vdrive_g->drive.cntl_id = bdf; -- vdrive_g->vq = vq; -- -- u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) & -- PCI_BASE_ADDRESS_IO_MASK; - -+ u16 ioaddr = vp_init_simple(bdf); - vdrive_g->ioaddr = ioaddr; -- -- vp_reset(ioaddr); -- vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | -- VIRTIO_CONFIG_S_DRIVER ); -- -- if (vp_find_vq(ioaddr, 0, vdrive_g->vq) < 0 ) { -+ if (vp_find_vq(ioaddr, 0, &vdrive_g->vq) < 0 ) { - dprintf(1, "fail to find vq for virtio-blk %x:%x\n", - pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); - goto fail; -@@ -161,8 +151,8 @@ init_virtio_blk(struct pci_device *pci) - return; - - fail: -+ free(vdrive_g->vq); - free(vdrive_g); -- free(vq); - } - - void -diff --git a/src/virtio-blk.h b/src/virtio-blk.h -index 7243704..0825f09 100644 ---- a/src/virtio-blk.h -+++ b/src/virtio-blk.h -@@ -37,7 +37,7 @@ struct virtio_blk_outhdr { - #define VIRTIO_BLK_S_UNSUPP 2 - - struct disk_op_s; --int process_virtio_op(struct disk_op_s *op); -+int process_virtio_blk_op(struct disk_op_s *op); - void virtio_blk_setup(void); - - #endif /* _VIRTIO_BLK_H */ -diff --git a/src/virtio-pci.c b/src/virtio-pci.c -index db19e97..7e0c1a5 100644 ---- a/src/virtio-pci.c -+++ b/src/virtio-pci.c -@@ -21,12 +21,18 @@ - #include "util.h" // dprintf - - int vp_find_vq(unsigned int ioaddr, int queue_index, -- struct vring_virtqueue *vq) -+ struct vring_virtqueue **p_vq) - { -- struct vring * vr = &vq->vring; - u16 num; - - ASSERT32FLAT(); -+ struct vring_virtqueue *vq = *p_vq = memalign_low(PAGE_SIZE, sizeof(*vq)); -+ if (!vq) { -+ warn_noalloc(); -+ goto fail; -+ } -+ memset(vq, 0, sizeof(*vq)); -+ - /* select the queue */ - - outw(queue_index, ioaddr + VIRTIO_PCI_QUEUE_SEL); -@@ -36,25 +42,26 @@ int vp_find_vq(unsigned int ioaddr, int queue_index, - num = inw(ioaddr + VIRTIO_PCI_QUEUE_NUM); - if (!num) { - dprintf(1, "ERROR: queue size is 0\n"); -- return -1; -+ goto fail; - } - - if (num > MAX_QUEUE_NUM) { - dprintf(1, "ERROR: queue size %d > %d\n", num, MAX_QUEUE_NUM); -- return -1; -+ goto fail; - } - - /* check if the queue is already active */ - - if (inl(ioaddr + VIRTIO_PCI_QUEUE_PFN)) { - dprintf(1, "ERROR: queue already active\n"); -- return -1; -+ goto fail; - } - - vq->queue_index = queue_index; - - /* initialize the queue */ - -+ struct vring * vr = &vq->vring; - vring_init(vr, num, (unsigned char*)&vq->queue); - - /* activate the queue -@@ -66,4 +73,20 @@ int vp_find_vq(unsigned int ioaddr, int queue_index, - ioaddr + VIRTIO_PCI_QUEUE_PFN); - - return num; -+ -+fail: -+ free(vq); -+ *p_vq = NULL; -+ return -1; -+} -+ -+u16 vp_init_simple(u16 bdf) -+{ -+ u16 ioaddr = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) & -+ PCI_BASE_ADDRESS_IO_MASK; -+ -+ vp_reset(ioaddr); -+ vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | -+ VIRTIO_CONFIG_S_DRIVER ); -+ return ioaddr; - } -diff --git a/src/virtio-pci.h b/src/virtio-pci.h -index d21d5a5..e1d972d 100644 ---- a/src/virtio-pci.h -+++ b/src/virtio-pci.h -@@ -99,6 +99,7 @@ static inline void vp_del_vq(unsigned int ioaddr, int queue_index) - } - - struct vring_virtqueue; -+u16 vp_init_simple(u16 bdf); - int vp_find_vq(unsigned int ioaddr, int queue_index, -- struct vring_virtqueue *vq); -+ struct vring_virtqueue **p_vq); - #endif /* _VIRTIO_PCI_H_ */ -diff --git a/src/virtio-scsi.c b/src/virtio-scsi.c -new file mode 100644 -index 0000000..2f6c48a ---- /dev/null -+++ b/src/virtio-scsi.c -@@ -0,0 +1,211 @@ -+// Virtio SCSI boot support. -+// -+// Copyright (C) 2011 Red Hat Inc. -+// -+// Authors: -+// Paolo Bonzini -+// -+// 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" // boot_add_hd -+#include "blockcmd.h" // CDB_CMD_WRITE_10, SCSI_TYPE_CDROM -+#include "virtio-pci.h" -+#include "virtio-ring.h" -+#include "virtio-scsi.h" -+#include "disk.h" -+ -+struct virtio_lun_s { -+ struct drive_s drive; -+ struct pci_device *pci; -+ struct vring_virtqueue *vq; -+ u16 ioaddr; -+ u16 target; -+ u16 lun; -+}; -+ -+static int -+virtio_scsi_cmd(u16 ioaddr, struct vring_virtqueue *vq, struct disk_op_s *op, -+ void *cdbcmd, u16 target, u16 lun, u32 len) -+{ -+ struct virtio_scsi_req_cmd req; -+ struct virtio_scsi_resp_cmd resp; -+ struct vring_list sg[3]; -+ -+ memset(&req, 0, sizeof(req)); -+ req.lun[0] = 1; -+ req.lun[1] = target; -+ req.lun[2] = (lun >> 8) | 0x40; -+ req.lun[3] = (lun & 0xff); -+ memcpy(req.cdb, cdbcmd, 16); -+ -+ int datain = (req.cdb[0] != CDB_CMD_WRITE_10); -+ int data_idx = (datain ? 2 : 1); -+ int out_num = (datain ? 1 : 2); -+ int in_num = (len ? 3 : 2) - out_num; -+ -+ sg[0].addr = MAKE_FLATPTR(GET_SEG(SS), &req); -+ sg[0].length = sizeof(req); -+ -+ sg[out_num].addr = MAKE_FLATPTR(GET_SEG(SS), &resp); -+ sg[out_num].length = sizeof(resp); -+ -+ sg[data_idx].addr = op->buf_fl; -+ sg[data_idx].length = len; -+ -+ /* Add to virtqueue and kick host */ -+ vring_add_buf(vq, sg, out_num, in_num, 0, 0); -+ vring_kick(ioaddr, vq, 1); -+ -+ /* Wait for reply */ -+ while (!vring_more_used(vq)) -+ usleep(5); -+ -+ /* Reclaim virtqueue element */ -+ vring_get_buf(vq, NULL); -+ -+ /* Clear interrupt status register. Avoid leaving interrupts stuck if -+ * VRING_AVAIL_F_NO_INTERRUPT was ignored and interrupts were raised. -+ */ -+ vp_get_isr(ioaddr); -+ -+ if (resp.response == VIRTIO_SCSI_S_OK && resp.status == 0) { -+ return DISK_RET_SUCCESS; -+ } -+ return DISK_RET_EBADTRACK; -+} -+ -+int -+virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) -+{ -+ struct virtio_lun_s *vlun = -+ container_of(op->drive_g, struct virtio_lun_s, drive); -+ -+ return virtio_scsi_cmd(GET_GLOBAL(vlun->ioaddr), -+ GET_GLOBAL(vlun->vq), op, cdbcmd, -+ GET_GLOBAL(vlun->target), GET_GLOBAL(vlun->lun), -+ blocksize * op->count); -+} -+ -+static int -+setup_lun_cdrom(struct virtio_lun_s *vlun, char *desc) -+{ -+ int prio = bootprio_find_scsi_device(vlun->pci, vlun->target, vlun->lun); -+ boot_add_cd(&vlun->drive, desc, prio); -+ return 0; -+} -+ -+static int -+setup_lun_hd(struct virtio_lun_s *vlun, char *desc) -+{ -+ if (vlun->drive.blksize != DISK_SECTOR_SIZE) { -+ dprintf(1, "Unsupported block size %d\n", vlun->drive.blksize); -+ return -1; -+ } -+ -+ // Register with bcv system. -+ int prio = bootprio_find_scsi_device(vlun->pci, vlun->target, vlun->lun); -+ boot_add_hd(&vlun->drive, desc, prio); -+ -+ return 0; -+} -+ -+static int -+virtio_scsi_add_lun(struct pci_device *pci, u16 ioaddr, -+ struct vring_virtqueue *vq, u16 target, u16 lun) -+{ -+ struct virtio_lun_s *vlun = malloc_fseg(sizeof(*vlun)); -+ if (!vlun) { -+ warn_noalloc(); -+ return -1; -+ } -+ memset(vlun, 0, sizeof(*vlun)); -+ vlun->drive.type = DTYPE_VIRTIO_SCSI; -+ vlun->drive.cntl_id = pci->bdf; -+ vlun->pci = pci; -+ vlun->ioaddr = ioaddr; -+ vlun->vq = vq; -+ vlun->target = target; -+ vlun->lun = lun; -+ -+ int pdt, ret; -+ char *desc = NULL; -+ ret = scsi_init_drive(&vlun->drive, "virtio-scsi", &pdt, &desc); -+ if (ret) -+ goto fail; -+ -+ if (pdt == SCSI_TYPE_CDROM) -+ ret = setup_lun_cdrom(vlun, desc); -+ else -+ ret = setup_lun_hd(vlun, desc); -+ if (ret) -+ goto fail; -+ return ret; -+ -+fail: -+ free(vlun); -+ return -1; -+} -+ -+static int -+virtio_scsi_scan_target(struct pci_device *pci, u16 ioaddr, -+ struct vring_virtqueue *vq, u16 target) -+{ -+ /* TODO: send REPORT LUNS. For now, only LUN 0 is recognized. */ -+ int ret = virtio_scsi_add_lun(pci, ioaddr, vq, target, 0); -+ return ret < 0 ? ret : 1; -+} -+ -+static void -+init_virtio_scsi(struct pci_device *pci) -+{ -+ u16 bdf = pci->bdf; -+ dprintf(1, "found virtio-scsi at %x:%x\n", pci_bdf_to_bus(bdf), -+ pci_bdf_to_dev(bdf)); -+ struct vring_virtqueue *vq = NULL; -+ u16 ioaddr = vp_init_simple(bdf); -+ if (vp_find_vq(ioaddr, 2, &vq) < 0 ) { -+ if (vq) { -+ dprintf(1, "fail to find vq for virtio-scsi %x:%x\n", -+ pci_bdf_to_bus(bdf), pci_bdf_to_dev(bdf)); -+ } -+ goto fail; -+ } -+ -+ int i, tot; -+ for (tot = 0, i = 0; i < 256; i++) -+ tot += virtio_scsi_scan_target(pci, ioaddr, vq, i); -+ -+ if (!tot) -+ goto fail; -+ -+ vp_set_status(ioaddr, VIRTIO_CONFIG_S_ACKNOWLEDGE | -+ VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK); -+ return; -+ -+fail: -+ free(vq); -+} -+ -+void -+virtio_scsi_setup(void) -+{ -+ ASSERT32FLAT(); -+ if (! CONFIG_VIRTIO_SCSI || CONFIG_COREBOOT) -+ return; -+ -+ dprintf(3, "init virtio-scsi\n"); -+ -+ struct pci_device *pci; -+ foreachpci(pci) { -+ if (pci->vendor != PCI_VENDOR_ID_REDHAT_QUMRANET -+ || pci->device != PCI_DEVICE_ID_VIRTIO_SCSI) -+ continue; -+ init_virtio_scsi(pci); -+ } -+} -diff --git a/src/virtio-scsi.h b/src/virtio-scsi.h -new file mode 100644 -index 0000000..28d48b0 ---- /dev/null -+++ b/src/virtio-scsi.h -@@ -0,0 +1,48 @@ -+#ifndef _VIRTIO_SCSI_H -+#define _VIRTIO_SCSI_H -+ -+#define VIRTIO_SCSI_CDB_SIZE 32 -+#define VIRTIO_SCSI_SENSE_SIZE 96 -+ -+struct virtio_scsi_config -+{ -+ u32 num_queues; -+ u32 seg_max; -+ u32 max_sectors; -+ u32 cmd_per_lun; -+ u32 event_info_size; -+ u32 sense_size; -+ u32 cdb_size; -+ u16 max_channel; -+ u16 max_target; -+ u32 max_lun; -+} __attribute__((packed)); -+ -+/* This is the first element of the "out" scatter-gather list. */ -+struct virtio_scsi_req_cmd { -+ u8 lun[8]; -+ u64 id; -+ u8 task_attr; -+ u8 prio; -+ u8 crn; -+ char cdb[VIRTIO_SCSI_CDB_SIZE]; -+}; -+ -+/* This is the first element of the "in" scatter-gather list. */ -+struct virtio_scsi_resp_cmd { -+ u32 sense_len; -+ u32 residual; -+ u16 status_qualifier; -+ u8 status; -+ u8 response; -+ u8 sense[VIRTIO_SCSI_SENSE_SIZE]; -+}; -+ -+#define VIRTIO_SCSI_S_OK 0 -+ -+struct disk_op_s; -+int process_virtio_scsi_op(struct disk_op_s *op); -+int virtio_scsi_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize); -+void virtio_scsi_setup(void); -+ -+#endif /* _VIRTIO_SCSI_H */ diff --git a/seabios.spec b/seabios.spec index 31a875b..297ac69 100644 --- a/seabios.spec +++ b/seabios.spec @@ -1,17 +1,16 @@ Name: seabios -Version: 1.6.3 -Release: 2%{?dist} +Version: 1.7.0 +Release: 1%{?dist} Summary: Open-source legacy BIOS implementation Group: Applications/Emulators License: LGPLv3 URL: http://www.coreboot.org/SeaBIOS Source0: http://www.linuxtogo.org/~kevin/SeaBIOS/%{name}-%{version}.tar.gz +# Don't advertise guest support for S3/S4 (bz 741375) +# keep: Non upstream, carry it until someone needs s3/s4 +Patch1: %{name}-do-not-advertise-S4-S3-in-DSDT.patch -Patch00: seabios-usb_fix_boot_paths.patch -Patch01: seabios-do-not-advertise-S4-S3-in-DSDT.patch -Patch02: seabios-virtio-scsi.patch -Patch03: seabios-usb-boot.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -29,7 +28,7 @@ SeaBIOS is an open-source legacy BIOS implementation which can be used as a coreboot payload. It implements the standard BIOS calling interfaces that a typical x86 proprietary BIOS implements. -%ifarch %{ix86} x86_64 +%ifarch %{ix86} x86_64 %package bin Summary: Seabios for x86 Buildarch: noarch @@ -42,27 +41,24 @@ that a typical x86 proprietary BIOS implements. %prep %setup -q +%patch1 -p1 -%patch00 -p1 -%patch01 -p1 -%patch02 -p1 -%patch03 -p1 # Makefile changes version to include date and buildhost sed -i 's,VERSION=%{version}.*,VERSION=%{version},g' Makefile %build -%ifarch %{ix86} x86_64 +%ifarch %{ix86} x86_64 export CFLAGS="$RPM_OPT_FLAGS" -make +make %endif %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{_datadir}/seabios -%ifarch %{ix86} x86_64 +%ifarch %{ix86} x86_64 install -m 0644 out/bios.bin $RPM_BUILD_ROOT%{_datadir}/seabios %endif @@ -75,7 +71,7 @@ rm -rf $RPM_BUILD_ROOT %defattr(-,root,root,-) %doc COPYING COPYING.LESSER README TODO -%ifarch %{ix86} x86_64 +%ifarch %{ix86} x86_64 %files bin %defattr(-,root,root,-) %dir %{_datadir}/seabios/ @@ -84,6 +80,12 @@ rm -rf $RPM_BUILD_ROOT %changelog +* Mon May 28 2012 Cole Robinson - 1.7.0-1 +- Rebased to version 1.7.0 +- Support for virtio-scsi +- Improved USB drive support +- Several USB controller bug fixes and improvements + * Wed Mar 28 2012 Paolo Bonzini - 1.6.3-2 - Fix bugs in booting from host (or redirected) USB pen drives diff --git a/sources b/sources index d98225b..c5bdabb 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -d7cd612ff34f9b910a63c2d73b25eef3 seabios-1.6.3.tar.gz +b3a6881a69a389e0463ce4e52d01c475 seabios-1.7.0.tar.gz