diff options
author | Tejun Heo <htejun@gmail.com> | 2006-08-20 04:56:38 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-08-22 06:07:48 -0400 |
commit | f1a58ecae527fc67c87ce4dcb9e73894f64aadfe (patch) | |
tree | e89e6440350a6990023b77fd5a0d7e9f5f9c4b28 /drivers | |
parent | d14b50cc60ca465290fcdb3b88e7d5fb684361ed (diff) |
[PATCH] ata_piix: fix ghost device probing by honoring PCS present bits
Move out PCS handling from piix_sata_prereset() into
piix_sata_present_mask() and use it from newly implemented
piix_sata_softreset(). Class codes for devices which are indicated to
be absent by PCS are cleared to ATA_DEV_NONE. This fixes ghost device
problem reported on ICH6 and 7.
This patch moves PCS handling from prereset to softreset, which makes
two behavior changes.
* perform softreset even when PCS indicates no device
* PCS handling is repeated before retrying softresets due to reset
failures.
Both behavior changes are intended and more consistent with how other
drivers behave.
Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/ata_piix.c | 60 |
1 files changed, 43 insertions, 17 deletions
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 5e8afc876980..01b3530cf6df 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c | |||
@@ -531,27 +531,25 @@ static void piix_pata_error_handler(struct ata_port *ap) | |||
531 | } | 531 | } |
532 | 532 | ||
533 | /** | 533 | /** |
534 | * piix_sata_prereset - prereset for SATA host controller | 534 | * piix_sata_present_mask - determine present mask for SATA host controller |
535 | * @ap: Target port | 535 | * @ap: Target port |
536 | * | 536 | * |
537 | * Reads and configures SATA PCI device's PCI config register | 537 | * Reads SATA PCI device's PCI config register Port Configuration |
538 | * Port Configuration and Status (PCS) to determine port and | 538 | * and Status (PCS) to determine port and device availability. |
539 | * device availability. Return -ENODEV to skip reset if no | ||
540 | * device is present. | ||
541 | * | 539 | * |
542 | * LOCKING: | 540 | * LOCKING: |
543 | * None (inherited from caller). | 541 | * None (inherited from caller). |
544 | * | 542 | * |
545 | * RETURNS: | 543 | * RETURNS: |
546 | * 0 if device is present, -ENODEV otherwise. | 544 | * determined present_mask |
547 | */ | 545 | */ |
548 | static int piix_sata_prereset(struct ata_port *ap) | 546 | static unsigned int piix_sata_present_mask(struct ata_port *ap) |
549 | { | 547 | { |
550 | struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); | 548 | struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); |
551 | struct piix_host_priv *hpriv = ap->host_set->private_data; | 549 | struct piix_host_priv *hpriv = ap->host_set->private_data; |
552 | const unsigned int *map = hpriv->map; | 550 | const unsigned int *map = hpriv->map; |
553 | int base = 2 * ap->hard_port_no; | 551 | int base = 2 * ap->hard_port_no; |
554 | unsigned int present = 0; | 552 | unsigned int present_mask = 0; |
555 | int port, i; | 553 | int port, i; |
556 | u16 pcs; | 554 | u16 pcs; |
557 | 555 | ||
@@ -564,24 +562,52 @@ static int piix_sata_prereset(struct ata_port *ap) | |||
564 | continue; | 562 | continue; |
565 | if ((ap->flags & PIIX_FLAG_IGNORE_PCS) || | 563 | if ((ap->flags & PIIX_FLAG_IGNORE_PCS) || |
566 | (pcs & 1 << (hpriv->map_db->present_shift + port))) | 564 | (pcs & 1 << (hpriv->map_db->present_shift + port))) |
567 | present = 1; | 565 | present_mask |= 1 << i; |
568 | } | 566 | } |
569 | 567 | ||
570 | DPRINTK("ata%u: LEAVE, pcs=0x%x present=0x%x\n", | 568 | DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n", |
571 | ap->id, pcs, present); | 569 | ap->id, pcs, present_mask); |
572 | 570 | ||
573 | if (!present) { | 571 | return present_mask; |
574 | ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n"); | 572 | } |
575 | ap->eh_context.i.action &= ~ATA_EH_RESET_MASK; | 573 | |
576 | return 0; | 574 | /** |
575 | * piix_sata_softreset - reset SATA host port via ATA SRST | ||
576 | * @ap: port to reset | ||
577 | * @classes: resulting classes of attached devices | ||
578 | * | ||
579 | * Reset SATA host port via ATA SRST. On controllers with | ||
580 | * reliable PCS present bits, the bits are used to determine | ||
581 | * device presence. | ||
582 | * | ||
583 | * LOCKING: | ||
584 | * Kernel thread context (may sleep) | ||
585 | * | ||
586 | * RETURNS: | ||
587 | * 0 on success, -errno otherwise. | ||
588 | */ | ||
589 | static int piix_sata_softreset(struct ata_port *ap, unsigned int *classes) | ||
590 | { | ||
591 | unsigned int present_mask; | ||
592 | int i, rc; | ||
593 | |||
594 | present_mask = piix_sata_present_mask(ap); | ||
595 | |||
596 | rc = ata_std_softreset(ap, classes); | ||
597 | if (rc) | ||
598 | return rc; | ||
599 | |||
600 | for (i = 0; i < ATA_MAX_DEVICES; i++) { | ||
601 | if (!(present_mask & (1 << i))) | ||
602 | classes[i] = ATA_DEV_NONE; | ||
577 | } | 603 | } |
578 | 604 | ||
579 | return ata_std_prereset(ap); | 605 | return 0; |
580 | } | 606 | } |
581 | 607 | ||
582 | static void piix_sata_error_handler(struct ata_port *ap) | 608 | static void piix_sata_error_handler(struct ata_port *ap) |
583 | { | 609 | { |
584 | ata_bmdma_drive_eh(ap, piix_sata_prereset, ata_std_softreset, NULL, | 610 | ata_bmdma_drive_eh(ap, ata_std_prereset, piix_sata_softreset, NULL, |
585 | ata_std_postreset); | 611 | ata_std_postreset); |
586 | } | 612 | } |
587 | 613 | ||