diff options
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/sata_nv.c | 147 |
1 files changed, 72 insertions, 75 deletions
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 77e47b74ae96..3dd5ca16a2ba 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c | |||
@@ -651,53 +651,62 @@ static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb) | |||
651 | return idx; | 651 | return idx; |
652 | } | 652 | } |
653 | 653 | ||
654 | static void nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) | 654 | static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err) |
655 | { | 655 | { |
656 | struct nv_adma_port_priv *pp = ap->private_data; | 656 | struct nv_adma_port_priv *pp = ap->private_data; |
657 | int complete = 0, have_err = 0; | ||
658 | u8 flags = pp->cpb[cpb_num].resp_flags; | 657 | u8 flags = pp->cpb[cpb_num].resp_flags; |
659 | 658 | ||
660 | VPRINTK("CPB %d, flags=0x%x\n", cpb_num, flags); | 659 | VPRINTK("CPB %d, flags=0x%x\n", cpb_num, flags); |
661 | 660 | ||
662 | if (flags & NV_CPB_RESP_DONE) { | 661 | if (unlikely((force_err || |
663 | VPRINTK("CPB flags done, flags=0x%x\n", flags); | 662 | flags & (NV_CPB_RESP_ATA_ERR | |
664 | complete = 1; | 663 | NV_CPB_RESP_CMD_ERR | |
665 | } | 664 | NV_CPB_RESP_CPB_ERR)))) { |
666 | if (flags & NV_CPB_RESP_ATA_ERR) { | 665 | struct ata_eh_info *ehi = &ap->eh_info; |
667 | ata_port_printk(ap, KERN_ERR, "CPB flags ATA err, flags=0x%x\n", flags); | 666 | int freeze = 0; |
668 | have_err = 1; | 667 | |
669 | complete = 1; | 668 | ata_ehi_clear_desc(ehi); |
670 | } | 669 | ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags ); |
671 | if (flags & NV_CPB_RESP_CMD_ERR) { | 670 | if (flags & NV_CPB_RESP_ATA_ERR) { |
672 | ata_port_printk(ap, KERN_ERR, "CPB flags CMD err, flags=0x%x\n", flags); | 671 | ata_ehi_push_desc(ehi, ": ATA error"); |
673 | have_err = 1; | 672 | ehi->err_mask |= AC_ERR_DEV; |
674 | complete = 1; | 673 | } else if (flags & NV_CPB_RESP_CMD_ERR) { |
675 | } | 674 | ata_ehi_push_desc(ehi, ": CMD error"); |
676 | if (flags & NV_CPB_RESP_CPB_ERR) { | 675 | ehi->err_mask |= AC_ERR_DEV; |
677 | ata_port_printk(ap, KERN_ERR, "CPB flags CPB err, flags=0x%x\n", flags); | 676 | } else if (flags & NV_CPB_RESP_CPB_ERR) { |
678 | have_err = 1; | 677 | ata_ehi_push_desc(ehi, ": CPB error"); |
679 | complete = 1; | 678 | ehi->err_mask |= AC_ERR_SYSTEM; |
679 | freeze = 1; | ||
680 | } else { | ||
681 | /* notifier error, but no error in CPB flags? */ | ||
682 | ehi->err_mask |= AC_ERR_OTHER; | ||
683 | freeze = 1; | ||
684 | } | ||
685 | /* Kill all commands. EH will determine what actually failed. */ | ||
686 | if (freeze) | ||
687 | ata_port_freeze(ap); | ||
688 | else | ||
689 | ata_port_abort(ap); | ||
690 | return 1; | ||
680 | } | 691 | } |
681 | if(complete || force_err) | 692 | |
682 | { | 693 | if (flags & NV_CPB_RESP_DONE) { |
683 | struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num); | 694 | struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num); |
684 | if(likely(qc)) { | 695 | VPRINTK("CPB flags done, flags=0x%x\n", flags); |
685 | u8 ata_status = 0; | 696 | if (likely(qc)) { |
686 | /* Only use the ATA port status for non-NCQ commands. | 697 | /* Grab the ATA port status for non-NCQ commands. |
687 | For NCQ commands the current status may have nothing to do with | 698 | For NCQ commands the current status may have nothing to do with |
688 | the command just completed. */ | 699 | the command just completed. */ |
689 | if(qc->tf.protocol != ATA_PROT_NCQ) | 700 | if (qc->tf.protocol != ATA_PROT_NCQ) { |
690 | ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4)); | 701 | u8 ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4)); |
691 | 702 | qc->err_mask |= ac_err_mask(ata_status); | |
692 | if(have_err || force_err) | 703 | } |
693 | ata_status |= ATA_ERR; | ||
694 | |||
695 | qc->err_mask |= ac_err_mask(ata_status); | ||
696 | DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num, | 704 | DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num, |
697 | qc->err_mask); | 705 | qc->err_mask); |
698 | ata_qc_complete(qc); | 706 | ata_qc_complete(qc); |
699 | } | 707 | } |
700 | } | 708 | } |
709 | return 0; | ||
701 | } | 710 | } |
702 | 711 | ||
703 | static int nv_host_intr(struct ata_port *ap, u8 irq_stat) | 712 | static int nv_host_intr(struct ata_port *ap, u8 irq_stat) |
@@ -741,7 +750,6 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) | |||
741 | void __iomem *mmio = pp->ctl_block; | 750 | void __iomem *mmio = pp->ctl_block; |
742 | u16 status; | 751 | u16 status; |
743 | u32 gen_ctl; | 752 | u32 gen_ctl; |
744 | int have_global_err = 0; | ||
745 | u32 notifier, notifier_error; | 753 | u32 notifier, notifier_error; |
746 | 754 | ||
747 | /* if in ATA register mode, use standard ata interrupt handler */ | 755 | /* if in ATA register mode, use standard ata interrupt handler */ |
@@ -777,42 +785,50 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) | |||
777 | readw(mmio + NV_ADMA_STAT); /* flush posted write */ | 785 | readw(mmio + NV_ADMA_STAT); /* flush posted write */ |
778 | rmb(); | 786 | rmb(); |
779 | 787 | ||
780 | /* freeze if hotplugged */ | 788 | handled++; /* irq handled if we got here */ |
781 | if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | NV_ADMA_STAT_HOTUNPLUG))) { | 789 | |
782 | ata_port_printk(ap, KERN_NOTICE, "Hotplug event, freezing\n"); | 790 | /* freeze if hotplugged or controller error */ |
791 | if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | | ||
792 | NV_ADMA_STAT_HOTUNPLUG | | ||
793 | NV_ADMA_STAT_TIMEOUT))) { | ||
794 | struct ata_eh_info *ehi = &ap->eh_info; | ||
795 | |||
796 | ata_ehi_clear_desc(ehi); | ||
797 | ata_ehi_push_desc(ehi, "ADMA status 0x%08x", status ); | ||
798 | if (status & NV_ADMA_STAT_TIMEOUT) { | ||
799 | ehi->err_mask |= AC_ERR_SYSTEM; | ||
800 | ata_ehi_push_desc(ehi, ": timeout"); | ||
801 | } else if (status & NV_ADMA_STAT_HOTPLUG) { | ||
802 | ata_ehi_hotplugged(ehi); | ||
803 | ata_ehi_push_desc(ehi, ": hotplug"); | ||
804 | } else if (status & NV_ADMA_STAT_HOTUNPLUG) { | ||
805 | ata_ehi_hotplugged(ehi); | ||
806 | ata_ehi_push_desc(ehi, ": hot unplug"); | ||
807 | } | ||
783 | ata_port_freeze(ap); | 808 | ata_port_freeze(ap); |
784 | handled++; | ||
785 | continue; | 809 | continue; |
786 | } | 810 | } |
787 | 811 | ||
788 | if (status & NV_ADMA_STAT_TIMEOUT) { | 812 | if (status & (NV_ADMA_STAT_DONE | |
789 | ata_port_printk(ap, KERN_ERR, "timeout, stat=0x%x\n", status); | 813 | NV_ADMA_STAT_CPBERR)) { |
790 | have_global_err = 1; | ||
791 | } | ||
792 | if (status & NV_ADMA_STAT_CPBERR) { | ||
793 | ata_port_printk(ap, KERN_ERR, "CPB error, stat=0x%x\n", status); | ||
794 | have_global_err = 1; | ||
795 | } | ||
796 | if ((status & NV_ADMA_STAT_DONE) || have_global_err) { | ||
797 | /** Check CPBs for completed commands */ | 814 | /** Check CPBs for completed commands */ |
798 | 815 | ||
799 | if(ata_tag_valid(ap->active_tag)) | 816 | if (ata_tag_valid(ap->active_tag)) { |
800 | /* Non-NCQ command */ | 817 | /* Non-NCQ command */ |
801 | nv_adma_check_cpb(ap, ap->active_tag, have_global_err || | 818 | nv_adma_check_cpb(ap, ap->active_tag, |
802 | (notifier_error & (1 << ap->active_tag))); | 819 | notifier_error & (1 << ap->active_tag)); |
803 | else { | 820 | } else { |
804 | int pos; | 821 | int pos, error = 0; |
805 | u32 active = ap->sactive; | 822 | u32 active = ap->sactive; |
806 | while( (pos = ffs(active)) ) { | 823 | |
824 | while ((pos = ffs(active)) && !error) { | ||
807 | pos--; | 825 | pos--; |
808 | nv_adma_check_cpb(ap, pos, have_global_err || | 826 | error = nv_adma_check_cpb(ap, pos, |
809 | (notifier_error & (1 << pos)) ); | 827 | notifier_error & (1 << pos) ); |
810 | active &= ~(1 << pos ); | 828 | active &= ~(1 << pos ); |
811 | } | 829 | } |
812 | } | 830 | } |
813 | } | 831 | } |
814 | |||
815 | handled++; /* irq handled if we got here */ | ||
816 | } | 832 | } |
817 | } | 833 | } |
818 | 834 | ||
@@ -1372,28 +1388,9 @@ static void nv_adma_error_handler(struct ata_port *ap) | |||
1372 | int i; | 1388 | int i; |
1373 | u16 tmp; | 1389 | u16 tmp; |
1374 | 1390 | ||
1375 | u32 notifier = readl(mmio + NV_ADMA_NOTIFIER); | ||
1376 | u32 notifier_error = readl(mmio + NV_ADMA_NOTIFIER_ERROR); | ||
1377 | u32 gen_ctl = readl(pp->gen_block + NV_ADMA_GEN_CTL); | ||
1378 | u32 status = readw(mmio + NV_ADMA_STAT); | ||
1379 | |||
1380 | ata_port_printk(ap, KERN_ERR, "EH in ADMA mode, notifier 0x%X " | ||
1381 | "notifier_error 0x%X gen_ctl 0x%X status 0x%X\n", | ||
1382 | notifier, notifier_error, gen_ctl, status); | ||
1383 | |||
1384 | for( i=0;i<NV_ADMA_MAX_CPBS;i++) { | ||
1385 | struct nv_adma_cpb *cpb = &pp->cpb[i]; | ||
1386 | if( cpb->ctl_flags || cpb->resp_flags ) | ||
1387 | ata_port_printk(ap, KERN_ERR, | ||
1388 | "CPB %d: ctl_flags 0x%x, resp_flags 0x%x\n", | ||
1389 | i, cpb->ctl_flags, cpb->resp_flags); | ||
1390 | } | ||
1391 | |||
1392 | /* Push us back into port register mode for error handling. */ | 1391 | /* Push us back into port register mode for error handling. */ |
1393 | nv_adma_register_mode(ap); | 1392 | nv_adma_register_mode(ap); |
1394 | 1393 | ||
1395 | ata_port_printk(ap, KERN_ERR, "Resetting port\n"); | ||
1396 | |||
1397 | /* Mark all of the CPBs as invalid to prevent them from being executed */ | 1394 | /* Mark all of the CPBs as invalid to prevent them from being executed */ |
1398 | for( i=0;i<NV_ADMA_MAX_CPBS;i++) | 1395 | for( i=0;i<NV_ADMA_MAX_CPBS;i++) |
1399 | pp->cpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID; | 1396 | pp->cpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID; |