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