aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/ahci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/ata/ahci.c')
-rw-r--r--drivers/ata/ahci.c99
1 files changed, 82 insertions, 17 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 1c62b8e39645..966ab401e523 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -255,6 +255,8 @@ static void ahci_pmp_attach(struct ata_port *ap);
255static void ahci_pmp_detach(struct ata_port *ap); 255static void ahci_pmp_detach(struct ata_port *ap);
256static int ahci_softreset(struct ata_link *link, unsigned int *class, 256static int ahci_softreset(struct ata_link *link, unsigned int *class,
257 unsigned long deadline); 257 unsigned long deadline);
258static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
259 unsigned long deadline);
258static int ahci_hardreset(struct ata_link *link, unsigned int *class, 260static int ahci_hardreset(struct ata_link *link, unsigned int *class,
259 unsigned long deadline); 261 unsigned long deadline);
260static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, 262static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
@@ -331,6 +333,12 @@ static struct ata_port_operations ahci_p5wdh_ops = {
331 .hardreset = ahci_p5wdh_hardreset, 333 .hardreset = ahci_p5wdh_hardreset,
332}; 334};
333 335
336static struct ata_port_operations ahci_sb600_ops = {
337 .inherits = &ahci_ops,
338 .softreset = ahci_sb600_softreset,
339 .pmp_softreset = ahci_sb600_softreset,
340};
341
334#define AHCI_HFLAGS(flags) .private_data = (void *)(flags) 342#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
335 343
336static const struct ata_port_info ahci_port_info[] = { 344static const struct ata_port_info ahci_port_info[] = {
@@ -361,11 +369,11 @@ static const struct ata_port_info ahci_port_info[] = {
361 { 369 {
362 AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | 370 AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
363 AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | 371 AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
364 AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP), 372 AHCI_HFLAG_SECT255),
365 .flags = AHCI_FLAG_COMMON, 373 .flags = AHCI_FLAG_COMMON,
366 .pio_mask = 0x1f, /* pio0-4 */ 374 .pio_mask = 0x1f, /* pio0-4 */
367 .udma_mask = ATA_UDMA6, 375 .udma_mask = ATA_UDMA6,
368 .port_ops = &ahci_ops, 376 .port_ops = &ahci_sb600_ops,
369 }, 377 },
370 /* board_ahci_mv */ 378 /* board_ahci_mv */
371 { 379 {
@@ -379,12 +387,11 @@ static const struct ata_port_info ahci_port_info[] = {
379 }, 387 },
380 /* board_ahci_sb700 */ 388 /* board_ahci_sb700 */
381 { 389 {
382 AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | 390 AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL),
383 AHCI_HFLAG_NO_PMP),
384 .flags = AHCI_FLAG_COMMON, 391 .flags = AHCI_FLAG_COMMON,
385 .pio_mask = 0x1f, /* pio0-4 */ 392 .pio_mask = 0x1f, /* pio0-4 */
386 .udma_mask = ATA_UDMA6, 393 .udma_mask = ATA_UDMA6,
387 .port_ops = &ahci_ops, 394 .port_ops = &ahci_sb600_ops,
388 }, 395 },
389 /* board_ahci_mcp65 */ 396 /* board_ahci_mcp65 */
390 { 397 {
@@ -1278,19 +1285,11 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
1278 return 0; 1285 return 0;
1279} 1286}
1280 1287
1281static int ahci_check_ready(struct ata_link *link) 1288static int ahci_do_softreset(struct ata_link *link, unsigned int *class,
1282{ 1289 int pmp, unsigned long deadline,
1283 void __iomem *port_mmio = ahci_port_base(link->ap); 1290 int (*check_ready)(struct ata_link *link))
1284 u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1285
1286 return ata_check_ready(status);
1287}
1288
1289static int ahci_softreset(struct ata_link *link, unsigned int *class,
1290 unsigned long deadline)
1291{ 1291{
1292 struct ata_port *ap = link->ap; 1292 struct ata_port *ap = link->ap;
1293 int pmp = sata_srst_pmp(link);
1294 const char *reason = NULL; 1293 const char *reason = NULL;
1295 unsigned long now, msecs; 1294 unsigned long now, msecs;
1296 struct ata_taskfile tf; 1295 struct ata_taskfile tf;
@@ -1328,7 +1327,7 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
1328 ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); 1327 ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
1329 1328
1330 /* wait for link to become ready */ 1329 /* wait for link to become ready */
1331 rc = ata_wait_after_reset(link, deadline, ahci_check_ready); 1330 rc = ata_wait_after_reset(link, deadline, check_ready);
1332 /* link occupied, -ENODEV too is an error */ 1331 /* link occupied, -ENODEV too is an error */
1333 if (rc) { 1332 if (rc) {
1334 reason = "device not ready"; 1333 reason = "device not ready";
@@ -1344,6 +1343,72 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class,
1344 return rc; 1343 return rc;
1345} 1344}
1346 1345
1346static int ahci_check_ready(struct ata_link *link)
1347{
1348 void __iomem *port_mmio = ahci_port_base(link->ap);
1349 u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1350
1351 return ata_check_ready(status);
1352}
1353
1354static int ahci_softreset(struct ata_link *link, unsigned int *class,
1355 unsigned long deadline)
1356{
1357 int pmp = sata_srst_pmp(link);
1358
1359 DPRINTK("ENTER\n");
1360
1361 return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
1362}
1363
1364static int ahci_sb600_check_ready(struct ata_link *link)
1365{
1366 void __iomem *port_mmio = ahci_port_base(link->ap);
1367 u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
1368 u32 irq_status = readl(port_mmio + PORT_IRQ_STAT);
1369
1370 /*
1371 * There is no need to check TFDATA if BAD PMP is found due to HW bug,
1372 * which can save timeout delay.
1373 */
1374 if (irq_status & PORT_IRQ_BAD_PMP)
1375 return -EIO;
1376
1377 return ata_check_ready(status);
1378}
1379
1380static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class,
1381 unsigned long deadline)
1382{
1383 struct ata_port *ap = link->ap;
1384 void __iomem *port_mmio = ahci_port_base(ap);
1385 int pmp = sata_srst_pmp(link);
1386 int rc;
1387 u32 irq_sts;
1388
1389 DPRINTK("ENTER\n");
1390
1391 rc = ahci_do_softreset(link, class, pmp, deadline,
1392 ahci_sb600_check_ready);
1393
1394 /*
1395 * Soft reset fails on some ATI chips with IPMS set when PMP
1396 * is enabled but SATA HDD/ODD is connected to SATA port,
1397 * do soft reset again to port 0.
1398 */
1399 if (rc == -EIO) {
1400 irq_sts = readl(port_mmio + PORT_IRQ_STAT);
1401 if (irq_sts & PORT_IRQ_BAD_PMP) {
1402 ata_link_printk(link, KERN_WARNING,
1403 "failed due to HW bug, retry pmp=0\n");
1404 rc = ahci_do_softreset(link, class, 0, deadline,
1405 ahci_check_ready);
1406 }
1407 }
1408
1409 return rc;
1410}
1411
1347static int ahci_hardreset(struct ata_link *link, unsigned int *class, 1412static int ahci_hardreset(struct ata_link *link, unsigned int *class,
1348 unsigned long deadline) 1413 unsigned long deadline)
1349{ 1414{