From: Ana Bobillo <[email protected]>

atapi_inquiry() takes the block size from the READ CAPACITY reply of an
ATAPI device as it is, while atapi_read() asks the device for, and moves
the buffer on by, ATAPI_READ_BLOCK_SIZE (2048) bytes for every block.
With any other block size the callers' buffers, which are sized by
blksz, do not match what atapi_read() writes into them: a 512-byte block
size makes a read of several blocks write past the end of the buffer.

Some CD drives report another block size although they read 2048-byte
blocks: 2340 (HP 4020i CD-Recorder), 2352 (Philips CD-Writers) or 0.
Take these as ATAPI_READ_BLOCK_SIZE, as Linux does in get_sectorsize(),
so that a drive reporting 0, which ide_probe() skipped until now, is
read with 2048-byte blocks too. Refuse any other value: a device
reporting one is left with a zero block size, which ide_probe() skips,
as for a drive without a medium. This refuses drives with 512-byte
blocks, such as ZIP drives, whose reads of more than one block already
overran the buffer; supporting them needs atapi_read() to use the block
size of the device.

Signed-off-by: Ana Bobillo <[email protected]>
---
Changes in v2:
- Take 0, 2340 and 2352 as 2048, as Linux get_sectorsize() does (Simon)
- Say what is skipped in the message (Simon)

 drivers/block/ide.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 44ce054bdf5..56e55bc8bc1 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -450,6 +450,7 @@ static void atapi_inquiry(struct blk_desc *desc)
 {
        u8 ccb[12];     /* Command descriptor block */
        u8 iobuf[64];   /* temp buf */
+       ulong blksz;
        u8 c;
        int device;
 
@@ -514,10 +515,28 @@ static void atapi_inquiry(struct blk_desc *desc)
                  iobuf[0], iobuf[1], iobuf[2], iobuf[3],
                  iobuf[4], iobuf[5], iobuf[6], iobuf[7]);
 
+       blksz = (ulong)iobuf[4] << 24 | (ulong)iobuf[5] << 16 |
+               (ulong)iobuf[6] << 8 | (ulong)iobuf[7];
+       /*
+        * atapi_read() transfers ATAPI_READ_BLOCK_SIZE bytes per block. Some
+        * CD drives report another size although they read 2048-byte blocks,
+        * which Linux takes as 2048 in get_sectorsize(): do the same.
+        */
+       switch (blksz) {
+       case 0:
+       case 2340:      /* HP 4020i CD-Recorder */
+       case 2352:      /* Philips CD-Writers */
+               blksz = ATAPI_READ_BLOCK_SIZE;
+               break;
+       case ATAPI_READ_BLOCK_SIZE:
+               break;
+       default:
+               printf("ATAPI block size %lu not supported, skipping\n", blksz);
+               return;
+       }
        desc->lba = (ulong)iobuf[0] << 24 | (ulong)iobuf[1] << 16 |
                (ulong)iobuf[2] << 8 | (ulong)iobuf[3];
-       desc->blksz = (ulong)iobuf[4] << 24 | (ulong)iobuf[5] << 16 |
-               (ulong)iobuf[6] << 8 | (ulong)iobuf[7];
+       desc->blksz = blksz;
        desc->log2blksz = LOG2(desc->blksz);
 
        /* ATAPI devices cannot use 48bit addressing (ATA/ATAPI v7) */

Reply via email to