[libata] replace sata_settings with devslp_timing

NCQ capability was used to check availability of SATA Settings page
from Identify Device Data Log, which contains DevSlp timing variables.
It does not work on some HDDs and leads to error messages.

IDENTIFY word 78 bit 5(Hardware Feature Control) can't work either
because it is only the sufficient condition of Identify Device data
log, not the necessary condition.

This patch replaced ata_device->sata_settings with ->devslp_timing
to only save DevSlp timing variables(8 bytes), instead of the whole
SATA Settings page(512 bytes).

Addresses https://bugzilla.kernel.org/show_bug.cgi?id=51881

Reported-by: Borislav Petkov <bp@alien8.de>
Signed-off-by: Shane Huang <shane.huang@amd.com>
Cc: stable@vger.kernel.org
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
Shane Huang 2012-12-17 23:18:59 +08:00 коммит произвёл Jeff Garzik
Родитель 7f9c9f8e24
Коммит 803739d25c
4 изменённых файлов: 23 добавлений и 17 удалений

Просмотреть файл

@ -1951,13 +1951,13 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
/* Use the nominal value 10 ms if the read MDAT is zero, /* Use the nominal value 10 ms if the read MDAT is zero,
* the nominal value of DETO is 20 ms. * the nominal value of DETO is 20 ms.
*/ */
if (dev->sata_settings[ATA_LOG_DEVSLP_VALID] & if (dev->devslp_timing[ATA_LOG_DEVSLP_VALID] &
ATA_LOG_DEVSLP_VALID_MASK) { ATA_LOG_DEVSLP_VALID_MASK) {
mdat = dev->sata_settings[ATA_LOG_DEVSLP_MDAT] & mdat = dev->devslp_timing[ATA_LOG_DEVSLP_MDAT] &
ATA_LOG_DEVSLP_MDAT_MASK; ATA_LOG_DEVSLP_MDAT_MASK;
if (!mdat) if (!mdat)
mdat = 10; mdat = 10;
deto = dev->sata_settings[ATA_LOG_DEVSLP_DETO]; deto = dev->devslp_timing[ATA_LOG_DEVSLP_DETO];
if (!deto) if (!deto)
deto = 20; deto = 20;
} else { } else {

Просмотреть файл

@ -2325,24 +2325,28 @@ int ata_dev_configure(struct ata_device *dev)
} }
} }
/* check and mark DevSlp capability */ /* Check and mark DevSlp capability. Get DevSlp timing variables
if (ata_id_has_devslp(dev->id)) * from SATA Settings page of Identify Device Data Log.
dev->flags |= ATA_DFLAG_DEVSLP;
/* Obtain SATA Settings page from Identify Device Data Log,
* which contains DevSlp timing variables etc.
* Exclude old devices with ata_id_has_ncq()
*/ */
if (ata_id_has_ncq(dev->id)) { if (ata_id_has_devslp(dev->id)) {
u8 sata_setting[ATA_SECT_SIZE];
int i, j;
dev->flags |= ATA_DFLAG_DEVSLP;
err_mask = ata_read_log_page(dev, err_mask = ata_read_log_page(dev,
ATA_LOG_SATA_ID_DEV_DATA, ATA_LOG_SATA_ID_DEV_DATA,
ATA_LOG_SATA_SETTINGS, ATA_LOG_SATA_SETTINGS,
dev->sata_settings, sata_setting,
1); 1);
if (err_mask) if (err_mask)
ata_dev_dbg(dev, ata_dev_dbg(dev,
"failed to get Identify Device Data, Emask 0x%x\n", "failed to get Identify Device Data, Emask 0x%x\n",
err_mask); err_mask);
else
for (i = 0; i < ATA_LOG_DEVSLP_SIZE; i++) {
j = ATA_LOG_DEVSLP_OFFSET + i;
dev->devslp_timing[i] = sata_setting[j];
}
} }
dev->cdb_len = 16; dev->cdb_len = 16;

Просмотреть файл

@ -297,10 +297,12 @@ enum {
ATA_LOG_SATA_NCQ = 0x10, ATA_LOG_SATA_NCQ = 0x10,
ATA_LOG_SATA_ID_DEV_DATA = 0x30, ATA_LOG_SATA_ID_DEV_DATA = 0x30,
ATA_LOG_SATA_SETTINGS = 0x08, ATA_LOG_SATA_SETTINGS = 0x08,
ATA_LOG_DEVSLP_MDAT = 0x30, ATA_LOG_DEVSLP_OFFSET = 0x30,
ATA_LOG_DEVSLP_SIZE = 0x08,
ATA_LOG_DEVSLP_MDAT = 0x00,
ATA_LOG_DEVSLP_MDAT_MASK = 0x1F, ATA_LOG_DEVSLP_MDAT_MASK = 0x1F,
ATA_LOG_DEVSLP_DETO = 0x31, ATA_LOG_DEVSLP_DETO = 0x01,
ATA_LOG_DEVSLP_VALID = 0x37, ATA_LOG_DEVSLP_VALID = 0x07,
ATA_LOG_DEVSLP_VALID_MASK = 0x80, ATA_LOG_DEVSLP_VALID_MASK = 0x80,
/* READ/WRITE LONG (obsolete) */ /* READ/WRITE LONG (obsolete) */

Просмотреть файл

@ -652,8 +652,8 @@ struct ata_device {
u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */ u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
}; };
/* Identify Device Data Log (30h), SATA Settings (page 08h) */ /* DEVSLP Timing Variables from Identify Device Data Log */
u8 sata_settings[ATA_SECT_SIZE]; u8 devslp_timing[ATA_LOG_DEVSLP_SIZE];
/* error history */ /* error history */
int spdn_cnt; int spdn_cnt;