|
@@ -193,6 +193,8 @@ enum {
|
|
ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
|
|
ATA_FLAG_ACPI_SATA | ATA_FLAG_AN |
|
|
ATA_FLAG_IPM,
|
|
ATA_FLAG_IPM,
|
|
AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY,
|
|
AHCI_LFLAG_COMMON = ATA_LFLAG_SKIP_D2H_BSY,
|
|
|
|
+
|
|
|
|
+ ICH_MAP = 0x90, /* ICH MAP register */
|
|
};
|
|
};
|
|
|
|
|
|
struct ahci_cmd_hdr {
|
|
struct ahci_cmd_hdr {
|
|
@@ -1271,9 +1273,9 @@ static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
|
|
|
|
|
|
/* prepare for SRST (AHCI-1.1 10.4.1) */
|
|
/* prepare for SRST (AHCI-1.1 10.4.1) */
|
|
rc = ahci_kick_engine(ap, 1);
|
|
rc = ahci_kick_engine(ap, 1);
|
|
- if (rc)
|
|
|
|
|
|
+ if (rc && rc != -EOPNOTSUPP)
|
|
ata_link_printk(link, KERN_WARNING,
|
|
ata_link_printk(link, KERN_WARNING,
|
|
- "failed to reset engine (errno=%d)", rc);
|
|
|
|
|
|
+ "failed to reset engine (errno=%d)\n", rc);
|
|
|
|
|
|
ata_tf_init(link->device, &tf);
|
|
ata_tf_init(link->device, &tf);
|
|
|
|
|
|
@@ -1638,7 +1640,7 @@ static void ahci_port_intr(struct ata_port *ap)
|
|
struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
struct ahci_host_priv *hpriv = ap->host->private_data;
|
|
int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
|
|
int resetting = !!(ap->pflags & ATA_PFLAG_RESETTING);
|
|
u32 status, qc_active;
|
|
u32 status, qc_active;
|
|
- int rc, known_irq = 0;
|
|
|
|
|
|
+ int rc;
|
|
|
|
|
|
status = readl(port_mmio + PORT_IRQ_STAT);
|
|
status = readl(port_mmio + PORT_IRQ_STAT);
|
|
writel(status, port_mmio + PORT_IRQ_STAT);
|
|
writel(status, port_mmio + PORT_IRQ_STAT);
|
|
@@ -1696,80 +1698,12 @@ static void ahci_port_intr(struct ata_port *ap)
|
|
|
|
|
|
rc = ata_qc_complete_multiple(ap, qc_active, NULL);
|
|
rc = ata_qc_complete_multiple(ap, qc_active, NULL);
|
|
|
|
|
|
- /* If resetting, spurious or invalid completions are expected,
|
|
|
|
- * return unconditionally.
|
|
|
|
- */
|
|
|
|
- if (resetting)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- if (rc > 0)
|
|
|
|
- return;
|
|
|
|
- if (rc < 0) {
|
|
|
|
|
|
+ /* while resetting, invalid completions are expected */
|
|
|
|
+ if (unlikely(rc < 0 && !resetting)) {
|
|
ehi->err_mask |= AC_ERR_HSM;
|
|
ehi->err_mask |= AC_ERR_HSM;
|
|
ehi->action |= ATA_EH_SOFTRESET;
|
|
ehi->action |= ATA_EH_SOFTRESET;
|
|
ata_port_freeze(ap);
|
|
ata_port_freeze(ap);
|
|
- return;
|
|
|
|
}
|
|
}
|
|
-
|
|
|
|
- /* hmmm... a spurious interrupt */
|
|
|
|
-
|
|
|
|
- /* if !NCQ, ignore. No modern ATA device has broken HSM
|
|
|
|
- * implementation for non-NCQ commands.
|
|
|
|
- */
|
|
|
|
- if (!ap->link.sactive)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- if (status & PORT_IRQ_D2H_REG_FIS) {
|
|
|
|
- if (!pp->ncq_saw_d2h)
|
|
|
|
- ata_port_printk(ap, KERN_INFO,
|
|
|
|
- "D2H reg with I during NCQ, "
|
|
|
|
- "this message won't be printed again\n");
|
|
|
|
- pp->ncq_saw_d2h = 1;
|
|
|
|
- known_irq = 1;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (status & PORT_IRQ_DMAS_FIS) {
|
|
|
|
- if (!pp->ncq_saw_dmas)
|
|
|
|
- ata_port_printk(ap, KERN_INFO,
|
|
|
|
- "DMAS FIS during NCQ, "
|
|
|
|
- "this message won't be printed again\n");
|
|
|
|
- pp->ncq_saw_dmas = 1;
|
|
|
|
- known_irq = 1;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (status & PORT_IRQ_SDB_FIS) {
|
|
|
|
- const __le32 *f = pp->rx_fis + RX_FIS_SDB;
|
|
|
|
-
|
|
|
|
- if (le32_to_cpu(f[1])) {
|
|
|
|
- /* SDB FIS containing spurious completions
|
|
|
|
- * might be dangerous, whine and fail commands
|
|
|
|
- * with HSM violation. EH will turn off NCQ
|
|
|
|
- * after several such failures.
|
|
|
|
- */
|
|
|
|
- ata_ehi_push_desc(ehi,
|
|
|
|
- "spurious completions during NCQ "
|
|
|
|
- "issue=0x%x SAct=0x%x FIS=%08x:%08x",
|
|
|
|
- readl(port_mmio + PORT_CMD_ISSUE),
|
|
|
|
- readl(port_mmio + PORT_SCR_ACT),
|
|
|
|
- le32_to_cpu(f[0]), le32_to_cpu(f[1]));
|
|
|
|
- ehi->err_mask |= AC_ERR_HSM;
|
|
|
|
- ehi->action |= ATA_EH_SOFTRESET;
|
|
|
|
- ata_port_freeze(ap);
|
|
|
|
- } else {
|
|
|
|
- if (!pp->ncq_saw_sdb)
|
|
|
|
- ata_port_printk(ap, KERN_INFO,
|
|
|
|
- "spurious SDB FIS %08x:%08x during NCQ, "
|
|
|
|
- "this message won't be printed again\n",
|
|
|
|
- le32_to_cpu(f[0]), le32_to_cpu(f[1]));
|
|
|
|
- pp->ncq_saw_sdb = 1;
|
|
|
|
- }
|
|
|
|
- known_irq = 1;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (!known_irq)
|
|
|
|
- ata_port_printk(ap, KERN_INFO, "spurious interrupt "
|
|
|
|
- "(irq_stat 0x%x active_tag 0x%x sactive 0x%x)\n",
|
|
|
|
- status, ap->link.active_tag, ap->link.sactive);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static void ahci_irq_clear(struct ata_port *ap)
|
|
static void ahci_irq_clear(struct ata_port *ap)
|
|
@@ -2273,6 +2207,22 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|
if (rc)
|
|
if (rc)
|
|
return rc;
|
|
return rc;
|
|
|
|
|
|
|
|
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
|
|
|
|
+ (pdev->device == 0x2652 || pdev->device == 0x2653)) {
|
|
|
|
+ u8 map;
|
|
|
|
+
|
|
|
|
+ /* ICH6s share the same PCI ID for both piix and ahci
|
|
|
|
+ * modes. Enabling ahci mode while MAP indicates
|
|
|
|
+ * combined mode is a bad idea. Yield to ata_piix.
|
|
|
|
+ */
|
|
|
|
+ pci_read_config_byte(pdev, ICH_MAP, &map);
|
|
|
|
+ if (map & 0x3) {
|
|
|
|
+ dev_printk(KERN_INFO, &pdev->dev, "controller is in "
|
|
|
|
+ "combined mode, can't enable AHCI mode\n");
|
|
|
|
+ return -ENODEV;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
|
|
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
|
|
if (!hpriv)
|
|
if (!hpriv)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|