Re: Booting from g_file_storage in cdrom mode

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On Fri, 4 Dec 2009 10:40:48 -0500 (EST)
Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:

> On Fri, 4 Dec 2009, Andreas Kemnade wrote:
> 
> > Hi,
> > 
> > I'm wondering if anyone is able to boot from an iso image provied by
> > g_file_storage. I get that far that I can select the device as a boot
> > option. But I never get any further. At best the BIOS tries some
> > time to boot from it but than it falls back to the next boot device.
> > 
> > I tried that with my freerunner.  Is it a known problem that BIOS
> > does not like g_file_storage cdroms or is it something special to
> > the freerunner?
> > With stall=0 I have no problems accessing g_file_storage. Booting
> > from g_file_storage with cdrom=0 and stall=0 works as well as booting 
> > from usb sticks. 
> 
> [...]
> You can find out what's going wrong by enabling the DUMP_MSGS symbol in 
> file_storage.c.
>
I analyzed it a bit with a thinkpad x31 
The g_file_storage gets upset by some non-zero bytes in the end of a
READ TOC command. 

<7>00000000: 55 53 42 43 42 49 4f 53 0c 00 00 00 80 00 0a 43 
<7>00000010: 00 00 00 00 00 00 00 0c 40 00 00 00 00 00 00  
<7>g_file_storage gadget: SCSI command: READ TOC;  Dc=10, Di=12;  Hc=10, Hi=12
<7>g_file_storage gadget: bulk-in, length 12:
<7>00000000: 00 00 00 00 00 00 00 00 00 00 00 00 
<7>g_file_storage gadget: sending command-failure status
<7>g_file_storage gadget:   sense data: SK x05, ASC x24, ASCQ x00;  info x0
<7>g_file_storage gadget: bulk-in, length 13:
<7>00000000: 55 53 42 53 42 49 4f 53 0c 00 00 00 01 

And then a sector size of 2048 (instead of 512) as usual for cdrom
drives is assumed. The following should read the el torito info block,
but the BIOS gets the wrong data due to the wrong sector size (offsets
are wrong). 

<7>g_file_storage gadget: bulk-out, length 31:
<7>00000000: 55 53 42 43 42 49 4f 53 00 08 00 00 80 00 0c 28 
<7>00000010: 00 00 00 00 11 00 00 01 00 00 00 00 00 00 00 
<7>SCSI CDB: 28 00 00 00 00 11 00 00 01 00 00 00 
<7>g_file_storage gadget: SCSI command: READ(10);  Dc=10, Di=512;  Hc=12, Hi=2048
<7>g_file_storage gadget: READ(10) is buggy! Expected length 10 but we got 12
<7>g_file_storage gadget-lun0: file read 512 @ 8704 -> 512
<7>g_file_storage gadget: bulk-in, length 13:
<7>00000000: 55 53 42 53 42 49 4f 53 00 06 00 00 00 

The following patch solves the problem for the BIOS. I am able to load
a kernel and an initrd with it correctly. Of course, it breaks everything
else but it can be considered as a proof of concept. I can boot from my
my g_file_storage cdrom drive with it on that thinkpad X31, on a mainboard with award
bios (with an AMD Geode 1700+ on it) and also on an INTEL D945GCLF board.

diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index b10fa31..f2550cc 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1599,10 +1599,10 @@ static int do_read(struct fsg_dev *fsg)
 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
 		return -EINVAL;
 	}
-	file_offset = ((loff_t) lba) << 9;
+	file_offset = ((loff_t) lba) << 11;
 
 	/* Carry out the file reads */
-	amount_left = fsg->data_size_from_cmnd;
+	amount_left = fsg->data_size_from_cmnd*4;
 	if (unlikely(amount_left == 0))
 		return -EIO;		// No default reply
 
@@ -2817,13 +2817,17 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
 		return -EINVAL;
 	}
 
-	/* Check that only command bytes listed in the mask are non-zero */
-	fsg->cmnd[1] &= 0x1f;			// Mask away the LUN
-	for (i = 1; i < cmnd_size; ++i) {
-		if (fsg->cmnd[i] && !(mask & (1 << i))) {
-			if (curlun)
-				curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
-			return -EINVAL;
+	/* Check that only command bytes listed in the mask are non-zero 
+	 * Some BIOSes put some non-zero values in READ_TOC requests in 
+	 * the last two bytes */
+	if (fsg->cmnd[0] != SC_READ_TOC) {
+		fsg->cmnd[1] &= 0x1f;			// Mask away the LUN
+		for (i = 1; i < cmnd_size; ++i) {
+			if (fsg->cmnd[i] && !(mask & (1 << i))) {
+				if (curlun)
+					curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
+				return -EINVAL;
+			}
 		}
 	}
 



Greetings
Andreas Kemnade

Attachment: signature.asc
Description: PGP signature


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux