Skip to content

Commit c96f173

Browse files
Alan CoxJeff Garzik
authored andcommitted
[libata] Improve timeout handling
On a timeout call a device specific handler early in the recovery so that we can complete and process successful commands which timed out due to IRQ loss or the like rather more elegantly. [Revised to exclude the timeout handling on a few devices that inherit from SFF but are not SFF enough to use the default timeout handler] Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
1 parent 3d47aa8 commit c96f173

File tree

10 files changed

+85
-5
lines changed

10 files changed

+85
-5
lines changed

drivers/ata/libata-eh.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -547,7 +547,7 @@ void ata_scsi_error(struct Scsi_Host *host)
547547

548548
/* For new EH, all qcs are finished in one of three ways -
549549
* normal completion, error completion, and SCSI timeout.
550-
* Both cmpletions can race against SCSI timeout. When normal
550+
* Both completions can race against SCSI timeout. When normal
551551
* completion wins, the qc never reaches EH. When error
552552
* completion wins, the qc has ATA_QCFLAG_FAILED set.
553553
*
@@ -562,7 +562,19 @@ void ata_scsi_error(struct Scsi_Host *host)
562562
int nr_timedout = 0;
563563

564564
spin_lock_irqsave(ap->lock, flags);
565-
565+
566+
/* This must occur under the ap->lock as we don't want
567+
a polled recovery to race the real interrupt handler
568+
569+
The lost_interrupt handler checks for any completed but
570+
non-notified command and completes much like an IRQ handler.
571+
572+
We then fall into the error recovery code which will treat
573+
this as if normal completion won the race */
574+
575+
if (ap->ops->lost_interrupt)
576+
ap->ops->lost_interrupt(ap);
577+
566578
list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
567579
struct ata_queued_cmd *qc;
568580

@@ -606,6 +618,9 @@ void ata_scsi_error(struct Scsi_Host *host)
606618
ap->eh_tries = ATA_EH_MAX_TRIES;
607619
} else
608620
spin_unlock_wait(ap->lock);
621+
622+
/* If we timed raced normal completion and there is nothing to
623+
recover nr_timedout == 0 why exactly are we doing error recovery ? */
609624

610625
repeat:
611626
/* invoke error handler */

drivers/ata/libata-sff.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ const struct ata_port_operations ata_sff_port_ops = {
6565
.sff_irq_on = ata_sff_irq_on,
6666
.sff_irq_clear = ata_sff_irq_clear,
6767

68+
.lost_interrupt = ata_sff_lost_interrupt,
69+
6870
.port_start = ata_sff_port_start,
6971
};
7072
EXPORT_SYMBOL_GPL(ata_sff_port_ops);
@@ -1647,7 +1649,7 @@ EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf);
16471649
* RETURNS:
16481650
* One if interrupt was handled, zero if not (shared irq).
16491651
*/
1650-
inline unsigned int ata_sff_host_intr(struct ata_port *ap,
1652+
unsigned int ata_sff_host_intr(struct ata_port *ap,
16511653
struct ata_queued_cmd *qc)
16521654
{
16531655
struct ata_eh_info *ehi = &ap->link.eh_info;
@@ -1775,6 +1777,48 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance)
17751777
}
17761778
EXPORT_SYMBOL_GPL(ata_sff_interrupt);
17771779

