[seabios] fix boot from passthrough USB pen drives
bonzini
bonzini at fedoraproject.org
Wed Mar 28 07:09:16 UTC 2012
commit 9b21378e475c7e777838ca3706d422ee07d9804b
Author: Paolo Bonzini <pbonzini at redhat.com>
Date: Wed Mar 28 09:01:54 2012 +0200
fix boot from passthrough USB pen drives
seabios-usb-boot.patch | 275 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 275 insertions(+), 0 deletions(-)
---
diff --git a/seabios-usb-boot.patch b/seabios-usb-boot.patch
new file mode 100644
index 0000000..06dcd54
--- /dev/null
+++ b/seabios-usb-boot.patch
@@ -0,0 +1,275 @@
+From 5c244dfbfcc8b610eac30ffa39c009724843695b Mon Sep 17 00:00:00 2001
+From: Paolo Bonzini <pbonzini at redhat.com>
+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 <dave at camp.se-eng.com>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+(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 <pbonzini at redhat.com>
+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 <kevin at koconnor.net>
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+(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 <pbonzini at redhat.com>
+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 <pbonzini at redhat.com>
+(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 <pbonzini at redhat.com>
+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 at gmx.net
+reported to cause boot failures.
+
+Signed-off-by: Paolo Bonzini <pbonzini at redhat.com>
+---
+ 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
+
More information about the scm-commits
mailing list