diff options
author | zhao, forrest <forrest.zhao@intel.com> | 2006-07-13 01:38:32 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-07-19 16:45:42 -0400 |
commit | 5457f2194ad198a0aba4190ec99a6a81846fdca5 (patch) | |
tree | 2daf5c3cc82bc7c0aea2dea04bfc1dde9287c5ef /drivers/scsi/ahci.c | |
parent | 13abf50df209008b5d44075bafeeab42ace56aa6 (diff) |
[PATCH] The redefinition of ahci_start_engine() and ahci_stop_engine()
- Make ahci_start_engine() and ahci_stop_engine() more consistent with
AHCI spec 1.1
- Change their input parameter from ap to port_mmio
- Update the existing users of ahci_start_engine() and ahci_stop_engine()
Signed-off-by: Forrest Zhao <forrest.zhao@intel.com>
Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Jens Axboe <axboe@suse.de>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/scsi/ahci.c')
-rw-r--r-- | drivers/scsi/ahci.c | 82 |
1 files changed, 57 insertions, 25 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index 77e7202a0eba..f1516ca2c52a 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c | |||
@@ -205,6 +205,8 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs * | |||
205 | static void ahci_irq_clear(struct ata_port *ap); | 205 | static void ahci_irq_clear(struct ata_port *ap); |
206 | static int ahci_port_start(struct ata_port *ap); | 206 | static int ahci_port_start(struct ata_port *ap); |
207 | static void ahci_port_stop(struct ata_port *ap); | 207 | static void ahci_port_stop(struct ata_port *ap); |
208 | static int ahci_start_engine(void __iomem *port_mmio); | ||
209 | static int ahci_stop_engine(void __iomem *port_mmio); | ||
208 | static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); | 210 | static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); |
209 | static void ahci_qc_prep(struct ata_queued_cmd *qc); | 211 | static void ahci_qc_prep(struct ata_queued_cmd *qc); |
210 | static u8 ahci_check_status(struct ata_port *ap); | 212 | static u8 ahci_check_status(struct ata_port *ap); |
@@ -508,41 +510,64 @@ static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in, | |||
508 | writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); | 510 | writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); |
509 | } | 511 | } |
510 | 512 | ||
511 | static int ahci_stop_engine(struct ata_port *ap) | 513 | static int ahci_stop_engine(void __iomem *port_mmio) |
512 | { | 514 | { |
513 | void __iomem *mmio = ap->host_set->mmio_base; | ||
514 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | ||
515 | int work; | ||
516 | u32 tmp; | 515 | u32 tmp; |
517 | 516 | ||
518 | tmp = readl(port_mmio + PORT_CMD); | 517 | tmp = readl(port_mmio + PORT_CMD); |
518 | |||
519 | /* Check if the HBA is idle */ | ||
520 | if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0) | ||
521 | return 0; | ||
522 | |||
523 | /* Setting HBA to idle */ | ||
519 | tmp &= ~PORT_CMD_START; | 524 | tmp &= ~PORT_CMD_START; |
520 | writel(tmp, port_mmio + PORT_CMD); | 525 | writel(tmp, port_mmio + PORT_CMD); |
521 | 526 | ||
522 | /* wait for engine to stop. TODO: this could be | 527 | /* wait for engine to stop. This could be |
523 | * as long as 500 msec | 528 | * as long as 500 msec |
524 | */ | 529 | */ |
525 | work = 1000; | 530 | tmp = ata_wait_register(port_mmio + PORT_CMD, |
526 | while (work-- > 0) { | 531 | PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500); |
527 | tmp = readl(port_mmio + PORT_CMD); | 532 | if(tmp & PORT_CMD_LIST_ON) |
528 | if ((tmp & PORT_CMD_LIST_ON) == 0) | 533 | return -EIO; |
529 | return 0; | ||
530 | udelay(10); | ||
531 | } | ||
532 | 534 | ||
533 | return -EIO; | 535 | return 0; |
534 | } | 536 | } |
535 | 537 | ||
536 | static void ahci_start_engine(struct ata_port *ap) | 538 | static int ahci_start_engine(void __iomem *port_mmio) |
537 | { | 539 | { |
538 | void __iomem *mmio = ap->host_set->mmio_base; | ||
539 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | ||
540 | u32 tmp; | 540 | u32 tmp; |
541 | 541 | ||
542 | /* | ||
543 | * Get current status | ||
544 | */ | ||
542 | tmp = readl(port_mmio + PORT_CMD); | 545 | tmp = readl(port_mmio + PORT_CMD); |
546 | |||
547 | /* | ||
548 | * AHCI rev 1.1 section 10.3.1: | ||
549 | * Software shall not set PxCMD.ST to '1' until it verifies | ||
550 | * that PxCMD.CR is '0' and has set PxCMD.FRE to '1' | ||
551 | */ | ||
552 | if ((tmp & PORT_CMD_FIS_RX) == 0) | ||
553 | return -EPERM; | ||
554 | |||
555 | /* | ||
556 | * wait for engine to become idle. | ||
557 | */ | ||
558 | tmp = ata_wait_register(port_mmio + PORT_CMD, | ||
559 | PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1,500); | ||
560 | if(tmp & PORT_CMD_LIST_ON) | ||
561 | return -EBUSY; | ||
562 | |||
563 | /* | ||
564 | * Start DMA | ||
565 | */ | ||
543 | tmp |= PORT_CMD_START; | 566 | tmp |= PORT_CMD_START; |
544 | writel(tmp, port_mmio + PORT_CMD); | 567 | writel(tmp, port_mmio + PORT_CMD); |
545 | readl(port_mmio + PORT_CMD); /* flush */ | 568 | readl(port_mmio + PORT_CMD); /* flush */ |
569 | |||
570 | return 0; | ||
546 | } | 571 | } |
547 | 572 | ||
548 | static unsigned int ahci_dev_classify(struct ata_port *ap) | 573 | static unsigned int ahci_dev_classify(struct ata_port *ap) |
@@ -626,7 +651,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) | |||
626 | } | 651 | } |
627 | 652 | ||
628 | /* prepare for SRST (AHCI-1.1 10.4.1) */ | 653 | /* prepare for SRST (AHCI-1.1 10.4.1) */ |
629 | rc = ahci_stop_engine(ap); | 654 | rc = ahci_stop_engine(port_mmio); |
630 | if (rc) { | 655 | if (rc) { |
631 | reason = "failed to stop engine"; | 656 | reason = "failed to stop engine"; |
632 | goto fail_restart; | 657 | goto fail_restart; |
@@ -647,7 +672,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) | |||
647 | } | 672 | } |
648 | 673 | ||
649 | /* restart engine */ | 674 | /* restart engine */ |
650 | ahci_start_engine(ap); | 675 | ahci_start_engine(port_mmio); |
651 | 676 | ||
652 | ata_tf_init(ap->device, &tf); | 677 | ata_tf_init(ap->device, &tf); |
653 | fis = pp->cmd_tbl; | 678 | fis = pp->cmd_tbl; |
@@ -706,7 +731,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class) | |||
706 | return 0; | 731 | return 0; |
707 | 732 | ||
708 | fail_restart: | 733 | fail_restart: |
709 | ahci_start_engine(ap); | 734 | ahci_start_engine(port_mmio); |
710 | fail: | 735 | fail: |
711 | ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); | 736 | ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); |
712 | return rc; | 737 | return rc; |
@@ -717,11 +742,13 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) | |||
717 | struct ahci_port_priv *pp = ap->private_data; | 742 | struct ahci_port_priv *pp = ap->private_data; |
718 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; | 743 | u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG; |
719 | struct ata_taskfile tf; | 744 | struct ata_taskfile tf; |
745 | void __iomem *mmio = ap->host_set->mmio_base; | ||
746 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | ||
720 | int rc; | 747 | int rc; |
721 | 748 | ||
722 | DPRINTK("ENTER\n"); | 749 | DPRINTK("ENTER\n"); |
723 | 750 | ||
724 | ahci_stop_engine(ap); | 751 | ahci_stop_engine(port_mmio); |
725 | 752 | ||
726 | /* clear D2H reception area to properly wait for D2H FIS */ | 753 | /* clear D2H reception area to properly wait for D2H FIS */ |
727 | ata_tf_init(ap->device, &tf); | 754 | ata_tf_init(ap->device, &tf); |
@@ -730,7 +757,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class) | |||
730 | 757 | ||
731 | rc = sata_std_hardreset(ap, class); | 758 | rc = sata_std_hardreset(ap, class); |
732 | 759 | ||
733 | ahci_start_engine(ap); | 760 | ahci_start_engine(port_mmio); |
734 | 761 | ||
735 | if (rc == 0 && ata_port_online(ap)) | 762 | if (rc == 0 && ata_port_online(ap)) |
736 | *class = ahci_dev_classify(ap); | 763 | *class = ahci_dev_classify(ap); |
@@ -1052,10 +1079,13 @@ static void ahci_thaw(struct ata_port *ap) | |||
1052 | 1079 | ||
1053 | static void ahci_error_handler(struct ata_port *ap) | 1080 | static void ahci_error_handler(struct ata_port *ap) |
1054 | { | 1081 | { |
1082 | void __iomem *mmio = ap->host_set->mmio_base; | ||
1083 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | ||
1084 | |||
1055 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) { | 1085 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) { |
1056 | /* restart engine */ | 1086 | /* restart engine */ |
1057 | ahci_stop_engine(ap); | 1087 | ahci_stop_engine(port_mmio); |
1058 | ahci_start_engine(ap); | 1088 | ahci_start_engine(port_mmio); |
1059 | } | 1089 | } |
1060 | 1090 | ||
1061 | /* perform recovery */ | 1091 | /* perform recovery */ |
@@ -1066,14 +1096,16 @@ static void ahci_error_handler(struct ata_port *ap) | |||
1066 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) | 1096 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) |
1067 | { | 1097 | { |
1068 | struct ata_port *ap = qc->ap; | 1098 | struct ata_port *ap = qc->ap; |
1099 | void __iomem *mmio = ap->host_set->mmio_base; | ||
1100 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | ||
1069 | 1101 | ||
1070 | if (qc->flags & ATA_QCFLAG_FAILED) | 1102 | if (qc->flags & ATA_QCFLAG_FAILED) |
1071 | qc->err_mask |= AC_ERR_OTHER; | 1103 | qc->err_mask |= AC_ERR_OTHER; |
1072 | 1104 | ||
1073 | if (qc->err_mask) { | 1105 | if (qc->err_mask) { |
1074 | /* make DMA engine forget about the failed command */ | 1106 | /* make DMA engine forget about the failed command */ |
1075 | ahci_stop_engine(ap); | 1107 | ahci_stop_engine(port_mmio); |
1076 | ahci_start_engine(ap); | 1108 | ahci_start_engine(port_mmio); |
1077 | } | 1109 | } |
1078 | } | 1110 | } |
1079 | 1111 | ||