
A couple months ago, a patch was submitted which changed the prototypes for block_write and block_read in the block_dev_desc_t structure (include/part.h). For both, the buffer parameter was changed from a ulong* to a void*. Seven functions were changed as a result of this. Four of those functions take that parameter and pass it to a local variable of a different type, thereby insulating them from this change. The other three were not so lucky..... Using the 2006-06-16 version of common/cmd_ide.c as the reference, lets look at ide_read(). The function begins on line 1230 and a while loop begins on line 1279. At the bottom of this loop, we see 1339 ++blknr; 1340 buffer += ATA_SECTORWORDS; 1341 } Back when buffer was a ulong*, this pointer addition would result in the pointer moving 0x200 bytes or 0x80 ulongs (ATA_SECTORWORDS is defined as 512/sizeof(unsigned long) in include/ata.h). Now that buffer is a void*, this pointer addition results in the pointer moving by only 0x80 bytes. In my debugging, I used the diskboot command to read an image into address 0x200000 and tftp to place the same image at 0x400000. When I compared these two locations, I discovered that the data was different starting at address 0x200280. The data at that location was the same as that found at 0x400400. Then 0x200300-0x200380 == 0x400600-0x400680, 0x200380-0x200400 == 0x400800-0x400880 and so on and so on. The first 0x200 is correct because that is done in a separate call to ide_read that only requests a single block. The second read copied 0x200 bytes to 0x200200, the third read is copied 0x200 bytes to 0x200280, etc. The following patch fixes the pointer manipulation in ide_read(), ide_write() and atapi_read().
diff -up a/common/cmd_ide.c b/common/cmd_ide.c --- a/common/cmd_ide.c 2007-04-12 09:12:49.000000000 -0500 +++ b/common/cmd_ide.c 2007-04-12 09:14:40.843750000 -0500 @@ -1344,7 +1344,7 @@ ulong ide_read (int device, lbaint_t blk
++n; ++blknr; - buffer += ATA_SECTORWORDS; + buffer += ATA_BLOCKSIZE; } IDE_READ_E: ide_led (DEVICE_LED(device), 0); /* LED off */ @@ -1428,7 +1428,7 @@ ulong ide_write (int device, lbaint_t bl c = ide_inb (device, ATA_STATUS); /* clear IRQ */ ++n; ++blknr; - buffer += ATA_SECTORWORDS; + buffer += ATA_BLOCKSIZE; } WR_OUT: ide_led (DEVICE_LED(device), 0); /* LED off */ @@ -2052,7 +2052,7 @@ ulong atapi_read (int device, lbaint_t b n+=cnt; blkcnt-=cnt; blknr+=cnt; - buffer+=cnt*(ATAPI_READ_BLOCK_SIZE/4); /* ulong blocksize in ulong */ + buffer+=(cnt*ATAPI_READ_BLOCK_SIZE); /* ulong blocksize in ulong */ } while (blkcnt > 0); return (n); }