]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
[PATCH] ata_piix: reimplement piix_sata_probe()
authorTejun Heo <htejun@gmail.com>
Tue, 28 Feb 2006 16:25:39 +0000 (01:25 +0900)
committerJeff Garzik <jeff@garzik.org>
Fri, 3 Mar 2006 20:39:54 +0000 (15:39 -0500)
Reimplement piix_sata_probe() such that it turns on PCS enable bits on
all avaliable ports and check present bits after a while to determine
device presence.  This should help broken BIOSes.  After device
presence detection is complete, PCS enable bits of unoccupied bits are
turned off unless the controller supports AHCI (ICH6/7 docs mandate
all enables bits are always set on AHCI capable controllers).

Note that PCS present bits are ignored on 6300ESB as described in the
datasheet.  This should fix device detection problems reported with
the controller.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/scsi/ata_piix.c

index 4080b8be847bc966c9f87ba66a595d4a9fbf8637..72e38e6ea756f24c2c4d0d79d513bc75d5349d32 100644 (file)
@@ -499,44 +499,59 @@ static int piix_pata_probe_reset(struct ata_port *ap, unsigned int *classes)
  *     piix_sata_probe - Probe PCI device for present SATA devices
  *     @ap: Port associated with the PCI device we wish to probe
  *
- *     Reads SATA PCI device's PCI config register Port Configuration
- *     and Status (PCS) to determine port and device availability.
+ *     Reads and configures SATA PCI device's PCI config register
+ *     Port Configuration and Status (PCS) to determine port and
+ *     device availability.
  *
  *     LOCKING:
  *     None (inherited from caller).
  *
  *     RETURNS:
- *     Non-zero if port is enabled, it may or may not have a device
- *     attached in that case (PRESENT bit would only be set if BIOS probe
- *     was done). Zero is returned if port is disabled.
+ *     Mask of avaliable devices on the port.
  */
-static int piix_sata_probe (struct ata_port *ap)
+static unsigned int piix_sata_probe (struct ata_port *ap)
 {
        struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
-       int combined = (ap->flags & ATA_FLAG_SLAVE_POSS);
-       int orig_mask, mask, i;
+       const unsigned int *map = ap->host_set->private_data;
+       int base = 2 * ap->hard_port_no;
+       unsigned int present_mask = 0;
+       int port, i;
        u8 pcs;
 
        pci_read_config_byte(pdev, ICH5_PCS, &pcs);
-       orig_mask = (int) pcs & 0xff;
-
-       /* TODO: this is vaguely wrong for ICH6 combined mode,
-        * where only two of the four SATA ports are mapped
-        * onto a single ATA channel.  It is also vaguely inaccurate
-        * for ICH5, which has only two ports.  However, this is ok,
-        * as further device presence detection code will handle
-        * any false positives produced here.
-        */
+       DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base);
 
-       for (i = 0; i < 4; i++) {
-               mask = (PIIX_PORT_ENABLED << i);
+       /* enable all ports on this ap and wait for them to settle */
+       for (i = 0; i < 2; i++) {
+               port = map[base + i];
+               if (port >= 0)
+                       pcs |= 1 << port;
+       }
 
-               if ((orig_mask & mask) == mask)
-                       if (combined || (i == ap->hard_port_no))
-                               return 1;
+       pci_write_config_byte(pdev, ICH5_PCS, pcs);
+       msleep(100);
+
+       /* let's see which devices are present */
+       pci_read_config_byte(pdev, ICH5_PCS, &pcs);
+
+       for (i = 0; i < 2; i++) {
+               port = map[base + i];
+               if (port < 0)
+                       continue;
+               if (ap->flags & PIIX_FLAG_IGN_PRESENT || pcs & 1 << (4 + port))
+                       present_mask |= 1 << i;
+               else
+                       pcs &= ~(1 << port);
        }
 
-       return 0;
+       /* disable offline ports on non-AHCI controllers */
+       if (!(ap->flags & PIIX_FLAG_AHCI))
+               pci_write_config_byte(pdev, ICH5_PCS, pcs);
+
+       DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
+               ap->id, pcs, present_mask);
+
+       return present_mask;
 }
 
 /**