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); |