diff options
Diffstat (limited to 'drivers/scsi/ahci.c')
-rw-r--r-- | drivers/scsi/ahci.c | 82 |
1 files changed, 55 insertions, 27 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 19bd346951dd..30676b0eb366 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c | |||
@@ -446,10 +446,61 @@ 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 void ahci_phy_reset(struct ata_port *ap) | 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 | |||
486 | static unsigned int ahci_dev_classify(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; |
452 | struct ata_taskfile tf; | 489 | struct ata_taskfile tf; |
490 | u32 tmp; | ||
491 | |||
492 | tmp = readl(port_mmio + PORT_SIG); | ||
493 | tf.lbah = (tmp >> 24) & 0xff; | ||
494 | tf.lbam = (tmp >> 16) & 0xff; | ||
495 | tf.lbal = (tmp >> 8) & 0xff; | ||
496 | tf.nsect = (tmp) & 0xff; | ||
497 | |||
498 | return ata_dev_classify(&tf); | ||
499 | } | ||
500 | |||
501 | static void ahci_phy_reset(struct ata_port *ap) | ||
502 | { | ||
503 | void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; | ||
453 | struct ata_device *dev = &ap->device[0]; | 504 | struct ata_device *dev = &ap->device[0]; |
454 | u32 new_tmp, tmp; | 505 | u32 new_tmp, tmp; |
455 | 506 | ||
@@ -458,13 +509,7 @@ static void ahci_phy_reset(struct ata_port *ap) | |||
458 | if (ap->flags & ATA_FLAG_PORT_DISABLED) | 509 | if (ap->flags & ATA_FLAG_PORT_DISABLED) |
459 | return; | 510 | return; |
460 | 511 | ||
461 | tmp = readl(port_mmio + PORT_SIG); | 512 | dev->class = ahci_dev_classify(ap); |
462 | tf.lbah = (tmp >> 24) & 0xff; | ||
463 | tf.lbam = (tmp >> 16) & 0xff; | ||
464 | tf.lbal = (tmp >> 8) & 0xff; | ||
465 | tf.nsect = (tmp) & 0xff; | ||
466 | |||
467 | dev->class = ata_dev_classify(&tf); | ||
468 | if (!ata_dev_present(dev)) { | 513 | if (!ata_dev_present(dev)) { |
469 | ata_port_disable(ap); | 514 | ata_port_disable(ap); |
470 | return; | 515 | return; |
@@ -572,7 +617,6 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) | |||
572 | void __iomem *mmio = ap->host_set->mmio_base; | 617 | void __iomem *mmio = ap->host_set->mmio_base; |
573 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | 618 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); |
574 | u32 tmp; | 619 | u32 tmp; |
575 | int work; | ||
576 | 620 | ||
577 | if ((ap->device[0].class != ATA_DEV_ATAPI) || | 621 | if ((ap->device[0].class != ATA_DEV_ATAPI) || |
578 | ((irq_stat & PORT_IRQ_TF_ERR) == 0)) | 622 | ((irq_stat & PORT_IRQ_TF_ERR) == 0)) |
@@ -588,20 +632,7 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) | |||
588 | readl(port_mmio + PORT_SCR_ERR)); | 632 | readl(port_mmio + PORT_SCR_ERR)); |
589 | 633 | ||
590 | /* stop DMA */ | 634 | /* stop DMA */ |
591 | tmp = readl(port_mmio + PORT_CMD); | 635 | 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 | 636 | ||
606 | /* clear SATA phy error, if any */ | 637 | /* clear SATA phy error, if any */ |
607 | tmp = readl(port_mmio + PORT_SCR_ERR); | 638 | tmp = readl(port_mmio + PORT_SCR_ERR); |
@@ -620,10 +651,7 @@ static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) | |||
620 | } | 651 | } |
621 | 652 | ||
622 | /* re-start DMA */ | 653 | /* re-start DMA */ |
623 | tmp = readl(port_mmio + PORT_CMD); | 654 | ahci_start_engine(ap); |
624 | tmp |= PORT_CMD_START; | ||
625 | writel(tmp, port_mmio + PORT_CMD); | ||
626 | readl(port_mmio + PORT_CMD); /* flush */ | ||
627 | } | 655 | } |
628 | 656 | ||
629 | static void ahci_eng_timeout(struct ata_port *ap) | 657 | static void ahci_eng_timeout(struct ata_port *ap) |