Merge branch 'upstream-2.6.28' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev

* 'upstream-2.6.28' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev:
  ata_piix: IDE Mode SATA patch for Intel Ibex Peak DeviceIDs
  libata-eh: clear UNIT ATTENTION after reset
  ata_piix: add Hercules EC-900 mini-notebook to ich_laptop short cable list
  libata: reorder ata_device to remove 8 bytes of padding on 64 bits
  [libata] pata_bf54x: Add proper PM operation
  pata_sil680: convert CONFIG_PPC_MERGE to CONFIG_PPC
  libata: Implement disk shock protection support
  [libata] Introduce ata_id_has_unload()
  PATA: RPC now selects HAVE_PATA_PLATFORM for pata platform driver
  ata_piix: drop merged SCR access and use slave_link instead
  libata: implement slave_link
  libata: misc updates to prepare for slave link
  libata: reimplement link iterator
  libata: make SCR access ops per-link
This commit is contained in:
Linus Torvalds 2008-10-10 07:46:45 -07:00
commit 82219fceeb
25 changed files with 923 additions and 362 deletions

View File

@ -663,7 +663,7 @@ config HAVE_PATA_PLATFORM
config PATA_PLATFORM config PATA_PLATFORM
tristate "Generic platform device PATA support" tristate "Generic platform device PATA support"
depends on EMBEDDED || ARCH_RPC || PPC || HAVE_PATA_PLATFORM depends on EMBEDDED || PPC || HAVE_PATA_PLATFORM
help help
This option enables support for generic directly connected ATA This option enables support for generic directly connected ATA
devices commonly found on embedded systems. devices commonly found on embedded systems.

View File

