Add support for LBA48 read command to standalone wdc/wd driver.

Thanks to bouyer@ for comments about LBA48 boundary checks.

Tested on:
> Cobalt Qube 2700
> wd0 at atabus0 drive 0: <Hitachi HDS721616PLA380>
> wd0: 153 GB, 319120 cyl, 16 head, 63 sec, 512 bytes/sect x 321672960 sectors
via SATA-IDE converter, and NetBSD partition allocated at:
> 1: NetBSD (sysid 169)
>     start 293603940, size 28069020 (13706 MB, Cyls 18276-20023/54/63)

Also bump version.
This commit is contained in:
tsutsui 2010-01-10 16:20:45 +00:00
parent a11ec02c51
commit f204082a1d
4 changed files with 70 additions and 24 deletions

View File

@ -1,4 +1,4 @@
$NetBSD: version,v 1.10 2008/05/28 14:04:07 tsutsui Exp $
$NetBSD: version,v 1.11 2010/01/10 16:20:45 tsutsui Exp $
NOTE ANY CHANGES YOU MAKE TO THE BOOTBLOCKS HERE. The format of this
file is important - make sure the entries are appended on end, last item
@ -14,3 +14,4 @@ is taken as the current.
0.7: Add support for netboot via 21041 on Qube2700
0.8: Add support for optional Z85C30 serial console on Qube2700
0.9: Print banner and a loading kernel name onto LCD
1.0: Add support for LBA48 read command

View File

