Skip to content

Commit

Permalink
sata_sis: convert to slave_link
Browse files Browse the repository at this point in the history
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=14075

Signed-off-by: Tejun Heo <tj@kernel.org>
Reported-by: TAXI <taxi@a-city.de>
Cc: Uwe Koziolek <uwe.koziolek@gmx.net>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed Sep 9, 2009
1 parent 4f1a0ee commit 72fee38
Showing 1 changed file with 25 additions and 50 deletions.
75 changes: 25 additions & 50 deletions drivers/ata/sata_sis.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,9 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
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);
unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
u8 pmr;
Expand All @@ -131,100 +132,63 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
break;
}
}
if (link->pmp)
addr += 0x10;

return addr;
}

static u32 sis_scr_cfg_read(struct ata_link *link,
unsigned int sc_reg, u32 *val)
{
struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg);
u32 val2 = 0;
u8 pmr;
unsigned int cfg_addr = get_scr_cfg_addr(link, sc_reg);

if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
return -EINVAL;

pci_read_config_byte(pdev, SIS_PMR, &pmr);

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;
}

static int sis_scr_cfg_write(struct ata_link *link,
unsigned int sc_reg, u32 val)
{
struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(link->ap, 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);
unsigned int cfg_addr = get_scr_cfg_addr(link, sc_reg);

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;
}

static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{
struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 pmr;
void __iomem *base = ap->ioaddr.scr_addr + link->pmp * 0x10;

if (sc_reg > SCR_CONTROL)
return -EINVAL;

if (ap->flags & SIS_FLAG_CFGSCR)
return sis_scr_cfg_read(link, sc_reg, val);

pci_read_config_byte(pdev, SIS_PMR, &pmr);

*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;

*val = ioread32(base + sc_reg * 4);
return 0;
}

static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{
struct ata_port *ap = link->ap;
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 pmr;
void __iomem *base = ap->ioaddr.scr_addr + link->pmp * 0x10;

if (sc_reg > SCR_CONTROL)
return -EINVAL;

pci_read_config_byte(pdev, SIS_PMR, &pmr);

if (ap->flags & SIS_FLAG_CFGSCR)
return sis_scr_cfg_write(link, sc_reg, val);
else {
iowrite32(val, ap->ioaddr.scr_addr + (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;
}

iowrite32(val, base + (sc_reg * 4));
return 0;
}

static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
Expand All @@ -236,7 +200,7 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
u32 genctl, val;
u8 pmr;
u8 port2_start = 0x20;
int rc;
int i, rc;

if (!printed_version++)
dev_printk(KERN_INFO, &pdev->dev, "version " DRV_VERSION "\n");
Expand Down Expand Up @@ -319,6 +283,17 @@ static int sis_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (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)) {
void __iomem *mmio;

Expand Down

0 comments on commit 72fee38

Please sign in to comment.