@ -267,8 +267,8 @@ struct ahci_port_priv {
* per PM slot */ * per PM slot */
}; };
static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc); static bool ahci_qc_fill_rtf(struct ata_queued_cmd *qc);
@ -316,6 +316,7 @@ static struct device_attribute *ahci_shost_attrs[] = {
static struct device_attribute *ahci_sdev_attrs[] = { static struct device_attribute *ahci_sdev_attrs[] = {
&dev_attr_sw_activity, &dev_attr_sw_activity,
&dev_attr_unload_heads,
NULL NULL
}; };
@ -820,10 +821,10 @@ static unsigned ahci_scr_offset(struct ata_port *ap, unsigned int sc_reg)
return 0; return 0;
} }
static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{ {
void __iomem *port_mmio = ahci_port_base(ap); void __iomem *port_mmio = ahci_port_base(link->ap);
int offset = ahci_scr_offset(ap, sc_reg); int offset = ahci_scr_offset(link->ap, sc_reg);
if (offset) { if (offset) {
*val = readl(port_mmio + offset); *val = readl(port_mmio + offset);
@ -832,10 +833,10 @@ static int ahci_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return -EINVAL; return -EINVAL;
} }
static int ahci_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{ {
void __iomem *port_mmio = ahci_port_base(ap); void __iomem *port_mmio = ahci_port_base(link->ap);
int offset = ahci_scr_offset(ap, sc_reg); int offset = ahci_scr_offset(link->ap, sc_reg);
if (offset) { if (offset) {
writel(val, port_mmio + offset); writel(val, port_mmio + offset);
@ -973,7 +974,7 @@ static void ahci_disable_alpm(struct ata_port *ap)
writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT); writel(PORT_IRQ_PHYRDY, port_mmio + PORT_IRQ_STAT);
/* go ahead and clean out PhyRdy Change from Serror too */ /* go ahead and clean out PhyRdy Change from Serror too */
ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
/* /*
* Clear flag to indicate that we should ignore all PhyRdy * Clear flag to indicate that we should ignore all PhyRdy
@ -1937,8 +1938,8 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat); ata_ehi_push_desc(host_ehi, "irq_stat 0x%08x", irq_stat);
/* AHCI needs SError cleared; otherwise, it might lock up */ /* AHCI needs SError cleared; otherwise, it might lock up */
ahci_scr_read(ap, SCR_ERROR, &serror); ahci_scr_read(&ap->link, SCR_ERROR, &serror);
ahci_scr_write(ap, SCR_ERROR, serror); ahci_scr_write(&ap->link, SCR_ERROR, serror);
host_ehi->serror |= serror; host_ehi->serror |= serror;
/* some controllers set IRQ_IF_ERR on device errors, ignore it */ /* some controllers set IRQ_IF_ERR on device errors, ignore it */
@ -2027,7 +2028,7 @@ static void ahci_port_intr(struct ata_port *ap)
if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) && if ((hpriv->flags & AHCI_HFLAG_NO_HOTPLUG) &&
(status & PORT_IRQ_PHYRDY)) { (status & PORT_IRQ_PHYRDY)) {
status &= ~PORT_IRQ_PHYRDY; status &= ~PORT_IRQ_PHYRDY;
ahci_scr_write(ap, SCR_ERROR, ((1 << 16) | (1 << 18))); ahci_scr_write(&ap->link, SCR_ERROR, ((1 << 16) | (1 << 18)));
} }
if (unlikely(status & PORT_IRQ_ERROR)) { if (unlikely(status & PORT_IRQ_ERROR)) {

View File

@ -165,8 +165,10 @@ static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev);
static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev); static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev);
static int ich_pata_cable_detect(struct ata_port *ap); static int ich_pata_cable_detect(struct ata_port *ap);
static u8 piix_vmw_bmdma_status(struct ata_port *ap); static u8 piix_vmw_bmdma_status(struct ata_port *ap);
static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val); static int piix_sidpr_scr_read(struct ata_link *link,
static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val); unsigned int reg, u32 *val);
static int piix_sidpr_scr_write(struct ata_link *link,
unsigned int reg, u32 val);
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
static int piix_pci_device_resume(struct pci_dev *pdev); static int piix_pci_device_resume(struct pci_dev *pdev);
@ -278,12 +280,15 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* SATA Controller IDE (PCH) */ /* SATA Controller IDE (PCH) */
{ 0x8086, 0x3b20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, { 0x8086, 0x3b20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (PCH) */ /* SATA Controller IDE (PCH) */
{ 0x8086, 0x3b21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
/* SATA Controller IDE (PCH) */
{ 0x8086, 0x3b26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { 0x8086, 0x3b26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
/* SATA Controller IDE (PCH) */ /* SATA Controller IDE (PCH) */
{ 0x8086, 0x3b28, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
/* SATA Controller IDE (PCH) */
{ 0x8086, 0x3b2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, { 0x8086, 0x3b2d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
/* SATA Controller IDE (PCH) */ /* SATA Controller IDE (PCH) */
{ 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, { 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata },
{ } /* terminate list */ { } /* terminate list */
}; };
@ -582,6 +587,7 @@ static const struct ich_laptop ich_laptop[] = {
{ 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */ { 0x27DF, 0x1025, 0x0110 }, /* ICH7 on Acer 3682WLMi */
{ 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */ { 0x27DF, 0x1043, 0x1267 }, /* ICH7 on Asus W5F */
{ 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */ { 0x27DF, 0x103C, 0x30A1 }, /* ICH7 on HP Compaq nc2400 */
{ 0x27DF, 0x1071, 0xD221 }, /* ICH7 on Hercules EC-900 */
{ 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */ { 0x24CA, 0x1025, 0x0061 }, /* ICH4 on ACER Aspire 2023WLMi */
{ 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */ { 0x24CA, 0x1025, 0x003d }, /* ICH4 on ACER TM290 */
{ 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */
@ -885,23 +891,9 @@ static void ich_set_dmamode(struct ata_port *ap, struct ata_device *adev)
* Serial ATA Index/Data Pair Superset Registers access * Serial ATA Index/Data Pair Superset Registers access
* *
* Beginning from ICH8, there's a sane way to access SCRs using index * Beginning from ICH8, there's a sane way to access SCRs using index
* and data register pair located at BAR5. This creates an * and data register pair located at BAR5 which means that we have
* interesting problem of mapping two SCRs to one port. * separate SCRs for master and slave. This is handled using libata
* * slave_link facility.
* Although they have separate SCRs, the master and slave aren't
* independent enough to be treated as separate links - e.g. softreset
* resets both. Also, there's no protocol defined for hard resetting
* singled device sharing the virtual port (no defined way to acquire
* device signature). This is worked around by merging the SCR values
* into one sensible value and requesting follow-up SRST after
* hardreset.
*
* SCR merging is perfomed in nibbles which is the unit contents in
* SCRs are organized. If two values are equal, the value is used.
* When they differ, merge table which lists precedence of possible
* values is consulted and the first match or the last entry when
* nothing matches is used. When there's no merge table for the
* specific nibble, value from the first port is used.
*/ */
static const int piix_sidx_map[] = { static const int piix_sidx_map[] = {
[SCR_STATUS] = 0, [SCR_STATUS] = 0,
@ -909,120 +901,38 @@ static const int piix_sidx_map[] = {
[SCR_CONTROL] = 1, [SCR_CONTROL] = 1,
}; };
static void piix_sidpr_sel(struct ata_device *dev, unsigned int reg) static void piix_sidpr_sel(struct ata_link *link, unsigned int reg)
{ {
struct ata_port *ap = dev->link->ap; struct ata_port *ap = link->ap;
struct piix_host_priv *hpriv = ap->host->private_data; struct piix_host_priv *hpriv = ap->host->private_data;
iowrite32(((ap->port_no * 2 + dev->devno) << 8) | piix_sidx_map[reg], iowrite32(((ap->port_no * 2 + link->pmp) << 8) | piix_sidx_map[reg],
hpriv->sidpr + PIIX_SIDPR_IDX); hpriv->sidpr + PIIX_SIDPR_IDX);
} }
static int piix_sidpr_read(struct ata_device *dev, unsigned int reg) static int piix_sidpr_scr_read(struct ata_link *link,
unsigned int reg, u32 *val)
{ {
struct piix_host_priv *hpriv = dev->link->ap->host->private_data; struct piix_host_priv *hpriv = link->ap->host->private_data;
piix_sidpr_sel(dev, reg);
return ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
}
static void piix_sidpr_write(struct ata_device *dev, unsigned int reg, u32 val)
{
struct piix_host_priv *hpriv = dev->link->ap->host->private_data;
piix_sidpr_sel(dev, reg);
iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
}
static u32 piix_merge_scr(u32 val0, u32 val1, const int * const *merge_tbl)
{
u32 val = 0;
int i, mi;
for (i = 0, mi = 0; i < 32 / 4; i++) {
u8 c0 = (val0 >> (i * 4)) & 0xf;
u8 c1 = (val1 >> (i * 4)) & 0xf;
u8 merged = c0;
const int *cur;
/* if no merge preference, assume the first value */
cur = merge_tbl[mi];
if (!cur)
goto done;
mi++;
/* if two values equal, use it */
if (c0 == c1)
goto done;
/* choose the first match or the last from the merge table */
while (*cur != -1) {
if (c0 == *cur || c1 == *cur)
break;
cur++;
}
if (*cur == -1)
cur--;
merged = *cur;
done:
val |= merged << (i * 4);
}
return val;
}
static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val)
{
const int * const sstatus_merge_tbl[] = {
/* DET */ (const int []){ 1, 3, 0, 4, 3, -1 },
/* SPD */ (const int []){ 2, 1, 0, -1 },
/* IPM */ (const int []){ 6, 2, 1, 0, -1 },
NULL,
};
const int * const scontrol_merge_tbl[] = {
/* DET */ (const int []){ 1, 0, 4, 0, -1 },
/* SPD */ (const int []){ 0, 2, 1, 0, -1 },
/* IPM */ (const int []){ 0, 1, 2, 3, 0, -1 },
NULL,
};
u32 v0, v1;
if (reg >= ARRAY_SIZE(piix_sidx_map)) if (reg >= ARRAY_SIZE(piix_sidx_map))
return -EINVAL; return -EINVAL;
if (!(ap->flags & ATA_FLAG_SLAVE_POSS)) { piix_sidpr_sel(link, reg);
*val = piix_sidpr_read(&ap->link.device[0], reg); *val = ioread32(hpriv->sidpr + PIIX_SIDPR_DATA);
return 0;
}
v0 = piix_sidpr_read(&ap->link.device[0], reg);
v1 = piix_sidpr_read(&ap->link.device[1], reg);
switch (reg) {
case SCR_STATUS:
*val = piix_merge_scr(v0, v1, sstatus_merge_tbl);
break;
case SCR_ERROR:
*val = v0 | v1;
break;
case SCR_CONTROL:
*val = piix_merge_scr(v0, v1, scontrol_merge_tbl);
break;
}
return 0; return 0;
} }
static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val) static int piix_sidpr_scr_write(struct ata_link *link,
unsigned int reg, u32 val)
{ {
struct piix_host_priv *hpriv = link->ap->host->private_data;
if (reg >= ARRAY_SIZE(piix_sidx_map)) if (reg >= ARRAY_SIZE(piix_sidx_map))
return -EINVAL; return -EINVAL;
piix_sidpr_write(&ap->link.device[0], reg, val); piix_sidpr_sel(link, reg);
iowrite32(val, hpriv->sidpr + PIIX_SIDPR_DATA);
if (ap->flags & ATA_FLAG_SLAVE_POSS)
piix_sidpr_write(&ap->link.device[1], reg, val);
return 0; return 0;
} }
@ -1363,28 +1273,28 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev,
return map; return map;
} }
static void __devinit piix_init_sidpr(struct ata_host *host) static int __devinit piix_init_sidpr(struct ata_host *host)
{ {
struct pci_dev *pdev = to_pci_dev(host->dev); struct pci_dev *pdev = to_pci_dev(host->dev);
struct piix_host_priv *hpriv = host->private_data; struct piix_host_priv *hpriv = host->private_data;
struct ata_device *dev0 = &host->ports[0]->link.device[0]; struct ata_link *link0 = &host->ports[0]->link;
u32 scontrol; u32 scontrol;
int i; int i, rc;
/* check for availability */ /* check for availability */
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
if (hpriv->map[i] == IDE) if (hpriv->map[i] == IDE)
return; return 0;
if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR)) if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
return; return 0;
if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 || if (pci_resource_start(pdev, PIIX_SIDPR_BAR) == 0 ||
pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN) pci_resource_len(pdev, PIIX_SIDPR_BAR) != PIIX_SIDPR_LEN)
return; return 0;
if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME)) if (pcim_iomap_regions(pdev, 1 << PIIX_SIDPR_BAR, DRV_NAME))
return; return 0;
hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR]; hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
@ -1392,7 +1302,7 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
* Give it a test drive by inhibiting power save modes which * Give it a test drive by inhibiting power save modes which
* we'll do anyway. * we'll do anyway.
*/ */
scontrol = piix_sidpr_read(dev0, SCR_CONTROL); piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
/* if IPM is already 3, SCR access is probably working. Don't /* if IPM is already 3, SCR access is probably working. Don't
* un-inhibit power save modes as BIOS might have inhibited * un-inhibit power save modes as BIOS might have inhibited
@ -1400,18 +1310,30 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
*/ */
if ((scontrol & 0xf00) != 0x300) { if ((scontrol & 0xf00) != 0x300) {
scontrol |= 0x300; scontrol |= 0x300;
piix_sidpr_write(dev0, SCR_CONTROL, scontrol); piix_sidpr_scr_write(link0, SCR_CONTROL, scontrol);
scontrol = piix_sidpr_read(dev0, SCR_CONTROL); piix_sidpr_scr_read(link0, SCR_CONTROL, &scontrol);
if ((scontrol & 0xf00) != 0x300) { if ((scontrol & 0xf00) != 0x300) {
dev_printk(KERN_INFO, host->dev, "SCR access via " dev_printk(KERN_INFO, host->dev, "SCR access via "
"SIDPR is available but doesn't work\n"); "SIDPR is available but doesn't work\n");
return; return 0;
} }
} }
host->ports[0]->ops = &piix_sidpr_sata_ops; /* okay, SCRs available, set ops and ask libata for slave_link */
host->ports[1]->ops = &piix_sidpr_sata_ops; for (i = 0; i < 2; i++) {
struct ata_port *ap = host->ports[i];
ap->ops = &piix_sidpr_sata_ops;
if (ap->flags & ATA_FLAG_SLAVE_POSS) {
rc = ata_slave_link_init(ap);
if (rc)
return rc;
}
}
return 0;
} }
static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) static void piix_iocfg_bit18_quirk(struct pci_dev *pdev)
@ -1521,7 +1443,9 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
/* initialize controller */ /* initialize controller */
if (port_flags & ATA_FLAG_SATA) { if (port_flags & ATA_FLAG_SATA) {
piix_init_pcs(host, piix_map_db_table[ent->driver_data]); piix_init_pcs(host, piix_map_db_table[ent->driver_data]);
piix_init_sidpr(host); rc = piix_init_sidpr(host);
if (rc)
return rc;
} }
/* apply IOCFG bit18 quirk */ /* apply IOCFG bit18 quirk */

View File

@ -163,6 +163,67 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION); MODULE_VERSION(DRV_VERSION);
/*
* Iterator helpers. Don't use directly.
*
* LOCKING:
* Host lock or EH context.
*/
struct ata_link *__ata_port_next_link(struct ata_port *ap,
struct ata_link *link, bool dev_only)
{
/* NULL link indicates start of iteration */
if (!link) {
if (dev_only && sata_pmp_attached(ap))
return ap->pmp_link;
return &ap->link;
}
/* we just iterated over the host master link, what's next? */
if (link == &ap->link) {
if (!sata_pmp_attached(ap)) {
if (unlikely(ap->slave_link) && !dev_only)
return ap->slave_link;
return NULL;
}
return ap->pmp_link;
}
/* slave_link excludes PMP */
if (unlikely(link == ap->slave_link))
return NULL;
/* iterate to the next PMP link */
if (++link < ap->pmp_link + ap->nr_pmp_links)
return link;
return NULL;
}
/**
* ata_dev_phys_link - find physical link for a device
* @dev: ATA device to look up physical link for
*
* Look up physical link which @dev is attached to. Note that
* this is different from @dev->link only when @dev is on slave
* link. For all other cases, it's the same as @dev->link.
*
* LOCKING:
* Don't care.
*
* RETURNS:
* Pointer to the found physical link.
*/
struct ata_link *ata_dev_phys_link(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
if (!ap->slave_link)
return dev->link;
if (!dev->devno)
return &ap->link;
return ap->slave_link;
}
/** /**
* ata_force_cbl - force cable type according to libata.force * ata_force_cbl - force cable type according to libata.force
* @ap: ATA port of interest * @ap: ATA port of interest
@ -206,7 +267,8 @@ void ata_force_cbl(struct ata_port *ap)
* the host link and all fan-out ports connected via PMP. If the * the host link and all fan-out ports connected via PMP. If the
* device part is specified as 0 (e.g. 1.00:), it specifies the * device part is specified as 0 (e.g. 1.00:), it specifies the
* first fan-out link not the host link. Device number 15 always * first fan-out link not the host link. Device number 15 always
* points to the host link whether PMP is attached or not. * points to the host link whether PMP is attached or not. If the
* controller has slave link, device number 16 points to it.
* *
* LOCKING: * LOCKING:
* EH context. * EH context.
@ -214,12 +276,11 @@ void ata_force_cbl(struct ata_port *ap)
static void ata_force_link_limits(struct ata_link *link) static void ata_force_link_limits(struct ata_link *link)
{ {
bool did_spd = false; bool did_spd = false;
int linkno, i; int linkno = link->pmp;
int i;
if (ata_is_host_link(link)) if (ata_is_host_link(link))
linkno = 15; linkno += 15;
else
linkno = link->pmp;
for (i = ata_force_tbl_size - 1; i >= 0; i--) { for (i = ata_force_tbl_size - 1; i >= 0; i--) {
const struct ata_force_ent *fe = &ata_force_tbl[i]; const struct ata_force_ent *fe = &ata_force_tbl[i];
@ -266,9 +327,9 @@ static void ata_force_xfermask(struct ata_device *dev)
int alt_devno = devno; int alt_devno = devno;
int i; int i;
/* allow n.15 for the first device attached to host port */ /* allow n.15/16 for devices attached to host port */
if (ata_is_host_link(dev->link) && devno == 0) if (ata_is_host_link(dev->link))
alt_devno = 15; alt_devno += 15;
for (i = ata_force_tbl_size - 1; i >= 0; i--) { for (i = ata_force_tbl_size - 1; i >= 0; i--) {
const struct ata_force_ent *fe = &ata_force_tbl[i]; const struct ata_force_ent *fe = &ata_force_tbl[i];
@ -320,9 +381,9 @@ static void ata_force_horkage(struct ata_device *dev)
int alt_devno = devno; int alt_devno = devno;
int i; int i;
/* allow n.15 for the first device attached to host port */ /* allow n.15/16 for devices attached to host port */
if (ata_is_host_link(dev->link) && devno == 0) if (ata_is_host_link(dev->link))
alt_devno = 15; alt_devno += 15;
for (i = 0; i < ata_force_tbl_size; i++) { for (i = 0; i < ata_force_tbl_size; i++) {
const struct ata_force_ent *fe = &ata_force_tbl[i]; const struct ata_force_ent *fe = &ata_force_tbl[i];
@ -2681,7 +2742,7 @@ static void sata_print_link_status(struct ata_link *link)
return; return;
sata_scr_read(link, SCR_CONTROL, &scontrol); sata_scr_read(link, SCR_CONTROL, &scontrol);
if (ata_link_online(link)) { if (ata_phys_link_online(link)) {
tmp = (sstatus >> 4) & 0xf; tmp = (sstatus >> 4) & 0xf;
ata_link_printk(link, KERN_INFO, ata_link_printk(link, KERN_INFO,
"SATA link up %s (SStatus %X SControl %X)\n", "SATA link up %s (SStatus %X SControl %X)\n",
@ -3372,6 +3433,12 @@ int ata_wait_ready(struct ata_link *link, unsigned long deadline,
unsigned long nodev_deadline = ata_deadline(start, ATA_TMOUT_FF_WAIT); unsigned long nodev_deadline = ata_deadline(start, ATA_TMOUT_FF_WAIT);
int warned = 0; int warned = 0;
/* Slave readiness can't be tested separately from master. On
* M/S emulation configuration, this function should be called
* only on the master and it will handle both master and slave.
*/
WARN_ON(link == link->ap->slave_link);
if (time_after(nodev_deadline, deadline)) if (time_after(nodev_deadline, deadline))
nodev_deadline = deadline; nodev_deadline = deadline;
@ -3593,7 +3660,7 @@ int ata_std_prereset(struct ata_link *link, unsigned long deadline)
} }
/* no point in trying softreset on offline link */ /* no point in trying softreset on offline link */
if (ata_link_offline(link)) if (ata_phys_link_offline(link))
ehc->i.action &= ~ATA_EH_SOFTRESET; ehc->i.action &= ~ATA_EH_SOFTRESET;
return 0; return 0;
@ -3671,7 +3738,7 @@ int sata_link_hardreset(struct ata_link *link, const unsigned long *timing,
if (rc) if (rc)
goto out; goto out;
/* if link is offline nothing more to do */ /* if link is offline nothing more to do */
if (ata_link_offline(link)) if (ata_phys_link_offline(link))
goto out; goto out;
/* Link is online. From this point, -ENODEV too is an error. */ /* Link is online. From this point, -ENODEV too is an error. */
@ -4868,10 +4935,8 @@ int sata_scr_valid(struct ata_link *link)
int sata_scr_read(struct ata_link *link, int reg, u32 *val) int sata_scr_read(struct ata_link *link, int reg, u32 *val)
{ {
if (ata_is_host_link(link)) { if (ata_is_host_link(link)) {
struct ata_port *ap = link->ap;
if (sata_scr_valid(link)) if (sata_scr_valid(link))
return ap->ops->scr_read(ap, reg, val); return link->ap->ops->scr_read(link, reg, val);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
@ -4897,10 +4962,8 @@ int sata_scr_read(struct ata_link *link, int reg, u32 *val)
int sata_scr_write(struct ata_link *link, int reg, u32 val) int sata_scr_write(struct ata_link *link, int reg, u32 val)
{ {
if (ata_is_host_link(link)) { if (ata_is_host_link(link)) {
struct ata_port *ap = link->ap;
if (sata_scr_valid(link)) if (sata_scr_valid(link))
return ap->ops->scr_write(ap, reg, val); return link->ap->ops->scr_write(link, reg, val);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
@ -4925,13 +4988,12 @@ int sata_scr_write(struct ata_link *link, int reg, u32 val)
int sata_scr_write_flush(struct ata_link *link, int reg, u32 val) int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
{ {
if (ata_is_host_link(link)) { if (ata_is_host_link(link)) {
struct ata_port *ap = link->ap;
int rc; int rc;
if (sata_scr_valid(link)) { if (sata_scr_valid(link)) {
rc = ap->ops->scr_write(ap, reg, val); rc = link->ap->ops->scr_write(link, reg, val);
if (rc == 0) if (rc == 0)
rc = ap->ops->scr_read(ap, reg, &val); rc = link->ap->ops->scr_read(link, reg, &val);
return rc; return rc;
} }
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -4941,7 +5003,7 @@ int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
} }
/** /**
* ata_link_online - test whether the given link is online * ata_phys_link_online - test whether the given link is online
* @link: ATA link to test * @link: ATA link to test
* *
* Test whether @link is online. Note that this function returns * Test whether @link is online. Note that this function returns
@ -4952,20 +5014,20 @@ int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
* None. * None.
* *
* RETURNS: * RETURNS:
* 1 if the port online status is available and online. * True if the port online status is available and online.
*/ */
int ata_link_online(struct ata_link *link) bool ata_phys_link_online(struct ata_link *link)
{ {
u32 sstatus; u32 sstatus;
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 && if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
(sstatus & 0xf) == 0x3) (sstatus & 0xf) == 0x3)
return 1; return true;
return 0; return false;
} }
/** /**
* ata_link_offline - test whether the given link is offline * ata_phys_link_offline - test whether the given link is offline
* @link: ATA link to test * @link: ATA link to test
* *
* Test whether @link is offline. Note that this function * Test whether @link is offline. Note that this function
@ -4976,16 +5038,68 @@ int ata_link_online(struct ata_link *link)
* None. * None.
* *
* RETURNS: * RETURNS:
* 1 if the port offline status is available and offline. * True if the port offline status is available and offline.
*/ */
int ata_link_offline(struct ata_link *link) bool ata_phys_link_offline(struct ata_link *link)
{ {
u32 sstatus; u32 sstatus;
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 && if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0 &&
(sstatus & 0xf) != 0x3) (sstatus & 0xf) != 0x3)
return 1; return true;
return 0; return false;
}
/**
* ata_link_online - test whether the given link is online
* @link: ATA link to test
*
* Test whether @link is online. This is identical to
* ata_phys_link_online() when there's no slave link. When
* there's a slave link, this function should only be called on
* the master link and will return true if any of M/S links is
* online.
*
* LOCKING:
* None.
*
* RETURNS:
* True if the port online status is available and online.
*/
bool ata_link_online(struct ata_link *link)
{
struct ata_link *slave = link->ap->slave_link;
WARN_ON(link == slave); /* shouldn't be called on slave link */
return ata_phys_link_online(link) ||
(slave && ata_phys_link_online(slave));
}
/**
* ata_link_offline - test whether the given link is offline
* @link: ATA link to test
*
* Test whether @link is offline. This is identical to
* ata_phys_link_offline() when there's no slave link. When
* there's a slave link, this function should only be called on
* the master link and will return true if both M/S links are
* offline.
*
* LOCKING:
* None.
*
* RETURNS:
* True if the port offline status is available and offline.
*/
bool ata_link_offline(struct ata_link *link)
{
struct ata_link *slave = link->ap->slave_link;
WARN_ON(link == slave); /* shouldn't be called on slave link */
return ata_phys_link_offline(link) &&
(!slave || ata_phys_link_offline(slave));
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
@ -5127,11 +5241,11 @@ int ata_port_start(struct ata_port *ap)
*/ */
void ata_dev_init(struct ata_device *dev) void ata_dev_init(struct ata_device *dev)
{ {
struct ata_link *link = dev->link; struct ata_link *link = ata_dev_phys_link(dev);
struct ata_port *ap = link->ap; struct ata_port *ap = link->ap;
unsigned long flags; unsigned long flags;
/* SATA spd limit is bound to the first device */ /* SATA spd limit is bound to the attached device, reset together */
link->sata_spd_limit = link->hw_sata_spd_limit; link->sata_spd_limit = link->hw_sata_spd_limit;
link->sata_spd = 0; link->sata_spd = 0;
@ -5264,6 +5378,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan); INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
INIT_LIST_HEAD(&ap->eh_done_q); INIT_LIST_HEAD(&ap->eh_done_q);
init_waitqueue_head(&ap->eh_wait_q); init_waitqueue_head(&ap->eh_wait_q);
init_completion(&ap->park_req_pending);
init_timer_deferrable(&ap->fastdrain_timer); init_timer_deferrable(&ap->fastdrain_timer);
ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn; ap->fastdrain_timer.function = ata_eh_fastdrain_timerfn;
ap->fastdrain_timer.data = (unsigned long)ap; ap->fastdrain_timer.data = (unsigned long)ap;
@ -5294,6 +5409,7 @@ static void ata_host_release(struct device *gendev, void *res)
scsi_host_put(ap->scsi_host); scsi_host_put(ap->scsi_host);
kfree(ap->pmp_link); kfree(ap->pmp_link);
kfree(ap->slave_link);
kfree(ap); kfree(ap);
host->ports[i] = NULL; host->ports[i] = NULL;
} }
@ -5414,6 +5530,68 @@ struct ata_host *ata_host_alloc_pinfo(struct device *dev,
return host; return host;
} }
/**
* ata_slave_link_init - initialize slave link
* @ap: port to initialize slave link for
*
* Create and initialize slave link for @ap. This enables slave
* link handling on the port.
*
* In libata, a port contains links and a link contains devices.
* There is single host link but if a PMP is attached to it,
* there can be multiple fan-out links. On SATA, there's usually
* a single device connected to a link but PATA and SATA
* controllers emulating TF based interface can have two - master
* and slave.
*
* However, there are a few controllers which don't fit into this
* abstraction too well - SATA controllers which emulate TF
* interface with both master and slave devices but also have
* separate SCR register sets for each device. These controllers
* need separate links for physical link handling
* (e.g. onlineness, link speed) but should be treated like a
* traditional M/S controller for everything else (e.g. command
* issue, softreset).
*
* slave_link is libata's way of handling this class of
* controllers without impacting core layer too much. For
* anything other than physical link handling, the default host
* link is used for both master and slave. For physical link
* handling, separate @ap->slave_link is used. All dirty details
* are implemented inside libata core layer. From LLD's POV, the
* only difference is that prereset, hardreset and postreset are
* called once more for the slave link, so the reset sequence
* looks like the following.
*
* prereset(M) -> prereset(S) -> hardreset(M) -> hardreset(S) ->
* softreset(M) -> postreset(M) -> postreset(S)
*
* Note that softreset is called only for the master. Softreset
* resets both M/S by definition, so SRST on master should handle
* both (the standard method will work just fine).
*
* LOCKING:
* Should be called before host is registered.
*
* RETURNS:
* 0 on success, -errno on failure.
*/
int ata_slave_link_init(struct ata_port *ap)
{
struct ata_link *link;
WARN_ON(ap->slave_link);
WARN_ON(ap->flags & ATA_FLAG_PMP);
link = kzalloc(sizeof(*link), GFP_KERNEL);
if (!link)
return -ENOMEM;
ata_link_init(ap, link, 1);
ap->slave_link = link;
return 0;
}
static void ata_host_stop(struct device *gendev, void *res) static void ata_host_stop(struct device *gendev, void *res)
{ {
struct ata_host *host = dev_get_drvdata(gendev); struct ata_host *host = dev_get_drvdata(gendev);
@ -5640,6 +5818,8 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht)
/* init sata_spd_limit to the current value */ /* init sata_spd_limit to the current value */
sata_link_init_spd(&ap->link); sata_link_init_spd(&ap->link);
if (ap->slave_link)
sata_link_init_spd(ap->slave_link);
/* print per-port info to dmesg */ /* print per-port info to dmesg */
xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask, xfer_mask = ata_pack_xfermask(ap->pio_mask, ap->mwdma_mask,
@ -6260,10 +6440,12 @@ EXPORT_SYMBOL_GPL(ata_base_port_ops);
EXPORT_SYMBOL_GPL(sata_port_ops); EXPORT_SYMBOL_GPL(sata_port_ops);
EXPORT_SYMBOL_GPL(ata_dummy_port_ops); EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
EXPORT_SYMBOL_GPL(ata_dummy_port_info); EXPORT_SYMBOL_GPL(ata_dummy_port_info);
EXPORT_SYMBOL_GPL(__ata_port_next_link);
EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_host_init); EXPORT_SYMBOL_GPL(ata_host_init);
EXPORT_SYMBOL_GPL(ata_host_alloc); EXPORT_SYMBOL_GPL(ata_host_alloc);
EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo); EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
EXPORT_SYMBOL_GPL(ata_slave_link_init);
EXPORT_SYMBOL_GPL(ata_host_start); EXPORT_SYMBOL_GPL(ata_host_start);
EXPORT_SYMBOL_GPL(ata_host_register); EXPORT_SYMBOL_GPL(ata_host_register);
EXPORT_SYMBOL_GPL(ata_host_activate); EXPORT_SYMBOL_GPL(ata_host_activate);

View File

@ -79,6 +79,8 @@ enum {
*/ */
ATA_EH_PRERESET_TIMEOUT = 10000, ATA_EH_PRERESET_TIMEOUT = 10000,
ATA_EH_FASTDRAIN_INTERVAL = 3000, ATA_EH_FASTDRAIN_INTERVAL = 3000,
ATA_EH_UA_TRIES = 5,
}; };
/* The following table determines how we sequence resets. Each entry /* The following table determines how we sequence resets. Each entry
@ -1356,6 +1358,37 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
return 0; return 0;
} }
/**
* atapi_eh_tur - perform ATAPI TEST_UNIT_READY
* @dev: target ATAPI device
* @r_sense_key: out parameter for sense_key
*
* Perform ATAPI TEST_UNIT_READY.
*
* LOCKING:
* EH context (may sleep).
*
* RETURNS:
* 0 on success, AC_ERR_* mask on failure.
*/
static unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
{
u8 cdb[ATAPI_CDB_LEN] = { TEST_UNIT_READY, 0, 0, 0, 0, 0 };
struct ata_taskfile tf;
unsigned int err_mask;
ata_tf_init(dev, &tf);
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf.command = ATA_CMD_PACKET;
tf.protocol = ATAPI_PROT_NODATA;
err_mask = ata_exec_internal(dev, &tf, cdb, DMA_NONE, NULL, 0, 0);
if (err_mask == AC_ERR_DEV)
*r_sense_key = tf.feature >> 4;
return err_mask;
}
/** /**
* atapi_eh_request_sense - perform ATAPI REQUEST_SENSE * atapi_eh_request_sense - perform ATAPI REQUEST_SENSE
* @dev: device to perform REQUEST_SENSE to * @dev: device to perform REQUEST_SENSE to
@ -1756,7 +1789,7 @@ static unsigned int ata_eh_speed_down_verdict(struct ata_device *dev)
static unsigned int ata_eh_speed_down(struct ata_device *dev, static unsigned int ata_eh_speed_down(struct ata_device *dev,
unsigned int eflags, unsigned int err_mask) unsigned int eflags, unsigned int err_mask)
{ {
struct ata_link *link = dev->link; struct ata_link *link = ata_dev_phys_link(dev);
int xfer_ok = 0; int xfer_ok = 0;
unsigned int verdict; unsigned int verdict;
unsigned int action = 0; unsigned int action = 0;
@ -1880,7 +1913,8 @@ static void ata_eh_link_autopsy(struct ata_link *link)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link) if (!(qc->flags & ATA_QCFLAG_FAILED) ||
ata_dev_phys_link(qc->dev) != link)
continue; continue;
/* inherit upper level err_mask */ /* inherit upper level err_mask */
@ -1967,6 +2001,23 @@ void ata_eh_autopsy(struct ata_port *ap)
ata_port_for_each_link(link, ap) ata_port_for_each_link(link, ap)
ata_eh_link_autopsy(link); ata_eh_link_autopsy(link);
/* Handle the frigging slave link. Autopsy is done similarly
* but actions and flags are transferred over to the master
* link and handled from there.
*/
if (ap->slave_link) {
struct ata_eh_context *mehc = &ap->link.eh_context;
struct ata_eh_context *sehc = &ap->slave_link->eh_context;
ata_eh_link_autopsy(ap->slave_link);
ata_eh_about_to_do(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS);
mehc->i.action |= sehc->i.action;
mehc->i.dev_action[1] |= sehc->i.dev_action[1];
mehc->i.flags |= sehc->i.flags;
ata_eh_done(ap->slave_link, NULL, ATA_EH_ALL_ACTIONS);
}
/* Autopsy of fanout ports can affect host link autopsy. /* Autopsy of fanout ports can affect host link autopsy.
* Perform host link autopsy last. * Perform host link autopsy last.
*/ */
@ -2001,7 +2052,8 @@ static void ata_eh_link_report(struct ata_link *link)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) { for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag); struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
if (!(qc->flags & ATA_QCFLAG_FAILED) || qc->dev->link != link || if (!(qc->flags & ATA_QCFLAG_FAILED) ||
ata_dev_phys_link(qc->dev) != link ||
((qc->flags & ATA_QCFLAG_QUIET) && ((qc->flags & ATA_QCFLAG_QUIET) &&
qc->err_mask == AC_ERR_DEV)) qc->err_mask == AC_ERR_DEV))
continue; continue;
@ -2068,7 +2120,7 @@ static void ata_eh_link_report(struct ata_link *link)
char cdb_buf[70] = ""; char cdb_buf[70] = "";
if (!(qc->flags & ATA_QCFLAG_FAILED) || if (!(qc->flags & ATA_QCFLAG_FAILED) ||
qc->dev->link != link || !qc->err_mask) ata_dev_phys_link(qc->dev) != link || !qc->err_mask)
continue; continue;
if (qc->dma_dir != DMA_NONE) { if (qc->dma_dir != DMA_NONE) {
@ -2160,12 +2212,14 @@ void ata_eh_report(struct ata_port *ap)
} }
static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset, static int ata_do_reset(struct ata_link *link, ata_reset_fn_t reset,
unsigned int *classes, unsigned long deadline) unsigned int *classes, unsigned long deadline,
bool clear_classes)
{ {
struct ata_device *dev; struct ata_device *dev;
ata_link_for_each_dev(dev, link) if (clear_classes)
classes[dev->devno] = ATA_DEV_UNKNOWN; ata_link_for_each_dev(dev, link)
classes[dev->devno] = ATA_DEV_UNKNOWN;
return reset(link, classes, deadline); return reset(link, classes, deadline);
} }
@ -2187,17 +2241,20 @@ int ata_eh_reset(struct ata_link *link, int classify,
ata_reset_fn_t hardreset, ata_postreset_fn_t postreset) ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
{ {
struct ata_port *ap = link->ap; struct ata_port *ap = link->ap;
struct ata_link *slave = ap->slave_link;
struct ata_eh_context *ehc = &link->eh_context; struct ata_eh_context *ehc = &link->eh_context;
struct ata_eh_context *sehc = &slave->eh_context;
unsigned int *classes = ehc->classes; unsigned int *classes = ehc->classes;
unsigned int lflags = link->flags; unsigned int lflags = link->flags;
int verbose = !(ehc->i.flags & ATA_EHI_QUIET); int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
int max_tries = 0, try = 0; int max_tries = 0, try = 0;
struct ata_link *failed_link;
struct ata_device *dev; struct ata_device *dev;
unsigned long deadline, now; unsigned long deadline, now;
ata_reset_fn_t reset; ata_reset_fn_t reset;
unsigned long flags; unsigned long flags;
u32 sstatus; u32 sstatus;
int nr_known, rc; int nr_unknown, rc;
/* /*
* Prepare to reset * Prepare to reset
@ -2252,8 +2309,30 @@ int ata_eh_reset(struct ata_link *link, int classify,
} }
if (prereset) { if (prereset) {
rc = prereset(link, unsigned long deadline = ata_deadline(jiffies,
ata_deadline(jiffies, ATA_EH_PRERESET_TIMEOUT)); ATA_EH_PRERESET_TIMEOUT);
if (slave) {
sehc->i.action &= ~ATA_EH_RESET;
sehc->i.action |= ehc->i.action;
}
rc = prereset(link, deadline);
/* If present, do prereset on slave link too. Reset
* is skipped iff both master and slave links report
* -ENOENT or clear ATA_EH_RESET.
*/
if (slave && (rc == 0 || rc == -ENOENT)) {
int tmp;
tmp = prereset(slave, deadline);
if (tmp != -ENOENT)
rc = tmp;
ehc->i.action |= sehc->i.action;
}
if (rc) { if (rc) {
if (rc == -ENOENT) { if (rc == -ENOENT) {
ata_link_printk(link, KERN_DEBUG, ata_link_printk(link, KERN_DEBUG,
@ -2302,25 +2381,51 @@ int ata_eh_reset(struct ata_link *link, int classify,
else else
ehc->i.flags |= ATA_EHI_DID_SOFTRESET; ehc->i.flags |= ATA_EHI_DID_SOFTRESET;
rc = ata_do_reset(link, reset, classes, deadline); rc = ata_do_reset(link, reset, classes, deadline, true);
if (rc && rc != -EAGAIN) if (rc && rc != -EAGAIN) {
failed_link = link;
goto fail; goto fail;
}
/* hardreset slave link if existent */
if (slave && reset == hardreset) {
int tmp;
if (verbose)
ata_link_printk(slave, KERN_INFO,
"hard resetting link\n");
ata_eh_about_to_do(slave, NULL, ATA_EH_RESET);
tmp = ata_do_reset(slave, reset, classes, deadline,
false);
switch (tmp) {
case -EAGAIN:
rc = -EAGAIN;
case 0:
break;
default:
failed_link = slave;
rc = tmp;
goto fail;
}
}
/* perform follow-up SRST if necessary */
if (reset == hardreset && if (reset == hardreset &&
ata_eh_followup_srst_needed(link, rc, classes)) { ata_eh_followup_srst_needed(link, rc, classes)) {
/* okay, let's do follow-up softreset */
reset = softreset; reset = softreset;
if (!reset) { if (!reset) {
ata_link_printk(link, KERN_ERR, ata_link_printk(link, KERN_ERR,
"follow-up softreset required " "follow-up softreset required "
"but no softreset avaliable\n"); "but no softreset avaliable\n");
failed_link = link;
rc = -EINVAL; rc = -EINVAL;
goto fail; goto fail;
} }
ata_eh_about_to_do(link, NULL, ATA_EH_RESET); ata_eh_about_to_do(link, NULL, ATA_EH_RESET);
rc = ata_do_reset(link, reset, classes, deadline); rc = ata_do_reset(link, reset, classes, deadline, true);
} }
} else { } else {
if (verbose) if (verbose)
@ -2341,7 +2446,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
dev->pio_mode = XFER_PIO_0; dev->pio_mode = XFER_PIO_0;
dev->flags &= ~ATA_DFLAG_SLEEPING; dev->flags &= ~ATA_DFLAG_SLEEPING;
if (ata_link_offline(link)) if (ata_phys_link_offline(ata_dev_phys_link(dev)))
continue; continue;
/* apply class override */ /* apply class override */
@ -2354,6 +2459,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
/* record current link speed */ /* record current link speed */
if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0) if (sata_scr_read(link, SCR_STATUS, &sstatus) == 0)
link->sata_spd = (sstatus >> 4) & 0xf; link->sata_spd = (sstatus >> 4) & 0xf;
if (slave && sata_scr_read(slave, SCR_STATUS, &sstatus) == 0)
slave->sata_spd = (sstatus >> 4) & 0xf;
/* thaw the port */ /* thaw the port */
if (ata_is_host_link(link)) if (ata_is_host_link(link))
@ -2366,12 +2473,17 @@ int ata_eh_reset(struct ata_link *link, int classify,
* reset and here. This race is mediated by cross checking * reset and here. This race is mediated by cross checking
* link onlineness and classification result later. * link onlineness and classification result later.
*/ */
if (postreset) if (postreset) {
postreset(link, classes); postreset(link, classes);
if (slave)
postreset(slave, classes);
}
/* clear cached SError */ /* clear cached SError */
spin_lock_irqsave(link->ap->lock, flags); spin_lock_irqsave(link->ap->lock, flags);
link->eh_info.serror = 0; link->eh_info.serror = 0;
if (slave)
slave->eh_info.serror = 0;
spin_unlock_irqrestore(link->ap->lock, flags); spin_unlock_irqrestore(link->ap->lock, flags);
/* Make sure onlineness and classification result correspond. /* Make sure onlineness and classification result correspond.
@ -2381,19 +2493,21 @@ int ata_eh_reset(struct ata_link *link, int classify,
* link onlineness and classification result, those conditions * link onlineness and classification result, those conditions
* can be reliably detected and retried. * can be reliably detected and retried.
*/ */
nr_known = 0; nr_unknown = 0;
ata_link_for_each_dev(dev, link) { ata_link_for_each_dev(dev, link) {
/* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */ /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
if (classes[dev->devno] == ATA_DEV_UNKNOWN) if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
classes[dev->devno] = ATA_DEV_NONE; classes[dev->devno] = ATA_DEV_NONE;
else if (ata_phys_link_online(ata_dev_phys_link(dev)))
nr_known++; nr_unknown++;
}
} }
if (classify && !nr_known && ata_link_online(link)) { if (classify && nr_unknown) {
if (try < max_tries) { if (try < max_tries) {
ata_link_printk(link, KERN_WARNING, "link online but " ata_link_printk(link, KERN_WARNING, "link online but "
"device misclassified, retrying\n"); "device misclassified, retrying\n");
failed_link = link;
rc = -EAGAIN; rc = -EAGAIN;
goto fail; goto fail;
} }
@ -2404,6 +2518,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
/* reset successful, schedule revalidation */ /* reset successful, schedule revalidation */
ata_eh_done(link, NULL, ATA_EH_RESET); ata_eh_done(link, NULL, ATA_EH_RESET);
if (slave)
ata_eh_done(slave, NULL, ATA_EH_RESET);
ehc->last_reset = jiffies; ehc->last_reset = jiffies;
ehc->i.action |= ATA_EH_REVALIDATE; ehc->i.action |= ATA_EH_REVALIDATE;
@ -2411,6 +2527,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
out: out:
/* clear hotplug flag */ /* clear hotplug flag */
ehc->i.flags &= ~ATA_EHI_HOTPLUGGED; ehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
if (slave)
sehc->i.flags &= ~ATA_EHI_HOTPLUGGED;
spin_lock_irqsave(ap->lock, flags); spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~ATA_PFLAG_RESETTING; ap->pflags &= ~ATA_PFLAG_RESETTING;
@ -2431,7 +2549,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
if (time_before(now, deadline)) { if (time_before(now, deadline)) {
unsigned long delta = deadline - now; unsigned long delta = deadline - now;
ata_link_printk(link, KERN_WARNING, ata_link_printk(failed_link, KERN_WARNING,
"reset failed (errno=%d), retrying in %u secs\n", "reset failed (errno=%d), retrying in %u secs\n",
rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000)); rc, DIV_ROUND_UP(jiffies_to_msecs(delta), 1000));
@ -2439,13 +2557,92 @@ int ata_eh_reset(struct ata_link *link, int classify,
delta = schedule_timeout_uninterruptible(delta); delta = schedule_timeout_uninterruptible(delta);
} }
if (rc == -EPIPE || try == max_tries - 1) if (try == max_tries - 1) {
sata_down_spd_limit(link); sata_down_spd_limit(link);
if (slave)
sata_down_spd_limit(slave);
} else if (rc == -EPIPE)
sata_down_spd_limit(failed_link);
if (hardreset) if (hardreset)
reset = hardreset; reset = hardreset;
goto retry; goto retry;
} }
static inline void ata_eh_pull_park_action(struct ata_port *ap)
{
struct ata_link *link;
struct ata_device *dev;
unsigned long flags;
/*
* This function can be thought of as an extended version of
* ata_eh_about_to_do() specially crafted to accommodate the
* requirements of ATA_EH_PARK handling. Since the EH thread
* does not leave the do {} while () loop in ata_eh_recover as
* long as the timeout for a park request to *one* device on
* the port has not expired, and since we still want to pick
* up park requests to other devices on the same port or
* timeout updates for the same device, we have to pull
* ATA_EH_PARK actions from eh_info into eh_context.i
* ourselves at the beginning of each pass over the loop.
*
* Additionally, all write accesses to &ap->park_req_pending
* through INIT_COMPLETION() (see below) or complete_all()
* (see ata_scsi_park_store()) are protected by the host lock.
* As a result we have that park_req_pending.done is zero on
* exit from this function, i.e. when ATA_EH_PARK actions for
* *all* devices on port ap have been pulled into the
* respective eh_context structs. If, and only if,
* park_req_pending.done is non-zero by the time we reach
* wait_for_completion_timeout(), another ATA_EH_PARK action
* has been scheduled for at least one of the devices on port
* ap and we have to cycle over the do {} while () loop in
* ata_eh_recover() again.
*/
spin_lock_irqsave(ap->lock, flags);
INIT_COMPLETION(ap->park_req_pending);
ata_port_for_each_link(link, ap) {
ata_link_for_each_dev(dev, link) {
struct ata_eh_info *ehi = &link->eh_info;
link->eh_context.i.dev_action[dev->devno] |=
ehi->dev_action[dev->devno] & ATA_EH_PARK;
ata_eh_clear_action(link, dev, ehi, ATA_EH_PARK);
}
}
spin_unlock_irqrestore(ap->lock, flags);
}
static void ata_eh_park_issue_cmd(struct ata_device *dev, int park)
{
struct ata_eh_context *ehc = &dev->link->eh_context;
struct ata_taskfile tf;
unsigned int err_mask;
ata_tf_init(dev, &tf);
if (park) {
ehc->unloaded_mask |= 1 << dev->devno;
tf.command = ATA_CMD_IDLEIMMEDIATE;
tf.feature = 0x44;
tf.lbal = 0x4c;
tf.lbam = 0x4e;
tf.lbah = 0x55;
} else {
ehc->unloaded_mask &= ~(1 << dev->devno);
tf.command = ATA_CMD_CHK_POWER;
}
tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
tf.protocol |= ATA_PROT_NODATA;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
if (park && (err_mask || tf.lbal != 0xc4)) {
ata_dev_printk(dev, KERN_ERR, "head unload failed!\n");
ehc->unloaded_mask &= ~(1 << dev->devno);
}
}
static int ata_eh_revalidate_and_attach(struct ata_link *link, static int ata_eh_revalidate_and_attach(struct ata_link *link,
struct ata_device **r_failed_dev) struct ata_device **r_failed_dev)
{ {
@ -2472,7 +2669,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) {
WARN_ON(dev->class == ATA_DEV_PMP); WARN_ON(dev->class == ATA_DEV_PMP);
if (ata_link_offline(link)) { if (ata_phys_link_offline(ata_dev_phys_link(dev))) {
rc = -EIO; rc = -EIO;
goto err; goto err;
} }
@ -2610,6 +2807,53 @@ int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev)
return rc; return rc;
} }
/**
* atapi_eh_clear_ua - Clear ATAPI UNIT ATTENTION after reset
* @dev: ATAPI device to clear UA for
*
* Resets and other operations can make an ATAPI device raise
* UNIT ATTENTION which causes the next operation to fail. This
* function clears UA.
*
* LOCKING:
* EH context (may sleep).
*
* RETURNS:
* 0 on success, -errno on failure.
*/
static int atapi_eh_clear_ua(struct ata_device *dev)
{
int i;
for (i = 0; i < ATA_EH_UA_TRIES; i++) {
u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
u8 sense_key = 0;
unsigned int err_mask;
err_mask = atapi_eh_tur(dev, &sense_key);
if (err_mask != 0 && err_mask != AC_ERR_DEV) {
ata_dev_printk(dev, KERN_WARNING, "TEST_UNIT_READY "
"failed (err_mask=0x%x)\n", err_mask);
return -EIO;
}
if (!err_mask || sense_key != UNIT_ATTENTION)
return 0;
err_mask = atapi_eh_request_sense(dev, sense_buffer, sense_key);
if (err_mask) {
ata_dev_printk(dev, KERN_WARNING, "failed to clear "
"UNIT ATTENTION (err_mask=0x%x)\n", err_mask);
return -EIO;
}
}
ata_dev_printk(dev, KERN_WARNING,
"UNIT ATTENTION persists after %d tries\n", ATA_EH_UA_TRIES);
return 0;
}
static int ata_link_nr_enabled(struct ata_link *link) static int ata_link_nr_enabled(struct ata_link *link)
{ {
struct ata_device *dev; struct ata_device *dev;
@ -2697,7 +2941,7 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
/* This is the last chance, better to slow /* This is the last chance, better to slow
* down than lose it. * down than lose it.
*/ */
sata_down_spd_limit(dev->link); sata_down_spd_limit(ata_dev_phys_link(dev));
ata_down_xfermask_limit(dev, ATA_DNXFER_PIO); ata_down_xfermask_limit(dev, ATA_DNXFER_PIO);
} }
} }
@ -2707,7 +2951,7 @@ static int ata_eh_handle_dev_fail(struct ata_device *dev, int err)
ata_dev_disable(dev); ata_dev_disable(dev);
/* detach if offline */ /* detach if offline */
if (ata_link_offline(dev->link)) if (ata_phys_link_offline(ata_dev_phys_link(dev)))
ata_eh_detach_dev(dev); ata_eh_detach_dev(dev);
/* schedule probe if necessary */ /* schedule probe if necessary */
@ -2755,7 +2999,7 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
struct ata_device *dev; struct ata_device *dev;
int nr_failed_devs; int nr_failed_devs;
int rc; int rc;
unsigned long flags; unsigned long flags, deadline;
DPRINTK("ENTER\n"); DPRINTK("ENTER\n");
@ -2829,6 +3073,56 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
} }
} }
do {
unsigned long now;
/*
* clears ATA_EH_PARK in eh_info and resets
* ap->park_req_pending
*/
ata_eh_pull_park_action(ap);
deadline = jiffies;
ata_port_for_each_link(link, ap) {
ata_link_for_each_dev(dev, link) {
struct ata_eh_context *ehc = &link->eh_context;
unsigned long tmp;
if (dev->class != ATA_DEV_ATA)
continue;
if (!(ehc->i.dev_action[dev->devno] &
ATA_EH_PARK))
continue;
tmp = dev->unpark_deadline;
if (time_before(deadline, tmp))
deadline = tmp;
else if (time_before_eq(tmp, jiffies))
continue;
if (ehc->unloaded_mask & (1 << dev->devno))
continue;
ata_eh_park_issue_cmd(dev, 1);
}
}
now = jiffies;
if (time_before_eq(deadline, now))
break;
deadline = wait_for_completion_timeout(&ap->park_req_pending,
deadline - now);
} while (deadline);
ata_port_for_each_link(link, ap) {
ata_link_for_each_dev(dev, link) {
if (!(link->eh_context.unloaded_mask &
(1 << dev->devno)))
continue;
ata_eh_park_issue_cmd(dev, 0);
ata_eh_done(link, dev, ATA_EH_PARK);
}
}
/* the rest */ /* the rest */
ata_port_for_each_link(link, ap) { ata_port_for_each_link(link, ap) {
struct ata_eh_context *ehc = &link->eh_context; struct ata_eh_context *ehc = &link->eh_context;
@ -2852,6 +3146,20 @@ int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
ehc->i.flags &= ~ATA_EHI_SETMODE; ehc->i.flags &= ~ATA_EHI_SETMODE;
} }
/* If reset has been issued, clear UA to avoid
* disrupting the current users of the device.
*/
if (ehc->i.flags & ATA_EHI_DID_RESET) {
ata_link_for_each_dev(dev, link) {
if (dev->class != ATA_DEV_ATAPI)
continue;
rc = atapi_eh_clear_ua(dev);
if (rc)
goto dev_fail;
}
}
/* configure link power saving */
if (ehc->i.action & ATA_EH_LPM) if (ehc->i.action & ATA_EH_LPM)
ata_link_for_each_dev(dev, link) ata_link_for_each_dev(dev, link)
ata_dev_enable_pm(dev, ap->pm_policy); ata_dev_enable_pm(dev, ap->pm_policy);

View File

@ -183,6 +183,105 @@ DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR,
ata_scsi_lpm_show, ata_scsi_lpm_put); ata_scsi_lpm_show, ata_scsi_lpm_put);
EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
static ssize_t ata_scsi_park_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct scsi_device *sdev = to_scsi_device(device);
struct ata_port *ap;
struct ata_link *link;
struct ata_device *dev;
unsigned long flags;
unsigned int uninitialized_var(msecs);
int rc = 0;
ap = ata_shost_to_port(sdev->host);
spin_lock_irqsave(ap->lock, flags);
dev = ata_scsi_find_dev(ap, sdev);
if (!dev) {
rc = -ENODEV;
goto unlock;
}
if (dev->flags & ATA_DFLAG_NO_UNLOAD) {
rc = -EOPNOTSUPP;
goto unlock;
}
link = dev->link;
if (ap->pflags & ATA_PFLAG_EH_IN_PROGRESS &&
link->eh_context.unloaded_mask & (1 << dev->devno) &&
time_after(dev->unpark_deadline, jiffies))
msecs = jiffies_to_msecs(dev->unpark_deadline - jiffies);
else
msecs = 0;
unlock:
spin_unlock_irq(ap->lock);
return rc ? rc : snprintf(buf, 20, "%u\n", msecs);
}
static ssize_t ata_scsi_park_store(struct device *device,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct scsi_device *sdev = to_scsi_device(device);
struct ata_port *ap;
struct ata_device *dev;
long int input;
unsigned long flags;
int rc;
rc = strict_strtol(buf, 10, &input);
if (rc || input < -2)
return -EINVAL;
if (input > ATA_TMOUT_MAX_PARK) {
rc = -EOVERFLOW;
input = ATA_TMOUT_MAX_PARK;
}
ap = ata_shost_to_port(sdev->host);
spin_lock_irqsave(ap->lock, flags);
dev = ata_scsi_find_dev(ap, sdev);
if (unlikely(!dev)) {
rc = -ENODEV;
goto unlock;
}
if (dev->class != ATA_DEV_ATA) {
rc = -EOPNOTSUPP;
goto unlock;
}
if (input >= 0) {
if (dev->flags & ATA_DFLAG_NO_UNLOAD) {
rc = -EOPNOTSUPP;
goto unlock;
}
dev->unpark_deadline = ata_deadline(jiffies, input);
dev->link->eh_info.dev_action[dev->devno] |= ATA_EH_PARK;
ata_port_schedule_eh(ap);
complete(&ap->park_req_pending);
} else {
switch (input) {
case -1:
dev->flags &= ~ATA_DFLAG_NO_UNLOAD;
break;
case -2:
dev->flags |= ATA_DFLAG_NO_UNLOAD;
break;
}
}
unlock:
spin_unlock_irqrestore(ap->lock, flags);
return rc ? rc : len;
}
DEVICE_ATTR(unload_heads, S_IRUGO | S_IWUSR,
ata_scsi_park_show, ata_scsi_park_store);
EXPORT_SYMBOL_GPL(dev_attr_unload_heads);
static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
{ {
cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
@ -269,6 +368,12 @@ DEVICE_ATTR(sw_activity, S_IWUGO | S_IRUGO, ata_scsi_activity_show,
ata_scsi_activity_store); ata_scsi_activity_store);
EXPORT_SYMBOL_GPL(dev_attr_sw_activity); EXPORT_SYMBOL_GPL(dev_attr_sw_activity);
struct device_attribute *ata_common_sdev_attrs[] = {
&dev_attr_unload_heads,
NULL
};
EXPORT_SYMBOL_GPL(ata_common_sdev_attrs);
static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *)) void (*done)(struct scsi_cmnd *))
{ {
@ -954,6 +1059,9 @@ static int atapi_drain_needed(struct request *rq)
static int ata_scsi_dev_config(struct scsi_device *sdev, static int ata_scsi_dev_config(struct scsi_device *sdev,
struct ata_device *dev) struct ata_device *dev)
{ {
if (!ata_id_has_unload(dev->id))
dev->flags |= ATA_DFLAG_NO_UNLOAD;
/* configure max sectors */ /* configure max sectors */
blk_queue_max_sectors(sdev->request_queue, dev->max_sectors); blk_queue_max_sectors(sdev->request_queue, dev->max_sectors);

View File

@ -70,6 +70,7 @@ extern int atapi_passthru16;
extern int libata_fua; extern int libata_fua;
extern int libata_noacpi; extern int libata_noacpi;
extern int libata_allow_tpm; extern int libata_allow_tpm;
extern struct ata_link *ata_dev_phys_link(struct ata_device *dev);
extern void ata_force_cbl(struct ata_port *ap); extern void ata_force_cbl(struct ata_port *ap);
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf); extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf); extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
@ -107,6 +108,8 @@ extern void ata_qc_issue(struct ata_queued_cmd *qc);
extern void __ata_qc_complete(struct ata_queued_cmd *qc); extern void __ata_qc_complete(struct ata_queued_cmd *qc);
extern int atapi_check_dma(struct ata_queued_cmd *qc); extern int atapi_check_dma(struct ata_queued_cmd *qc);
extern void swap_buf_le16(u16 *buf, unsigned int buf_words); extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
extern bool ata_phys_link_online(struct ata_link *link);
extern bool ata_phys_link_offline(struct ata_link *link);
extern void ata_dev_init(struct ata_device *dev); extern void ata_dev_init(struct ata_device *dev);
extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp); extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
extern int sata_link_init_spd(struct ata_link *link); extern int sata_link_init_spd(struct ata_link *link);

View File

@ -1632,6 +1632,8 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
dev_set_drvdata(&pdev->dev, host);
return 0; return 0;
} }
@ -1648,6 +1650,7 @@ static int __devexit bfin_atapi_remove(struct platform_device *pdev)
struct ata_host *host = dev_get_drvdata(dev); struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host); ata_host_detach(host);
dev_set_drvdata(&pdev->dev, NULL);
peripheral_free_list(atapi_io_port); peripheral_free_list(atapi_io_port);
@ -1655,27 +1658,44 @@ static int __devexit bfin_atapi_remove(struct platform_device *pdev)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state) static int bfin_atapi_suspend(struct platform_device *pdev, pm_message_t state)
{ {
return 0; struct ata_host *host = dev_get_drvdata(&pdev->dev);
if (host)
return ata_host_suspend(host, state);
else
return 0;
} }
int bfin_atapi_resume(struct platform_device *pdev) static int bfin_atapi_resume(struct platform_device *pdev)
{ {
struct ata_host *host = dev_get_drvdata(&pdev->dev);
int ret;
if (host) {
ret = bfin_reset_controller(host);
if (ret) {
printk(KERN_ERR DRV_NAME ": Error during HW init\n");
return ret;
}
ata_host_resume(host);
}
return 0; return 0;
} }
#else
#define bfin_atapi_suspend NULL
#define bfin_atapi_resume NULL
#endif #endif
static struct platform_driver bfin_atapi_driver = { static struct platform_driver bfin_atapi_driver = {
.probe = bfin_atapi_probe, .probe = bfin_atapi_probe,
.remove = __devexit_p(bfin_atapi_remove), .remove = __devexit_p(bfin_atapi_remove),
.suspend = bfin_atapi_suspend,
.resume = bfin_atapi_resume,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef CONFIG_PM
.suspend = bfin_atapi_suspend,
.resume = bfin_atapi_resume,
#endif
}, },
}; };

View File

@ -230,7 +230,7 @@ static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio)
tmpbyte & 1, tmpbyte & 0x30); tmpbyte & 1, tmpbyte & 0x30);
*try_mmio = 0; *try_mmio = 0;
#ifdef CONFIG_PPC_MERGE #ifdef CONFIG_PPC
if (machine_is(cell)) if (machine_is(cell))
*try_mmio = (tmpbyte & 1) || pci_resource_start(pdev, 5); *try_mmio = (tmpbyte & 1) || pci_resource_start(pdev, 5);
#endif #endif

View File

@ -469,10 +469,10 @@ static bool sata_fsl_qc_fill_rtf(struct ata_queued_cmd *qc)
return true; return true;
} }
static int sata_fsl_scr_write(struct ata_port *ap, unsigned int sc_reg_in, static int sata_fsl_scr_write(struct ata_link *link,
u32 val) unsigned int sc_reg_in, u32 val)
{ {
struct sata_fsl_host_priv *host_priv = ap->host->private_data; struct sata_fsl_host_priv *host_priv = link->ap->host->private_data;
void __iomem *ssr_base = host_priv->ssr_base; void __iomem *ssr_base = host_priv->ssr_base;
unsigned int sc_reg; unsigned int sc_reg;
@ -493,10 +493,10 @@ static int sata_fsl_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
return 0; return 0;
} }
static int sata_fsl_scr_read(struct ata_port *ap, unsigned int sc_reg_in, static int sata_fsl_scr_read(struct ata_link *link,
u32 *val) unsigned int sc_reg_in, u32 *val)
{ {
struct sata_fsl_host_priv *host_priv = ap->host->private_data; struct sata_fsl_host_priv *host_priv = link->ap->host->private_data;
void __iomem *ssr_base = host_priv->ssr_base; void __iomem *ssr_base = host_priv->ssr_base;
unsigned int sc_reg; unsigned int sc_reg;
@ -645,12 +645,12 @@ static int sata_fsl_port_start(struct ata_port *ap)
* Workaround for 8315DS board 3gbps link-up issue, * Workaround for 8315DS board 3gbps link-up issue,
* currently limit SATA port to GEN1 speed * currently limit SATA port to GEN1 speed
*/ */
sata_fsl_scr_read(ap, SCR_CONTROL, &temp); sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp);
temp &= ~(0xF << 4); temp &= ~(0xF << 4);
temp |= (0x1 << 4); temp |= (0x1 << 4);
sata_fsl_scr_write(ap, SCR_CONTROL, temp); sata_fsl_scr_write(&ap->link, SCR_CONTROL, temp);
sata_fsl_scr_read(ap, SCR_CONTROL, &temp); sata_fsl_scr_read(&ap->link, SCR_CONTROL, &temp);
dev_printk(KERN_WARNING, dev, "scr_control, speed limited to %x\n", dev_printk(KERN_WARNING, dev, "scr_control, speed limited to %x\n",
temp); temp);
#endif #endif
@ -868,7 +868,7 @@ issue_srst:
ioread32(CQ + hcr_base), ioread32(CQ + hcr_base),
ioread32(CA + hcr_base), ioread32(CC + hcr_base)); ioread32(CA + hcr_base), ioread32(CC + hcr_base));
sata_fsl_scr_read(ap, SCR_ERROR, &Serror); sata_fsl_scr_read(&ap->link, SCR_ERROR, &Serror);
DPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS)); DPRINTK("HStatus = 0x%x\n", ioread32(hcr_base + HSTATUS));
DPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL)); DPRINTK("HControl = 0x%x\n", ioread32(hcr_base + HCONTROL));
@ -972,9 +972,9 @@ static void sata_fsl_error_intr(struct ata_port *ap)
* Handle & Clear SError * Handle & Clear SError
*/ */
sata_fsl_scr_read(ap, SCR_ERROR, &SError); sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError);
if (unlikely(SError & 0xFFFF0000)) { if (unlikely(SError & 0xFFFF0000)) {
sata_fsl_scr_write(ap, SCR_ERROR, SError); sata_fsl_scr_write(&ap->link, SCR_ERROR, SError);
} }
DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n", DPRINTK("error_intr,hStat=0x%x,CE=0x%x,DE =0x%x,SErr=0x%x\n",
@ -1091,7 +1091,7 @@ static void sata_fsl_host_intr(struct ata_port *ap)
hstatus = ioread32(hcr_base + HSTATUS); hstatus = ioread32(hcr_base + HSTATUS);
sata_fsl_scr_read(ap, SCR_ERROR, &SError); sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError);
if (unlikely(SError & 0xFFFF0000)) { if (unlikely(SError & 0xFFFF0000)) {
DPRINTK("serror @host_intr : 0x%x\n", SError); DPRINTK("serror @host_intr : 0x%x\n", SError);

View File

@ -269,9 +269,9 @@ static void inic_reset_port(void __iomem *port_base)
writeb(0xff, port_base + PORT_IRQ_STAT); writeb(0xff, port_base + PORT_IRQ_STAT);
} }
static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val) static int inic_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val)
{ {
void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR; void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR;
void __iomem *addr; void __iomem *addr;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
@ -286,9 +286,9 @@ static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
return 0; return 0;
} }
static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) static int inic_scr_write(struct ata_link *link, unsigned sc_reg, u32 val)
{ {
void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR; void __iomem *scr_addr = inic_port_base(link->ap) + PORT_SCR;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map))) if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
return -EINVAL; return -EINVAL;

