aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata/sata_nv.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2010-06-25 09:03:34 -0400
committerJeff Garzik <jgarzik@redhat.com>2010-10-21 20:21:03 -0400
commit1aadf5c3bbbbb0db09dcb5aa26c61326e0d3e9e7 (patch)
tree6aff1f6dc2761f85488be2ed2be5e7f4c92c907c /drivers/ata/sata_nv.c
parentd9027470b88631d0956ac37cdadfdeb9cdcf2c99 (diff)
libata: always use ata_qc_complete_multiple() for NCQ command completions
Currently, sata_fsl, mv and nv call ata_qc_complete() multiple times from their interrupt handlers to indicate completion of NCQ commands. This limits the visibility the libata core layer has into how commands are being executed and completed, which is necessary to support IRQ expecting in generic way. libata already has an interface to complete multiple commands at once - ata_qc_complete_multiple() which ahci and sata_sil24 already use. This patch updates the three drivers to use ata_qc_complete_multiple() too and updates comments on ata_qc_complete[_multiple]() regarding their usages with NCQ completions. This change not only provides better visibility into command execution to the core layer but also simplifies low level drivers. * sata_fsl: It already builds done_mask. Conversion is straight forward. * sata_mv: mv_process_crpb_response() no longer checks for illegal completions, it just returns whether the tag is completed or not. mv_process_crpb_entries() builds done_mask from it and passes it to ata_qc_complete_multiple() which will check for illegal completions. * sata_nv adma: Similar to sata_mv. nv_adma_check_cpb() now just returns the tag status and nv_adma_interrupt() builds done_mask from it and passes it to ata_qc_complete_multiple(). * sata_nv swncq: It already builds done_mask. Drop unnecessary illegal transition checks and call ata_qc_complete_multiple(). In the long run, it might be a good idea to make ata_qc_complete() whine if called when multiple NCQ commands are in flight. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Ashish Kalra <ashish.kalra@freescale.com> Cc: Saeed Bishara <saeed@marvell.com> Cc: Mark Lord <liml@rtr.ca> Cc: Robert Hancock <hancockr@shaw.ca> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/sata_nv.c')
-rw-r--r--drivers/ata/sata_nv.c57
1 files changed, 13 insertions, 44 deletions
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index cb89ef8d99d9..7254e255fd78 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -873,29 +873,11 @@ static int nv_adma_check_cpb(struct ata_port *ap, int cpb_num, int force_err)
873 ata_port_freeze(ap); 873 ata_port_freeze(ap);
874 else 874 else
875 ata_port_abort(ap); 875 ata_port_abort(ap);
876 return 1; 876 return -1;
877 } 877 }
878 878
879 if (likely(flags & NV_CPB_RESP_DONE)) { 879 if (likely(flags & NV_CPB_RESP_DONE))
880 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num); 880 return 1;
881 VPRINTK("CPB flags done, flags=0x%x\n", flags);
882 if (likely(qc)) {
883 DPRINTK("Completing qc from tag %d\n", cpb_num);
884 ata_qc_complete(qc);
885 } else {
886 struct ata_eh_info *ehi = &ap->link.eh_info;
887 /* Notifier bits set without a command may indicate the drive
888 is misbehaving. Raise host state machine violation on this
889 condition. */
890 ata_port_printk(ap, KERN_ERR,
891 "notifier for tag %d with no cmd?\n",
892 cpb_num);
893 ehi->err_mask |= AC_ERR_HSM;
894 ehi->action |= ATA_EH_RESET;
895 ata_port_freeze(ap);
896 return 1;
897 }
898 }
899 return 0; 881 return 0;
900} 882}
901 883
@@ -1018,6 +1000,7 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
1018 NV_ADMA_STAT_CPBERR | 1000 NV_ADMA_STAT_CPBERR |
1019 NV_ADMA_STAT_CMD_COMPLETE)) { 1001 NV_ADMA_STAT_CMD_COMPLETE)) {
1020 u32 check_commands = notifier_clears[i]; 1002 u32 check_commands = notifier_clears[i];
1003 u32 done_mask = 0;
1021 int pos, rc; 1004 int pos, rc;
1022 1005
1023 if (status & NV_ADMA_STAT_CPBERR) { 1006 if (status & NV_ADMA_STAT_CPBERR) {
@@ -1034,10 +1017,13 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance)
1034 pos--; 1017 pos--;
1035 rc = nv_adma_check_cpb(ap, pos, 1018 rc = nv_adma_check_cpb(ap, pos,
1036 notifier_error & (1 << pos)); 1019 notifier_error & (1 << pos));
1037 if (unlikely(rc)) 1020 if (rc > 0)
1021 done_mask |= 1 << pos;
1022 else if (unlikely(rc < 0))
1038 check_commands = 0; 1023 check_commands = 0;
1039 check_commands &= ~(1 << pos); 1024 check_commands &= ~(1 << pos);
1040 } 1025 }
1026 ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
1041 } 1027 }
1042 } 1028 }
1043 1029
@@ -2132,7 +2118,6 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
2132 struct ata_eh_info *ehi = &ap->link.eh_info; 2118 struct ata_eh_info *ehi = &ap->link.eh_info;
2133 u32 sactive; 2119 u32 sactive;
2134 u32 done_mask; 2120 u32 done_mask;
2135 int i;
2136 u8 host_stat; 2121 u8 host_stat;
2137 u8 lack_dhfis = 0; 2122 u8 lack_dhfis = 0;
2138 2123
@@ -2152,27 +2137,11 @@ static int nv_swncq_sdbfis(struct ata_port *ap)
2152 sactive = readl(pp->sactive_block); 2137 sactive = readl(pp->sactive_block);
2153 done_mask = pp->qc_active ^ sactive; 2138 done_mask = pp->qc_active ^ sactive;
2154 2139
2155 if (unlikely(done_mask & sactive)) { 2140 pp->qc_active &= ~done_mask;
2156 ata_ehi_clear_desc(ehi); 2141 pp->dhfis_bits &= ~done_mask;
2157 ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition" 2142 pp->dmafis_bits &= ~done_mask;
2158 "(%08x->%08x)", pp->qc_active, sactive); 2143 pp->sdbfis_bits |= done_mask;
2159 ehi->err_mask |= AC_ERR_HSM; 2144 ata_qc_complete_multiple(ap, ap->qc_active ^ done_mask);
2160 ehi->action |= ATA_EH_RESET;
2161 return -EINVAL;
2162 }
2163 for (i = 0; i < ATA_MAX_QUEUE; i++) {
2164 if (!(done_mask & (1 << i)))
2165 continue;
2166
2167 qc = ata_qc_from_tag(ap, i);
2168 if (qc) {
2169 ata_qc_complete(qc);
2170 pp->qc_active &= ~(1 << i);
2171 pp->dhfis_bits &= ~(1 << i);
2172 pp->dmafis_bits &= ~(1 << i);
2173 pp->sdbfis_bits |= (1 << i);
2174 }
2175 }
2176 2145
2177 if (!ap->qc_active) { 2146 if (!ap->qc_active) {
2178 DPRINTK("over\n"); 2147 DPRINTK("over\n");