diff options
author | Jeff Garzik <jeff@garzik.org> | 2009-04-08 16:02:18 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2009-05-15 14:05:22 -0400 |
commit | 67651ee5710c45ea62fae68b768d65395ccf47c2 (patch) | |
tree | 91232a79eb11e7f68091cf4c062a97b250e58553 /drivers/ata | |
parent | 5d41343ac88eeddd25dc4ffb7050c9095c41a70d (diff) |
[libata] sata_sx4: convert to new exception handling methods
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/sata_sx4.c | 166 |
1 files changed, 121 insertions, 45 deletions
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c index dce3dccced3f..1ce98afa69b6 100644 --- a/drivers/ata/sata_sx4.c +++ b/drivers/ata/sata_sx4.c | |||
@@ -213,8 +213,9 @@ struct pdc_host_priv { | |||
213 | 213 | ||
214 | 214 | ||
215 | static int pdc_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); | 215 | static int pdc_sata_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); |
216 | static void pdc_eng_timeout(struct ata_port *ap); | 216 | static void pdc_error_handler(struct ata_port *ap); |
217 | static void pdc_20621_phy_reset(struct ata_port *ap); | 217 | static void pdc_freeze(struct ata_port *ap); |
218 | static void pdc_thaw(struct ata_port *ap); | ||
218 | static int pdc_port_start(struct ata_port *ap); | 219 | static int pdc_port_start(struct ata_port *ap); |
219 | static void pdc20621_qc_prep(struct ata_queued_cmd *qc); | 220 | static void pdc20621_qc_prep(struct ata_queued_cmd *qc); |
220 | static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); | 221 | static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); |
@@ -233,6 +234,10 @@ static void pdc20621_put_to_dimm(struct ata_host *host, | |||
233 | void *psource, u32 offset, u32 size); | 234 | void *psource, u32 offset, u32 size); |
234 | static void pdc20621_irq_clear(struct ata_port *ap); | 235 | static void pdc20621_irq_clear(struct ata_port *ap); |
235 | static unsigned int pdc20621_qc_issue(struct ata_queued_cmd *qc); | 236 | static unsigned int pdc20621_qc_issue(struct ata_queued_cmd *qc); |
237 | static int pdc_softreset(struct ata_link *link, unsigned int *class, | ||
238 | unsigned long deadline); | ||
239 | static void pdc_post_internal_cmd(struct ata_queued_cmd *qc); | ||
240 | static int pdc_check_atapi_dma(struct ata_queued_cmd *qc); | ||
236 | 241 | ||
237 | 242 | ||
238 | static struct scsi_host_template pdc_sata_sht = { | 243 | static struct scsi_host_template pdc_sata_sht = { |
@@ -243,20 +248,24 @@ static struct scsi_host_template pdc_sata_sht = { | |||
243 | 248 | ||
244 | /* TODO: inherit from base port_ops after converting to new EH */ | 249 | /* TODO: inherit from base port_ops after converting to new EH */ |
245 | static struct ata_port_operations pdc_20621_ops = { | 250 | static struct ata_port_operations pdc_20621_ops = { |
246 | .sff_tf_load = pdc_tf_load_mmio, | 251 | .inherits = &ata_sff_port_ops, |
247 | .sff_tf_read = ata_sff_tf_read, | 252 | |
248 | .sff_check_status = ata_sff_check_status, | 253 | .check_atapi_dma = pdc_check_atapi_dma, |
249 | .sff_exec_command = pdc_exec_command_mmio, | ||
250 | .sff_dev_select = ata_sff_dev_select, | ||
251 | .phy_reset = pdc_20621_phy_reset, | ||
252 | .qc_prep = pdc20621_qc_prep, | 254 | .qc_prep = pdc20621_qc_prep, |
253 | .qc_issue = pdc20621_qc_issue, | 255 | .qc_issue = pdc20621_qc_issue, |
254 | .qc_fill_rtf = ata_sff_qc_fill_rtf, | 256 | |
255 | .sff_data_xfer = ata_sff_data_xfer, | 257 | .freeze = pdc_freeze, |
256 | .eng_timeout = pdc_eng_timeout, | 258 | .thaw = pdc_thaw, |
257 | .sff_irq_clear = pdc20621_irq_clear, | 259 | .softreset = pdc_softreset, |
258 | .sff_irq_on = ata_sff_irq_on, | 260 | .error_handler = pdc_error_handler, |
261 | .lost_interrupt = ATA_OP_NULL, | ||
262 | .post_internal_cmd = pdc_post_internal_cmd, | ||
263 | |||
259 | .port_start = pdc_port_start, | 264 | .port_start = pdc_port_start, |
265 | |||
266 | .sff_tf_load = pdc_tf_load_mmio, | ||
267 | .sff_exec_command = pdc_exec_command_mmio, | ||
268 | .sff_irq_clear = pdc20621_irq_clear, | ||
260 | }; | 269 | }; |
261 | 270 | ||
262 | static const struct ata_port_info pdc_port_info[] = { | 271 | static const struct ata_port_info pdc_port_info[] = { |
@@ -310,14 +319,6 @@ static int pdc_port_start(struct ata_port *ap) | |||
310 | return 0; | 319 | return 0; |
311 | } | 320 | } |
312 | 321 | ||
313 | static void pdc_20621_phy_reset(struct ata_port *ap) | ||
314 | { | ||
315 | VPRINTK("ENTER\n"); | ||
316 | ap->cbl = ATA_CBL_SATA; | ||
317 | ata_port_probe(ap); | ||
318 | ata_bus_reset(ap); | ||
319 | } | ||
320 | |||
321 | static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf, | 322 | static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf, |
322 | unsigned int portno, | 323 | unsigned int portno, |
323 | unsigned int total_len) | 324 | unsigned int total_len) |
@@ -859,40 +860,115 @@ static irqreturn_t pdc20621_interrupt(int irq, void *dev_instance) | |||
859 | return IRQ_RETVAL(handled); | 860 | return IRQ_RETVAL(handled); |
860 | } | 861 | } |
861 | 862 | ||
862 | static void pdc_eng_timeout(struct ata_port *ap) | 863 | static void pdc_freeze(struct ata_port *ap) |
863 | { | 864 | { |
864 | u8 drv_stat; | 865 | void __iomem *mmio = ap->ioaddr.cmd_addr; |
865 | struct ata_host *host = ap->host; | 866 | u32 tmp; |
866 | struct ata_queued_cmd *qc; | ||
867 | unsigned long flags; | ||
868 | 867 | ||
869 | DPRINTK("ENTER\n"); | 868 | /* FIXME: if all 4 ATA engines are stopped, also stop HDMA engine */ |
870 | 869 | ||
871 | spin_lock_irqsave(&host->lock, flags); | 870 | tmp = readl(mmio + PDC_CTLSTAT); |
871 | tmp |= PDC_MASK_INT; | ||
872 | tmp &= ~PDC_DMA_ENABLE; | ||
873 | writel(tmp, mmio + PDC_CTLSTAT); | ||
874 | readl(mmio + PDC_CTLSTAT); /* flush */ | ||
875 | } | ||
872 | 876 | ||
873 | qc = ata_qc_from_tag(ap, ap->link.active_tag); | 877 | static void pdc_thaw(struct ata_port *ap) |
878 | { | ||
879 | void __iomem *mmio = ap->ioaddr.cmd_addr; | ||
880 | void __iomem *mmio_base; | ||
881 | u32 tmp; | ||
874 | 882 | ||
875 | switch (qc->tf.protocol) { | 883 | /* FIXME: start HDMA engine, if zero ATA engines running */ |
876 | case ATA_PROT_DMA: | ||
877 | case ATA_PROT_NODATA: | ||
878 | ata_port_printk(ap, KERN_ERR, "command timeout\n"); | ||
879 | qc->err_mask |= __ac_err_mask(ata_wait_idle(ap)); | ||
880 | break; | ||
881 | 884 | ||
882 | default: | 885 | /* reading SEQ mask register clears IRQ */ |
883 | drv_stat = ata_sff_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); | 886 | mmio_base = ap->host->iomap[PDC_MMIO_BAR] + PDC_CHIP0_OFS; |
887 | readl(mmio_base + PDC_20621_SEQMASK); | ||
884 | 888 | ||
885 | ata_port_printk(ap, KERN_ERR, | 889 | /* turn IRQ back on */ |
886 | "unknown timeout, cmd 0x%x stat 0x%x\n", | 890 | tmp = readl(mmio + PDC_CTLSTAT); |
887 | qc->tf.command, drv_stat); | 891 | tmp &= ~PDC_MASK_INT; |
892 | writel(tmp, mmio + PDC_CTLSTAT); | ||
893 | readl(mmio + PDC_CTLSTAT); /* flush */ | ||
894 | } | ||
888 | 895 | ||
889 | qc->err_mask |= ac_err_mask(drv_stat); | 896 | static void pdc_reset_port(struct ata_port *ap) |
890 | break; | 897 | { |
898 | void __iomem *mmio = ap->ioaddr.cmd_addr + PDC_CTLSTAT; | ||
899 | unsigned int i; | ||
900 | u32 tmp; | ||
901 | |||
902 | /* FIXME: handle HDMA copy engine */ | ||
903 | |||
904 | for (i = 11; i > 0; i--) { | ||
905 | tmp = readl(mmio); | ||
906 | if (tmp & PDC_RESET) | ||
907 | break; | ||
908 | |||
909 | udelay(100); | ||
910 | |||
911 | tmp |= PDC_RESET; | ||
912 | writel(tmp, mmio); | ||
891 | } | 913 | } |
892 | 914 | ||
893 | spin_unlock_irqrestore(&host->lock, flags); | 915 | tmp &= ~PDC_RESET; |
894 | ata_eh_qc_complete(qc); | 916 | writel(tmp, mmio); |
895 | DPRINTK("EXIT\n"); | 917 | readl(mmio); /* flush */ |
918 | } | ||
919 | |||
920 | static int pdc_softreset(struct ata_link *link, unsigned int *class, | ||
921 | unsigned long deadline) | ||
922 | { | ||
923 | pdc_reset_port(link->ap); | ||
924 | return ata_sff_softreset(link, class, deadline); | ||
925 | } | ||
926 | |||
927 | static void pdc_error_handler(struct ata_port *ap) | ||
928 | { | ||
929 | if (!(ap->pflags & ATA_PFLAG_FROZEN)) | ||
930 | pdc_reset_port(ap); | ||
931 | |||
932 | ata_std_error_handler(ap); | ||
933 | } | ||
934 | |||
935 | static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) | ||
936 | { | ||
937 | struct ata_port *ap = qc->ap; | ||
938 | |||
939 | /* make DMA engine forget about the failed command */ | ||
940 | if (qc->flags & ATA_QCFLAG_FAILED) | ||
941 | pdc_reset_port(ap); | ||
942 | } | ||
943 | |||
944 | static int pdc_check_atapi_dma(struct ata_queued_cmd *qc) | ||
945 | { | ||
946 | u8 *scsicmd = qc->scsicmd->cmnd; | ||
947 | int pio = 1; /* atapi dma off by default */ | ||
948 | |||
949 | /* Whitelist commands that may use DMA. */ | ||
950 | switch (scsicmd[0]) { | ||
951 | case WRITE_12: | ||
952 | case WRITE_10: | ||
953 | case WRITE_6: | ||
954 | case READ_12: | ||
955 | case READ_10: | ||
956 | case READ_6: | ||
957 | case 0xad: /* READ_DVD_STRUCTURE */ | ||
958 | case 0xbe: /* READ_CD */ | ||
959 | pio = 0; | ||
960 | } | ||
961 | /* -45150 (FFFF4FA2) to -1 (FFFFFFFF) shall use PIO mode */ | ||
962 | if (scsicmd[0] == WRITE_10) { | ||
963 | unsigned int lba = | ||
964 | (scsicmd[2] << 24) | | ||
965 | (scsicmd[3] << 16) | | ||
966 | (scsicmd[4] << 8) | | ||
967 | scsicmd[5]; | ||
968 | if (lba >= 0xFFFF4FA2) | ||
969 | pio = 1; | ||
970 | } | ||
971 | return pio; | ||
896 | } | 972 | } |
897 | 973 | ||
898 | static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) | 974 | static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) |