Skip to content

Commit 5bd28a4

Browse files
Robert HancockJeff Garzik
authored andcommitted
sata_nv: cleanup ADMA error handling
This cleans up a few issues with the error handling in sata_nv in ADMA mode to make it more consistent with other NCQ-capable drivers like ahci and sata_sil24: - When a command failed, we would effectively set AC_ERR_DEV on the queued command always. In the case of NCQ commands this prevents libata from doing a log page query to determine the details of the failed command, since it thinks we've already analyzed. Just set flags in the port ehi->err_mask, then freeze or abort and let libata figure out what went wrong. - The code handled NV_ADMA_STAT_CPBERR as a "really bad error" which caused it to set error flags on every queued command. I don't know exactly what this flag means (no docs, grr!) but from what I can guess from the standard ADMA spec, it just means that one or more of the CPBs had an error, so we just need to go through and do our normal checks in this case. - In the error_handler function the code would always dump the state of all the CPBs. This output seems redundant at this point since libata already dumps the state of all active commands on errors (and it also triggers at times when it shouldn't, like when suspending). Take this out. [[email protected]: many coding-style fixes] Signed-off-by: Robert Hancock <[email protected]> Cc: Jeff Garzik <[email protected]> Cc: Tejun Heo <[email protected]> Cc: Allen Martin <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Jeff Garzik <[email protected]>
1 parent 92ae784 commit 5bd28a4

File tree

1 file changed

+72
-75
lines changed

1 file changed

+72
-75
lines changed

drivers/ata/sata_nv.c

Lines changed: 72 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -651,53 +651,62 @@ static unsigned int nv_adma_tf_to_cpb(struct ata_taskfile *tf, __le16 *cpb)
651651
return idx;
652652
}
653653

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)
655655
{
656656
struct nv_adma_port_priv *pp = ap->private_data;
657-
int complete = 0, have_err = 0;
658657
u8 flags = pp->cpb[cpb_num].resp_flags;
659658

660659
VPRINTK("CPB %d, flags=0x%x\n", cpb_num, flags);
661660

662-
if (flags & NV_CPB_RESP_DONE) {
663-
VPRINTK("CPB flags done, flags=0x%x\n", flags);
664-
complete = 1;
665-
}
666-
if (flags & NV_CPB_RESP_ATA_ERR) {
667-
ata_port_printk(ap, KERN_ERR, "CPB flags ATA err, flags=0x%x\n", flags);
668-
have_err = 1;
669-
complete = 1;
670-
}
671-
if (flags & NV_CPB_RESP_CMD_ERR) {
672-
ata_port_printk(ap, KERN_ERR, "CPB flags CMD err, flags=0x%x\n", flags);
673-
have_err = 1;
674-
complete = 1;
675-
}
676-
if (flags & NV_CPB_RESP_CPB_ERR) {
677-
ata_port_printk(ap, KERN_ERR, "CPB flags CPB err, flags=0x%x\n", flags);
678-
have_err = 1;
679-
complete = 1;
661+
if (unlikely((force_err ||
662+
flags & (NV_CPB_RESP_ATA_ERR |
663+
NV_CPB_RESP_CMD_ERR |
664+
NV_CPB_RESP_CPB_ERR)))) {
665+
struct ata_eh_info *ehi = &ap->eh_info;
666+
int freeze = 0;
667+
668+
ata_ehi_clear_desc(ehi);
669+
ata_ehi_push_desc(ehi, "CPB resp_flags 0x%x", flags );
670+
if (flags & NV_CPB_RESP_ATA_ERR) {
671+
ata_ehi_push_desc(ehi, ": ATA error");
672+
ehi->err_mask |= AC_ERR_DEV;
673+
} else if (flags & NV_CPB_RESP_CMD_ERR) {
674+
ata_ehi_push_desc(ehi, ": CMD error");
675+
ehi->err_mask |= AC_ERR_DEV;
676+
} else if (flags & NV_CPB_RESP_CPB_ERR) {
677+
ata_ehi_push_desc(ehi, ": CPB error");
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;
680691
}
681-
if(complete || force_err)
682-
{
692+
693+
if (flags & NV_CPB_RESP_DONE) {
683694
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, cpb_num);
684-
if(likely(qc)) {
685-
u8 ata_status = 0;
686-
/* Only use the ATA port status for non-NCQ commands.
695+
VPRINTK("CPB flags done, flags=0x%x\n", flags);
696+
if (likely(qc)) {
697+
/* Grab the ATA port status for non-NCQ commands.
687698
For NCQ commands the current status may have nothing to do with
688699
the command just completed. */
689-
if(qc->tf.protocol != ATA_PROT_NCQ)
690-
ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4));
691-
692-
if(have_err || force_err)
693-
ata_status |= ATA_ERR;
694-
695-
qc->err_mask |= ac_err_mask(ata_status);
700+
if (qc->tf.protocol != ATA_PROT_NCQ) {
701+
u8 ata_status = readb(pp->ctl_block + (ATA_REG_STATUS * 4));
702+
qc->err_mask |= ac_err_mask(ata_status);
703+
}
696704
DPRINTK("Completing qc from tag %d with err_mask %u\n",cpb_num,
697705
qc->err_mask);
698706
ata_qc_complete(qc);
699707
}
700708
}
709+
return 0;
701710
}
702711

