Commit 72fee382 authored by Tejun Heo's avatar Tejun Heo Committed by Jeff Garzik

sata_sis: convert to slave_link

During introduction of slave_link, sata_sis slipped through the crack
and left with ad-hoc merged SCR access.  As SCR status was shared for
both the master and slave devices, when only one of the device is
online, libata EH would think both are online but would only get valid
device signature for the actually present one, which in turn trigger
the probing safety net mechanism and make EH retry causing large delay
during boot.  This patch converts sata_sis to slave_link mechanism.

This bug was reported by TAXI in bko#14075.

 http://bugzilla.kernel.org/show_bug.cgi?id=14075Signed-off-by: default avatarTejun Heo <tj@kernel.org>
Reported-by: default avatarTAXI <taxi@a-city.de>
Cc: Uwe Koziolek <uwe.koziolek@gmx.net>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 4f1a0ee1
...@@ -109,8 +109,9 @@ MODULE_LICENSE("GPL"); ...@@ -109,8 +109,9 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sis_pci_tbl); MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
MODULE_VERSION(DRV_VERSION); MODULE_VERSION(DRV_VERSION);
static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg) static unsigned int get_scr_cfg_addr(struct ata_link *link, unsigned int sc_reg)
{ {
struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int addr = SIS_SCR_BASE + (4 * sc_reg); unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
u8 pmr; u8 pmr;
...@@ -131,6 +132,9 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg) ...@@ -131,6 +132,9 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
break; break;
} }
} }
if (link->pmp)
addr += 0x10;
return addr; return addr;
} }
...@@ -138,24 +142,12 @@ static u32 sis_scr_cfg_read(struct ata_link *link, ...@@ -138,24 +142,12 @@ static u32 sis_scr_cfg_read(struct ata_link *link,
unsigned int sc_reg, u32 *val) unsigned int sc_reg, u32 *val)
{ {
struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg); unsigned int cfg_addr = get_scr_cfg_addr(link, sc_reg);
u32 val2 = 0;
u8 pmr;
if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
return -EINVAL; return -EINVAL;
pci_read_config_byte(pdev, SIS_PMR, &pmr);
pci_read_config_dword(pdev, cfg_addr, val); pci_read_config_dword(pdev, cfg_addr, val);
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
pci_read_config_dword(pdev, cfg_addr+0x10, &val2);
*val |= val2;
*val &= 0xfffffffb; /* avoid problems with powerdowned ports */
return 0; return 0;
} }
...@@ -163,28 +155,16 @@ static int sis_scr_cfg_write(struct ata_link *link, ...@@ -163,28 +155,16 @@ static int sis_scr_cfg_write(struct ata_link *link,
unsigned int sc_reg, u32 val) unsigned int sc_reg, u32 val)
{ {
struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg); unsigned int cfg_addr = get_scr_cfg_addr(link, sc_reg);
u8 pmr;
if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
return -EINVAL;
pci_read_config_byte(pdev, SIS_PMR, &pmr);
pci_write_config_dword(pdev, cfg_addr, val); pci_write_config_dword(pdev, cfg_addr, val);
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
pci_write_config_dword(pdev, cfg_addr+0x10, val);
return 0; return 0;
} }
static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{ {
struct ata_port *ap = link->ap; struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev); void __iomem *base = ap->ioaddr.scr_addr + link->pmp * 0x10;
u8 pmr;
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
...@@ -192,39 +172,23 @@ static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) ...@@ -192,39 +172,23 @@ static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
if (ap->flags & SIS_FLAG_CFGSCR) if (ap->flags & SIS_FLAG_CFGSCR)
return sis_scr_cfg_read(link, sc_reg, val); return sis_scr_cfg_read(link, sc_reg, val);
pci_read_config_byte(pdev, SIS_PMR, &pmr); *val = ioread32(base + sc_reg * 4);
*val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4));
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
*val |= ioread32(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10);
*val &= 0xfffffffb;
return 0; return 0;
} }
static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{ {
struct ata_port *ap = link->ap; struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev); void __iomem *base = ap->ioaddr.scr_addr + link->pmp * 0x10;
u8 pmr;
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
pci_read_config_byte(pdev, SIS_PMR, &pmr);
if (ap->flags & SIS_FLAG_CFGSCR) if (ap->flags & SIS_FLAG_CFGSCR)
return sis_scr_cfg_write(link, sc_reg, val); return sis_scr_cfg_write(link, sc_reg, val);
else {
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); iowrite32(val, base + (sc_reg * 4));
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||
(pdev->device == 0x1182) || (pmr & SIS_PMR_COMBINED))
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10);
return 0; return 0;
}
} }
static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
...@@ -236,7 +200,7 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -236,7 +200,7 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
u32 genctl, val; u32 genctl, val;
u8 pmr; u8 pmr;
u8 port2_start = 0x20; u8 port2_start = 0x20;
int rc; int i, rc;
if (!printed_version++) if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n"); dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
...@@ -319,6 +283,17 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -319,6 +283,17 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc) if (rc)
return rc; return rc;
for (i = 0; i < 2; i++) {
struct ata_port *ap = host->ports[i];
if (ap->flags & ATA_FLAG_SATA &&
ap->flags & ATA_FLAG_SLAVE_POSS) {
rc = ata_slave_link_init(ap);
if (rc)
return rc;
}
}
if (!(pi.flags & SIS_FLAG_CFGSCR)) { if (!(pi.flags & SIS_FLAG_CFGSCR)) {
void __iomem *mmio; void __iomem *mmio;
......
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