Skip to content

Commit

Permalink
[PATCH] ata_piix: reimplement piix_sata_probe()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed Mar 3, 2006
1 parent d33f58b commit d133eca
Showing 1 changed file with 38 additions and 23 deletions.
61 changes: 38 additions & 23 deletions drivers/scsi/ata_piix.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down

0 comments on commit d133eca

Please sign in to comment.