703712
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)
741750
void __iomem *mmio = pp->ctl_block;
742751
u16 status;
743752
u32 gen_ctl;
744-
int have_global_err = 0;
745753
u32 notifier, notifier_error;
746754

747755
/* 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)
777785
readw(mmio + NV_ADMA_STAT); /* flush posted write */
778786
rmb();
779787

780-
/* freeze if hotplugged */
781-
if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | NV_ADMA_STAT_HOTUNPLUG))) {
782-
ata_port_printk(ap, KERN_NOTICE, "Hotplug event, freezing\n");
788+
handled++; /* irq handled if we got here */
789+
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+
}
783808
ata_port_freeze(ap);
784-
handled++;
785809
continue;
786810
}
787811

788-
if (status & NV_ADMA_STAT_TIMEOUT) {
789-
ata_port_printk(ap, KERN_ERR, "timeout, stat=0x%x\n", status);
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) {
812+
if (status & (NV_ADMA_STAT_DONE |
813+
NV_ADMA_STAT_CPBERR)) {
797814
/** Check CPBs for completed commands */
798815

799-
if(ata_tag_valid(ap->active_tag))
816+
if (ata_tag_valid(ap->active_tag)) {
800817
/* Non-NCQ command */
801-
nv_adma_check_cpb(ap, ap->active_tag, have_global_err ||
802-
(notifier_error & (1 << ap->active_tag)));
803-
else {
804-
int pos;
818+
nv_adma_check_cpb(ap, ap->active_tag,
819+
notifier_error & (1 << ap->active_tag));
820+
} else {
821+
int pos, error = 0;
805822
u32 active = ap->sactive;
806-
while( (pos = ffs(active)) ) {
823+
824+
while ((pos = ffs(active)) && !error) {
807825
pos--;
808-
nv_adma_check_cpb(ap, pos, have_global_err ||
809-
(notifier_error & (1 << pos)) );
826+
error = nv_adma_check_cpb(ap, pos,
827+
notifier_error & (1 << pos) );
810828
active &= ~(1 << pos );
811829
}
812830
}
813831
}
814-
815-
handled++; /* irq handled if we got here */
816832
}
817833
}
818834

@@ -1372,28 +1388,9 @@ static void nv_adma_error_handler(struct ata_port *ap)
13721388
int i;
13731389
u16 tmp;
13741390

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-
13921391
/* Push us back into port register mode for error handling. */
13931392
nv_adma_register_mode(ap);
13941393

1395-
ata_port_printk(ap, KERN_ERR, "Resetting port\n");
1396-
13971394
/* Mark all of the CPBs as invalid to prevent them from being executed */
13981395
for( i=0;i<NV_ADMA_MAX_CPBS;i++)
13991396
pp->cpb[i].ctl_flags &= ~NV_CPB_CTL_CPB_VALID;

0 commit comments

Comments
 (0)