aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-01-27 10:50:41 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-27 10:50:41 -0500
commit490a8d70cdd77d6262c3d5815bc0b1c54a3a63f8 (patch)
treecf8feb25b7ce349b375a6bdfab8d4d83b3fc9715
parent8c022fdd5fc1b9949bad21d26e0cb115d045c7f9 (diff)
parent5f451fe1ab5d73b987051f0d23c85216c552e163 (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
-rw-r--r--drivers/ata/ahci.c32
-rw-r--r--drivers/ata/ata_piix.c34
-rw-r--r--drivers/ata/libata-scsi.c20
-rw-r--r--drivers/ata/sata_sil.c36
-rw-r--r--drivers/firmware/dmi_scan.c74
-rw-r--r--include/linux/dmi.h1
-rw-r--r--include/linux/libata.h2
-rw-r--r--include/linux/suspend.h2
-rw-r--r--kernel/power/disk.c10
9 files changed, 188 insertions, 23 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
2551static 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
2551static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 2577static 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
1390static 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
1346invalid_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
698static 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
698static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 724static 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;
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index d76adfea5df7..8f0f7c449305 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -415,6 +415,29 @@ void __init dmi_scan_machine(void)
415} 415}
416 416
417/** 417/**
418 * dmi_matches - check if dmi_system_id structure matches system DMI data
419 * @dmi: pointer to the dmi_system_id structure to check
420 */
421static bool dmi_matches(const struct dmi_system_id *dmi)
422{
423 int i;
424
425 WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n");
426
427 for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) {
428 int s = dmi->matches[i].slot;
429 if (s == DMI_NONE)
430 continue;
431 if (dmi_ident[s]
432 && strstr(dmi_ident[s], dmi->matches[i].substr))
433 continue;
434 /* No match */
435 return false;
436 }
437 return true;
438}
439
440/**
418 * dmi_check_system - check system DMI data 441 * dmi_check_system - check system DMI data
419 * @list: array of dmi_system_id structures to match against 442 * @list: array of dmi_system_id structures to match against
420 * All non-null elements of the list must match 443 * All non-null elements of the list must match
@@ -429,32 +452,45 @@ void __init dmi_scan_machine(void)
429 */ 452 */
430int dmi_check_system(const struct dmi_system_id *list) 453int dmi_check_system(const struct dmi_system_id *list)
431{ 454{
432 int i, count = 0; 455 int count = 0;
433 const struct dmi_system_id *d = list; 456 const struct dmi_system_id *d;
434 457
435 WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); 458 for (d = list; d->ident; d++)
436 459 if (dmi_matches(d)) {
437 while (d->ident) { 460 count++;
438 for (i = 0; i < ARRAY_SIZE(d->matches); i++) { 461 if (d->callback && d->callback(d))
439 int s = d->matches[i].slot; 462 break;
440 if (s == DMI_NONE)
441 continue;
442 if (dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr))
443 continue;
444 /* No match */
445 goto fail;
446 } 463 }
447 count++;
448 if (d->callback && d->callback(d))
449 break;
450fail: d++;
451 }
452 464
453 return count; 465 return count;
454} 466}
455EXPORT_SYMBOL(dmi_check_system); 467EXPORT_SYMBOL(dmi_check_system);
456 468
457/** 469/**
470 * dmi_first_match - find dmi_system_id structure matching system DMI data
471 * @list: array of dmi_system_id structures to match against
472 * All non-null elements of the list must match
473 * their slot's (field index's) data (i.e., each
474 * list string must be a substring of the specified
475 * DMI slot's string data) to be considered a
476 * successful match.
477 *
478 * Walk the blacklist table until the first match is found. Return the
479 * pointer to the matching entry or NULL if there's no match.
480 */
481const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list)
482{
483 const struct dmi_system_id *d;
484
485 for (d = list; d->ident; d++)
486 if (dmi_matches(d))
487 return d;
488
489 return NULL;
490}
491EXPORT_SYMBOL(dmi_first_match);
492
493/**
458 * dmi_get_system_info - return DMI data value 494 * dmi_get_system_info - return DMI data value
459 * @field: data index (see enum dmi_field) 495 * @field: data index (see enum dmi_field)
460 * 496 *
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index 34161907b2f8..aea23105d3ed 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -38,6 +38,7 @@ struct dmi_device {
38#ifdef CONFIG_DMI 38#ifdef CONFIG_DMI
39 39
40extern int dmi_check_system(const struct dmi_system_id *list); 40extern int dmi_check_system(const struct dmi_system_id *list);
41const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list);
41extern const char * dmi_get_system_info(int field); 42extern const char * dmi_get_system_info(int field);
42extern const struct dmi_device * dmi_find_device(int type, const char *name, 43extern const struct dmi_device * dmi_find_device(int type, const char *name,
43 const struct dmi_device *from); 44 const struct dmi_device *from);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 2c6bd66209ff..bca3ba25f52a 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -187,6 +187,8 @@ enum {
187 ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD 187 ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD
188 * doesn't handle PIO interrupts */ 188 * doesn't handle PIO interrupts */
189 ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */ 189 ATA_FLAG_NCQ = (1 << 10), /* host supports NCQ */
190 ATA_FLAG_NO_POWEROFF_SPINDOWN = (1 << 11), /* don't spindown before poweroff */
191 ATA_FLAG_NO_HIBERNATE_SPINDOWN = (1 << 12), /* don't spindown before hibernation */
190 ATA_FLAG_DEBUGMSG = (1 << 13), 192 ATA_FLAG_DEBUGMSG = (1 << 13),
191 ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ 193 ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */
192 ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */ 194 ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 2b409c44db83..c7d9bb1832ba 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -237,6 +237,7 @@ extern int hibernate_nvs_alloc(void);
237extern void hibernate_nvs_free(void); 237extern void hibernate_nvs_free(void);
238extern void hibernate_nvs_save(void); 238extern void hibernate_nvs_save(void);
239extern void hibernate_nvs_restore(void); 239extern void hibernate_nvs_restore(void);
240extern bool system_entering_hibernation(void);
240#else /* CONFIG_HIBERNATION */ 241#else /* CONFIG_HIBERNATION */
241static inline int swsusp_page_is_forbidden(struct page *p) { return 0; } 242static inline int swsusp_page_is_forbidden(struct page *p) { return 0; }
242static inline void swsusp_set_page_free(struct page *p) {} 243static inline void swsusp_set_page_free(struct page *p) {}
@@ -252,6 +253,7 @@ static inline int hibernate_nvs_alloc(void) { return 0; }
252static inline void hibernate_nvs_free(void) {} 253static inline void hibernate_nvs_free(void) {}
253static inline void hibernate_nvs_save(void) {} 254static inline void hibernate_nvs_save(void) {}
254static inline void hibernate_nvs_restore(void) {} 255static inline void hibernate_nvs_restore(void) {}
256static inline bool system_entering_hibernation(void) { return false; }
255#endif /* CONFIG_HIBERNATION */ 257#endif /* CONFIG_HIBERNATION */
256 258
257#ifdef CONFIG_PM_SLEEP 259#ifdef CONFIG_PM_SLEEP
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 45e8541ab7e3..432ee575c9ee 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -71,6 +71,14 @@ void hibernation_set_ops(struct platform_hibernation_ops *ops)
71 mutex_unlock(&pm_mutex); 71 mutex_unlock(&pm_mutex);
72} 72}
73 73
74static bool entering_platform_hibernation;
75
76bool system_entering_hibernation(void)
77{
78 return entering_platform_hibernation;
79}
80EXPORT_SYMBOL(system_entering_hibernation);
81
74#ifdef CONFIG_PM_DEBUG 82#ifdef CONFIG_PM_DEBUG
75static void hibernation_debug_sleep(void) 83static void hibernation_debug_sleep(void)
76{ 84{
@@ -411,6 +419,7 @@ int hibernation_platform_enter(void)
411 if (error) 419 if (error)
412 goto Close; 420 goto Close;
413 421
422 entering_platform_hibernation = true;
414 suspend_console(); 423 suspend_console();
415 error = device_suspend(PMSG_HIBERNATE); 424 error = device_suspend(PMSG_HIBERNATE);
416 if (error) { 425 if (error) {
@@ -445,6 +454,7 @@ int hibernation_platform_enter(void)
445 Finish: 454 Finish:
446 hibernation_ops->finish(); 455 hibernation_ops->finish();
447 Resume_devices: 456 Resume_devices:
457 entering_platform_hibernation = false;
448 device_resume(PMSG_RESTORE); 458 device_resume(PMSG_RESTORE);
449 resume_console(); 459 resume_console();
450 Close: 460 Close: