Commit fea63e38 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

[PATCH] libata: fix non-uniform ports handling

Non-uniform ports handling got broken while updating libata to handle
those in the same host.  Only separate irq for the non-uniform
secondary port was implemented while all other fields (host flags,
transfer mode...) of the secondary port simply shared those of the
first.

For ata_piix combined mode, which ATM is the only user of non-uniform
ports, this causes the secondary port assume the wrong type.  This can
cause PATA port to use SATA ops, which results in bogus check on PCS
and detection failure.

This patch adds ata_probe_ent->pinfo2 which points to optional
port_info for the secondary port.  For the time being, this seems to
be the simplest solution.  This workaround will be removed together
with ata_probe_ent itself after init model is updated to allow more
flexibility.
Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Nelson A. de Oliveira <naoliv@gmail.com>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent a64f97f2
...@@ -5269,11 +5269,19 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host, ...@@ -5269,11 +5269,19 @@ void ata_port_init(struct ata_port *ap, struct ata_host *host,
ap->host = host; ap->host = host;
ap->dev = ent->dev; ap->dev = ent->dev;
ap->port_no = port_no; ap->port_no = port_no;
if (port_no == 1 && ent->pinfo2) {
ap->pio_mask = ent->pinfo2->pio_mask;
ap->mwdma_mask = ent->pinfo2->mwdma_mask;
ap->udma_mask = ent->pinfo2->udma_mask;
ap->flags |= ent->pinfo2->flags;
ap->ops = ent->pinfo2->port_ops;
} else {
ap->pio_mask = ent->pio_mask; ap->pio_mask = ent->pio_mask;
ap->mwdma_mask = ent->mwdma_mask; ap->mwdma_mask = ent->mwdma_mask;
ap->udma_mask = ent->udma_mask; ap->udma_mask = ent->udma_mask;
ap->flags |= ent->port_flags; ap->flags |= ent->port_flags;
ap->ops = ent->port_ops; ap->ops = ent->port_ops;
}
ap->hw_sata_spd_limit = UINT_MAX; ap->hw_sata_spd_limit = UINT_MAX;
ap->active_tag = ATA_TAG_POISON; ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF; ap->last_ctl = 0xFF;
......
...@@ -858,6 +858,7 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ...@@ -858,6 +858,7 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
probe_ent->port[p].bmdma_addr = bmdma; probe_ent->port[p].bmdma_addr = bmdma;
} }
ata_std_ports(&probe_ent->port[p]); ata_std_ports(&probe_ent->port[p]);
probe_ent->pinfo2 = port[1];
p++; p++;
} }
...@@ -907,6 +908,7 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, ...@@ -907,6 +908,7 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
probe_ent->_host_flags |= ATA_HOST_SIMPLEX; probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
} }
ata_std_ports(&probe_ent->port[1]); ata_std_ports(&probe_ent->port[1]);
probe_ent->pinfo2 = port[1];
} else } else
probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY; probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY;
......
...@@ -361,6 +361,14 @@ struct ata_probe_ent { ...@@ -361,6 +361,14 @@ struct ata_probe_ent {
unsigned long _host_flags; unsigned long _host_flags;
void __iomem *mmio_base; void __iomem *mmio_base;
void *private_data; void *private_data;
/* port_info for the secondary port. Together with irq2, it's
* used to implement non-uniform secondary port. Currently,
* the only user is ata_piix combined mode. This workaround
* will be removed together with ata_probe_ent when init model
* is updated.
*/
const struct ata_port_info *pinfo2;
}; };
struct ata_host { struct ata_host {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment