From 6960463bf170d62c9d4af9e82e3572cb72018aa1 Mon Sep 17 00:00:00 2001 From: Justin M. Forbes Date: Feb 08 2012 20:06:34 +0000 Subject: update to 1.6.3 upstream --- diff --git a/.gitignore b/.gitignore index f412bfe..0b098a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,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 diff --git a/seabios-0.6.2-build.patch b/seabios-0.6.2-build.patch deleted file mode 100644 index 3d9fb51..0000000 --- a/seabios-0.6.2-build.patch +++ /dev/null @@ -1,49 +0,0 @@ -diff -ruNp seabios-0.6.2.orig/Makefile seabios-0.6.2/Makefile ---- seabios-0.6.2.orig/Makefile 2011-07-13 10:52:50.000000000 -0500 -+++ seabios-0.6.2/Makefile 2011-07-13 11:14:14.000000000 -0500 -@@ -5,7 +5,7 @@ - # This file may be distributed under the terms of the GNU LGPLv3 license. - - # Program version --VERSION=0.6.2-$(shell date +"%Y%m%d_%H%M%S")-$(shell hostname) -+VERSION=0.6.2 - - # Output directory - OUT=out/ -diff -ruNp seabios-0.6.2.orig/src/ahci.c seabios-0.6.2/src/ahci.c ---- seabios-0.6.2.orig/src/ahci.c 2011-07-13 10:52:50.000000000 -0500 -+++ seabios-0.6.2/src/ahci.c 2011-07-13 11:14:14.000000000 -0500 -@@ -408,7 +408,6 @@ static void - ahci_detect(void *data) - { - struct ahci_ctrl_s *ctrl = data; -- struct ahci_port_s *port; - u32 pnr, max; - int rc; - -@@ -422,7 +421,7 @@ ahci_detect(void *data) - dprintf(1, "AHCI/%d: link %s\n", pnr, rc == 0 ? "up" : "down"); - if (rc != 0) - continue; -- port = ahci_port_init(ctrl, pnr); -+ ahci_port_init(ctrl, pnr); - } - } - -diff -ruNp seabios-0.6.2.orig/src/bregs.h seabios-0.6.2/src/bregs.h ---- seabios-0.6.2.orig/src/bregs.h 2011-07-13 10:52:50.000000000 -0500 -+++ seabios-0.6.2/src/bregs.h 2011-07-13 11:16:04.000000000 -0500 -@@ -37,9 +37,9 @@ - struct bregs { - u16 ds; - u16 es; -- UREG(edi, di, di_hi, di_lo); -- UREG(esi, si, si_hi, si_lo); -- UREG(ebp, bp, bp_hi, bp_lo); -+ UREG(edi, di, di8u, di8l); -+ UREG(esi, si, si8u, si8l); -+ UREG(ebp, bp, bp8u, bp8l); - UREG(ebx, bx, bh, bl); - UREG(edx, dx, dh, dl); - UREG(ecx, cx, ch, cl); -Binary files seabios-0.6.2.orig/tools/layoutrom.pyc and seabios-0.6.2/tools/layoutrom.pyc differ diff --git a/seabios-0.6.2-fix-QXL.patch b/seabios-0.6.2-fix-QXL.patch deleted file mode 100644 index 800c5ca..0000000 --- a/seabios-0.6.2-fix-QXL.patch +++ /dev/null @@ -1,17 +0,0 @@ - -Beware that seabios 0.6.2 is broken for QXL. You need to apply this -patch - -diff --git a/src/config.h b/src/config.h -index e6e07c9..cd71c3a 100644 ---- a/src/config.h -+++ b/src/config.h -@@ -51,7 +51,7 @@ - #define BUILD_PCIPREFMEM_END 0 - #else - #define BUILD_PCIMEM_START 0xf0000000 --#define BUILD_PCIMEM_SIZE 0x08000000 /* half- of pci window */ -+#define BUILD_PCIMEM_SIZE 0x09000000 /* half- of pci window */ - #define BUILD_PCIMEM_END (BUILD_PCIMEM_START + BUILD_PCIMEM_SIZE) - #define BUILD_PCIPREFMEM_START BUILD_PCIMEM_END - #define BUILD_PCIPREFMEM_SIZE (BUILD_PCIPREFMEM_END - BUILD_PCIPREFMEM_START) diff --git a/seabios-usb_fix_boot_paths.patch b/seabios-usb_fix_boot_paths.patch new file mode 100644 index 0000000..d5104b5 --- /dev/null +++ b/seabios-usb_fix_boot_paths.patch @@ -0,0 +1,27 @@ +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 new file mode 100644 index 0000000..47a4527 --- /dev/null +++ b/seabios-virtio-scsi.patch @@ -0,0 +1,1557 @@ +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 f94a07d..ad756cb 100644 --- a/seabios.spec +++ b/seabios.spec @@ -1,6 +1,6 @@ Name: seabios -Version: 0.6.2 -Release: 4%{?dist} +Version: 1.6.3 +Release: 1%{?dist} Summary: Open-source legacy BIOS implementation Group: Applications/Emulators @@ -8,9 +8,9 @@ License: LGPLv3 URL: http://www.coreboot.org/SeaBIOS Source0: http://www.linuxtogo.org/~kevin/SeaBIOS/%{name}-%{version}.tar.gz -Patch00: seabios-0.6.2-build.patch -Patch01: seabios-0.6.2-fix-QXL.patch -Patch02: seabios-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 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -82,6 +82,10 @@ rm -rf $RPM_BUILD_ROOT %changelog +* Wed Feb 08 2012 Justin M. Forbes - 1.6.3-1 +- Update to 1.6.3 upstream +- Add virtio-scsi + * Sat Jan 14 2012 Fedora Release Engineering - 0.6.2-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild diff --git a/sources b/sources index feab5a9..d98225b 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -ec58d93b93fa29550164693f714c9320 seabios-0.6.2.tar.gz +d7cd612ff34f9b910a63c2d73b25eef3 seabios-1.6.3.tar.gz