@ -1,4 +1,4 @@
/* $NetBSD: wd.c,v 1.10 2008/04/28 20:23:16 martin Exp $ */
/* $NetBSD: wd.c,v 1.11 2010/01/10 16:20:45 tsutsui Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@ -61,18 +61,45 @@ wd_get_params(struct wd_softc *wd)
wd->sc_params = *(struct ataparams *)buf;
/* 48-bit LBA addressing */
if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0) {
DPRINTF(("Drive supports LBA48.\n"));
#if defined(_ENABLE_LBA48)
if ((wd->sc_params.atap_cmd2_en & ATA_CMD2_LBA48) != 0)
wd->sc_flags |= WDF_LBA48;
#endif
}
/* Prior to ATA-4, LBA was optional. */
if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0) {
DPRINTF(("Drive supports LBA.\n"));
if ((wd->sc_params.atap_capabilities1 & WDC_CAP_LBA) != 0)
wd->sc_flags |= WDF_LBA;
if ((wd->sc_flags & WDF_LBA48) != 0) {
DPRINTF(("Drive supports LBA48.\n"));
wd->sc_capacity =
((uint64_t)wd->sc_params.atap_max_lba[3] << 48) |
((uint64_t)wd->sc_params.atap_max_lba[2] << 32) |
((uint64_t)wd->sc_params.atap_max_lba[1] << 16) |
((uint64_t)wd->sc_params.atap_max_lba[0] << 0);
DPRINTF(("atap_max_lba = (0x%x, 0x%x, 0x%x, 0x%x)\n",
wd->sc_params.atap_max_lba[3],
wd->sc_params.atap_max_lba[2],
wd->sc_params.atap_max_lba[1],
wd->sc_params.atap_max_lba[0]));
wd->sc_capacity28 =
((uint32_t)wd->sc_params.atap_capacity[1] << 16) |
((uint32_t)wd->sc_params.atap_capacity[0] << 0);
DPRINTF(("atap_capacity = (0x%x, 0x%x)\n",
wd->sc_params.atap_capacity[1],
wd->sc_params.atap_capacity[0]));
} else if ((wd->sc_flags & WDF_LBA) != 0) {
DPRINTF(("Drive supports LBA.\n"));
wd->sc_capacity = wd->sc_capacity28 =
((uint32_t)wd->sc_params.atap_capacity[1] << 16) |
((uint32_t)wd->sc_params.atap_capacity[0] << 0);
} else {
DPRINTF(("Drive doesn't support LBA; using CHS.\n"));
wd->sc_capacity = wd->sc_capacity28 =
wd->sc_params.atap_cylinders *
wd->sc_params.atap_heads *
wd->sc_params.atap_sectors;
}
DPRINTF(("wd->sc_capacity = %ld, wd->sc_capacity28 = %d.\n",
(u_long)wd->sc_capacity, wd->sc_capacity28));
return 0;
}
@ -173,7 +200,7 @@ wdgetdisklabel(struct wd_softc *wd)
}
DPRINTF(("label info: d_secsize %d, d_nsectors %d, d_ncylinders %d,"
"d_ntracks %d, d_secpercyl %d\n",
" d_ntracks %d, d_secpercyl %d\n",
wd->sc_label.d_secsize,
wd->sc_label.d_nsectors,
wd->sc_label.d_ncylinders,

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdc.c,v 1.11 2008/04/28 20:23:16 martin Exp $ */
/* $NetBSD: wdc.c,v 1.12 2010/01/10 16:20:45 tsutsui Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@ -229,7 +229,7 @@ wdccommand(struct wd_softc *sc, struct wdc_command *wd_c)
wd_c->r_precomp));
#endif
WDC_WRITE_REG(chp, wd_precomp, wd_c->r_precomp);
WDC_WRITE_REG(chp, wd_features, wd_c->r_features);
WDC_WRITE_REG(chp, wd_seccnt, wd_c->r_count);
WDC_WRITE_REG(chp, wd_sector, wd_c->r_sector);
WDC_WRITE_REG(chp, wd_cyl_lo, wd_c->r_cyl);
@ -258,6 +258,12 @@ wdccommandext(struct wd_softc *wd, struct wdc_command *wd_c)
{
struct wdc_channel *chp = &wd->sc_channel;
#if 0
DPRINTF(("%s(%d, %x, %ld, %d)\n", __func__,
wd_c->drive, wd_c->r_command,
(u_long)wd_c->r_blkno, wd_c->r_count));
#endif
/* Select drive, head, and addressing mode. */
WDC_WRITE_REG(chp, wd_sdh, (wd_c->drive << 4) | WDSD_LBA);
@ -320,20 +326,37 @@ wdc_exec_read(struct wd_softc *wd, uint8_t cmd, daddr_t blkno, void *data)
{
int error;
struct wdc_command wd_c;
bool lba, lba48;
memset(&wd_c, 0, sizeof(wd_c));
lba = false;
lba48 = false;
if (wd->sc_flags & WDF_LBA48) {
wd_c.data = data;
wd_c.r_count = 1;
wd_c.r_features = 0;
wd_c.drive = wd->sc_unit;
wd_c.bcount = wd->sc_label.d_secsize;
if ((wd->sc_flags & WDF_LBA48) != 0 && blkno > wd->sc_capacity28)
lba48 = true;
else if ((wd->sc_flags & WDF_LBA) != 0)
lba = true;
if (lba48) {
/* LBA48 */
wd_c.r_command = atacmd_to48(cmd);
wd_c.r_blkno = blkno;
} else if (wd->sc_flags & WDF_LBA) {
} else if (lba) {
/* LBA */
wd_c.r_command = cmd;
wd_c.r_sector = (blkno >> 0) & 0xff;
wd_c.r_cyl = (blkno >> 8) & 0xffff;
wd_c.r_head = (blkno >> 24) & 0x0f;
wd_c.r_head |= WDSD_LBA;
} else {
/* LHS */
/* CHS */
wd_c.r_command = cmd;
wd_c.r_sector = blkno % wd->sc_label.d_nsectors;
wd_c.r_sector++; /* Sectors begin with 1, not 0. */
blkno /= wd->sc_label.d_nsectors;
@ -343,13 +366,7 @@ wdc_exec_read(struct wd_softc *wd, uint8_t cmd, daddr_t blkno, void *data)
wd_c.r_head |= WDSD_CHS;
}
wd_c.data = data;
wd_c.r_count = 1;
wd_c.drive = wd->sc_unit;
wd_c.r_command = cmd;
wd_c.bcount = wd->sc_label.d_secsize;
if (wd->sc_flags & WDF_LBA48)
if (lba48)
error = wdccommandext(wd, &wd_c);
else
error = wdccommand(wd, &wd_c);

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdvar.h,v 1.8 2007/10/17 19:54:10 garbled Exp $ */
/* $NetBSD: wdvar.h,v 1.9 2010/01/10 16:20:45 tsutsui Exp $ */
/*-
* Copyright (c) 2003 The NetBSD Foundation, Inc.
@ -72,6 +72,7 @@ struct wd_softc {
u_int sc_unit;
uint64_t sc_capacity;
uint32_t sc_capacity28;
struct ataparams sc_params;
struct disklabel sc_label;
@ -86,7 +87,7 @@ struct wdc_command {
uint16_t r_cyl;
uint8_t r_sector;
uint8_t r_count;
uint8_t r_precomp;
uint8_t r_features;
uint16_t bcount;
void *data;