1780+
/**
1781+
* ata_sff_lost_interrupt - Check for an apparent lost interrupt
1782+
* @ap: port that appears to have timed out
1783+
*
1784+
* Called from the libata error handlers when the core code suspects
1785+
* an interrupt has been lost. If it has complete anything we can and
1786+
* then return. Interface must support altstatus for this faster
1787+
* recovery to occur.
1788+
*
1789+
* Locking:
1790+
* Caller holds host lock
1791+
*/
1792+
1793+
void ata_sff_lost_interrupt(struct ata_port *ap)
1794+
{
1795+
u8 status;
1796+
struct ata_queued_cmd *qc;
1797+
1798+
/* Only one outstanding command per SFF channel */
1799+
qc = ata_qc_from_tag(ap, ap->link.active_tag);
1800+
/* Check we have a live one.. */
1801+
if (qc == NULL || !(qc->flags & ATA_QCFLAG_ACTIVE))
1802+
return;
1803+
/* We cannot lose an interrupt on a polled command */
1804+
if (qc->tf.flags & ATA_TFLAG_POLLING)
1805+
return;
1806+
/* See if the controller thinks it is still busy - if so the command
1807+
isn't a lost IRQ but is still in progress */
1808+
status = ata_sff_altstatus(ap);
1809+
if (status & ATA_BUSY)
1810+
return;
1811+
1812+
/* There was a command running, we are no longer busy and we have
1813+
no interrupt. */
1814+
ata_port_printk(ap, KERN_WARNING, "lost interrupt (Status 0x%x)\n",
1815+
status);
1816+
/* Run the host interrupt logic as if the interrupt had not been
1817+
lost */
1818+
ata_sff_host_intr(ap, qc);
1819+
}
1820+
EXPORT_SYMBOL_GPL(ata_sff_lost_interrupt);
1821+
17781822
/**
17791823
* ata_sff_freeze - Freeze SFF controller port
17801824
* @ap: port to freeze

drivers/ata/pata_isapnp.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include <linux/libata.h>
1818

1919
#define DRV_NAME "pata_isapnp"
20-
#define DRV_VERSION "0.2.2"
20+
#define DRV_VERSION "0.2.5"
2121

2222
static struct scsi_host_template isapnp_sht = {
2323
ATA_PIO_SHT(DRV_NAME),
@@ -28,6 +28,13 @@ static struct ata_port_operations isapnp_port_ops = {
2828
.cable_detect = ata_cable_40wire,
2929
};
3030

31+
static struct ata_port_operations isapnp_noalt_port_ops = {
32+
.inherits = &ata_sff_port_ops,
33+
.cable_detect = ata_cable_40wire,
34+
/* No altstatus so we don't want to use the lost interrupt poll */
35+
.lost_interrupt = ATA_OP_NULL,
36+
};
37+
3138
/**
3239
* isapnp_init_one - attach an isapnp interface
3340
* @idev: PnP device
@@ -65,7 +72,7 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
6572

6673
ap = host->ports[0];
6774

68-
ap->ops = &isapnp_port_ops;
75+
ap->ops = &isapnp_noalt_port_ops;
6976
ap->pio_mask = ATA_PIO0;
7077
ap->flags |= ATA_FLAG_SLAVE_POSS;
7178

@@ -76,6 +83,7 @@ static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev
7683
pnp_port_start(idev, 1), 1);
7784
ap->ioaddr.altstatus_addr = ctl_addr;
7885
ap->ioaddr.ctl_addr = ctl_addr;
86+
ap->ops = &isapnp_port_ops;
7987
}
8088

8189
ata_sff_std_ports(&ap->ioaddr);

drivers/ata/pdc_adma.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ static struct scsi_host_template adma_ata_sht = {
148148
static struct ata_port_operations adma_ata_ops = {
149149
.inherits = &ata_sff_port_ops,
150150

151+
.lost_interrupt = ATA_OP_NULL,
152+
151153
.check_atapi_dma = adma_check_atapi_dma,
152154
.qc_prep = adma_qc_prep,
153155
.qc_issue = adma_qc_issue,

drivers/ata/sata_mv.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,8 @@ static struct scsi_host_template mv6_sht = {
646646
static struct ata_port_operations mv5_ops = {
647647
.inherits = &ata_sff_port_ops,
648648

649+
.lost_interrupt = ATA_OP_NULL,
650+
649651
.qc_defer = mv_qc_defer,
650652
.qc_prep = mv_qc_prep,
651653
.qc_issue = mv_qc_issue,

drivers/ata/sata_nv.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ static struct scsi_host_template nv_swncq_sht = {
408408

409409
static struct ata_port_operations nv_common_ops = {
410410
.inherits = &ata_bmdma_port_ops,
411+
.lost_interrupt = ATA_OP_NULL,
411412
.scr_read = nv_scr_read,
412413
.scr_write = nv_scr_write,
413414
};

drivers/ata/sata_promise.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,9 @@ static const struct ata_port_operations pdc_common_ops = {
176176
.check_atapi_dma = pdc_check_atapi_dma,
177177
.qc_prep = pdc_qc_prep,
178178
.qc_issue = pdc_qc_issue,
179+
179180
.sff_irq_clear = pdc_irq_clear,
181+
.lost_interrupt = ATA_OP_NULL,
180182

181183
.post_internal_cmd = pdc_post_internal_cmd,
182184
.error_handler = pdc_error_handler,

drivers/ata/sata_qstor.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ static struct ata_port_operations qs_ata_ops = {
147147
.softreset = ATA_OP_NULL,
148148
.error_handler = qs_error_handler,
149149
.post_internal_cmd = ATA_OP_NULL,
150+
.lost_interrupt = ATA_OP_NULL,
150151

151152
.scr_read = qs_scr_read,
152153
.scr_write = qs_scr_write,

drivers/ata/sata_vsc.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ static struct scsi_host_template vsc_sata_sht = {
308308

309309
static struct ata_port_operations vsc_sata_ops = {
310310
.inherits = &ata_bmdma_port_ops,
311+
/* The IRQ handling is not quite standard SFF behaviour so we
312+
cannot use the default lost interrupt handler */
313+
.lost_interrupt = ATA_OP_NULL,
311314
.sff_tf_load = vsc_sata_tf_load,
312315
.sff_tf_read = vsc_sata_tf_read,
313316
.freeze = vsc_freeze,

include/linux/libata.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,7 @@ struct ata_port_operations {
795795
ata_reset_fn_t pmp_hardreset;
796796
ata_postreset_fn_t pmp_postreset;
797797
void (*error_handler)(struct ata_port *ap);
798+
void (*lost_interrupt)(struct ata_port *ap);
798799
void (*post_internal_cmd)(struct ata_queued_cmd *qc);
799800

800801
/*
@@ -1577,6 +1578,7 @@ extern bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc);
15771578
extern unsigned int ata_sff_host_intr(struct ata_port *ap,
15781579
struct ata_queued_cmd *qc);
15791580
extern irqreturn_t ata_sff_interrupt(int irq, void *dev_instance);
1581+
extern void ata_sff_lost_interrupt(struct ata_port *ap);
15801582
extern void ata_sff_freeze(struct ata_port *ap);
15811583
extern void ata_sff_thaw(struct ata_port *ap);
15821584
extern int ata_sff_prereset(struct ata_link *link, unsigned long deadline);

0 commit comments

Comments
 (0)