Commit 4e541699 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-4.5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata

Pull libata fixes from Tejun Heo:

 - PORTS_IMPL workaround for very early ahci controllers is misbehaving
   on new systems.  Disabled on recent ahci versions.

 - Old-style PIO state machine had a horrible locking problem.  Don't
   know how we've been getting away this far.  Fixed.

 - Other device specific updates.

* 'for-4.5-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata:
  ahci: Intel DNV device IDs SATA
  libata: fix sff host state machine locking while polling
  libata-sff: use WARN instead of BUG on illegal host state machine state
  libata: disable forced PORTS_IMPL for >= AHCI 1.3
  libata: blacklist a Viking flash model for MWDMA corruption
  drivers: ata: wake port before DMA stop for ALPM
parents fb0dc5f1 342decff
...@@ -264,6 +264,26 @@ static const struct pci_device_id ahci_pci_tbl[] = { ...@@ -264,6 +264,26 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */ { PCI_VDEVICE(INTEL, 0x3b2b), board_ahci }, /* PCH RAID */
{ PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */ { PCI_VDEVICE(INTEL, 0x3b2c), board_ahci }, /* PCH RAID */
{ PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */ { PCI_VDEVICE(INTEL, 0x3b2f), board_ahci }, /* PCH AHCI */
{ PCI_VDEVICE(INTEL, 0x19b0), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19b1), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19b2), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19b3), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19b4), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19b5), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19b6), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19b7), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19bE), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19bF), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19c0), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19c1), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19c2), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19c3), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19c4), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19c5), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19c6), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19c7), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19cE), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x19cF), board_ahci }, /* DNV AHCI */
{ PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */ { PCI_VDEVICE(INTEL, 0x1c02), board_ahci }, /* CPT AHCI */
{ PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */ { PCI_VDEVICE(INTEL, 0x1c03), board_ahci }, /* CPT AHCI */
{ PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */ { PCI_VDEVICE(INTEL, 0x1c04), board_ahci }, /* CPT RAID */
......
...@@ -250,6 +250,7 @@ enum { ...@@ -250,6 +250,7 @@ enum {
AHCI_HFLAG_MULTI_MSI = 0, AHCI_HFLAG_MULTI_MSI = 0,
AHCI_HFLAG_MULTI_MSIX = 0, AHCI_HFLAG_MULTI_MSIX = 0,
#endif #endif
AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */
/* ap->flags bits */ /* ap->flags bits */
......
...@@ -317,6 +317,7 @@ static int brcm_ahci_probe(struct platform_device *pdev) ...@@ -317,6 +317,7 @@ static int brcm_ahci_probe(struct platform_device *pdev)
if (IS_ERR(hpriv)) if (IS_ERR(hpriv))
return PTR_ERR(hpriv); return PTR_ERR(hpriv);
hpriv->plat_data = priv; hpriv->plat_data = priv;
hpriv->flags = AHCI_HFLAG_WAKE_BEFORE_STOP;
brcm_sata_alpm_init(hpriv); brcm_sata_alpm_init(hpriv);
......
...@@ -496,8 +496,8 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv) ...@@ -496,8 +496,8 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
} }
} }
/* fabricate port_map from cap.nr_ports */ /* fabricate port_map from cap.nr_ports for < AHCI 1.3 */
if (!port_map) { if (!port_map && vers < 0x10300) {
port_map = (1 << ahci_nr_ports(cap)) - 1; port_map = (1 << ahci_nr_ports(cap)) - 1;
dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map); dev_warn(dev, "forcing PORTS_IMPL to 0x%x\n", port_map);
...@@ -593,8 +593,22 @@ EXPORT_SYMBOL_GPL(ahci_start_engine); ...@@ -593,8 +593,22 @@ EXPORT_SYMBOL_GPL(ahci_start_engine);
int ahci_stop_engine(struct ata_port *ap) int ahci_stop_engine(struct ata_port *ap)
{ {
void __iomem *port_mmio = ahci_port_base(ap); void __iomem *port_mmio = ahci_port_base(ap);
struct ahci_host_priv *hpriv = ap->host->private_data;
u32 tmp; u32 tmp;
/*
* On some controllers, stopping a port's DMA engine while the port
* is in ALPM state (partial or slumber) results in failures on
* subsequent DMA engine starts. For those controllers, put the
* port back in active state before stopping its DMA engine.
*/
if ((hpriv->flags & AHCI_HFLAG_WAKE_BEFORE_STOP) &&
(ap->link.lpm_policy > ATA_LPM_MAX_POWER) &&
ahci_set_lpm(&ap->link, ATA_LPM_MAX_POWER, ATA_LPM_WAKE_ONLY)) {
dev_err(ap->host->dev, "Failed to wake up port before engine stop\n");
return -EIO;
}
tmp = readl(port_mmio + PORT_CMD); tmp = readl(port_mmio + PORT_CMD);
/* check if the HBA is idle */ /* check if the HBA is idle */
...@@ -689,6 +703,9 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, ...@@ -689,6 +703,9 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
void __iomem *port_mmio = ahci_port_base(ap); void __iomem *port_mmio = ahci_port_base(ap);
if (policy != ATA_LPM_MAX_POWER) { if (policy != ATA_LPM_MAX_POWER) {
/* wakeup flag only applies to the max power policy */
hints &= ~ATA_LPM_WAKE_ONLY;
/* /*
* Disable interrupts on Phy Ready. This keeps us from * Disable interrupts on Phy Ready. This keeps us from
* getting woken up due to spurious phy ready * getting woken up due to spurious phy ready
...@@ -704,6 +721,7 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, ...@@ -704,6 +721,7 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
u32 cmd = readl(port_mmio + PORT_CMD); u32 cmd = readl(port_mmio + PORT_CMD);
if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) { if (policy == ATA_LPM_MAX_POWER || !(hints & ATA_LPM_HIPM)) {
if (!(hints & ATA_LPM_WAKE_ONLY))
cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE); cmd &= ~(PORT_CMD_ASP | PORT_CMD_ALPE);
cmd |= PORT_CMD_ICC_ACTIVE; cmd |= PORT_CMD_ICC_ACTIVE;
...@@ -712,6 +730,9 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, ...@@ -712,6 +730,9 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
/* wait 10ms to be sure we've come out of LPM state */ /* wait 10ms to be sure we've come out of LPM state */
ata_msleep(ap, 10); ata_msleep(ap, 10);
if (hints & ATA_LPM_WAKE_ONLY)
return 0;
} else { } else {
cmd |= PORT_CMD_ALPE; cmd |= PORT_CMD_ALPE;
if (policy == ATA_LPM_MIN_POWER) if (policy == ATA_LPM_MIN_POWER)
......
...@@ -4125,6 +4125,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ...@@ -4125,6 +4125,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA }, { "SAMSUNG CD-ROM SN-124", "N001", ATA_HORKAGE_NODMA },
{ "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA }, { "Seagate STT20000A", NULL, ATA_HORKAGE_NODMA },
{ " 2GB ATA Flash Disk", "ADMA428M", ATA_HORKAGE_NODMA }, { " 2GB ATA Flash Disk", "ADMA428M", ATA_HORKAGE_NODMA },
{ "VRFDFC22048UCHC-TE*", NULL, ATA_HORKAGE_NODMA },
/* Odd clown on sil3726/4726 PMPs */ /* Odd clown on sil3726/4726 PMPs */
{ "Config Disk", NULL, ATA_HORKAGE_DISABLE }, { "Config Disk", NULL, ATA_HORKAGE_DISABLE },
......
...@@ -997,12 +997,9 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap, ...@@ -997,12 +997,9 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap,
static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
{ {
struct ata_port *ap = qc->ap; struct ata_port *ap = qc->ap;
unsigned long flags;
if (ap->ops->error_handler) { if (ap->ops->error_handler) {
if (in_wq) { if (in_wq) {
spin_lock_irqsave(ap->lock, flags);
/* EH might have kicked in while host lock is /* EH might have kicked in while host lock is
* released. * released.
*/ */
...@@ -1014,8 +1011,6 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) ...@@ -1014,8 +1011,6 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
} else } else
ata_port_freeze(ap); ata_port_freeze(ap);
} }
spin_unlock_irqrestore(ap->lock, flags);
} else { } else {
if (likely(!(qc->err_mask & AC_ERR_HSM))) if (likely(!(qc->err_mask & AC_ERR_HSM)))
ata_qc_complete(qc); ata_qc_complete(qc);
...@@ -1024,10 +1019,8 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq) ...@@ -1024,10 +1019,8 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
} }
} else { } else {
if (in_wq) { if (in_wq) {
spin_lock_irqsave(ap->lock, flags);
ata_sff_irq_on(ap); ata_sff_irq_on(ap);
ata_qc_complete(qc); ata_qc_complete(qc);
spin_unlock_irqrestore(ap->lock, flags);
} else } else
ata_qc_complete(qc); ata_qc_complete(qc);
} }
...@@ -1048,9 +1041,10 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, ...@@ -1048,9 +1041,10 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
{ {
struct ata_link *link = qc->dev->link; struct ata_link *link = qc->dev->link;
struct ata_eh_info *ehi = &link->eh_info; struct ata_eh_info *ehi = &link->eh_info;
unsigned long flags = 0;
int poll_next; int poll_next;
lockdep_assert_held(ap->lock);
WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0); WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0);
/* Make sure ata_sff_qc_issue() does not throw things /* Make sure ata_sff_qc_issue() does not throw things
...@@ -1112,14 +1106,6 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, ...@@ -1112,14 +1106,6 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
} }
} }
/* Send the CDB (atapi) or the first data block (ata pio out).
* During the state transition, interrupt handler shouldn't
* be invoked before the data transfer is complete and
* hsm_task_state is changed. Hence, the following locking.
*/
if (in_wq)
spin_lock_irqsave(ap->lock, flags);
if (qc->tf.protocol == ATA_PROT_PIO) { if (qc->tf.protocol == ATA_PROT_PIO) {
/* PIO data out protocol. /* PIO data out protocol.
* send first data block. * send first data block.
...@@ -1135,9 +1121,6 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, ...@@ -1135,9 +1121,6 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
/* send CDB */ /* send CDB */
atapi_send_cdb(ap, qc); atapi_send_cdb(ap, qc);
if (in_wq)
spin_unlock_irqrestore(ap->lock, flags);
/* if polling, ata_sff_pio_task() handles the rest. /* if polling, ata_sff_pio_task() handles the rest.
* otherwise, interrupt handler takes over from here. * otherwise, interrupt handler takes over from here.
*/ */
...@@ -1296,7 +1279,8 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, ...@@ -1296,7 +1279,8 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
break; break;
default: default:
poll_next = 0; poll_next = 0;
BUG(); WARN(true, "ata%d: SFF host state machine in invalid state %d",
ap->print_id, ap->hsm_task_state);
} }
return poll_next; return poll_next;
...@@ -1361,12 +1345,14 @@ static void ata_sff_pio_task(struct work_struct *work) ...@@ -1361,12 +1345,14 @@ static void ata_sff_pio_task(struct work_struct *work)
u8 status; u8 status;
int poll_next; int poll_next;
spin_lock_irq(ap->lock);
BUG_ON(ap->sff_pio_task_link == NULL); BUG_ON(ap->sff_pio_task_link == NULL);
/* qc can be NULL if timeout occurred */ /* qc can be NULL if timeout occurred */
qc = ata_qc_from_tag(ap, link->active_tag); qc = ata_qc_from_tag(ap, link->active_tag);
if (!qc) { if (!qc) {
ap->sff_pio_task_link = NULL; ap->sff_pio_task_link = NULL;
return; goto out_unlock;
} }
fsm_start: fsm_start:
...@@ -1381,11 +1367,14 @@ static void ata_sff_pio_task(struct work_struct *work) ...@@ -1381,11 +1367,14 @@ static void ata_sff_pio_task(struct work_struct *work)
*/ */
status = ata_sff_busy_wait(ap, ATA_BUSY, 5); status = ata_sff_busy_wait(ap, ATA_BUSY, 5);
if (status & ATA_BUSY) { if (status & ATA_BUSY) {
spin_unlock_irq(ap->lock);
ata_msleep(ap, 2); ata_msleep(ap, 2);
spin_lock_irq(ap->lock);
status = ata_sff_busy_wait(ap, ATA_BUSY, 10); status = ata_sff_busy_wait(ap, ATA_BUSY, 10);
if (status & ATA_BUSY) { if (status & ATA_BUSY) {
ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE); ata_sff_queue_pio_task(link, ATA_SHORT_PAUSE);
return; goto out_unlock;
} }
} }
...@@ -1402,6 +1391,8 @@ static void ata_sff_pio_task(struct work_struct *work) ...@@ -1402,6 +1391,8 @@ static void ata_sff_pio_task(struct work_struct *work)
*/ */
if (poll_next) if (poll_next)
goto fsm_start; goto fsm_start;
out_unlock:
spin_unlock_irq(ap->lock);
} }
/** /**
......
...@@ -526,6 +526,7 @@ enum ata_lpm_policy { ...@@ -526,6 +526,7 @@ enum ata_lpm_policy {
enum ata_lpm_hints { enum ata_lpm_hints {
ATA_LPM_EMPTY = (1 << 0), /* port empty/probing */ ATA_LPM_EMPTY = (1 << 0), /* port empty/probing */
ATA_LPM_HIPM = (1 << 1), /* may use HIPM */ ATA_LPM_HIPM = (1 << 1), /* may use HIPM */
ATA_LPM_WAKE_ONLY = (1 << 2), /* only wake up link */
}; };
/* forward declarations */ /* forward declarations */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment