Re: Booting from g_file_storage in cdrom mode

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

 



On Sat, 5 Dec 2009 15:34:07 -0500 (EST)
Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:

> > 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.
> 
> No, this isn't a good approach.  A better fix would be to change the
> byte mask in do_scsi_command()'s SC_READ_TOC case.  In the fourth
> argument to check_command(), change (7<<6) to (0xf<<6).  It's hard to 
> know whether this will fix the incorrect block size, though.
> 
The X31 BIOS issues the READ_TOC command several times,
if it failes, no further attempts are made to boot from cd.
  

> But that's just a workaround.  The fact is, the BIOS is sending 
> incorrect data.  The same is true with the 12-byte READ(10) command, 
> although here g_file_storage accepts the bad length with only a 
> warning.
> 
Of course, it is a workaround. 
With my first patch, which should break everything which cares about
the actual sector size (since I'm using 2048 only in the READ(x) command
 but not in the READ_CAPACITY) but there seems to be no BIOS
using the sector size from the READ_CAPACITY command. Linux does honor
it and does not work with my patched g_file_storage.

I cleaned up the patch especially the sector size stuff and with that patch 
I have installed ubuntu from a g_file_storage_gadget in cdrom mode successfully.

diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index b10fa31..52815d9 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1599,13 +1599,17 @@ 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;
+        if (mod_data.cdrom)
+		file_offset = ((loff_t) lba) << 11;
+	else
+		file_offset = ((loff_t) lba) << 9;
 
 	/* Carry out the file reads */
 	amount_left = fsg->data_size_from_cmnd;
 	if (unlikely(amount_left == 0))
 		return -EIO;		// No default reply
-
+	if (mod_data.cdrom)
+		amount_left <<=2;
 	for (;;) {
 
 		/* Figure out how much we need to read:
@@ -2121,7 +2125,7 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 	}
 
 	put_be32(&buf[0], curlun->num_sectors - 1);	// Max logical block
-	put_be32(&buf[4], 512);				// Block length
+	put_be32(&buf[4], mod_data.cdrom ? 2048 : 512);				// Block length
 	return 8;
 }
 
@@ -2130,7 +2134,6 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)
 {
 	if (msf) {
 		/* Convert to Minutes-Seconds-Frames */
-		addr >>= 2;		/* Convert to 2048-byte frames */
 		addr += 2*75;		/* Lead-in occupies 2 seconds */
 		dest[3] = addr % 75;	/* Frames */
 		addr /= 75;
@@ -2357,7 +2360,7 @@ static int do_read_format_capacities(struct fsg_dev *fsg,
 	buf += 4;
 
 	put_be32(&buf[0], curlun->num_sectors);		// Number of blocks
-	put_be32(&buf[4], 512);				// Block length
+	put_be32(&buf[4], mod_data.cdrom ? 2048 : 512);				// Block length
 	buf[4] = 0x02;					// Current capacity
 	return 12;
 }
@@ -2817,7 +2820,9 @@ 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 */
+	/* 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 */
 	fsg->cmnd[1] &= 0x1f;			// Mask away the LUN
 	for (i = 1; i < cmnd_size; ++i) {
 		if (fsg->cmnd[i] && !(mask & (1 << i))) {
@@ -2957,7 +2962,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 			goto unknown_cmnd;
 		fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
 		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
-				(7<<6) | (1<<1), 1,
+				(0xf<<6) | (1<<1), 1,
 				"READ TOC")) == 0)
 			reply = do_read_toc(fsg, bh);
 		break;
@@ -3660,10 +3665,10 @@ static int open_backing_file(struct lun *curlun, const char *filename)
 	num_sectors = size >> 9;	// File size in 512-byte blocks
 	min_sectors = 1;
 	if (mod_data.cdrom) {
-		num_sectors &= ~3;	// Reduce to a multiple of 2048
-		min_sectors = 300*4;	// Smallest track is 300 frames
-		if (num_sectors >= 256*60*75*4) {
-			num_sectors = (256*60*75 - 1) * 4;
+		num_sectors >>= 2;	// Reduce to a multiple of 2048
+		min_sectors = 300;	// Smallest track is 300 frames
+		if (num_sectors >= 256*60*75) {
+			num_sectors = (256*60*75 - 1);
 			LINFO(curlun, "file too big: %s\n", filename);
 			LINFO(curlun, "using only first %d blocks\n",
 					(int) num_sectors);


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