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:
sos 1998-04-08 20:04:39 +00:00
parent 37a5acbbc1
commit d0be3f7fd7
2 changed files with 71 additions and 43 deletions

View File

@ -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 =

View File

@ -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
/*