Add LBA mode support for large drives.
Use config flags 0x1000 to enable LBA mode. It should be enabled in the BIOS too to avoid geometry confusion. One catch though, I'm not sure all BIOS's uses the 64head/63secs translation, all mine does but....
This commit is contained in:
parent
37a5acbbc1
commit
d0be3f7fd7
@ -34,7 +34,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)wd.c 7.2 (Berkeley) 5/9/91
|
||||
* $Id: wd.c,v 1.151 1998/02/16 23:57:41 eivind Exp $
|
||||
* $Id: wd.c,v 1.152 1998/04/02 02:10:47 eivind Exp $
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
@ -115,6 +115,7 @@ extern void wdstart(int ctrlr);
|
||||
#define WDOPT_32BIT 0x8000
|
||||
#define WDOPT_SLEEPHACK 0x4000
|
||||
#define WDOPT_DMA 0x2000
|
||||
#define WDOPT_LBA 0x1000
|
||||
#define WDOPT_FORCEHD(x) (((x)&0x0f00)>>8)
|
||||
#define WDOPT_MULTIMASK 0x00ff
|
||||
|
||||
@ -184,6 +185,7 @@ struct disk {
|
||||
#define DKFL_DMA 0x01000 /* using DMA on this transfer-- DKFL_SINGLE
|
||||
* overrides this
|
||||
*/
|
||||
#define DKFL_LBA 0x02000 /* use LBA for data transfers */
|
||||
struct wdparams dk_params; /* ESDI/IDE drive/controller parameters */
|
||||
int dk_dkunit; /* disk stats unit number */
|
||||
int dk_multi; /* multi transfers */
|
||||
@ -472,6 +474,8 @@ wdattach(struct isa_device *dvp)
|
||||
dvp->id_unit, unit, lunit,
|
||||
sizeof du->dk_params.wdp_model,
|
||||
du->dk_params.wdp_model);
|
||||
if (du->dk_flags & DKFL_LBA)
|
||||
printf(", LBA");
|
||||
if (du->dk_flags & DKFL_USEDMA)
|
||||
printf(", DMA");
|
||||
if (du->dk_flags & DKFL_32BIT)
|
||||
@ -836,10 +840,16 @@ wdstart(int ctrlr)
|
||||
u_int count1;
|
||||
long cylin, head, sector;
|
||||
|
||||
cylin = blknum / secpercyl;
|
||||
head = (blknum % secpercyl) / secpertrk;
|
||||
sector = blknum % secpertrk;
|
||||
|
||||
if (du->dk_flags & DKFL_LBA) {
|
||||
sector = (blknum >> 0) & 0xff;
|
||||
cylin = (blknum >> 8) & 0xffff;
|
||||
head = ((blknum >> 24) & 0xf) | WDSD_LBA;
|
||||
}
|
||||
else {
|
||||
cylin = blknum / secpercyl;
|
||||
head = (blknum % secpercyl) / secpertrk;
|
||||
sector = blknum % secpertrk;
|
||||
}
|
||||
/*
|
||||
* XXX this looks like an attempt to skip bad sectors
|
||||
* on write.
|
||||
@ -1564,7 +1574,10 @@ wdcommand(struct disk *du, u_int cylinder, u_int head, u_int sector,
|
||||
outb(wdc + wd_cyl_lo, cylinder);
|
||||
outb(wdc + wd_cyl_hi, cylinder >> 8);
|
||||
outb(wdc + wd_sdh, WDSD_IBM | (du->dk_unit << 4) | head);
|
||||
outb(wdc + wd_sector, sector + 1);
|
||||
if (head &= WDSD_LBA)
|
||||
outb(wdc + wd_sector, sector);
|
||||
else
|
||||
outb(wdc + wd_sector, sector + 1);
|
||||
outb(wdc + wd_seccnt, count);
|
||||
}
|
||||
if (wdwait(du, (command == WDCC_DIAGNOSE || command == WDCC_IDC)
|
||||
@ -1611,42 +1624,44 @@ wdsetctlr(struct disk *du)
|
||||
du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks,
|
||||
du->dk_dd.d_nsectors);
|
||||
#endif
|
||||
if (du->dk_dd.d_ntracks == 0 || du->dk_dd.d_ntracks > 16) {
|
||||
struct wdparams *wp;
|
||||
|
||||
printf("wd%d: can't handle %lu heads from partition table ",
|
||||
du->dk_lunit, du->dk_dd.d_ntracks);
|
||||
/* obtain parameters */
|
||||
wp = &du->dk_params;
|
||||
if (wp->wdp_heads > 0 && wp->wdp_heads <= 16) {
|
||||
printf("(controller value %u restored)\n",
|
||||
wp->wdp_heads);
|
||||
du->dk_dd.d_ntracks = wp->wdp_heads;
|
||||
if (!(du->dk_flags &= DKFL_LBA)) {
|
||||
if (du->dk_dd.d_ntracks == 0 || du->dk_dd.d_ntracks > 16) {
|
||||
struct wdparams *wp;
|
||||
|
||||
printf("wd%d: can't handle %lu heads from partition table ",
|
||||
du->dk_lunit, du->dk_dd.d_ntracks);
|
||||
/* obtain parameters */
|
||||
wp = &du->dk_params;
|
||||
if (wp->wdp_heads > 0 && wp->wdp_heads <= 16) {
|
||||
printf("(controller value %u restored)\n",
|
||||
wp->wdp_heads);
|
||||
du->dk_dd.d_ntracks = wp->wdp_heads;
|
||||
}
|
||||
else {
|
||||
printf("(truncating to 16)\n");
|
||||
du->dk_dd.d_ntracks = 16;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("(truncating to 16)\n");
|
||||
du->dk_dd.d_ntracks = 16;
|
||||
|
||||
if (du->dk_dd.d_nsectors == 0 || du->dk_dd.d_nsectors > 255) {
|
||||
printf("wd%d: cannot handle %lu sectors (max 255)\n",
|
||||
du->dk_lunit, du->dk_dd.d_nsectors);
|
||||
error = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (du->dk_dd.d_nsectors == 0 || du->dk_dd.d_nsectors > 255) {
|
||||
printf("wd%d: cannot handle %lu sectors (max 255)\n",
|
||||
du->dk_lunit, du->dk_dd.d_nsectors);
|
||||
error = 1;
|
||||
}
|
||||
if (error) {
|
||||
if (error) {
|
||||
#ifdef CMD640
|
||||
wdtab[du->dk_ctrlr_cmd640].b_errcnt += RETRIES;
|
||||
wdtab[du->dk_ctrlr_cmd640].b_errcnt += RETRIES;
|
||||
#else
|
||||
wdtab[du->dk_ctrlr].b_errcnt += RETRIES;
|
||||
wdtab[du->dk_ctrlr].b_errcnt += RETRIES;
|
||||
#endif
|
||||
return (1);
|
||||
}
|
||||
if (wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0,
|
||||
du->dk_dd.d_nsectors, WDCC_IDC) != 0
|
||||
|| wdwait(du, WDCS_READY, TIMEOUT) < 0) {
|
||||
wderror((struct buf *)NULL, du, "wdsetctlr failed");
|
||||
return (1);
|
||||
return (1);
|
||||
}
|
||||
if (wdcommand(du, du->dk_dd.d_ncylinders, du->dk_dd.d_ntracks - 1, 0,
|
||||
du->dk_dd.d_nsectors, WDCC_IDC) != 0
|
||||
|| wdwait(du, WDCS_READY, TIMEOUT) < 0) {
|
||||
wderror((struct buf *)NULL, du, "wdsetctlr failed");
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
wdsetmulti(du);
|
||||
@ -1884,11 +1899,23 @@ wdgetctlr(struct disk *du)
|
||||
|
||||
/* update disklabel given drive information */
|
||||
du->dk_dd.d_secsize = DEV_BSIZE;
|
||||
du->dk_dd.d_ncylinders = wp->wdp_cylinders; /* +- 1 */
|
||||
du->dk_dd.d_ntracks = wp->wdp_heads;
|
||||
du->dk_dd.d_nsectors = wp->wdp_sectors;
|
||||
du->dk_dd.d_secpercyl = du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
|
||||
du->dk_dd.d_secperunit = du->dk_dd.d_secpercyl * du->dk_dd.d_ncylinders;
|
||||
if ((du->cfg_flags & WDOPT_LBA) && wp->wdp_lbasize) {
|
||||
du->dk_dd.d_nsectors = 63;
|
||||
du->dk_dd.d_ntracks = 64;
|
||||
du->dk_dd.d_ncylinders = wp->wdp_lbasize / (63*64);
|
||||
du->dk_dd.d_secpercyl= 63*64;
|
||||
du->dk_dd.d_secperunit = wp->wdp_lbasize;
|
||||
du->dk_flags |= DKFL_LBA;
|
||||
}
|
||||
else {
|
||||
du->dk_dd.d_ncylinders = wp->wdp_cylinders; /* +- 1 */
|
||||
du->dk_dd.d_ntracks = wp->wdp_heads;
|
||||
du->dk_dd.d_nsectors = wp->wdp_sectors;
|
||||
du->dk_dd.d_secpercyl =
|
||||
du->dk_dd.d_ntracks * du->dk_dd.d_nsectors;
|
||||
du->dk_dd.d_secperunit =
|
||||
du->dk_dd.d_secpercyl * du->dk_dd.d_ncylinders;
|
||||
}
|
||||
if (WDOPT_FORCEHD(du->cfg_flags)) {
|
||||
du->dk_dd.d_ntracks = WDOPT_FORCEHD(du->cfg_flags);
|
||||
du->dk_dd.d_secpercyl =
|
||||
|
@ -34,7 +34,7 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)wdreg.h 7.1 (Berkeley) 5/9/91
|
||||
* $Id: wdreg.h,v 1.20 1997/09/20 07:41:45 dyson Exp $
|
||||
* $Id: wdreg.h,v 1.21 1998/01/14 08:08:42 kato Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -137,6 +137,7 @@
|
||||
#define WD_STEP 0 /* winchester- default 35us step */
|
||||
|
||||
#define WDSD_IBM 0xa0 /* forced to 512 byte sector, ecc */
|
||||
#define WDSD_LBA 0x40 /* use Logical Block Adressing */
|
||||
|
||||
#ifdef KERNEL
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user