diff options
Diffstat (limited to 'drivers/scsi/ata_piix.c')
| -rw-r--r-- | drivers/scsi/ata_piix.c | 81 | 
1 files changed, 64 insertions, 17 deletions
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 19745a31072b..2d20caf377f5 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c  | |||
| @@ -390,7 +390,8 @@ static struct ata_port_info piix_port_info[] = { | |||
| 390 | /* ich5_sata */ | 390 | /* ich5_sata */ | 
| 391 | { | 391 | { | 
| 392 | .sht = &piix_sht, | 392 | .sht = &piix_sht, | 
| 393 | .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, | 393 | .host_flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR | | 
| 394 | PIIX_FLAG_IGNORE_PCS, | ||
| 394 | .pio_mask = 0x1f, /* pio0-4 */ | 395 | .pio_mask = 0x1f, /* pio0-4 */ | 
| 395 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 396 | .mwdma_mask = 0x07, /* mwdma0-2 */ | 
| 396 | .udma_mask = 0x7f, /* udma0-6 */ | 397 | .udma_mask = 0x7f, /* udma0-6 */ | 
| @@ -467,6 +468,11 @@ MODULE_LICENSE("GPL"); | |||
| 467 | MODULE_DEVICE_TABLE(pci, piix_pci_tbl); | 468 | MODULE_DEVICE_TABLE(pci, piix_pci_tbl); | 
| 468 | MODULE_VERSION(DRV_VERSION); | 469 | MODULE_VERSION(DRV_VERSION); | 
| 469 | 470 | ||
| 471 | static int force_pcs = 0; | ||
| 472 | module_param(force_pcs, int, 0444); | ||
| 473 | MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around " | ||
| 474 | "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)"); | ||
| 475 | |||
| 470 | /** | 476 | /** | 
| 471 | * piix_pata_cbl_detect - Probe host controller cable detect info | 477 | * piix_pata_cbl_detect - Probe host controller cable detect info | 
| 472 | * @ap: Port for which cable detect info is desired | 478 | * @ap: Port for which cable detect info is desired | 
| @@ -531,27 +537,25 @@ static void piix_pata_error_handler(struct ata_port *ap) | |||
| 531 | } | 537 | } | 
| 532 | 538 | ||
| 533 | /** | 539 | /** | 
| 534 | * piix_sata_prereset - prereset for SATA host controller | 540 | * piix_sata_present_mask - determine present mask for SATA host controller | 
| 535 | * @ap: Target port | 541 | * @ap: Target port | 
| 536 | * | 542 | * | 
| 537 | * Reads and configures SATA PCI device's PCI config register | 543 | * Reads SATA PCI device's PCI config register Port Configuration | 
| 538 | * Port Configuration and Status (PCS) to determine port and | 544 | * and Status (PCS) to determine port and device availability. | 
| 539 | * device availability. Return -ENODEV to skip reset if no | ||
| 540 | * device is present. | ||
| 541 | * | 545 | * | 
| 542 | * LOCKING: | 546 | * LOCKING: | 
| 543 | * None (inherited from caller). | 547 | * None (inherited from caller). | 
| 544 | * | 548 | * | 
| 545 | * RETURNS: | 549 | * RETURNS: | 
| 546 | * 0 if device is present, -ENODEV otherwise. | 550 | * determined present_mask | 
| 547 | */ | 551 | */ | 
| 548 | static int piix_sata_prereset(struct ata_port *ap) | 552 | static unsigned int piix_sata_present_mask(struct ata_port *ap) | 
| 549 | { | 553 | { | 
| 550 | struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); | 554 | struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); | 
| 551 | struct piix_host_priv *hpriv = ap->host_set->private_data; | 555 | struct piix_host_priv *hpriv = ap->host_set->private_data; | 
| 552 | const unsigned int *map = hpriv->map; | 556 | const unsigned int *map = hpriv->map; | 
| 553 | int base = 2 * ap->hard_port_no; | 557 | int base = 2 * ap->hard_port_no; | 
| 554 | unsigned int present = 0; | 558 | unsigned int present_mask = 0; | 
| 555 | int port, i; | 559 | int port, i; | 
| 556 | u16 pcs; | 560 | u16 pcs; | 
| 557 | 561 | ||
| @@ -564,24 +568,52 @@ static int piix_sata_prereset(struct ata_port *ap) | |||
| 564 | continue; | 568 | continue; | 
| 565 | if ((ap->flags & PIIX_FLAG_IGNORE_PCS) || | 569 | if ((ap->flags & PIIX_FLAG_IGNORE_PCS) || | 
| 566 | (pcs & 1 << (hpriv->map_db->present_shift + port))) | 570 | (pcs & 1 << (hpriv->map_db->present_shift + port))) | 
| 567 | present = 1; | 571 | present_mask |= 1 << i; | 
| 568 | } | 572 | } | 
| 569 | 573 | ||
| 570 | DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n", | 574 | DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n", | 
| 571 | ap->id, pcs, present_mask); | 575 | ap->id, pcs, present_mask); | 
| 572 | 576 | ||
| 573 | if (!present) { | 577 | return present_mask; | 
| 574 | ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n"); | 578 | } | 
| 575 | ap->eh_context.i.action &= ~ATA_EH_RESET_MASK; | 579 | |
| 576 | return 0; | 580 | /** | 
| 581 | * piix_sata_softreset - reset SATA host port via ATA SRST | ||
| 582 | * @ap: port to reset | ||
| 583 | * @classes: resulting classes of attached devices | ||
| 584 | * | ||
| 585 | * Reset SATA host port via ATA SRST. On controllers with | ||
| 586 | * reliable PCS present bits, the bits are used to determine | ||
| 587 | * device presence. | ||
| 588 | * | ||
| 589 | * LOCKING: | ||
| 590 | * Kernel thread context (may sleep) | ||
| 591 | * | ||
| 592 | * RETURNS: | ||
| 593 | * 0 on success, -errno otherwise. | ||
| 594 | */ | ||
| 595 | static int piix_sata_softreset(struct ata_port *ap, unsigned int *classes) | ||
| 596 | { | ||
| 597 | unsigned int present_mask; | ||
| 598 | int i, rc; | ||
| 599 | |||
| 600 | present_mask = piix_sata_present_mask(ap); | ||
| 601 | |||
| 602 | rc = ata_std_softreset(ap, classes); | ||
| 603 | if (rc) | ||
| 604 | return rc; | ||
| 605 | |||
| 606 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
| 607 | if (!(present_mask & (1 << i))) | ||
| 608 | classes[i] = ATA_DEV_NONE; | ||
| 577 | } | 609 | } | 
| 578 | 610 | ||
| 579 | return ata_std_prereset(ap); | 611 | return 0; | 
| 580 | } | 612 | } | 
| 581 | 613 | ||
| 582 | static void piix_sata_error_handler(struct ata_port *ap) | 614 | static void piix_sata_error_handler(struct ata_port *ap) | 
| 583 | { | 615 | { | 
| 584 | ata_bmdma_drive_eh(ap, piix_sata_prereset, ata_std_softreset, NULL, | 616 | ata_bmdma_drive_eh(ap, ata_std_prereset, piix_sata_softreset, NULL, | 
| 585 | ata_std_postreset); | 617 | ata_std_postreset); | 
| 586 | } | 618 | } | 
| 587 | 619 | ||
| @@ -785,6 +817,7 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev) | |||
| 785 | } | 817 | } | 
| 786 | 818 | ||
| 787 | static void __devinit piix_init_pcs(struct pci_dev *pdev, | 819 | static void __devinit piix_init_pcs(struct pci_dev *pdev, | 
| 820 | struct ata_port_info *pinfo, | ||
| 788 | const struct piix_map_db *map_db) | 821 | const struct piix_map_db *map_db) | 
| 789 | { | 822 | { | 
| 790 | u16 pcs, new_pcs; | 823 | u16 pcs, new_pcs; | 
| @@ -798,6 +831,18 @@ static void __devinit piix_init_pcs(struct pci_dev *pdev, | |||
| 798 | pci_write_config_word(pdev, ICH5_PCS, new_pcs); | 831 | pci_write_config_word(pdev, ICH5_PCS, new_pcs); | 
| 799 | msleep(150); | 832 | msleep(150); | 
| 800 | } | 833 | } | 
| 834 | |||
| 835 | if (force_pcs == 1) { | ||
| 836 | dev_printk(KERN_INFO, &pdev->dev, | ||
| 837 | "force ignoring PCS (0x%x)\n", new_pcs); | ||
| 838 | pinfo[0].host_flags |= PIIX_FLAG_IGNORE_PCS; | ||
| 839 | pinfo[1].host_flags |= PIIX_FLAG_IGNORE_PCS; | ||
| 840 | } else if (force_pcs == 2) { | ||
| 841 | dev_printk(KERN_INFO, &pdev->dev, | ||
| 842 | "force honoring PCS (0x%x)\n", new_pcs); | ||
| 843 | pinfo[0].host_flags &= ~PIIX_FLAG_IGNORE_PCS; | ||
| 844 | pinfo[1].host_flags &= ~PIIX_FLAG_IGNORE_PCS; | ||
| 845 | } | ||
| 801 | } | 846 | } | 
| 802 | 847 | ||
| 803 | static void __devinit piix_init_sata_map(struct pci_dev *pdev, | 848 | static void __devinit piix_init_sata_map(struct pci_dev *pdev, | 
| @@ -828,6 +873,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev, | |||
| 828 | case IDE: | 873 | case IDE: | 
| 829 | WARN_ON((i & 1) || map[i + 1] != IDE); | 874 | WARN_ON((i & 1) || map[i + 1] != IDE); | 
| 830 | pinfo[i / 2] = piix_port_info[ich5_pata]; | 875 | pinfo[i / 2] = piix_port_info[ich5_pata]; | 
| 876 | pinfo[i / 2].private_data = hpriv; | ||
| 831 | i++; | 877 | i++; | 
| 832 | printk(" IDE IDE"); | 878 | printk(" IDE IDE"); | 
| 833 | break; | 879 | break; | 
| @@ -905,7 +951,8 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 905 | if (host_flags & ATA_FLAG_SATA) { | 951 | if (host_flags & ATA_FLAG_SATA) { | 
| 906 | piix_init_sata_map(pdev, port_info, | 952 | piix_init_sata_map(pdev, port_info, | 
| 907 | piix_map_db_table[ent->driver_data]); | 953 | piix_map_db_table[ent->driver_data]); | 
| 908 | piix_init_pcs(pdev, piix_map_db_table[ent->driver_data]); | 954 | piix_init_pcs(pdev, port_info, | 
| 955 | piix_map_db_table[ent->driver_data]); | ||
| 909 | } | 956 | } | 
| 910 | 957 | ||
| 911 | /* On ICH5, some BIOSen disable the interrupt using the | 958 | /* On ICH5, some BIOSen disable the interrupt using the | 