View File

@ -493,10 +493,10 @@ struct mv_hw_ops {
void (*reset_bus)(struct ata_host *host, void __iomem *mmio); void (*reset_bus)(struct ata_host *host, void __iomem *mmio);
}; };
static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); static int mv_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val);
static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val);
static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val); static int mv5_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val);
static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val); static int mv5_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val);
static int mv_port_start(struct ata_port *ap); static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap); static void mv_port_stop(struct ata_port *ap);
static int mv_qc_defer(struct ata_queued_cmd *qc); static int mv_qc_defer(struct ata_queued_cmd *qc);
@ -1070,23 +1070,23 @@ static unsigned int mv_scr_offset(unsigned int sc_reg_in)
return ofs; return ofs;
} }
static int mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) static int mv_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val)
{ {
unsigned int ofs = mv_scr_offset(sc_reg_in); unsigned int ofs = mv_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) { if (ofs != 0xffffffffU) {
*val = readl(mv_ap_base(ap) + ofs); *val = readl(mv_ap_base(link->ap) + ofs);
return 0; return 0;
} else } else
return -EINVAL; return -EINVAL;
} }
static int mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) static int mv_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)
{ {
unsigned int ofs = mv_scr_offset(sc_reg_in); unsigned int ofs = mv_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) { if (ofs != 0xffffffffU) {
writelfl(val, mv_ap_base(ap) + ofs); writelfl(val, mv_ap_base(link->ap) + ofs);
return 0; return 0;
} else } else
return -EINVAL; return -EINVAL;
@ -2251,11 +2251,11 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
return ofs; return ofs;
} }
static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val) static int mv5_scr_read(struct ata_link *link, unsigned int sc_reg_in, u32 *val)
{ {
struct mv_host_priv *hpriv = ap->host->private_data; struct mv_host_priv *hpriv = link->ap->host->private_data;
void __iomem *mmio = hpriv->base; void __iomem *mmio = hpriv->base;
void __iomem *addr = mv5_phy_base(mmio, ap->port_no); void __iomem *addr = mv5_phy_base(mmio, link->ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in); unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) { if (ofs != 0xffffffffU) {
@ -2265,11 +2265,11 @@ static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val)
return -EINVAL; return -EINVAL;
} }
static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val) static int mv5_scr_write(struct ata_link *link, unsigned int sc_reg_in, u32 val)
{ {
struct mv_host_priv *hpriv = ap->host->private_data; struct mv_host_priv *hpriv = link->ap->host->private_data;
void __iomem *mmio = hpriv->base; void __iomem *mmio = hpriv->base;
void __iomem *addr = mv5_phy_base(mmio, ap->port_no); void __iomem *addr = mv5_phy_base(mmio, link->ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in); unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU) { if (ofs != 0xffffffffU) {

View File

@ -302,8 +302,8 @@ static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance); static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance); static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance); static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static void nv_nf2_freeze(struct ata_port *ap); static void nv_nf2_freeze(struct ata_port *ap);
static void nv_nf2_thaw(struct ata_port *ap); static void nv_nf2_thaw(struct ata_port *ap);
@ -1511,21 +1511,21 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
return ret; return ret;
} }
static int nv_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
*val = ioread32(ap->ioaddr.scr_addr + (sc_reg * 4)); *val = ioread32(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0; return 0;
} }
static int nv_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); iowrite32(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0; return 0;
} }
@ -2218,9 +2218,9 @@ static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis)
if (!pp->qc_active) if (!pp->qc_active)
return; return;
if (ap->ops->scr_read(ap, SCR_ERROR, &serror)) if (ap->ops->scr_read(&ap->link, SCR_ERROR, &serror))
return; return;
ap->ops->scr_write(ap, SCR_ERROR, serror); ap->ops->scr_write(&ap->link, SCR_ERROR, serror);
if (ata_stat & ATA_ERR) { if (ata_stat & ATA_ERR) {
ata_ehi_clear_desc(ehi); ata_ehi_clear_desc(ehi);

View File

@ -137,8 +137,8 @@ struct pdc_port_priv {
dma_addr_t pkt_dma; dma_addr_t pkt_dma;
}; };
static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int pdc_sata_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_sata_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int pdc_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int pdc_common_port_start(struct ata_port *ap); static int pdc_common_port_start(struct ata_port *ap);
static int pdc_sata_port_start(struct ata_port *ap); static int pdc_sata_port_start(struct ata_port *ap);
@ -386,19 +386,21 @@ static int pdc_sata_cable_detect(struct ata_port *ap)
return ATA_CBL_SATA; return ATA_CBL_SATA;
} }
static int pdc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) static int pdc_sata_scr_read(struct ata_link *link,
unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0; return 0;
} }
static int pdc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static int pdc_sata_scr_write(struct ata_link *link,
unsigned int sc_reg, u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0; return 0;
} }
@ -731,7 +733,7 @@ static void pdc_error_intr(struct ata_port *ap, struct ata_queued_cmd *qc,
if (sata_scr_valid(&ap->link)) { if (sata_scr_valid(&ap->link)) {
u32 serror; u32 serror;
pdc_sata_scr_read(ap, SCR_ERROR, &serror); pdc_sata_scr_read(&ap->link, SCR_ERROR, &serror);
ehi->serror |= serror; ehi->serror |= serror;
} }

View File

@ -111,8 +111,8 @@ struct qs_port_priv {
qs_state_t state; qs_state_t state;
}; };
static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int qs_ata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int qs_port_start(struct ata_port *ap); static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host); static void qs_host_stop(struct ata_host *host);
@ -242,11 +242,11 @@ static int qs_prereset(struct ata_link *link, unsigned long deadline)
return ata_sff_prereset(link, deadline); return ata_sff_prereset(link, deadline);
} }
static int qs_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) static int qs_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
*val = readl(ap->ioaddr.scr_addr + (sc_reg * 8)); *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 8));
return 0; return 0;
} }
@ -256,11 +256,11 @@ static void qs_error_handler(struct ata_port *ap)
ata_std_error_handler(ap); ata_std_error_handler(ap);
} }
static int qs_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static int qs_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 8)); writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 8));
return 0; return 0;
} }

