diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-27 10:50:41 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-27 10:50:41 -0500 |
commit | 490a8d70cdd77d6262c3d5815bc0b1c54a3a63f8 (patch) | |
tree | cf8feb25b7ce349b375a6bdfab8d4d83b3fc9715 /drivers/ata | |
parent | 8c022fdd5fc1b9949bad21d26e0cb115d045c7f9 (diff) | |
parent | 5f451fe1ab5d73b987051f0d23c85216c552e163 (diff) |
Merge branch 'hibern_fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev
* 'hibern_fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev:
SATA PIIX: Blacklist system that spins off disks during ACPI power off
SATA Sil: Blacklist system that spins off disks during ACPI power off
SATA AHCI: Blacklist system that spins off disks during ACPI power off
SATA: Blacklisting of systems that spin off disks during ACPI power off
DMI: Introduce dmi_first_match to make the interface more flexible
Hibernation: Introduce system_entering_hibernation
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/ahci.c | 32 | ||||
-rw-r--r-- | drivers/ata/ata_piix.c | 34 | ||||
-rw-r--r-- | drivers/ata/libata-scsi.c | 20 | ||||
-rw-r--r-- | drivers/ata/sata_sil.c | 36 |
4 files changed, 118 insertions, 4 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 96039671e3b9..77bba4c083cb 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -2548,6 +2548,32 @@ static void ahci_p5wdh_workaround(struct ata_host *host) | |||
2548 | } | 2548 | } |
2549 | } | 2549 | } |
2550 | 2550 | ||
2551 | static bool ahci_broken_system_poweroff(struct pci_dev *pdev) | ||
2552 | { | ||
2553 | static const struct dmi_system_id broken_systems[] = { | ||
2554 | { | ||
2555 | .ident = "HP Compaq nx6310", | ||
2556 | .matches = { | ||
2557 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
2558 | DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6310"), | ||
2559 | }, | ||
2560 | /* PCI slot number of the controller */ | ||
2561 | .driver_data = (void *)0x1FUL, | ||
2562 | }, | ||
2563 | |||
2564 | { } /* terminate list */ | ||
2565 | }; | ||
2566 | const struct dmi_system_id *dmi = dmi_first_match(broken_systems); | ||
2567 | |||
2568 | if (dmi) { | ||
2569 | unsigned long slot = (unsigned long)dmi->driver_data; | ||
2570 | /* apply the quirk only to on-board controllers */ | ||
2571 | return slot == PCI_SLOT(pdev->devfn); | ||
2572 | } | ||
2573 | |||
2574 | return false; | ||
2575 | } | ||
2576 | |||
2551 | static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 2577 | static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
2552 | { | 2578 | { |
2553 | static int printed_version; | 2579 | static int printed_version; |
@@ -2647,6 +2673,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
2647 | } | 2673 | } |
2648 | } | 2674 | } |
2649 | 2675 | ||
2676 | if (ahci_broken_system_poweroff(pdev)) { | ||
2677 | pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN; | ||
2678 | dev_info(&pdev->dev, | ||
2679 | "quirky BIOS, skipping spindown on poweroff\n"); | ||
2680 | } | ||
2681 | |||
2650 | /* CAP.NP sometimes indicate the index of the last enabled | 2682 | /* CAP.NP sometimes indicate the index of the last enabled |
2651 | * port, at other times, that of the last possible port, so | 2683 | * port, at other times, that of the last possible port, so |
2652 | * determining the maximum port number requires looking at | 2684 | * determining the maximum port number requires looking at |
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 887d8f46a287..54961c0b2c73 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c | |||
@@ -1387,6 +1387,32 @@ static void piix_iocfg_bit18_quirk(struct ata_host *host) | |||
1387 | } | 1387 | } |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | static bool piix_broken_system_poweroff(struct pci_dev *pdev) | ||
1391 | { | ||
1392 | static const struct dmi_system_id broken_systems[] = { | ||
1393 | { | ||
1394 | .ident = "HP Compaq 2510p", | ||
1395 | .matches = { | ||
1396 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
1397 | DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 2510p"), | ||
1398 | }, | ||
1399 | /* PCI slot number of the controller */ | ||
1400 | .driver_data = (void *)0x1FUL, | ||
1401 | }, | ||
1402 | |||
1403 | { } /* terminate list */ | ||
1404 | }; | ||
1405 | const struct dmi_system_id *dmi = dmi_first_match(broken_systems); | ||
1406 | |||
1407 | if (dmi) { | ||
1408 | unsigned long slot = (unsigned long)dmi->driver_data; | ||
1409 | /* apply the quirk only to on-board controllers */ | ||
1410 | return slot == PCI_SLOT(pdev->devfn); | ||
1411 | } | ||
1412 | |||
1413 | return false; | ||
1414 | } | ||
1415 | |||
1390 | /** | 1416 | /** |
1391 | * piix_init_one - Register PIIX ATA PCI device with kernel services | 1417 | * piix_init_one - Register PIIX ATA PCI device with kernel services |
1392 | * @pdev: PCI device to register | 1418 | * @pdev: PCI device to register |
@@ -1422,6 +1448,14 @@ static int __devinit piix_init_one(struct pci_dev *pdev, | |||
1422 | if (!in_module_init) | 1448 | if (!in_module_init) |
1423 | return -ENODEV; | 1449 | return -ENODEV; |
1424 | 1450 | ||
1451 | if (piix_broken_system_poweroff(pdev)) { | ||
1452 | piix_port_info[ent->driver_data].flags |= | ||
1453 | ATA_FLAG_NO_POWEROFF_SPINDOWN | | ||
1454 | ATA_FLAG_NO_HIBERNATE_SPINDOWN; | ||
1455 | dev_info(&pdev->dev, "quirky BIOS, skipping spindown " | ||
1456 | "on poweroff and hibernation\n"); | ||
1457 | } | ||
1458 | |||
1425 | port_info[0] = piix_port_info[ent->driver_data]; | 1459 | port_info[0] = piix_port_info[ent->driver_data]; |
1426 | port_info[1] = piix_port_info[ent->driver_data]; | 1460 | port_info[1] = piix_port_info[ent->driver_data]; |
1427 | 1461 | ||
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index a1a6e6298c33..3c4c5ae277ba 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/libata.h> | 46 | #include <linux/libata.h> |
47 | #include <linux/hdreg.h> | 47 | #include <linux/hdreg.h> |
48 | #include <linux/uaccess.h> | 48 | #include <linux/uaccess.h> |
49 | #include <linux/suspend.h> | ||
49 | 50 | ||
50 | #include "libata.h" | 51 | #include "libata.h" |
51 | 52 | ||
@@ -1303,6 +1304,17 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) | |||
1303 | 1304 | ||
1304 | tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ | 1305 | tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ |
1305 | } else { | 1306 | } else { |
1307 | /* Some odd clown BIOSen issue spindown on power off (ACPI S4 | ||
1308 | * or S5) causing some drives to spin up and down again. | ||
1309 | */ | ||
1310 | if ((qc->ap->flags & ATA_FLAG_NO_POWEROFF_SPINDOWN) && | ||
1311 | system_state == SYSTEM_POWER_OFF) | ||
1312 | goto skip; | ||
1313 | |||
1314 | if ((qc->ap->flags & ATA_FLAG_NO_HIBERNATE_SPINDOWN) && | ||
1315 | system_entering_hibernation()) | ||
1316 | goto skip; | ||
1317 | |||
1306 | /* XXX: This is for backward compatibility, will be | 1318 | /* XXX: This is for backward compatibility, will be |
1307 | * removed. Read Documentation/feature-removal-schedule.txt | 1319 | * removed. Read Documentation/feature-removal-schedule.txt |
1308 | * for more info. | 1320 | * for more info. |
@@ -1326,8 +1338,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) | |||
1326 | scmd->scsi_done = qc->scsidone; | 1338 | scmd->scsi_done = qc->scsidone; |
1327 | qc->scsidone = ata_delayed_done; | 1339 | qc->scsidone = ata_delayed_done; |
1328 | } | 1340 | } |
1329 | scmd->result = SAM_STAT_GOOD; | 1341 | goto skip; |
1330 | return 1; | ||
1331 | } | 1342 | } |
1332 | 1343 | ||
1333 | /* Issue ATA STANDBY IMMEDIATE command */ | 1344 | /* Issue ATA STANDBY IMMEDIATE command */ |
@@ -1343,10 +1354,13 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) | |||
1343 | 1354 | ||
1344 | return 0; | 1355 | return 0; |
1345 | 1356 | ||
1346 | invalid_fld: | 1357 | invalid_fld: |
1347 | ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); | 1358 | ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); |
1348 | /* "Invalid field in cbd" */ | 1359 | /* "Invalid field in cbd" */ |
1349 | return 1; | 1360 | return 1; |
1361 | skip: | ||
1362 | scmd->result = SAM_STAT_GOOD; | ||
1363 | return 1; | ||
1350 | } | 1364 | } |
1351 | 1365 | ||
1352 | 1366 | ||
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index 564c142b03b0..bfd55b085ae6 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c | |||
@@ -695,11 +695,38 @@ static void sil_init_controller(struct ata_host *host) | |||
695 | } | 695 | } |
696 | } | 696 | } |
697 | 697 | ||
698 | static bool sil_broken_system_poweroff(struct pci_dev *pdev) | ||
699 | { | ||
700 | static const struct dmi_system_id broken_systems[] = { | ||
701 | { | ||
702 | .ident = "HP Compaq nx6325", | ||
703 | .matches = { | ||
704 | DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), | ||
705 | DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"), | ||
706 | }, | ||
707 | /* PCI slot number of the controller */ | ||
708 | .driver_data = (void *)0x12UL, | ||
709 | }, | ||
710 | |||
711 | { } /* terminate list */ | ||
712 | }; | ||
713 | const struct dmi_system_id *dmi = dmi_first_match(broken_systems); | ||
714 | |||
715 | if (dmi) { | ||
716 | unsigned long slot = (unsigned long)dmi->driver_data; | ||
717 | /* apply the quirk only to on-board controllers */ | ||
718 | return slot == PCI_SLOT(pdev->devfn); | ||
719 | } | ||
720 | |||
721 | return false; | ||
722 | } | ||
723 | |||
698 | static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | 724 | static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) |
699 | { | 725 | { |
700 | static int printed_version; | 726 | static int printed_version; |
701 | int board_id = ent->driver_data; | 727 | int board_id = ent->driver_data; |
702 | const struct ata_port_info *ppi[] = { &sil_port_info[board_id], NULL }; | 728 | struct ata_port_info pi = sil_port_info[board_id]; |
729 | const struct ata_port_info *ppi[] = { &pi, NULL }; | ||
703 | struct ata_host *host; | 730 | struct ata_host *host; |
704 | void __iomem *mmio_base; | 731 | void __iomem *mmio_base; |
705 | int n_ports, rc; | 732 | int n_ports, rc; |
@@ -713,6 +740,13 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
713 | if (board_id == sil_3114) | 740 | if (board_id == sil_3114) |
714 | n_ports = 4; | 741 | n_ports = 4; |
715 | 742 | ||
743 | if (sil_broken_system_poweroff(pdev)) { | ||
744 | pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN | | ||
745 | ATA_FLAG_NO_HIBERNATE_SPINDOWN; | ||
746 | dev_info(&pdev->dev, "quirky BIOS, skipping spindown " | ||
747 | "on poweroff and hibernation\n"); | ||
748 | } | ||
749 | |||
716 | host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); | 750 | host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); |
717 | if (!host) | 751 | if (!host) |
718 | return -ENOMEM; | 752 | return -ENOMEM; |