Add ata(4) ability to limit initial ATA mode for devices via device hints.

After boot this mode can be changed with atacontrol/camcontrol as usual.
It works for both legacy and ATA_CAM wrapper mode.

PR:		kern/123980
This commit is contained in:
Alexander Motin 2010-07-03 14:14:42 +00:00
parent 478fbccb67
commit 7ce1f3e580
3 changed files with 61 additions and 3 deletions

View File

@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd March 3, 2010
.Dd July 3, 2010
.Dt ATA 4
.Os
.Sh NAME
@ -103,6 +103,10 @@ can cause data loss on power failures and crashes.
.It Va hint.atapci.X.msi
set to 1 to allow Message Signalled Interrupts (MSI) to be used by
specified PCI ATA controller, if supported.
.It Va hint.ata.X.devX.mode
limits initial ATA mode for specified device on specified channel.
.It Va hint.ata.X.mode
limits initial ATA mode for every device on specified channel.
.It Va hint.ata.X.pm_level
controls SATA interface Power Management for specified channel,
allowing to save some power by the cost of additional command latency.

View File

@ -133,7 +133,9 @@ ata_attach(device_t dev)
int error, rid;
#ifdef ATA_CAM
struct cam_devq *devq;
int i;
const char *res;
char buf[64];
int i, mode;
#endif
/* check that we have a virgin channel to attach */
@ -152,6 +154,17 @@ ata_attach(device_t dev)
#ifdef ATA_CAM
for (i = 0; i < 16; i++) {
ch->user[i].mode = 0;
snprintf(buf, sizeof(buf), "dev%d.mode", i);
if (resource_string_value(device_get_name(dev),
device_get_unit(dev), buf, &res) == 0)
mode = ata_str2mode(res);
else if (resource_string_value(device_get_name(dev),
device_get_unit(dev), "mode", &res) == 0)
mode = ata_str2mode(res);
else
mode = -1;
if (mode >= 0)
ch->user[i].mode = mode;
if (ch->flags & ATA_SATA)
ch->user[i].bytecount = 8192;
else
@ -826,8 +839,10 @@ ata_getparam(struct ata_device *atadev, int init)
{
struct ata_channel *ch = device_get_softc(device_get_parent(atadev->dev));
struct ata_request *request;
const char *res;
char buf[64];
u_int8_t command = 0;
int error = ENOMEM, retries = 2;
int error = ENOMEM, retries = 2, mode = -1;
if (ch->devices & (ATA_ATA_MASTER << atadev->unit))
command = ATA_ATA_IDENTIFY;
@ -907,6 +922,15 @@ ata_getparam(struct ata_device *atadev, int init)
ata_wmode(&atadev->param) > 0))
atadev->mode = ATA_DMA_MAX;
}
snprintf(buf, sizeof(buf), "dev%d.mode", atadev->unit);
if (resource_string_value(device_get_name(ch->dev),
device_get_unit(ch->dev), buf, &res) == 0)
mode = ata_str2mode(res);
else if (resource_string_value(device_get_name(ch->dev),
device_get_unit(ch->dev), "mode", &res) == 0)
mode = ata_str2mode(res);
if (mode >= 0)
atadev->mode = mode;
}
}
else {
@ -1163,6 +1187,35 @@ ata_mode2str(int mode)
}
}
int
ata_str2mode(const char *str)
{
if (!strcasecmp(str, "PIO0")) return (ATA_PIO0);
if (!strcasecmp(str, "PIO1")) return (ATA_PIO1);
if (!strcasecmp(str, "PIO2")) return (ATA_PIO2);
if (!strcasecmp(str, "PIO3")) return (ATA_PIO3);
if (!strcasecmp(str, "PIO4")) return (ATA_PIO4);
if (!strcasecmp(str, "WDMA0")) return (ATA_WDMA0);
if (!strcasecmp(str, "WDMA1")) return (ATA_WDMA1);
if (!strcasecmp(str, "WDMA2")) return (ATA_WDMA2);
if (!strcasecmp(str, "UDMA0")) return (ATA_UDMA0);
if (!strcasecmp(str, "UDMA16")) return (ATA_UDMA0);
if (!strcasecmp(str, "UDMA1")) return (ATA_UDMA1);
if (!strcasecmp(str, "UDMA25")) return (ATA_UDMA1);
if (!strcasecmp(str, "UDMA2")) return (ATA_UDMA2);
if (!strcasecmp(str, "UDMA33")) return (ATA_UDMA2);
if (!strcasecmp(str, "UDMA3")) return (ATA_UDMA3);
if (!strcasecmp(str, "UDMA44")) return (ATA_UDMA3);
if (!strcasecmp(str, "UDMA4")) return (ATA_UDMA4);
if (!strcasecmp(str, "UDMA66")) return (ATA_UDMA4);
if (!strcasecmp(str, "UDMA5")) return (ATA_UDMA5);
if (!strcasecmp(str, "UDMA100")) return (ATA_UDMA5);
if (!strcasecmp(str, "UDMA6")) return (ATA_UDMA6);
if (!strcasecmp(str, "UDMA133")) return (ATA_UDMA6);
return (-1);
}
const char *
ata_satarev2str(int rev)
{

View File

@ -625,6 +625,7 @@ void ata_modify_if_48bit(struct ata_request *request);
void ata_udelay(int interval);
char *ata_unit2str(struct ata_device *atadev);
const char *ata_mode2str(int mode);
int ata_str2mode(const char *str);
const char *ata_satarev2str(int rev);
int ata_atapi(device_t dev, int target);
int ata_pmode(struct ata_params *ap);