diff options
Diffstat (limited to 'drivers/scsi/ahci.c')
-rw-r--r-- | drivers/scsi/ahci.c | 58 |
1 files changed, 39 insertions, 19 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 19bd346951dd..f3dfdab173f2 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c | |||
@@ -446,6 +446,43 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, | |||
446 | writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); | 446 | writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); |
447 | } | 447 | } |
448 | 448 | ||
449 | static int ahci_stop_engine(struct ata_port *ap) | ||
450 | { | ||
451 | void __iomem *mmio = ap->host_set->mmio_base; | ||
452 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | ||
453 | int work; | ||
454 | u32 tmp; | ||
455 | |||
456 | tmp = readl(port_mmio + PORT_CMD); | ||
457 | tmp &= ~PORT_CMD_START; | ||
458 | writel(tmp, port_mmio + PORT_CMD); | ||
459 | |||
460 | /* wait for engine to stop. TODO: this could be | ||
461 | * as long as 500 msec | ||
462 | */ | ||
463 | work = 1000; | ||
464 | while (work-- > 0) { | ||
465 | tmp = readl(port_mmio + PORT_CMD); | ||
466 | if ((tmp & PORT_CMD_LIST_ON) == 0) | ||
467 | return 0; | ||
468 | udelay(10); | ||
469 | } | ||
470 | |||
471 | return -EIO; | ||
472 | } | ||
473 | |||
474 | static void ahci_start_engine(struct ata_port *ap) | ||
475 | { | ||
476 | void __iomem *mmio = ap->host_set->mmio_base; | ||
477 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | ||
478 | u32 tmp; | ||
479 | |||
480 | tmp = readl(port_mmio + PORT_CMD); | ||
481 | tmp |= PORT_CMD_START; | ||
482 | writel(tmp, port_mmio + PORT_CMD); | ||
483 | readl(port_mmio + PORT_CMD); /* flush */ | ||
484 | } | ||
485 | |||
449 | static void ahci_phy_reset(struct ata_port *ap) | 486 | static void ahci_phy_reset(struct ata_port *ap) |
450 | { | 487 | { |
451 | void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; | 488 | void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; |
@@ -572,7 +609,6 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) | |||
572 | void __iomem *mmio = ap->host_set->mmio_base; | 609 | void __iomem *mmio = ap->host_set->mmio_base; |
573 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | 610 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); |
574 | u32 tmp; | 611 | u32 tmp; |
575 | int work; | ||
576 | 612 | ||
577 | if ((ap->device[0].class != ATA_DEV_ATAPI) || | 613 | if ((ap->device[0].class != ATA_DEV_ATAPI) || |
578 | ((irq_stat & PORT_IRQ_TF_ERR) == 0)) | 614 | ((irq_stat & PORT_IRQ_TF_ERR) == 0)) |
@@ -588,20 +624,7 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) | |||
588 | readl(port_mmio + PORT_SCR_ERR)); | 624 | readl(port_mmio + PORT_SCR_ERR)); |
589 | 625 | ||
590 | /* stop DMA */ | 626 | /* stop DMA */ |
591 | tmp = readl(port_mmio + PORT_CMD); | 627 | ahci_stop_engine(ap); |
592 | tmp &= ~PORT_CMD_START; | ||
593 | writel(tmp, port_mmio + PORT_CMD); | ||
594 | |||
595 | /* wait for engine to stop. TODO: this could be | ||
596 | * as long as 500 msec | ||
597 | */ | ||
598 | work = 1000; | ||
599 | while (work-- > 0) { | ||
600 | tmp = readl(port_mmio + PORT_CMD); | ||
601 | if ((tmp & PORT_CMD_LIST_ON) == 0) | ||
602 | break; | ||
603 | udelay(10); | ||
604 | } | ||
605 | 628 | ||
606 | /* clear SATA phy error, if any */ | 629 | /* clear SATA phy error, if any */ |
607 | tmp = readl(port_mmio + PORT_SCR_ERR); | 630 | tmp = readl(port_mmio + PORT_SCR_ERR); |
@@ -620,10 +643,7 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) | |||
620 | } | 643 | } |
621 | 644 | ||
622 | /* re-start DMA */ | 645 | /* re-start DMA */ |
623 | tmp = readl(port_mmio + PORT_CMD); | 646 | ahci_start_engine(ap); |
624 | tmp |= PORT_CMD_START; | ||
625 | writel(tmp, port_mmio + PORT_CMD); | ||
626 | readl(port_mmio + PORT_CMD); /* flush */ | ||
627 | } | 647 | } |
628 | 648 | ||
629 | static void ahci_eng_timeout(struct ata_port *ap) | 649 | static void ahci_eng_timeout(struct ata_port *ap) |