diff options
| -rw-r--r-- | drivers/scsi/ahci.c | 237 |
1 files changed, 137 insertions, 100 deletions
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index a4fb8d0a6c08..d6894bd67980 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c | |||
| @@ -71,6 +71,7 @@ enum { | |||
| 71 | AHCI_CMD_CLR_BUSY = (1 << 10), | 71 | AHCI_CMD_CLR_BUSY = (1 << 10), |
| 72 | 72 | ||
| 73 | RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ | 73 | RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */ |
| 74 | RX_FIS_UNK = 0x60, /* offset of Unknown FIS data */ | ||
| 74 | 75 | ||
| 75 | board_ahci = 0, | 76 | board_ahci = 0, |
| 76 | board_ahci_vt8251 = 1, | 77 | board_ahci_vt8251 = 1, |
| @@ -128,15 +129,16 @@ enum { | |||
| 128 | PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ | 129 | PORT_IRQ_PIOS_FIS = (1 << 1), /* PIO Setup FIS rx'd */ |
| 129 | PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ | 130 | PORT_IRQ_D2H_REG_FIS = (1 << 0), /* D2H Register FIS rx'd */ |
| 130 | 131 | ||
| 131 | PORT_IRQ_FATAL = PORT_IRQ_TF_ERR | | 132 | PORT_IRQ_FREEZE = PORT_IRQ_HBUS_ERR | |
| 132 | PORT_IRQ_HBUS_ERR | | 133 | PORT_IRQ_IF_ERR | |
| 133 | PORT_IRQ_HBUS_DATA_ERR | | 134 | PORT_IRQ_CONNECT | |
| 134 | PORT_IRQ_IF_ERR, | 135 | PORT_IRQ_UNK_FIS, |
| 135 | DEF_PORT_IRQ = PORT_IRQ_FATAL | PORT_IRQ_PHYRDY | | 136 | PORT_IRQ_ERROR = PORT_IRQ_FREEZE | |
| 136 | PORT_IRQ_CONNECT | PORT_IRQ_SG_DONE | | 137 | PORT_IRQ_TF_ERR | |
| 137 | PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_FIS | | 138 | PORT_IRQ_HBUS_DATA_ERR, |
| 138 | PORT_IRQ_DMAS_FIS | PORT_IRQ_PIOS_FIS | | 139 | DEF_PORT_IRQ = PORT_IRQ_ERROR | PORT_IRQ_SG_DONE | |
| 139 | PORT_IRQ_D2H_REG_FIS, | 140 | PORT_IRQ_SDB_FIS | PORT_IRQ_DMAS_FIS | |
| 141 | PORT_IRQ_PIOS_FIS | PORT_IRQ_D2H_REG_FIS, | ||
| 140 | 142 | ||
| 141 | /* PORT_CMD bits */ | 143 | /* PORT_CMD bits */ |
| 142 | PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ | 144 | PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ |
| @@ -197,13 +199,15 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc); | |||
| 197 | static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs); | 199 | static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs); |
| 198 | static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes); | 200 | static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes); |
| 199 | static void ahci_irq_clear(struct ata_port *ap); | 201 | static void ahci_irq_clear(struct ata_port *ap); |
| 200 | static void ahci_eng_timeout(struct ata_port *ap); | ||
| 201 | static int ahci_port_start(struct ata_port *ap); | 202 | static int ahci_port_start(struct ata_port *ap); |
| 202 | static void ahci_port_stop(struct ata_port *ap); | 203 | static void ahci_port_stop(struct ata_port *ap); |
| 203 | static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); | 204 | static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); |
| 204 | static void ahci_qc_prep(struct ata_queued_cmd *qc); | 205 | static void ahci_qc_prep(struct ata_queued_cmd *qc); |
| 205 | static u8 ahci_check_status(struct ata_port *ap); | 206 | static u8 ahci_check_status(struct ata_port *ap); |
| 206 | static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); | 207 | static void ahci_freeze(struct ata_port *ap); |
| 208 | static void ahci_thaw(struct ata_port *ap); | ||
| 209 | static void ahci_error_handler(struct ata_port *ap); | ||
| 210 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc); | ||
| 207 | static void ahci_remove_one (struct pci_dev *pdev); | 211 | static void ahci_remove_one (struct pci_dev *pdev); |
| 208 | 212 | ||
| 209 | static struct scsi_host_template ahci_sht = { | 213 | static struct scsi_host_template ahci_sht = { |
| @@ -237,14 +241,18 @@ static const struct ata_port_operations ahci_ops = { | |||
| 237 | .qc_prep = ahci_qc_prep, | 241 | .qc_prep = ahci_qc_prep, |
| 238 | .qc_issue = ahci_qc_issue, | 242 | .qc_issue = ahci_qc_issue, |
| 239 | 243 | ||
| 240 | .eng_timeout = ahci_eng_timeout, | ||
| 241 | |||
| 242 | .irq_handler = ahci_interrupt, | 244 | .irq_handler = ahci_interrupt, |
| 243 | .irq_clear = ahci_irq_clear, | 245 | .irq_clear = ahci_irq_clear, |
| 244 | 246 | ||
| 245 | .scr_read = ahci_scr_read, | 247 | .scr_read = ahci_scr_read, |
| 246 | .scr_write = ahci_scr_write, | 248 | .scr_write = ahci_scr_write, |
| 247 | 249 | ||
| 250 | .freeze = ahci_freeze, | ||
| 251 | .thaw = ahci_thaw, | ||
| 252 | |||
| 253 | .error_handler = ahci_error_handler, | ||
| 254 | .post_internal_cmd = ahci_post_internal_cmd, | ||
| 255 | |||
| 248 | .port_start = ahci_port_start, | 256 | .port_start = ahci_port_start, |
| 249 | .port_stop = ahci_port_stop, | 257 | .port_stop = ahci_port_stop, |
| 250 | }; | 258 | }; |
| @@ -789,108 +797,97 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc) | |||
| 789 | ahci_fill_cmd_slot(pp, opts); | 797 | ahci_fill_cmd_slot(pp, opts); |
| 790 | } | 798 | } |
| 791 | 799 | ||
| 792 | static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) | 800 | static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) |
| 793 | { | 801 | { |
| 794 | void __iomem *mmio = ap->host_set->mmio_base; | 802 | struct ahci_port_priv *pp = ap->private_data; |
| 795 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | 803 | struct ata_eh_info *ehi = &ap->eh_info; |
| 796 | u32 tmp; | 804 | unsigned int err_mask = 0, action = 0; |
| 805 | struct ata_queued_cmd *qc; | ||
| 806 | u32 serror; | ||
| 797 | 807 | ||
| 798 | if ((ap->device[0].class != ATA_DEV_ATAPI) || | 808 | ata_ehi_clear_desc(ehi); |
| 799 | ((irq_stat & PORT_IRQ_TF_ERR) == 0)) | ||
| 800 | ata_port_printk(ap, KERN_WARNING, "port reset, " | ||
| 801 | "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n", | ||
| 802 | irq_stat, | ||
| 803 | readl(mmio + HOST_IRQ_STAT), | ||
| 804 | readl(port_mmio + PORT_IRQ_STAT), | ||
| 805 | readl(port_mmio + PORT_CMD), | ||
| 806 | readl(port_mmio + PORT_TFDATA), | ||
| 807 | readl(port_mmio + PORT_SCR_STAT), | ||
| 808 | readl(port_mmio + PORT_SCR_ERR)); | ||
| 809 | |||
| 810 | /* stop DMA */ | ||
| 811 | ahci_stop_engine(ap); | ||
| 812 | 809 | ||
| 813 | /* clear SATA phy error, if any */ | 810 | /* AHCI needs SError cleared; otherwise, it might lock up */ |
| 814 | tmp = readl(port_mmio + PORT_SCR_ERR); | 811 | serror = ahci_scr_read(ap, SCR_ERROR); |
| 815 | writel(tmp, port_mmio + PORT_SCR_ERR); | 812 | ahci_scr_write(ap, SCR_ERROR, serror); |
| 816 | 813 | ||
| 817 | /* if DRQ/BSY is set, device needs to be reset. | 814 | /* analyze @irq_stat */ |
| 818 | * if so, issue COMRESET | 815 | ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); |
| 819 | */ | 816 | |
| 820 | tmp = readl(port_mmio + PORT_TFDATA); | 817 | if (irq_stat & PORT_IRQ_TF_ERR) |
| 821 | if (tmp & (ATA_BUSY | ATA_DRQ)) { | 818 | err_mask |= AC_ERR_DEV; |
| 822 | writel(0x301, port_mmio + PORT_SCR_CTL); | 819 | |
| 823 | readl(port_mmio + PORT_SCR_CTL); /* flush */ | 820 | if (irq_stat & (PORT_IRQ_HBUS_ERR | PORT_IRQ_HBUS_DATA_ERR)) { |
| 824 | udelay(10); | 821 | err_mask |= AC_ERR_HOST_BUS; |
| 825 | writel(0x300, port_mmio + PORT_SCR_CTL); | 822 | action |= ATA_EH_SOFTRESET; |
| 826 | readl(port_mmio + PORT_SCR_CTL); /* flush */ | ||
| 827 | } | 823 | } |
| 828 | 824 | ||
| 829 | /* re-start DMA */ | 825 | if (irq_stat & PORT_IRQ_IF_ERR) { |
| 830 | ahci_start_engine(ap); | 826 | err_mask |= AC_ERR_ATA_BUS; |
| 831 | } | 827 | action |= ATA_EH_SOFTRESET; |
| 828 | ata_ehi_push_desc(ehi, ", interface fatal error"); | ||
| 829 | } | ||
| 832 | 830 | ||
| 833 | static void ahci_eng_timeout(struct ata_port *ap) | 831 | if (irq_stat & (PORT_IRQ_CONNECT | PORT_IRQ_PHYRDY)) { |
| 834 | { | 832 | err_mask |= AC_ERR_ATA_BUS; |
| 835 | struct ata_host_set *host_set = ap->host_set; | 833 | action |= ATA_EH_SOFTRESET; |
| 836 | void __iomem *mmio = host_set->mmio_base; | 834 | ata_ehi_push_desc(ehi, ", %s", irq_stat & PORT_IRQ_CONNECT ? |
| 837 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | 835 | "connection status changed" : "PHY RDY changed"); |
| 838 | struct ata_queued_cmd *qc; | 836 | } |
| 839 | unsigned long flags; | 837 | |
| 838 | if (irq_stat & PORT_IRQ_UNK_FIS) { | ||
| 839 | u32 *unk = (u32 *)(pp->rx_fis + RX_FIS_UNK); | ||
| 840 | 840 | ||
| 841 | ata_port_printk(ap, KERN_WARNING, "handling error/timeout\n"); | 841 | err_mask |= AC_ERR_HSM; |
| 842 | action |= ATA_EH_SOFTRESET; | ||
| 843 | ata_ehi_push_desc(ehi, ", unknown FIS %08x %08x %08x %08x", | ||
| 844 | unk[0], unk[1], unk[2], unk[3]); | ||
| 845 | } | ||
| 842 | 846 | ||
| 843 | spin_lock_irqsave(&host_set->lock, flags); | 847 | /* okay, let's hand over to EH */ |
| 848 | ehi->serror |= serror; | ||
| 849 | ehi->action |= action; | ||
| 844 | 850 | ||
| 845 | ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT)); | ||
| 846 | qc = ata_qc_from_tag(ap, ap->active_tag); | 851 | qc = ata_qc_from_tag(ap, ap->active_tag); |
| 847 | qc->err_mask |= AC_ERR_TIMEOUT; | 852 | if (qc) |
| 848 | 853 | qc->err_mask |= err_mask; | |
| 849 | spin_unlock_irqrestore(&host_set->lock, flags); | 854 | else |
| 855 | ehi->err_mask |= err_mask; | ||
| 850 | 856 | ||
| 851 | ata_eh_qc_complete(qc); | 857 | if (irq_stat & PORT_IRQ_FREEZE) |
| 858 | ata_port_freeze(ap); | ||
| 859 | else | ||
| 860 | ata_port_abort(ap); | ||
| 852 | } | 861 | } |
| 853 | 862 | ||
| 854 | static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc) | 863 | static void ahci_host_intr(struct ata_port *ap) |
| 855 | { | 864 | { |
| 856 | void __iomem *mmio = ap->host_set->mmio_base; | 865 | void __iomem *mmio = ap->host_set->mmio_base; |
| 857 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | 866 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); |
| 858 | u32 status, serr, ci; | 867 | struct ata_queued_cmd *qc; |
| 859 | 868 | u32 status, ci; | |
| 860 | serr = readl(port_mmio + PORT_SCR_ERR); | ||
| 861 | writel(serr, port_mmio + PORT_SCR_ERR); | ||
| 862 | 869 | ||
| 863 | status = readl(port_mmio + PORT_IRQ_STAT); | 870 | status = readl(port_mmio + PORT_IRQ_STAT); |
| 864 | writel(status, port_mmio + PORT_IRQ_STAT); | 871 | writel(status, port_mmio + PORT_IRQ_STAT); |
| 865 | 872 | ||
| 866 | ci = readl(port_mmio + PORT_CMD_ISSUE); | 873 | if (unlikely(status & PORT_IRQ_ERROR)) { |
| 867 | if (likely((ci & 0x1) == 0)) { | 874 | ahci_error_intr(ap, status); |
| 868 | if (qc) { | 875 | return; |
| 869 | WARN_ON(qc->err_mask); | ||
| 870 | ata_qc_complete(qc); | ||
| 871 | qc = NULL; | ||
| 872 | } | ||
| 873 | } | 876 | } |
| 874 | 877 | ||
| 875 | if (status & PORT_IRQ_FATAL) { | 878 | if ((qc = ata_qc_from_tag(ap, ap->active_tag))) { |
| 876 | unsigned int err_mask; | 879 | ci = readl(port_mmio + PORT_CMD_ISSUE); |
| 877 | if (status & PORT_IRQ_TF_ERR) | 880 | if ((ci & 0x1) == 0) { |
| 878 | err_mask = AC_ERR_DEV; | ||
| 879 | else if (status & PORT_IRQ_IF_ERR) | ||
| 880 | err_mask = AC_ERR_ATA_BUS; | ||
| 881 | else | ||
| 882 | err_mask = AC_ERR_HOST_BUS; | ||
| 883 | |||
| 884 | /* command processing has stopped due to error; restart */ | ||
| 885 | ahci_restart_port(ap, status); | ||
| 886 | |||
| 887 | if (qc) { | ||
| 888 | qc->err_mask |= err_mask; | ||
| 889 | ata_qc_complete(qc); | 881 | ata_qc_complete(qc); |
| 882 | return; | ||
| 890 | } | 883 | } |
| 891 | } | 884 | } |
| 892 | 885 | ||
| 893 | return 1; | 886 | /* spurious interrupt */ |
| 887 | if (ata_ratelimit()) | ||
| 888 | ata_port_printk(ap, KERN_INFO, "spurious interrupt " | ||
| 889 | "(irq_stat 0x%x active_tag %d)\n", | ||
| 890 | status, ap->active_tag); | ||
| 894 | } | 891 | } |
| 895 | 892 | ||
| 896 | static void ahci_irq_clear(struct ata_port *ap) | 893 | static void ahci_irq_clear(struct ata_port *ap) |
| @@ -927,14 +924,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs * | |||
| 927 | 924 | ||
| 928 | ap = host_set->ports[i]; | 925 | ap = host_set->ports[i]; |
| 929 | if (ap) { | 926 | if (ap) { |
| 930 | struct ata_queued_cmd *qc; | 927 | ahci_host_intr(ap); |
| 931 | qc = ata_qc_from_tag(ap, ap->active_tag); | ||
| 932 | if (!ahci_host_intr(ap, qc)) | ||
| 933 | if (ata_ratelimit()) | ||
| 934 | dev_printk(KERN_WARNING, host_set->dev, | ||
| 935 | "unhandled interrupt on port %u\n", | ||
| 936 | i); | ||
| 937 | |||
| 938 | VPRINTK("port %u\n", i); | 928 | VPRINTK("port %u\n", i); |
| 939 | } else { | 929 | } else { |
| 940 | VPRINTK("port %u (no irq)\n", i); | 930 | VPRINTK("port %u (no irq)\n", i); |
| @@ -951,7 +941,7 @@ static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs * | |||
| 951 | handled = 1; | 941 | handled = 1; |
| 952 | } | 942 | } |
| 953 | 943 | ||
| 954 | spin_unlock(&host_set->lock); | 944 | spin_unlock(&host_set->lock); |
| 955 | 945 | ||
| 956 | VPRINTK("EXIT\n"); | 946 | VPRINTK("EXIT\n"); |
| 957 | 947 | ||
| @@ -969,6 +959,56 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc) | |||
| 969 | return 0; | 959 | return 0; |
| 970 | } | 960 | } |
| 971 | 961 | ||
| 962 | static void ahci_freeze(struct ata_port *ap) | ||
| 963 | { | ||
| 964 | void __iomem *mmio = ap->host_set->mmio_base; | ||
| 965 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | ||
| 966 | |||
| 967 | /* turn IRQ off */ | ||
| 968 | writel(0, port_mmio + PORT_IRQ_MASK); | ||
| 969 | } | ||
| 970 | |||
| 971 | static void ahci_thaw(struct ata_port *ap) | ||
| 972 | { | ||
| 973 | void __iomem *mmio = ap->host_set->mmio_base; | ||
| 974 | void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); | ||
| 975 | u32 tmp; | ||
| 976 | |||
| 977 | /* clear IRQ */ | ||
| 978 | tmp = readl(port_mmio + PORT_IRQ_STAT); | ||
| 979 | writel(tmp, port_mmio + PORT_IRQ_STAT); | ||
| 980 | writel(1 << ap->id, mmio + HOST_IRQ_STAT); | ||
| 981 | |||
| 982 | /* turn IRQ back on */ | ||
| 983 | writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK); | ||
| 984 | } | ||
| 985 | |||
| 986 | static void ahci_error_handler(struct ata_port *ap) | ||
| 987 | { | ||
| 988 | if (!(ap->flags & ATA_FLAG_FROZEN)) { | ||
| 989 | /* restart engine */ | ||
| 990 | ahci_stop_engine(ap); | ||
| 991 | ahci_start_engine(ap); | ||
| 992 | } | ||
| 993 | |||
| 994 | /* perform recovery */ | ||
| 995 | ata_do_eh(ap, ahci_softreset, ahci_hardreset, ahci_postreset); | ||
| 996 | } | ||
| 997 | |||
| 998 | static void ahci_post_internal_cmd(struct ata_queued_cmd *qc) | ||
| 999 | { | ||
| 1000 | struct ata_port *ap = qc->ap; | ||
| 1001 | |||
| 1002 | if (qc->flags & ATA_QCFLAG_FAILED) | ||
| 1003 | qc->err_mask |= AC_ERR_OTHER; | ||
| 1004 | |||
| 1005 | if (qc->err_mask) { | ||
| 1006 | /* make DMA engine forget about the failed command */ | ||
| 1007 | ahci_stop_engine(ap); | ||
| 1008 | ahci_start_engine(ap); | ||
| 1009 | } | ||
| 1010 | } | ||
| 1011 | |||
| 972 | static void ahci_setup_port(struct ata_ioports *port, unsigned long base, | 1012 | static void ahci_setup_port(struct ata_ioports *port, unsigned long base, |
| 973 | unsigned int port_idx) | 1013 | unsigned int port_idx) |
| 974 | { | 1014 | { |
| @@ -1113,9 +1153,6 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent) | |||
| 1113 | writel(tmp, port_mmio + PORT_IRQ_STAT); | 1153 | writel(tmp, port_mmio + PORT_IRQ_STAT); |
| 1114 | 1154 | ||
| 1115 | writel(1 << i, mmio + HOST_IRQ_STAT); | 1155 | writel(1 << i, mmio + HOST_IRQ_STAT); |
| 1116 | |||
| 1117 | /* set irq mask (enables interrupts) */ | ||
| 1118 | writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK); | ||
| 1119 | } | 1156 | } |
| 1120 | 1157 | ||
| 1121 | tmp = readl(mmio + HOST_CTL); | 1158 | tmp = readl(mmio + HOST_CTL); |
