--- pdcraid.bak 2003-09-08 07:37:03.000000000 +0200 +++ pdcraid.c 2003-09-08 13:21:10.000000000 +0200 @@ -399,15 +399,56 @@ return 0; - /* first sector of the last cluster */ + /* first sector of the last track */ if (ideinfo->head==0) return 0; if (ideinfo->sect==0) return 0; + /* + * A comment by Frank Rysanek + * + * struct ide_drive_t contains a lot of information, namely: + * cyl = number of cylinders in this disk drive + * head = number of heads + * sect = sectors per "track" (per head per cylinder) + * capacity = total disk capacity in sectors. + * + * Common sense says that capacity = C*H*S. + * Based on my recent experience debugging this driver, + * this is not necessarily true! + * + * It seems that my drives have a few tracks in + * excess of the C*H*S integer multiplication product: + * + * capacity > C*H*S + * + * It's a well known fact that modern IDE drives translate/hide + * the real geometry and prefer to work with LBA-style linear + * addressing, and only present some fictious geometry that + * fits the old BIOS data type limitations. + * + * When calculating the LBA offset of the PDC superblock, + * the original formula used by this driver derives the cyls + * from capacity and H*S, then produces an integer C*H*S, + * and subtracts one track. + * + * For my drives at least, I had to change this: now the + * driver accepts the miraculous reported capacity (greater + * than CHS) and subtracts one track. + * + * The algorithm could be different with different models of + * the Promise hardware, or even with different firmware revisions. + * + * This is the original formula: + lba = (ideinfo->capacity / (ideinfo->head*ideinfo->sect)); lba = lba * (ideinfo->head*ideinfo->sect); lba = lba - ideinfo->sect; + * And this is the repaired one: + */ + lba = ideinfo->capacity - ideinfo->sect; + return lba; } @@ -425,7 +466,7 @@ /* * Calculate the position of the superblock, - * it's at first sector of the last cylinder + * it's at first sector of the last track */ sb_offset = calc_pdcblock_offset(major,minor)/8; /* The /8 transforms sectors into 4Kb blocks */