View File

@ -115,8 +115,8 @@ static int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int sil_pci_device_resume(struct pci_dev *pdev); static int sil_pci_device_resume(struct pci_dev *pdev);
#endif #endif
static void sil_dev_config(struct ata_device *dev); static void sil_dev_config(struct ata_device *dev);
static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed); static int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
static void sil_freeze(struct ata_port *ap); static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap); static void sil_thaw(struct ata_port *ap);
@ -317,9 +317,9 @@ static inline void __iomem *sil_scr_addr(struct ata_port *ap,
return NULL; return NULL;
} }
static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) static int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{ {
void __iomem *mmio = sil_scr_addr(ap, sc_reg); void __iomem *mmio = sil_scr_addr(link->ap, sc_reg);
if (mmio) { if (mmio) {
*val = readl(mmio); *val = readl(mmio);
@ -328,9 +328,9 @@ static int sil_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return -EINVAL; return -EINVAL;
} }
static int sil_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{ {
void __iomem *mmio = sil_scr_addr(ap, sc_reg); void __iomem *mmio = sil_scr_addr(link->ap, sc_reg);
if (mmio) { if (mmio) {
writel(val, mmio); writel(val, mmio);
@ -352,8 +352,8 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* controllers continue to assert IRQ as long as * controllers continue to assert IRQ as long as
* SError bits are pending. Clear SError immediately. * SError bits are pending. Clear SError immediately.
*/ */
sil_scr_read(ap, SCR_ERROR, &serror); sil_scr_read(&ap->link, SCR_ERROR, &serror);
sil_scr_write(ap, SCR_ERROR, serror); sil_scr_write(&ap->link, SCR_ERROR, serror);
/* Sometimes spurious interrupts occur, double check /* Sometimes spurious interrupts occur, double check
* it's PHYRDY CHG. * it's PHYRDY CHG.

View File

@ -340,8 +340,8 @@ struct sil24_port_priv {
}; };
static void sil24_dev_config(struct ata_device *dev); static void sil24_dev_config(struct ata_device *dev);
static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val); static int sil24_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val);
static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val); static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val);
static int sil24_qc_defer(struct ata_queued_cmd *qc); static int sil24_qc_defer(struct ata_queued_cmd *qc);
static void sil24_qc_prep(struct ata_queued_cmd *qc); static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
@ -504,9 +504,9 @@ static int sil24_scr_map[] = {
[SCR_ACTIVE] = 3, [SCR_ACTIVE] = 3,
}; };
static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val) static int sil24_scr_read(struct ata_link *link, unsigned sc_reg, u32 *val)
{ {
void __iomem *scr_addr = sil24_port_base(ap) + PORT_SCONTROL; void __iomem *scr_addr = sil24_port_base(link->ap) + PORT_SCONTROL;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr; void __iomem *addr;
@ -517,9 +517,9 @@ static int sil24_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
return -EINVAL; return -EINVAL;
} }
static int sil24_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val) static int sil24_scr_write(struct ata_link *link, unsigned sc_reg, u32 val)
{ {
void __iomem *scr_addr = sil24_port_base(ap) + PORT_SCONTROL; void __iomem *scr_addr = sil24_port_base(link->ap) + PORT_SCONTROL;
if (sc_reg < ARRAY_SIZE(sil24_scr_map)) { if (sc_reg < ARRAY_SIZE(sil24_scr_map)) {
void __iomem *addr; void __iomem *addr;

View File

@ -64,8 +64,8 @@ enum {
}; };
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);
static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int sis_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int sis_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static const struct pci_device_id sis_pci_tbl[] = { static const struct pci_device_id sis_pci_tbl[] = {
{ PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */ { PCI_VDEVICE(SI, 0x0180), sis_180 }, /* SiS 964/180 */
@ -134,10 +134,11 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
return addr; return addr;
} }
static u32 sis_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) static u32 sis_scr_cfg_read(struct ata_link *link,
unsigned int sc_reg, u32 *val)
{ {
struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg); unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg);
u32 val2 = 0; u32 val2 = 0;
u8 pmr; u8 pmr;
@ -158,10 +159,11 @@ static u32 sis_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return 0; return 0;
} }
static int sis_scr_cfg_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static int sis_scr_cfg_write(struct ata_link *link,
unsigned int sc_reg, u32 val)
{ {
struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg); unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg);
u8 pmr; 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 */
@ -178,8 +180,9 @@ static int sis_scr_cfg_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
return 0; return 0;
} }
static int sis_scr_read(struct ata_port *ap, 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 pci_dev *pdev = to_pci_dev(ap->host->dev); struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 pmr; u8 pmr;
@ -187,7 +190,7 @@ static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return -EINVAL; return -EINVAL;
if (ap->flags & SIS_FLAG_CFGSCR) if (ap->flags & SIS_FLAG_CFGSCR)
return sis_scr_cfg_read(ap, sc_reg, val); return sis_scr_cfg_read(link, sc_reg, val);
pci_read_config_byte(pdev, SIS_PMR, &pmr); pci_read_config_byte(pdev, SIS_PMR, &pmr);
@ -202,8 +205,9 @@ static int sis_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val)
return 0; return 0;
} }
static int sis_scr_write(struct ata_port *ap, 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 pci_dev *pdev = to_pci_dev(ap->host->dev); struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 pmr; u8 pmr;
@ -213,7 +217,7 @@ static int sis_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val)
pci_read_config_byte(pdev, SIS_PMR, &pmr); 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(ap, sc_reg, val); return sis_scr_cfg_write(link, sc_reg, val);
else { else {
iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4)); iowrite32(val, ap->ioaddr.scr_addr + (sc_reg * 4));
if ((pdev->device == 0x0182) || (pdev->device == 0x0183) || if ((pdev->device == 0x0182) || (pdev->device == 0x0183) ||

View File

@ -123,20 +123,22 @@ static int k2_sata_check_atapi_dma(struct ata_queued_cmd *qc)
} }
} }
static int k2_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) static int k2_sata_scr_read(struct ata_link *link,
unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0; return 0;
} }
static int k2_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static int k2_sata_scr_write(struct ata_link *link,
unsigned int sc_reg, u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0; return 0;
} }

