diff options
Diffstat (limited to 'drivers/scsi/sata_sil24.c')
-rw-r--r-- | drivers/scsi/sata_sil24.c | 394 |
1 files changed, 229 insertions, 165 deletions
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c index e9fd869140c5..4c76f05d9b65 100644 --- a/drivers/scsi/sata_sil24.c +++ b/drivers/scsi/sata_sil24.c | |||
@@ -156,6 +156,9 @@ enum { | |||
156 | PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */ | 156 | PORT_IRQ_HANDSHAKE = (1 << 10), /* handshake error threshold */ |
157 | PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */ | 157 | PORT_IRQ_SDB_NOTIFY = (1 << 11), /* SDB notify received */ |
158 | 158 | ||
159 | DEF_PORT_IRQ = PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | | ||
160 | PORT_IRQ_DEV_XCHG | PORT_IRQ_UNK_FIS, | ||
161 | |||
159 | /* bits[27:16] are unmasked (raw) */ | 162 | /* bits[27:16] are unmasked (raw) */ |
160 | PORT_IRQ_RAW_SHIFT = 16, | 163 | PORT_IRQ_RAW_SHIFT = 16, |
161 | PORT_IRQ_MASKED_MASK = 0x7ff, | 164 | PORT_IRQ_MASKED_MASK = 0x7ff, |
@@ -213,6 +216,8 @@ enum { | |||
213 | SGE_DRD = (1 << 29), /* discard data read (/dev/null) | 216 | SGE_DRD = (1 << 29), /* discard data read (/dev/null) |
214 | data address ignored */ | 217 | data address ignored */ |
215 | 218 | ||
219 | SIL24_MAX_CMDS = 31, | ||
220 | |||
216 | /* board id */ | 221 | /* board id */ |
217 | BID_SIL3124 = 0, | 222 | BID_SIL3124 = 0, |
218 | BID_SIL3132 = 1, | 223 | BID_SIL3132 = 1, |
@@ -220,7 +225,8 @@ enum { | |||
220 | 225 | ||
221 | /* host flags */ | 226 | /* host flags */ |
222 | SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | | 227 | SIL24_COMMON_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | |
223 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, | 228 | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA | |
229 | ATA_FLAG_NCQ, | ||
224 | SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */ | 230 | SIL24_FLAG_PCIX_IRQ_WOC = (1 << 24), /* IRQ loss errata on PCI-X */ |
225 | 231 | ||
226 | IRQ_STAT_4PORTS = 0xf, | 232 | IRQ_STAT_4PORTS = 0xf, |
@@ -242,6 +248,58 @@ union sil24_cmd_block { | |||
242 | struct sil24_atapi_block atapi; | 248 | struct sil24_atapi_block atapi; |
243 | }; | 249 | }; |
244 | 250 | ||
251 | static struct sil24_cerr_info { | ||
252 | unsigned int err_mask, action; | ||
253 | const char *desc; | ||
254 | } sil24_cerr_db[] = { | ||
255 | [0] = { AC_ERR_DEV, ATA_EH_REVALIDATE, | ||
256 | "device error" }, | ||
257 | [PORT_CERR_DEV] = { AC_ERR_DEV, ATA_EH_REVALIDATE, | ||
258 | "device error via D2H FIS" }, | ||
259 | [PORT_CERR_SDB] = { AC_ERR_DEV, ATA_EH_REVALIDATE, | ||
260 | "device error via SDB FIS" }, | ||
261 | [PORT_CERR_DATA] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET, | ||
262 | "error in data FIS" }, | ||
263 | [PORT_CERR_SEND] = { AC_ERR_ATA_BUS, ATA_EH_SOFTRESET, | ||
264 | "failed to transmit command FIS" }, | ||
265 | [PORT_CERR_INCONSISTENT] = { AC_ERR_HSM, ATA_EH_SOFTRESET, | ||
266 | "protocol mismatch" }, | ||
267 | [PORT_CERR_DIRECTION] = { AC_ERR_HSM, ATA_EH_SOFTRESET, | ||
268 | "data directon mismatch" }, | ||
269 | [PORT_CERR_UNDERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET, | ||
270 | "ran out of SGEs while writing" }, | ||
271 | [PORT_CERR_OVERRUN] = { AC_ERR_HSM, ATA_EH_SOFTRESET, | ||
272 | "ran out of SGEs while reading" }, | ||
273 | [PORT_CERR_PKT_PROT] = { AC_ERR_HSM, ATA_EH_SOFTRESET, | ||
274 | "invalid data directon for ATAPI CDB" }, | ||
275 | [PORT_CERR_SGT_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET, | ||
276 | "SGT no on qword boundary" }, | ||
277 | [PORT_CERR_SGT_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, | ||
278 | "PCI target abort while fetching SGT" }, | ||
279 | [PORT_CERR_SGT_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, | ||
280 | "PCI master abort while fetching SGT" }, | ||
281 | [PORT_CERR_SGT_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, | ||
282 | "PCI parity error while fetching SGT" }, | ||
283 | [PORT_CERR_CMD_BOUNDARY] = { AC_ERR_SYSTEM, ATA_EH_SOFTRESET, | ||
284 | "PRB not on qword boundary" }, | ||
285 | [PORT_CERR_CMD_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, | ||
286 | "PCI target abort while fetching PRB" }, | ||
287 | [PORT_CERR_CMD_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, | ||
288 | "PCI master abort while fetching PRB" }, | ||
289 | [PORT_CERR_CMD_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, | ||
290 | "PCI parity error while fetching PRB" }, | ||
291 | [PORT_CERR_XFR_UNDEF] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, | ||
292 | "undefined error while transferring data" }, | ||
293 | [PORT_CERR_XFR_TGTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, | ||
294 | "PCI target abort while transferring data" }, | ||
295 | [PORT_CERR_XFR_MSTABRT] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, | ||
296 | "PCI master abort while transferring data" }, | ||
297 | [PORT_CERR_XFR_PCIPERR] = { AC_ERR_HOST_BUS, ATA_EH_SOFTRESET, | ||
298 | "PCI parity error while transferring data" }, | ||
299 | [PORT_CERR_SENDSERVICE] = { AC_ERR_HSM, ATA_EH_SOFTRESET, | ||
300 | "FIS received while sending service FIS" }, | ||
301 | }; | ||
302 | |||
245 | /* | 303 | /* |
246 | * ap->private_data | 304 | * ap->private_data |
247 | * | 305 | * |
@@ -269,8 +327,11 @@ static int sil24_probe_reset(struct ata_port *ap, unsigned int *classes); | |||
269 | static void sil24_qc_prep(struct ata_queued_cmd *qc); | 327 | static void sil24_qc_prep(struct ata_queued_cmd *qc); |
270 | static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); | 328 | static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc); |
271 | static void sil24_irq_clear(struct ata_port *ap); | 329 | static void sil24_irq_clear(struct ata_port *ap); |
272 | static void sil24_eng_timeout(struct ata_port *ap); | ||
273 | static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs); | 330 | static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs); |
331 | static void sil24_freeze(struct ata_port *ap); | ||
332 | static void sil24_thaw(struct ata_port *ap); | ||
333 | static void sil24_error_handler(struct ata_port *ap); | ||
334 | static void sil24_post_internal_cmd(struct ata_queued_cmd *qc); | ||
274 | static int sil24_port_start(struct ata_port *ap); | 335 | static int sil24_port_start(struct ata_port *ap); |
275 | static void sil24_port_stop(struct ata_port *ap); | 336 | static void sil24_port_stop(struct ata_port *ap); |
276 | static void sil24_host_stop(struct ata_host_set *host_set); | 337 | static void sil24_host_stop(struct ata_host_set *host_set); |
@@ -297,7 +358,8 @@ static struct scsi_host_template sil24_sht = { | |||
297 | .name = DRV_NAME, | 358 | .name = DRV_NAME, |
298 | .ioctl = ata_scsi_ioctl, | 359 | .ioctl = ata_scsi_ioctl, |
299 | .queuecommand = ata_scsi_queuecmd, | 360 | .queuecommand = ata_scsi_queuecmd, |
300 | .can_queue = ATA_DEF_QUEUE, | 361 | .change_queue_depth = ata_scsi_change_queue_depth, |
362 | .can_queue = SIL24_MAX_CMDS, | ||
301 | .this_id = ATA_SHT_THIS_ID, | 363 | .this_id = ATA_SHT_THIS_ID, |
302 | .sg_tablesize = LIBATA_MAX_PRD, | 364 | .sg_tablesize = LIBATA_MAX_PRD, |
303 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, | 365 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, |
@@ -325,14 +387,17 @@ static const struct ata_port_operations sil24_ops = { | |||
325 | .qc_prep = sil24_qc_prep, | 387 | .qc_prep = sil24_qc_prep, |
326 | .qc_issue = sil24_qc_issue, | 388 | .qc_issue = sil24_qc_issue, |
327 | 389 | ||
328 | .eng_timeout = sil24_eng_timeout, | ||
329 | |||
330 | .irq_handler = sil24_interrupt, | 390 | .irq_handler = sil24_interrupt, |
331 | .irq_clear = sil24_irq_clear, | 391 | .irq_clear = sil24_irq_clear, |
332 | 392 | ||
333 | .scr_read = sil24_scr_read, | 393 | .scr_read = sil24_scr_read, |
334 | .scr_write = sil24_scr_write, | 394 | .scr_write = sil24_scr_write, |
335 | 395 | ||
396 | .freeze = sil24_freeze, | ||
397 | .thaw = sil24_thaw, | ||
398 | .error_handler = sil24_error_handler, | ||
399 | .post_internal_cmd = sil24_post_internal_cmd, | ||
400 | |||
336 | .port_start = sil24_port_start, | 401 | .port_start = sil24_port_start, |
337 | .port_stop = sil24_port_stop, | 402 | .port_stop = sil24_port_stop, |
338 | .host_stop = sil24_host_stop, | 403 | .host_stop = sil24_host_stop, |
@@ -376,6 +441,13 @@ static struct ata_port_info sil24_port_info[] = { | |||
376 | }, | 441 | }, |
377 | }; | 442 | }; |
378 | 443 | ||
444 | static int sil24_tag(int tag) | ||
445 | { | ||
446 | if (unlikely(ata_tag_internal(tag))) | ||
447 | return 0; | ||
448 | return tag; | ||
449 | } | ||
450 | |||
379 | static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev) | 451 | static void sil24_dev_config(struct ata_port *ap, struct ata_device *dev) |
380 | { | 452 | { |
381 | void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; | 453 | void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; |
@@ -459,21 +531,17 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) | |||
459 | struct sil24_port_priv *pp = ap->private_data; | 531 | struct sil24_port_priv *pp = ap->private_data; |
460 | struct sil24_prb *prb = &pp->cmd_block[0].ata.prb; | 532 | struct sil24_prb *prb = &pp->cmd_block[0].ata.prb; |
461 | dma_addr_t paddr = pp->cmd_block_dma; | 533 | dma_addr_t paddr = pp->cmd_block_dma; |
462 | u32 mask, irq_enable, irq_stat; | 534 | u32 mask, irq_stat; |
463 | const char *reason; | 535 | const char *reason; |
464 | 536 | ||
465 | DPRINTK("ENTER\n"); | 537 | DPRINTK("ENTER\n"); |
466 | 538 | ||
467 | if (!sata_dev_present(ap)) { | 539 | if (ata_port_offline(ap)) { |
468 | DPRINTK("PHY reports no device\n"); | 540 | DPRINTK("PHY reports no device\n"); |
469 | *class = ATA_DEV_NONE; | 541 | *class = ATA_DEV_NONE; |
470 | goto out; | 542 | goto out; |
471 | } | 543 | } |
472 | 544 | ||
473 | /* temporarily turn off IRQs during SRST */ | ||
474 | irq_enable = readl(port + PORT_IRQ_ENABLE_SET); | ||
475 | writel(irq_enable, port + PORT_IRQ_ENABLE_CLR); | ||
476 | |||
477 | /* put the port into known state */ | 545 | /* put the port into known state */ |
478 | if (sil24_init_port(ap)) { | 546 | if (sil24_init_port(ap)) { |
479 | reason ="port not ready"; | 547 | reason ="port not ready"; |
@@ -494,9 +562,6 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) | |||
494 | writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */ | 562 | writel(irq_stat, port + PORT_IRQ_STAT); /* clear IRQs */ |
495 | irq_stat >>= PORT_IRQ_RAW_SHIFT; | 563 | irq_stat >>= PORT_IRQ_RAW_SHIFT; |
496 | 564 | ||
497 | /* restore IRQs */ | ||
498 | writel(irq_enable, port + PORT_IRQ_ENABLE_SET); | ||
499 | |||
500 | if (!(irq_stat & PORT_IRQ_COMPLETE)) { | 565 | if (!(irq_stat & PORT_IRQ_COMPLETE)) { |
501 | if (irq_stat & PORT_IRQ_ERROR) | 566 | if (irq_stat & PORT_IRQ_ERROR) |
502 | reason = "SRST command error"; | 567 | reason = "SRST command error"; |
@@ -516,7 +581,7 @@ static int sil24_softreset(struct ata_port *ap, unsigned int *class) | |||
516 | return 0; | 581 | return 0; |
517 | 582 | ||
518 | err: | 583 | err: |
519 | printk(KERN_ERR "ata%u: softreset failed (%s)\n", ap->id, reason); | 584 | ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason); |
520 | return -EIO; | 585 | return -EIO; |
521 | } | 586 | } |
522 | 587 | ||
@@ -528,10 +593,10 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) | |||
528 | u32 tmp; | 593 | u32 tmp; |
529 | 594 | ||
530 | /* sil24 does the right thing(tm) without any protection */ | 595 | /* sil24 does the right thing(tm) without any protection */ |
531 | ata_set_sata_spd(ap); | 596 | sata_set_spd(ap); |
532 | 597 | ||
533 | tout_msec = 100; | 598 | tout_msec = 100; |
534 | if (sata_dev_present(ap)) | 599 | if (ata_port_online(ap)) |
535 | tout_msec = 5000; | 600 | tout_msec = 5000; |
536 | 601 | ||
537 | writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); | 602 | writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); |
@@ -544,7 +609,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) | |||
544 | msleep(100); | 609 | msleep(100); |
545 | 610 | ||
546 | if (tmp & PORT_CS_DEV_RST) { | 611 | if (tmp & PORT_CS_DEV_RST) { |
547 | if (!sata_dev_present(ap)) | 612 | if (ata_port_offline(ap)) |
548 | return 0; | 613 | return 0; |
549 | reason = "link not ready"; | 614 | reason = "link not ready"; |
550 | goto err; | 615 | goto err; |
@@ -561,7 +626,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class) | |||
561 | return 0; | 626 | return 0; |
562 | 627 | ||
563 | err: | 628 | err: |
564 | printk(KERN_ERR "ata%u: hardreset failed (%s)\n", ap->id, reason); | 629 | ata_port_printk(ap, KERN_ERR, "hardreset failed (%s)\n", reason); |
565 | return -EIO; | 630 | return -EIO; |
566 | } | 631 | } |
567 | 632 | ||
@@ -595,14 +660,17 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) | |||
595 | { | 660 | { |
596 | struct ata_port *ap = qc->ap; | 661 | struct ata_port *ap = qc->ap; |
597 | struct sil24_port_priv *pp = ap->private_data; | 662 | struct sil24_port_priv *pp = ap->private_data; |
598 | union sil24_cmd_block *cb = pp->cmd_block + qc->tag; | 663 | union sil24_cmd_block *cb; |
599 | struct sil24_prb *prb; | 664 | struct sil24_prb *prb; |
600 | struct sil24_sge *sge; | 665 | struct sil24_sge *sge; |
601 | u16 ctrl = 0; | 666 | u16 ctrl = 0; |
602 | 667 | ||
668 | cb = &pp->cmd_block[sil24_tag(qc->tag)]; | ||
669 | |||
603 | switch (qc->tf.protocol) { | 670 | switch (qc->tf.protocol) { |
604 | case ATA_PROT_PIO: | 671 | case ATA_PROT_PIO: |
605 | case ATA_PROT_DMA: | 672 | case ATA_PROT_DMA: |
673 | case ATA_PROT_NCQ: | ||
606 | case ATA_PROT_NODATA: | 674 | case ATA_PROT_NODATA: |
607 | prb = &cb->ata.prb; | 675 | prb = &cb->ata.prb; |
608 | sge = cb->ata.sge; | 676 | sge = cb->ata.sge; |
@@ -640,12 +708,17 @@ static void sil24_qc_prep(struct ata_queued_cmd *qc) | |||
640 | static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc) | 708 | static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc) |
641 | { | 709 | { |
642 | struct ata_port *ap = qc->ap; | 710 | struct ata_port *ap = qc->ap; |
643 | void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; | ||
644 | struct sil24_port_priv *pp = ap->private_data; | 711 | struct sil24_port_priv *pp = ap->private_data; |
645 | dma_addr_t paddr = pp->cmd_block_dma + qc->tag * sizeof(*pp->cmd_block); | 712 | void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; |
713 | unsigned int tag = sil24_tag(qc->tag); | ||
714 | dma_addr_t paddr; | ||
715 | void __iomem *activate; | ||
646 | 716 | ||
647 | writel((u32)paddr, port + PORT_CMD_ACTIVATE); | 717 | paddr = pp->cmd_block_dma + tag * sizeof(*pp->cmd_block); |
648 | writel((u64)paddr >> 32, port + PORT_CMD_ACTIVATE + 4); | 718 | activate = port + PORT_CMD_ACTIVATE + tag * 8; |
719 | |||
720 | writel((u32)paddr, activate); | ||
721 | writel((u64)paddr >> 32, activate + 4); | ||
649 | 722 | ||
650 | return 0; | 723 | return 0; |
651 | } | 724 | } |
@@ -655,166 +728,141 @@ static void sil24_irq_clear(struct ata_port *ap) | |||
655 | /* unused */ | 728 | /* unused */ |
656 | } | 729 | } |
657 | 730 | ||
658 | static int __sil24_restart_controller(void __iomem *port) | 731 | static void sil24_freeze(struct ata_port *ap) |
659 | { | 732 | { |
660 | u32 tmp; | 733 | void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; |
661 | int cnt; | ||
662 | |||
663 | writel(PORT_CS_INIT, port + PORT_CTRL_STAT); | ||
664 | |||
665 | /* Max ~10ms */ | ||
666 | for (cnt = 0; cnt < 10000; cnt++) { | ||
667 | tmp = readl(port + PORT_CTRL_STAT); | ||
668 | if (tmp & PORT_CS_RDY) | ||
669 | return 0; | ||
670 | udelay(1); | ||
671 | } | ||
672 | 734 | ||
673 | return -1; | 735 | /* Port-wide IRQ mask in HOST_CTRL doesn't really work, clear |
736 | * PORT_IRQ_ENABLE instead. | ||
737 | */ | ||
738 | writel(0xffff, port + PORT_IRQ_ENABLE_CLR); | ||
674 | } | 739 | } |
675 | 740 | ||
676 | static void sil24_restart_controller(struct ata_port *ap) | 741 | static void sil24_thaw(struct ata_port *ap) |
677 | { | 742 | { |
678 | if (__sil24_restart_controller((void __iomem *)ap->ioaddr.cmd_addr)) | 743 | void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; |
679 | printk(KERN_ERR DRV_NAME | 744 | u32 tmp; |
680 | " ata%u: failed to restart controller\n", ap->id); | 745 | |
746 | /* clear IRQ */ | ||
747 | tmp = readl(port + PORT_IRQ_STAT); | ||
748 | writel(tmp, port + PORT_IRQ_STAT); | ||
749 | |||
750 | /* turn IRQ back on */ | ||
751 | writel(DEF_PORT_IRQ, port + PORT_IRQ_ENABLE_SET); | ||
681 | } | 752 | } |
682 | 753 | ||
683 | static int __sil24_reset_controller(void __iomem *port) | 754 | static void sil24_error_intr(struct ata_port *ap) |
684 | { | 755 | { |
685 | int cnt; | 756 | void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; |
686 | u32 tmp; | 757 | struct ata_eh_info *ehi = &ap->eh_info; |
758 | int freeze = 0; | ||
759 | u32 irq_stat; | ||
687 | 760 | ||
688 | /* Reset controller state. Is this correct? */ | 761 | /* on error, we need to clear IRQ explicitly */ |
689 | writel(PORT_CS_DEV_RST, port + PORT_CTRL_STAT); | 762 | irq_stat = readl(port + PORT_IRQ_STAT); |
690 | readl(port + PORT_CTRL_STAT); /* sync */ | 763 | writel(irq_stat, port + PORT_IRQ_STAT); |
691 | 764 | ||
692 | /* Max ~100ms */ | 765 | /* first, analyze and record host port events */ |
693 | for (cnt = 0; cnt < 1000; cnt++) { | 766 | ata_ehi_clear_desc(ehi); |
694 | udelay(100); | ||
695 | tmp = readl(port + PORT_CTRL_STAT); | ||
696 | if (!(tmp & PORT_CS_DEV_RST)) | ||
697 | break; | ||
698 | } | ||
699 | 767 | ||
700 | if (tmp & PORT_CS_DEV_RST) | 768 | ata_ehi_push_desc(ehi, "irq_stat 0x%08x", irq_stat); |
701 | return -1; | ||
702 | 769 | ||
703 | if (tmp & PORT_CS_RDY) | 770 | if (irq_stat & PORT_IRQ_DEV_XCHG) { |
704 | return 0; | 771 | ehi->err_mask |= AC_ERR_ATA_BUS; |
772 | /* sil24 doesn't recover very well from phy | ||
773 | * disconnection with a softreset. Force hardreset. | ||
774 | */ | ||
775 | ehi->action |= ATA_EH_HARDRESET; | ||
776 | ata_ehi_push_desc(ehi, ", device_exchanged"); | ||
777 | freeze = 1; | ||
778 | } | ||
705 | 779 | ||
706 | return __sil24_restart_controller(port); | 780 | if (irq_stat & PORT_IRQ_UNK_FIS) { |
707 | } | 781 | ehi->err_mask |= AC_ERR_HSM; |
782 | ehi->action |= ATA_EH_SOFTRESET; | ||
783 | ata_ehi_push_desc(ehi , ", unknown FIS"); | ||
784 | freeze = 1; | ||
785 | } | ||
708 | 786 | ||
709 | static void sil24_reset_controller(struct ata_port *ap) | 787 | /* deal with command error */ |
710 | { | 788 | if (irq_stat & PORT_IRQ_ERROR) { |
711 | printk(KERN_NOTICE DRV_NAME | 789 | struct sil24_cerr_info *ci = NULL; |
712 | " ata%u: resetting controller...\n", ap->id); | 790 | unsigned int err_mask = 0, action = 0; |
713 | if (__sil24_reset_controller((void __iomem *)ap->ioaddr.cmd_addr)) | 791 | struct ata_queued_cmd *qc; |
714 | printk(KERN_ERR DRV_NAME | 792 | u32 cerr; |
715 | " ata%u: failed to reset controller\n", ap->id); | 793 | |
716 | } | 794 | /* analyze CMD_ERR */ |
795 | cerr = readl(port + PORT_CMD_ERR); | ||
796 | if (cerr < ARRAY_SIZE(sil24_cerr_db)) | ||
797 | ci = &sil24_cerr_db[cerr]; | ||
798 | |||
799 | if (ci && ci->desc) { | ||
800 | err_mask |= ci->err_mask; | ||
801 | action |= ci->action; | ||
802 | ata_ehi_push_desc(ehi, ", %s", ci->desc); | ||
803 | } else { | ||
804 | err_mask |= AC_ERR_OTHER; | ||
805 | action |= ATA_EH_SOFTRESET; | ||
806 | ata_ehi_push_desc(ehi, ", unknown command error %d", | ||
807 | cerr); | ||
808 | } | ||
717 | 809 | ||
718 | static void sil24_eng_timeout(struct ata_port *ap) | 810 | /* record error info */ |
719 | { | 811 | qc = ata_qc_from_tag(ap, ap->active_tag); |
720 | struct ata_queued_cmd *qc; | 812 | if (qc) { |
813 | sil24_update_tf(ap); | ||
814 | qc->err_mask |= err_mask; | ||
815 | } else | ||
816 | ehi->err_mask |= err_mask; | ||
721 | 817 | ||
722 | qc = ata_qc_from_tag(ap, ap->active_tag); | 818 | ehi->action |= action; |
819 | } | ||
723 | 820 | ||
724 | printk(KERN_ERR "ata%u: command timeout\n", ap->id); | 821 | /* freeze or abort */ |
725 | qc->err_mask |= AC_ERR_TIMEOUT; | 822 | if (freeze) |
726 | ata_eh_qc_complete(qc); | 823 | ata_port_freeze(ap); |
824 | else | ||
825 | ata_port_abort(ap); | ||
826 | } | ||
727 | 827 | ||
728 | sil24_reset_controller(ap); | 828 | static void sil24_finish_qc(struct ata_queued_cmd *qc) |
829 | { | ||
830 | if (qc->flags & ATA_QCFLAG_RESULT_TF) | ||
831 | sil24_update_tf(qc->ap); | ||
729 | } | 832 | } |
730 | 833 | ||
731 | static void sil24_error_intr(struct ata_port *ap, u32 slot_stat) | 834 | static inline void sil24_host_intr(struct ata_port *ap) |
732 | { | 835 | { |
733 | struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); | ||
734 | struct sil24_port_priv *pp = ap->private_data; | ||
735 | void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; | 836 | void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; |
736 | u32 irq_stat, cmd_err, sstatus, serror; | 837 | u32 slot_stat, qc_active; |
737 | unsigned int err_mask; | 838 | int rc; |
738 | 839 | ||
739 | irq_stat = readl(port + PORT_IRQ_STAT); | 840 | slot_stat = readl(port + PORT_SLOT_STAT); |
740 | writel(irq_stat, port + PORT_IRQ_STAT); /* clear irq */ | ||
741 | 841 | ||
742 | if (!(irq_stat & PORT_IRQ_ERROR)) { | 842 | if (unlikely(slot_stat & HOST_SSTAT_ATTN)) { |
743 | /* ignore non-completion, non-error irqs for now */ | 843 | sil24_error_intr(ap); |
744 | printk(KERN_WARNING DRV_NAME | ||
745 | "ata%u: non-error exception irq (irq_stat %x)\n", | ||
746 | ap->id, irq_stat); | ||
747 | return; | 844 | return; |
748 | } | 845 | } |
749 | 846 | ||
750 | cmd_err = readl(port + PORT_CMD_ERR); | 847 | if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) |
751 | sstatus = readl(port + PORT_SSTATUS); | 848 | writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT); |
752 | serror = readl(port + PORT_SERROR); | ||
753 | if (serror) | ||
754 | writel(serror, port + PORT_SERROR); | ||
755 | 849 | ||
756 | /* | 850 | qc_active = slot_stat & ~HOST_SSTAT_ATTN; |
757 | * Don't log ATAPI device errors. They're supposed to happen | 851 | rc = ata_qc_complete_multiple(ap, qc_active, sil24_finish_qc); |
758 | * and any serious errors will be logged using sense data by | 852 | if (rc > 0) |
759 | * the SCSI layer. | 853 | return; |
760 | */ | 854 | if (rc < 0) { |
761 | if (ap->device[0].class != ATA_DEV_ATAPI || cmd_err > PORT_CERR_SDB) | 855 | struct ata_eh_info *ehi = &ap->eh_info; |
762 | printk("ata%u: error interrupt on port%d\n" | 856 | ehi->err_mask |= AC_ERR_HSM; |
763 | " stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x\n", | 857 | ehi->action |= ATA_EH_SOFTRESET; |
764 | ap->id, ap->port_no, slot_stat, irq_stat, cmd_err, sstatus, serror); | 858 | ata_port_freeze(ap); |
765 | 859 | return; | |
766 | if (cmd_err == PORT_CERR_DEV || cmd_err == PORT_CERR_SDB) { | ||
767 | /* | ||
768 | * Device is reporting error, tf registers are valid. | ||
769 | */ | ||
770 | sil24_update_tf(ap); | ||
771 | err_mask = ac_err_mask(pp->tf.command); | ||
772 | sil24_restart_controller(ap); | ||
773 | } else { | ||
774 | /* | ||
775 | * Other errors. libata currently doesn't have any | ||
776 | * mechanism to report these errors. Just turn on | ||
777 | * ATA_ERR. | ||
778 | */ | ||
779 | err_mask = AC_ERR_OTHER; | ||
780 | sil24_reset_controller(ap); | ||
781 | } | 860 | } |
782 | 861 | ||
783 | if (qc) { | 862 | if (ata_ratelimit()) |
784 | qc->err_mask |= err_mask; | 863 | ata_port_printk(ap, KERN_INFO, "spurious interrupt " |
785 | ata_qc_complete(qc); | 864 | "(slot_stat 0x%x active_tag %d sactive 0x%x)\n", |
786 | } | 865 | slot_stat, ap->active_tag, ap->sactive); |
787 | } | ||
788 | |||
789 | static inline void sil24_host_intr(struct ata_port *ap) | ||
790 | { | ||
791 | struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); | ||
792 | void __iomem *port = (void __iomem *)ap->ioaddr.cmd_addr; | ||
793 | u32 slot_stat; | ||
794 | |||
795 | slot_stat = readl(port + PORT_SLOT_STAT); | ||
796 | if (!(slot_stat & HOST_SSTAT_ATTN)) { | ||
797 | struct sil24_port_priv *pp = ap->private_data; | ||
798 | |||
799 | if (ap->flags & SIL24_FLAG_PCIX_IRQ_WOC) | ||
800 | writel(PORT_IRQ_COMPLETE, port + PORT_IRQ_STAT); | ||
801 | |||
802 | /* | ||
803 | * !HOST_SSAT_ATTN guarantees successful completion, | ||
804 | * so reading back tf registers is unnecessary for | ||
805 | * most commands. TODO: read tf registers for | ||
806 | * commands which require these values on successful | ||
807 | * completion (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER, | ||
808 | * DEVICE RESET and READ PORT MULTIPLIER (any more?). | ||
809 | */ | ||
810 | sil24_update_tf(ap); | ||
811 | |||
812 | if (qc) { | ||
813 | qc->err_mask |= ac_err_mask(pp->tf.command); | ||
814 | ata_qc_complete(qc); | ||
815 | } | ||
816 | } else | ||
817 | sil24_error_intr(ap, slot_stat); | ||
818 | } | 866 | } |
819 | 867 | ||
820 | static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs) | 868 | static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs) |
@@ -854,9 +902,34 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs * | |||
854 | return IRQ_RETVAL(handled); | 902 | return IRQ_RETVAL(handled); |
855 | } | 903 | } |
856 | 904 | ||
905 | static void sil24_error_handler(struct ata_port *ap) | ||
906 | { | ||
907 | struct ata_eh_context *ehc = &ap->eh_context; | ||
908 | |||
909 | if (sil24_init_port(ap)) { | ||
910 | ata_eh_freeze_port(ap); | ||
911 | ehc->i.action |= ATA_EH_HARDRESET; | ||
912 | } | ||
913 | |||
914 | /* perform recovery */ | ||
915 | ata_do_eh(ap, sil24_softreset, sil24_hardreset, ata_std_postreset); | ||
916 | } | ||
917 | |||
918 | static void sil24_post_internal_cmd(struct ata_queued_cmd *qc) | ||
919 | { | ||
920 | struct ata_port *ap = qc->ap; | ||
921 | |||
922 | if (qc->flags & ATA_QCFLAG_FAILED) | ||
923 | qc->err_mask |= AC_ERR_OTHER; | ||
924 | |||
925 | /* make DMA engine forget about the failed command */ | ||
926 | if (qc->err_mask) | ||
927 | sil24_init_port(ap); | ||
928 | } | ||
929 | |||
857 | static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev) | 930 | static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *dev) |
858 | { | 931 | { |
859 | const size_t cb_size = sizeof(*pp->cmd_block); | 932 | const size_t cb_size = sizeof(*pp->cmd_block) * SIL24_MAX_CMDS; |
860 | 933 | ||
861 | dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma); | 934 | dma_free_coherent(dev, cb_size, pp->cmd_block, pp->cmd_block_dma); |
862 | } | 935 | } |
@@ -866,7 +939,7 @@ static int sil24_port_start(struct ata_port *ap) | |||
866 | struct device *dev = ap->host_set->dev; | 939 | struct device *dev = ap->host_set->dev; |
867 | struct sil24_port_priv *pp; | 940 | struct sil24_port_priv *pp; |
868 | union sil24_cmd_block *cb; | 941 | union sil24_cmd_block *cb; |
869 | size_t cb_size = sizeof(*cb); | 942 | size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS; |
870 | dma_addr_t cb_dma; | 943 | dma_addr_t cb_dma; |
871 | int rc = -ENOMEM; | 944 | int rc = -ENOMEM; |
872 | 945 | ||
@@ -1066,15 +1139,6 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1066 | /* Always use 64bit activation */ | 1139 | /* Always use 64bit activation */ |
1067 | writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); | 1140 | writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR); |
1068 | 1141 | ||
1069 | /* Configure interrupts */ | ||
1070 | writel(0xffff, port + PORT_IRQ_ENABLE_CLR); | ||
1071 | writel(PORT_IRQ_COMPLETE | PORT_IRQ_ERROR | | ||
1072 | PORT_IRQ_SDB_NOTIFY, port + PORT_IRQ_ENABLE_SET); | ||
1073 | |||
1074 | /* Clear interrupts */ | ||
1075 | writel(0x0fff0fff, port + PORT_IRQ_STAT); | ||
1076 | writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR); | ||
1077 | |||
1078 | /* Clear port multiplier enable and resume bits */ | 1142 | /* Clear port multiplier enable and resume bits */ |
1079 | writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); | 1143 | writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR); |
1080 | } | 1144 | } |