aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/ahci.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 95229e77bffe..49cf4cf1a5a2 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -41,6 +41,7 @@
41#include <linux/interrupt.h> 41#include <linux/interrupt.h>
42#include <linux/dma-mapping.h> 42#include <linux/dma-mapping.h>
43#include <linux/device.h> 43#include <linux/device.h>
44#include <linux/dmi.h>
44#include <scsi/scsi_host.h> 45#include <scsi/scsi_host.h>
45#include <scsi/scsi_cmnd.h> 46#include <scsi/scsi_cmnd.h>
46#include <linux/libata.h> 47#include <linux/libata.h>
@@ -241,6 +242,7 @@ static void ahci_pmp_attach(struct ata_port *ap);
241static void ahci_pmp_detach(struct ata_port *ap); 242static void ahci_pmp_detach(struct ata_port *ap);
242static void ahci_error_handler(struct ata_port *ap); 243static void ahci_error_handler(struct ata_port *ap);
243static void ahci_vt8251_error_handler(struct ata_port *ap); 244static void ahci_vt8251_error_handler(struct ata_port *ap);
245static void ahci_p5wdh_error_handler(struct ata_port *ap);
244static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); 246static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
245static int ahci_port_resume(struct ata_port *ap); 247static int ahci_port_resume(struct ata_port *ap);
246static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl); 248static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
@@ -339,6 +341,40 @@ static const struct ata_port_operations ahci_vt8251_ops = {
339 .port_stop = ahci_port_stop, 341 .port_stop = ahci_port_stop,
340}; 342};
341 343
344static const struct ata_port_operations ahci_p5wdh_ops = {
345 .check_status = ahci_check_status,
346 .check_altstatus = ahci_check_status,
347 .dev_select = ata_noop_dev_select,
348
349 .tf_read = ahci_tf_read,
350
351 .qc_defer = sata_pmp_qc_defer_cmd_switch,
352 .qc_prep = ahci_qc_prep,
353 .qc_issue = ahci_qc_issue,
354
355 .irq_clear = ahci_irq_clear,
356
357 .scr_read = ahci_scr_read,
358 .scr_write = ahci_scr_write,
359
360 .freeze = ahci_freeze,
361 .thaw = ahci_thaw,
362
363 .error_handler = ahci_p5wdh_error_handler,
364 .post_internal_cmd = ahci_post_internal_cmd,
365
366 .pmp_attach = ahci_pmp_attach,
367 .pmp_detach = ahci_pmp_detach,
368
369#ifdef CONFIG_PM
370 .port_suspend = ahci_port_suspend,
371 .port_resume = ahci_port_resume,
372#endif
373
374 .port_start = ahci_port_start,
375 .port_stop = ahci_port_stop,
376};
377
342#define AHCI_HFLAGS(flags) .private_data = (void *)(flags) 378#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
343 379
344static const struct ata_port_info ahci_port_info[] = { 380static const struct ata_port_info ahci_port_info[] = {
@@ -1213,6 +1249,53 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
1213 return rc ?: -EAGAIN; 1249 return rc ?: -EAGAIN;
1214} 1250}
1215 1251
1252static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
1253 unsigned long deadline)
1254{
1255 struct ata_port *ap = link->ap;
1256 struct ahci_port_priv *pp = ap->private_data;
1257 u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
1258 struct ata_taskfile tf;
1259 int rc;
1260
1261 ahci_stop_engine(ap);
1262
1263 /* clear D2H reception area to properly wait for D2H FIS */
1264 ata_tf_init(link->device, &tf);
1265 tf.command = 0x80;
1266 ata_tf_to_fis(&tf, 0, 0, d2h_fis);
1267
1268 rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
1269 deadline);
1270
1271 ahci_start_engine(ap);
1272
1273 if (rc || ata_link_offline(link))
1274 return rc;
1275
1276 /* spec mandates ">= 2ms" before checking status */
1277 msleep(150);
1278
1279 /* The pseudo configuration device on SIMG4726 attached to
1280 * ASUS P5W-DH Deluxe doesn't send signature FIS after
1281 * hardreset if no device is attached to the first downstream
1282 * port && the pseudo device locks up on SRST w/ PMP==0. To
1283 * work around this, wait for !BSY only briefly. If BSY isn't
1284 * cleared, perform CLO and proceed to IDENTIFY (achieved by
1285 * ATA_LFLAG_NO_SRST and ATA_LFLAG_ASSUME_ATA).
1286 *
1287 * Wait for two seconds. Devices attached to downstream port
1288 * which can't process the following IDENTIFY after this will
1289 * have to be reset again. For most cases, this should
1290 * suffice while making probing snappish enough.
1291 */
1292 rc = ata_wait_ready(ap, jiffies + 2 * HZ);
1293 if (rc)
1294 ahci_kick_engine(ap, 0);
1295
1296 return 0;
1297}
1298
1216static void ahci_postreset(struct ata_link *link, unsigned int *class) 1299static void ahci_postreset(struct ata_link *link, unsigned int *class)
1217{ 1300{
1218 struct ata_port *ap = link->ap; 1301 struct ata_port *ap = link->ap;
@@ -1670,6 +1753,19 @@ static void ahci_vt8251_error_handler(struct ata_port *ap)
1670 ahci_postreset); 1753 ahci_postreset);
1671} 1754}
1672 1755
1756static void ahci_p5wdh_error_handler(struct ata_port *ap)
1757{
1758 if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
1759 /* restart engine */
1760 ahci_stop_engine(ap);
1761 ahci_start_engine(ap);
1762 }
1763
1764 /* perform recovery */
1765 ata_do_eh(ap, ata_std_prereset, ahci_softreset, ahci_p5wdh_hardreset,
1766 ahci_postreset);
1767}
1768
1673static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) 1769static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
1674{ 1770{
1675 struct ata_port *ap = qc->ap; 1771 struct ata_port *ap = qc->ap;
@@ -1955,6 +2051,51 @@ static void ahci_print_info(struct ata_host *host)
1955 ); 2051 );
1956} 2052}
1957 2053
2054/* On ASUS P5W DH Deluxe, the second port of PCI device 00:1f.2 is
2055 * hardwired to on-board SIMG 4726. The chipset is ICH8 and doesn't
2056 * support PMP and the 4726 either directly exports the device
2057 * attached to the first downstream port or acts as a hardware storage
2058 * controller and emulate a single ATA device (can be RAID 0/1 or some
2059 * other configuration).
2060 *
2061 * When there's no device attached to the first downstream port of the
2062 * 4726, "Config Disk" appears, which is a pseudo ATA device to
2063 * configure the 4726. However, ATA emulation of the device is very
2064 * lame. It doesn't send signature D2H Reg FIS after the initial
2065 * hardreset, pukes on SRST w/ PMP==0 and has bunch of other issues.
2066 *
2067 * The following function works around the problem by always using
2068 * hardreset on the port and not depending on receiving signature FIS
2069 * afterward. If signature FIS isn't received soon, ATA class is
2070 * assumed without follow-up softreset.
2071 */
2072static void ahci_p5wdh_workaround(struct ata_host *host)
2073{
2074 static struct dmi_system_id sysids[] = {
2075 {
2076 .ident = "P5W DH Deluxe",
2077 .matches = {
2078 DMI_MATCH(DMI_SYS_VENDOR,
2079 "ASUSTEK COMPUTER INC"),
2080 DMI_MATCH(DMI_PRODUCT_NAME, "P5W DH Deluxe"),
2081 },
2082 },
2083 { }
2084 };
2085 struct pci_dev *pdev = to_pci_dev(host->dev);
2086
2087 if (pdev->bus->number == 0 && pdev->devfn == PCI_DEVFN(0x1f, 2) &&
2088 dmi_check_system(sysids)) {
2089 struct ata_port *ap = host->ports[1];
2090
2091 dev_printk(KERN_INFO, &pdev->dev, "enabling ASUS P5W DH "
2092 "Deluxe on-board SIMG4726 workaround\n");
2093
2094 ap->ops = &ahci_p5wdh_ops;
2095 ap->link.flags |= ATA_LFLAG_NO_SRST | ATA_LFLAG_ASSUME_ATA;
2096 }
2097}
2098
1958static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 2099static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
1959{ 2100{
1960 static int printed_version; 2101 static int printed_version;
@@ -2024,6 +2165,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2024 ap->ops = &ata_dummy_port_ops; 2165 ap->ops = &ata_dummy_port_ops;
2025 } 2166 }
2026 2167
2168 /* apply workaround for ASUS P5W DH Deluxe mainboard */
2169 ahci_p5wdh_workaround(host);
2170
2027 /* initialize adapter */ 2171 /* initialize adapter */
2028 rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64); 2172 rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
2029 if (rc) 2173 if (rc)