View File

@ -57,8 +57,8 @@ struct uli_priv {
}; };
static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int uli_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int uli_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int uli_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int uli_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int uli_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static const struct pci_device_id uli_pci_tbl[] = { static const struct pci_device_id uli_pci_tbl[] = {
{ PCI_VDEVICE(AL, 0x5289), uli_5289 }, { PCI_VDEVICE(AL, 0x5289), uli_5289 },
@ -107,39 +107,39 @@ static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg); return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg);
} }
static u32 uli_scr_cfg_read(struct ata_port *ap, unsigned int sc_reg) static u32 uli_scr_cfg_read(struct ata_link *link, unsigned int sc_reg)
{ {
struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg); unsigned int cfg_addr = get_scr_cfg_addr(link->ap, sc_reg);
u32 val; u32 val;
pci_read_config_dword(pdev, cfg_addr, &val); pci_read_config_dword(pdev, cfg_addr, &val);
return val; return val;
} }
static void uli_scr_cfg_write(struct ata_port *ap, unsigned int scr, u32 val) static void uli_scr_cfg_write(struct ata_link *link, unsigned int scr, u32 val)
{ {
struct pci_dev *pdev = to_pci_dev(ap->host->dev); struct pci_dev *pdev = to_pci_dev(link->ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap, scr); unsigned int cfg_addr = get_scr_cfg_addr(link->ap, scr);
pci_write_config_dword(pdev, cfg_addr, val); pci_write_config_dword(pdev, cfg_addr, val);
} }
static int uli_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) static int uli_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
*val = uli_scr_cfg_read(ap, sc_reg); *val = uli_scr_cfg_read(link, sc_reg);
return 0; return 0;
} }
static int uli_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static int uli_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{ {
if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0 if (sc_reg > SCR_CONTROL) //SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
return -EINVAL; return -EINVAL;
uli_scr_cfg_write(ap, sc_reg, val); uli_scr_cfg_write(link, sc_reg, val);
return 0; return 0;
} }

