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

+187 -22
+32
drivers/ata/ahci.c
··· 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 2577 static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 2552 2578 { 2553 2579 static int printed_version; ··· 2671 2645 if (!(em_ctl & EM_CTL_ALHD)) 2672 2646 pi.flags |= ATA_FLAG_SW_ACTIVITY; 2673 2647 } 2648 + } 2649 + 2650 + if (ahci_broken_system_poweroff(pdev)) { 2651 + pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN; 2652 + dev_info(&pdev->dev, 2653 + "quirky BIOS, skipping spindown on poweroff\n"); 2674 2654 } 2675 2655 2676 2656 /* CAP.NP sometimes indicate the index of the last enabled
+34
drivers/ata/ata_piix.c
··· 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 1417 * piix_init_one - Register PIIX ATA PCI device with kernel services 1392 1418 * @pdev: PCI device to register ··· 1447 1421 /* no hotplugging support (FIXME) */ 1448 1422 if (!in_module_init) 1449 1423 return -ENODEV; 1424 + 1425 + if (piix_broken_system_poweroff(pdev)) { 1426 + piix_port_info[ent->driver_data].flags |= 1427 + ATA_FLAG_NO_POWEROFF_SPINDOWN | 1428 + ATA_FLAG_NO_HIBERNATE_SPINDOWN; 1429 + dev_info(&pdev->dev, "quirky BIOS, skipping spindown " 1430 + "on poweroff and hibernation\n"); 1431 + } 1450 1432 1451 1433 port_info[0] = piix_port_info[ent->driver_data]; 1452 1434 port_info[1] = piix_port_info[ent->driver_data];
+17 -3
drivers/ata/libata-scsi.c
··· 46 46 #include <linux/libata.h> 47 47 #include <linux/hdreg.h> 48 48 #include <linux/uaccess.h> 49 + #include <linux/suspend.h> 49 50 50 51 #include "libata.h" 51 52 ··· 1304 1303 1305 1304 tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ 1306 1305 } else { 1306 + /* Some odd clown BIOSen issue spindown on power off (ACPI S4 1307 + * or S5) causing some drives to spin up and down again. 1308 + */ 1309 + if ((qc->ap->flags & ATA_FLAG_NO_POWEROFF_SPINDOWN) && 1310 + system_state == SYSTEM_POWER_OFF) 1311 + goto skip; 1312 + 1313 + if ((qc->ap->flags & ATA_FLAG_NO_HIBERNATE_SPINDOWN) && 1314 + system_entering_hibernation()) 1315 + goto skip; 1316 + 1307 1317 /* XXX: This is for backward compatibility, will be 1308 1318 * removed. Read Documentation/feature-removal-schedule.txt 1309 1319 * for more info. ··· 1338 1326 scmd->scsi_done = qc->scsidone; 1339 1327 qc->scsidone = ata_delayed_done; 1340 1328 } 1341 - scmd->result = SAM_STAT_GOOD; 1342 - return 1; 1329 + goto skip; 1343 1330 } 1344 1331 1345 1332 /* Issue ATA STANDBY IMMEDIATE command */ ··· 1354 1343 1355 1344 return 0; 1356 1345 1357 - invalid_fld: 1346 + invalid_fld: 1358 1347 ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0); 1359 1348 /* "Invalid field in cbd" */ 1349 + return 1; 1350 + skip: 1351 + scmd->result = SAM_STAT_GOOD; 1360 1352 return 1; 1361 1353 } 1362 1354
+35 -1
drivers/ata/sata_sil.c
··· 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 724 static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 699 725 { 700 726 static int printed_version; 701 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 730 struct ata_host *host; 704 731 void __iomem *mmio_base; 705 732 int n_ports, rc; ··· 739 712 n_ports = 2; 740 713 if (board_id == sil_3114) 741 714 n_ports = 4; 715 + 716 + if (sil_broken_system_poweroff(pdev)) { 717 + pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN | 718 + ATA_FLAG_NO_HIBERNATE_SPINDOWN; 719 + dev_info(&pdev->dev, "quirky BIOS, skipping spindown " 720 + "on poweroff and hibernation\n"); 721 + } 742 722 743 723 host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); 744 724 if (!host)
+54 -18
drivers/firmware/dmi_scan.c
··· 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 + */ 421 + static 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 441 * dmi_check_system - check system DMI data 419 442 * @list: array of dmi_system_id structures to match against 420 443 * All non-null elements of the list must match ··· 452 429 */ 453 430 int dmi_check_system(const struct dmi_system_id *list) 454 431 { 455 - int i, count = 0; 456 - const struct dmi_system_id *d = list; 432 + int count = 0; 433 + const struct dmi_system_id *d; 457 434 458 - WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); 459 - 460 - while (d->ident) { 461 - for (i = 0; i < ARRAY_SIZE(d->matches); i++) { 462 - int s = d->matches[i].slot; 463 - if (s == DMI_NONE) 464 - continue; 465 - if (dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr)) 466 - continue; 467 - /* No match */ 468 - goto fail; 435 + for (d = list; d->ident; d++) 436 + if (dmi_matches(d)) { 437 + count++; 438 + if (d->callback && d->callback(d)) 439 + break; 469 440 } 470 - count++; 471 - if (d->callback && d->callback(d)) 472 - break; 473 - fail: d++; 474 - } 475 441 476 442 return count; 477 443 } 478 444 EXPORT_SYMBOL(dmi_check_system); 445 + 446 + /** 447 + * dmi_first_match - find dmi_system_id structure matching system DMI data 448 + * @list: array of dmi_system_id structures to match against 449 + * All non-null elements of the list must match 450 + * their slot's (field index's) data (i.e., each 451 + * list string must be a substring of the specified 452 + * DMI slot's string data) to be considered a 453 + * successful match. 454 + * 455 + * Walk the blacklist table until the first match is found. Return the 456 + * pointer to the matching entry or NULL if there's no match. 457 + */ 458 + const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) 459 + { 460 + const struct dmi_system_id *d; 461 + 462 + for (d = list; d->ident; d++) 463 + if (dmi_matches(d)) 464 + return d; 465 + 466 + return NULL; 467 + } 468 + EXPORT_SYMBOL(dmi_first_match); 479 469 480 470 /** 481 471 * dmi_get_system_info - return DMI data value
+1
include/linux/dmi.h
··· 38 38 #ifdef CONFIG_DMI 39 39 40 40 extern int dmi_check_system(const struct dmi_system_id *list); 41 + const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); 41 42 extern const char * dmi_get_system_info(int field); 42 43 extern const struct dmi_device * dmi_find_device(int type, const char *name, 43 44 const struct dmi_device *from);
+2
include/linux/libata.h
··· 187 187 ATA_FLAG_PIO_POLLING = (1 << 9), /* use polling PIO if LLD 188 188 * doesn't handle PIO interrupts */ 189 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 192 ATA_FLAG_DEBUGMSG = (1 << 13), 191 193 ATA_FLAG_IGN_SIMPLEX = (1 << 15), /* ignore SIMPLEX */ 192 194 ATA_FLAG_NO_IORDY = (1 << 16), /* controller lacks iordy */
+2
include/linux/suspend.h
··· 237 237 extern void hibernate_nvs_free(void); 238 238 extern void hibernate_nvs_save(void); 239 239 extern void hibernate_nvs_restore(void); 240 + extern bool system_entering_hibernation(void); 240 241 #else /* CONFIG_HIBERNATION */ 241 242 static inline int swsusp_page_is_forbidden(struct page *p) { return 0; } 242 243 static inline void swsusp_set_page_free(struct page *p) {} ··· 253 252 static inline void hibernate_nvs_free(void) {} 254 253 static inline void hibernate_nvs_save(void) {} 255 254 static inline void hibernate_nvs_restore(void) {} 255 + static inline bool system_entering_hibernation(void) { return false; } 256 256 #endif /* CONFIG_HIBERNATION */ 257 257 258 258 #ifdef CONFIG_PM_SLEEP
+10
kernel/power/disk.c
··· 71 71 mutex_unlock(&pm_mutex); 72 72 } 73 73 74 + static bool entering_platform_hibernation; 75 + 76 + bool system_entering_hibernation(void) 77 + { 78 + return entering_platform_hibernation; 79 + } 80 + EXPORT_SYMBOL(system_entering_hibernation); 81 + 74 82 #ifdef CONFIG_PM_DEBUG 75 83 static void hibernation_debug_sleep(void) 76 84 { ··· 419 411 if (error) 420 412 goto Close; 421 413 414 + entering_platform_hibernation = true; 422 415 suspend_console(); 423 416 error = device_suspend(PMSG_HIBERNATE); 424 417 if (error) { ··· 454 445 Finish: 455 446 hibernation_ops->finish(); 456 447 Resume_devices: 448 + entering_platform_hibernation = false; 457 449 device_resume(PMSG_RESTORE); 458 450 resume_console(); 459 451 Close: