aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-05-15 07:58:29 -0400
committerTejun Heo <htejun@gmail.com>2006-05-15 07:58:29 -0400
commit78cd52d02fa0735949a9fa30a6b79bf02c94c250 (patch)
treef52d2053c5fd930357130c9bf6a00743920bf19c /drivers
parentf6aae27ed002ba9c0a98aff811dbde32ce749d28 (diff)
[PATCH] ahci: convert to new EH
Convert AHCI to new EH. Unfortunately, ICH7 AHCI reacts badly if IRQ mask is diddled during operation. So, freezing is implemented by unconditionally clearing interrupt conditions while frozen. * Interrupts are categorized according to required action. e.g. Connection status or unknown FIS error requires freezing the port while TF or HBUS_DATA don't. * Only CONNECT (reflects SErr.X) interrupt is taken into account not PHYRDY (SErr.N), as CONNECT is better cue for starting EH. * AHCI may be invoked without any active command. e.g. CONNECT irq occuring while no qc in progress still triggers EH and will reset the port and revalidate attached device. Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/ahci.c237
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);
197static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs); 199static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
198static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes); 200static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
199static void ahci_irq_clear(struct ata_port *ap); 201static void ahci_irq_clear(struct ata_port *ap);
200static void ahci_eng_timeout(struct ata_port *ap);
201static int ahci_port_start(struct ata_port *ap); 202static int ahci_port_start(struct ata_port *ap);
202static void ahci_port_stop(struct ata_port *ap); 203static void ahci_port_stop(struct ata_port *ap);
203static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); 204static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
204static void ahci_qc_prep(struct ata_queued_cmd *qc); 205static void ahci_qc_prep(struct ata_queued_cmd *qc);
205static u8 ahci_check_status(struct ata_port *ap); 206static u8 ahci_check_status(struct ata_port *ap);
206static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); 207static void ahci_freeze(struct ata_port *ap);
208static void ahci_thaw(struct ata_port *ap);
209static void ahci_error_handler(struct ata_port *ap);
210static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
207static void ahci_remove_one (struct pci_dev *pdev); 211static void ahci_remove_one (struct pci_dev *pdev);
208 212
209static struct scsi_host_template ahci_sht = { 213static 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
792static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) 800static 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
833static 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
854static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc) 863static 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
896static void ahci_irq_clear(struct ata_port *ap) 893static 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
962static 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
971static 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
986static 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
998static 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
972static void ahci_setup_port(struct ata_ioports *port, unsigned long base, 1012static 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);