View File

@ -68,8 +68,8 @@ enum {
}; };
static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val); static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val); static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
static void svia_noop_freeze(struct ata_port *ap); static void svia_noop_freeze(struct ata_port *ap);
static int vt6420_prereset(struct ata_link *link, unsigned long deadline); static int vt6420_prereset(struct ata_link *link, unsigned long deadline);
static int vt6421_pata_cable_detect(struct ata_port *ap); static int vt6421_pata_cable_detect(struct ata_port *ap);
@ -152,19 +152,19 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, svia_pci_tbl); MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
MODULE_VERSION(DRV_VERSION); MODULE_VERSION(DRV_VERSION);
static int svia_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
*val = ioread32(ap->ioaddr.scr_addr + (4 * sc_reg)); *val = ioread32(link->ap->ioaddr.scr_addr + (4 * sc_reg));
return 0; return 0;
} }
static int svia_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
iowrite32(val, ap->ioaddr.scr_addr + (4 * sc_reg)); iowrite32(val, link->ap->ioaddr.scr_addr + (4 * sc_reg));
return 0; return 0;
} }
@ -210,20 +210,20 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
goto skip_scr; goto skip_scr;
/* Resume phy. This is the old SATA resume sequence */ /* Resume phy. This is the old SATA resume sequence */
svia_scr_write(ap, SCR_CONTROL, 0x300); svia_scr_write(link, SCR_CONTROL, 0x300);
svia_scr_read(ap, SCR_CONTROL, &scontrol); /* flush */ svia_scr_read(link, SCR_CONTROL, &scontrol); /* flush */
/* wait for phy to become ready, if necessary */ /* wait for phy to become ready, if necessary */
do { do {
msleep(200); msleep(200);
svia_scr_read(ap, SCR_STATUS, &sstatus); svia_scr_read(link, SCR_STATUS, &sstatus);
if ((sstatus & 0xf) != 1) if ((sstatus & 0xf) != 1)
break; break;
} while (time_before(jiffies, timeout)); } while (time_before(jiffies, timeout));
/* open code sata_print_link_status() */ /* open code sata_print_link_status() */
svia_scr_read(ap, SCR_STATUS, &sstatus); svia_scr_read(link, SCR_STATUS, &sstatus);
svia_scr_read(ap, SCR_CONTROL, &scontrol); svia_scr_read(link, SCR_CONTROL, &scontrol);
online = (sstatus & 0xf) == 0x3; online = (sstatus & 0xf) == 0x3;
@ -232,7 +232,7 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline)
online ? "up" : "down", sstatus, scontrol); online ? "up" : "down", sstatus, scontrol);
/* SStatus is read one more time */ /* SStatus is read one more time */
svia_scr_read(ap, SCR_STATUS, &sstatus); svia_scr_read(link, SCR_STATUS, &sstatus);
if (!online) { if (!online) {
/* tell EH to bail */ /* tell EH to bail */

View File

@ -98,20 +98,22 @@ enum {
VSC_SATA_INT_PHY_CHANGE), VSC_SATA_INT_PHY_CHANGE),
}; };
static int vsc_sata_scr_read(struct ata_port *ap, unsigned int sc_reg, u32 *val) static int vsc_sata_scr_read(struct ata_link *link,
unsigned int sc_reg, u32 *val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
*val = readl(ap->ioaddr.scr_addr + (sc_reg * 4)); *val = readl(link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0; return 0;
} }
static int vsc_sata_scr_write(struct ata_port *ap, unsigned int sc_reg, u32 val) static int vsc_sata_scr_write(struct ata_link *link,
unsigned int sc_reg, u32 val)
{ {
if (sc_reg > SCR_CONTROL) if (sc_reg > SCR_CONTROL)
return -EINVAL; return -EINVAL;
writel(val, ap->ioaddr.scr_addr + (sc_reg * 4)); writel(val, link->ap->ioaddr.scr_addr + (sc_reg * 4));
return 0; return 0;
} }

View File

@ -294,10 +294,10 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc)
} }
} }
static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in, static int sas_ata_scr_write(struct ata_link *link, unsigned int sc_reg_in,
u32 val) u32 val)
{ {
struct domain_device *dev = ap->private_data; struct domain_device *dev = link->ap->private_data;
SAS_DPRINTK("STUB %s\n", __func__); SAS_DPRINTK("STUB %s\n", __func__);
switch (sc_reg_in) { switch (sc_reg_in) {
@ -319,10 +319,10 @@ static int sas_ata_scr_write(struct ata_port *ap, unsigned int sc_reg_in,
return 0; return 0;
} }
static int sas_ata_scr_read(struct ata_port *ap, unsigned int sc_reg_in, static int sas_ata_scr_read(struct ata_link *link, unsigned int sc_reg_in,
u32 *val) u32 *val)
{ {
struct domain_device *dev = ap->private_data; struct domain_device *dev = link->ap->private_data;
SAS_DPRINTK("STUB %s\n", __func__); SAS_DPRINTK("STUB %s\n", __func__);
switch (sc_reg_in) { switch (sc_reg_in) {

View File

@ -667,6 +667,15 @@ static inline int ata_id_has_dword_io(const u16 *id)
return 0; return 0;
} }
static inline int ata_id_has_unload(const u16 *id)
{
if (ata_id_major_version(id) >= 7 &&
(id[ATA_ID_CFSSE] & 0xC000) == 0x4000 &&
id[ATA_ID_CFSSE] & (1 << 13))
return 1;
return 0;
}
static inline int ata_id_current_chs_valid(const u16 *id) static inline int ata_id_current_chs_valid(const u16 *id)
{ {
/* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command

View File

@ -146,6 +146,7 @@ enum {
ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */ ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */
ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */ ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */
ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */ ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */
ATA_DFLAG_NO_UNLOAD = (1 << 17), /* device doesn't support unload */
ATA_DFLAG_INIT_MASK = (1 << 24) - 1, ATA_DFLAG_INIT_MASK = (1 << 24) - 1,
ATA_DFLAG_DETACH = (1 << 24), ATA_DFLAG_DETACH = (1 << 24),
@ -244,6 +245,7 @@ enum {
ATA_TMOUT_BOOT = 30000, /* heuristic */ ATA_TMOUT_BOOT = 30000, /* heuristic */
ATA_TMOUT_BOOT_QUICK = 7000, /* heuristic */ ATA_TMOUT_BOOT_QUICK = 7000, /* heuristic */
ATA_TMOUT_INTERNAL_QUICK = 5000, ATA_TMOUT_INTERNAL_QUICK = 5000,
ATA_TMOUT_MAX_PARK = 30000,
/* FIXME: GoVault needs 2s but we can't afford that without /* FIXME: GoVault needs 2s but we can't afford that without
* parallel probing. 800ms is enough for iVDR disk * parallel probing. 800ms is enough for iVDR disk
@ -319,8 +321,11 @@ enum {
ATA_EH_RESET = ATA_EH_SOFTRESET | ATA_EH_HARDRESET, ATA_EH_RESET = ATA_EH_SOFTRESET | ATA_EH_HARDRESET,
ATA_EH_ENABLE_LINK = (1 << 3), ATA_EH_ENABLE_LINK = (1 << 3),
ATA_EH_LPM = (1 << 4), /* link power management action */ ATA_EH_LPM = (1 << 4), /* link power management action */
ATA_EH_PARK = (1 << 5), /* unload heads and stop I/O */
ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE, ATA_EH_PERDEV_MASK = ATA_EH_REVALIDATE | ATA_EH_PARK,
ATA_EH_ALL_ACTIONS = ATA_EH_REVALIDATE | ATA_EH_RESET |
ATA_EH_ENABLE_LINK | ATA_EH_LPM,
/* ata_eh_info->flags */ /* ata_eh_info->flags */
ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */ ATA_EHI_HOTPLUGGED = (1 << 0), /* could have been hotplugged */
@ -452,6 +457,7 @@ enum link_pm {
MEDIUM_POWER, MEDIUM_POWER,
}; };
extern struct device_attribute dev_attr_link_power_management_policy; extern struct device_attribute dev_attr_link_power_management_policy;
extern struct device_attribute dev_attr_unload_heads;
extern struct device_attribute dev_attr_em_message_type; extern struct device_attribute dev_attr_em_message_type;
extern struct device_attribute dev_attr_em_message; extern struct device_attribute dev_attr_em_message;
extern struct device_attribute dev_attr_sw_activity; extern struct device_attribute dev_attr_sw_activity;
@ -554,8 +560,8 @@ struct ata_ering {
struct ata_device { struct ata_device {
struct ata_link *link; struct ata_link *link;
unsigned int devno; /* 0 or 1 */ unsigned int devno; /* 0 or 1 */
unsigned long flags; /* ATA_DFLAG_xxx */
unsigned int horkage; /* List of broken features */ unsigned int horkage; /* List of broken features */
unsigned long flags; /* ATA_DFLAG_xxx */
struct scsi_device *sdev; /* attached SCSI device */ struct scsi_device *sdev; /* attached SCSI device */
#ifdef CONFIG_ATA_ACPI #ifdef CONFIG_ATA_ACPI
acpi_handle acpi_handle; acpi_handle acpi_handle;
@ -564,6 +570,7 @@ struct ata_device {
/* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */ /* n_sector is used as CLEAR_OFFSET, read comment above CLEAR_OFFSET */
u64 n_sectors; /* size of device, if ATA */ u64 n_sectors; /* size of device, if ATA */
unsigned int class; /* ATA_DEV_xxx */ unsigned int class; /* ATA_DEV_xxx */
unsigned long unpark_deadline;
u8 pio_mode; u8 pio_mode;
u8 dma_mode; u8 dma_mode;
@ -621,6 +628,7 @@ struct ata_eh_context {
[ATA_EH_CMD_TIMEOUT_TABLE_SIZE]; [ATA_EH_CMD_TIMEOUT_TABLE_SIZE];
unsigned int classes[ATA_MAX_DEVICES]; unsigned int classes[ATA_MAX_DEVICES];
unsigned int did_probe_mask; unsigned int did_probe_mask;
unsigned int unloaded_mask;
unsigned int saved_ncq_enabled; unsigned int saved_ncq_enabled;
u8 saved_xfer_mode[ATA_MAX_DEVICES]; u8 saved_xfer_mode[ATA_MAX_DEVICES];
/* timestamp for the last reset attempt or success */ /* timestamp for the last reset attempt or success */
@ -688,7 +696,8 @@ struct ata_port {
unsigned int qc_active; unsigned int qc_active;
int nr_active_links; /* #links with active qcs */ int nr_active_links; /* #links with active qcs */
struct ata_link link; /* host default link */ struct ata_link link; /* host default link */
struct ata_link *slave_link; /* see ata_slave_link_init() */
int nr_pmp_links; /* nr of available PMP links */ int nr_pmp_links; /* nr of available PMP links */
struct ata_link *pmp_link; /* array of PMP links */ struct ata_link *pmp_link; /* array of PMP links */
@ -709,6 +718,7 @@ struct ata_port {
struct list_head eh_done_q; struct list_head eh_done_q;
wait_queue_head_t eh_wait_q; wait_queue_head_t eh_wait_q;
int eh_tries; int eh_tries;
struct completion park_req_pending;
pm_message_t pm_mesg; pm_message_t pm_mesg;
int *pm_result; int *pm_result;
@ -772,8 +782,8 @@ struct ata_port_operations {
/* /*
* Optional features * Optional features
*/ */
int (*scr_read)(struct ata_port *ap, unsigned int sc_reg, u32 *val); int (*scr_read)(struct ata_link *link, unsigned int sc_reg, u32 *val);
int (*scr_write)(struct ata_port *ap, unsigned int sc_reg, u32 val); int (*scr_write)(struct ata_link *link, unsigned int sc_reg, u32 val);
void (*pmp_attach)(struct ata_port *ap); void (*pmp_attach)(struct ata_port *ap);
void (*pmp_detach)(struct ata_port *ap); void (*pmp_detach)(struct ata_port *ap);
int (*enable_pm)(struct ata_port *ap, enum link_pm policy); int (*enable_pm)(struct ata_port *ap, enum link_pm policy);
@ -895,6 +905,7 @@ extern void ata_port_disable(struct ata_port *);
extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports); extern struct ata_host *ata_host_alloc(struct device *dev, int max_ports);
extern struct ata_host *ata_host_alloc_pinfo(struct device *dev, extern struct ata_host *ata_host_alloc_pinfo(struct device *dev,
const struct ata_port_info * const * ppi, int n_ports); const struct ata_port_info * const * ppi, int n_ports);
extern int ata_slave_link_init(struct ata_port *ap);
extern int ata_host_start(struct ata_host *host); extern int ata_host_start(struct ata_host *host);
extern int ata_host_register(struct ata_host *host, extern int ata_host_register(struct ata_host *host,
struct scsi_host_template *sht); struct scsi_host_template *sht);
@ -920,8 +931,8 @@ extern int sata_scr_valid(struct ata_link *link);
extern int sata_scr_read(struct ata_link *link, int reg, u32 *val); extern int sata_scr_read(struct ata_link *link, int reg, u32 *val);
extern int sata_scr_write(struct ata_link *link, int reg, u32 val); extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val); extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val);
extern int ata_link_online(struct ata_link *link); extern bool ata_link_online(struct ata_link *link);
extern int ata_link_offline(struct ata_link *link); extern bool ata_link_offline(struct ata_link *link);
#ifdef CONFIG_PM #ifdef CONFIG_PM
extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg); extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
extern void ata_host_resume(struct ata_host *host); extern void ata_host_resume(struct ata_host *host);
@ -1098,6 +1109,7 @@ extern void ata_std_error_handler(struct ata_port *ap);
*/ */
extern const struct ata_port_operations ata_base_port_ops; extern const struct ata_port_operations ata_base_port_ops;
extern const struct ata_port_operations sata_port_ops; extern const struct ata_port_operations sata_port_ops;
extern struct device_attribute *ata_common_sdev_attrs[];
#define ATA_BASE_SHT(drv_name) \ #define ATA_BASE_SHT(drv_name) \
.module = THIS_MODULE, \ .module = THIS_MODULE, \
@ -1112,7 +1124,8 @@ extern const struct ata_port_operations sata_port_ops;
.proc_name = drv_name, \ .proc_name = drv_name, \
.slave_configure = ata_scsi_slave_config, \ .slave_configure = ata_scsi_slave_config, \
.slave_destroy = ata_scsi_slave_destroy, \ .slave_destroy = ata_scsi_slave_destroy, \
.bios_param = ata_std_bios_param .bios_param = ata_std_bios_param, \
.sdev_attrs = ata_common_sdev_attrs
#define ATA_NCQ_SHT(drv_name) \ #define ATA_NCQ_SHT(drv_name) \
ATA_BASE_SHT(drv_name), \ ATA_BASE_SHT(drv_name), \
@ -1134,7 +1147,7 @@ static inline bool sata_pmp_attached(struct ata_port *ap)
static inline int ata_is_host_link(const struct ata_link *link) static inline int ata_is_host_link(const struct ata_link *link)
{ {
return link == &link->ap->link; return link == &link->ap->link || link == link->ap->slave_link;
} }
#else /* CONFIG_SATA_PMP */ #else /* CONFIG_SATA_PMP */
static inline bool sata_pmp_supported(struct ata_port *ap) static inline bool sata_pmp_supported(struct ata_port *ap)
@ -1167,7 +1180,7 @@ static inline int sata_srst_pmp(struct ata_link *link)
printk("%sata%u: "fmt, lv, (ap)->print_id , ##args) printk("%sata%u: "fmt, lv, (ap)->print_id , ##args)
#define ata_link_printk(link, lv, fmt, args...) do { \ #define ata_link_printk(link, lv, fmt, args...) do { \
if (sata_pmp_attached((link)->ap)) \ if (sata_pmp_attached((link)->ap) || (link)->ap->slave_link) \
printk("%sata%u.%02u: "fmt, lv, (link)->ap->print_id, \ printk("%sata%u.%02u: "fmt, lv, (link)->ap->print_id, \
(link)->pmp , ##args); \ (link)->pmp , ##args); \
else \ else \
@ -1265,34 +1278,17 @@ static inline int ata_link_active(struct ata_link *link)
return ata_tag_valid(link->active_tag) || link->sactive; return ata_tag_valid(link->active_tag) || link->sactive;
} }
static inline struct ata_link *ata_port_first_link(struct ata_port *ap) extern struct ata_link *__ata_port_next_link(struct ata_port *ap,
{ struct ata_link *link,
if (sata_pmp_attached(ap)) bool dev_only);
return ap->pmp_link;
return &ap->link;
}
static inline struct ata_link *ata_port_next_link(struct ata_link *link) #define __ata_port_for_each_link(link, ap) \
{ for ((link) = __ata_port_next_link((ap), NULL, false); (link); \
struct ata_port *ap = link->ap; (link) = __ata_port_next_link((ap), (link), false))
if (ata_is_host_link(link)) {
if (!sata_pmp_attached(ap))
return NULL;
return ap->pmp_link;
}
if (++link < ap->nr_pmp_links + ap->pmp_link)
return link;
return NULL;
}
#define __ata_port_for_each_link(lk, ap) \
for ((lk) = &(ap)->link; (lk); (lk) = ata_port_next_link(lk))
#define ata_port_for_each_link(link, ap) \ #define ata_port_for_each_link(link, ap) \
for ((link) = ata_port_first_link(ap); (link); \ for ((link) = __ata_port_next_link((ap), NULL, true); (link); \
(link) = ata_port_next_link(link)) (link) = __ata_port_next_link((ap), (link), true))
#define ata_link_for_each_dev(dev, link) \ #define ata_link_for_each_dev(dev, link) \
for ((dev) = (link)->device; \ for ((dev) = (link)->device; \