From: Tejun Heo <htejun@gmail.com>
To: jgarzik@pobox.com, albertcc@tw.ibm.com, linux-ide@vger.kernel.org
Cc: Tejun Heo <htejun@gmail.com>
Subject: [PATCH 2/4] libata: implement ata_scsi_timed_out()
Date: Fri, 10 Feb 2006 15:10:48 +0900 [thread overview]
Message-ID: <11395518483886-git-send-email-htejun@gmail.com> (raw)
In-Reply-To: <11395518482722-git-send-email-htejun@gmail.com>
Implement ata_scsi_timed_out(), to be used as
scsi_host_template->eh_timed_out callback for all libata drivers.
Without this function, the following race exists.
If a qc completes after SCSI timer expires but before libata EH kicks
in, the qc gets completed but the scsicmd still gets passed to libata
EH resulting in ->eng_timeout invocation with NULL qc, which none is
handling properly.
This patch makes sure that scmd and qc share the same lifetime.
Original idea from Jeff Garzik <jgarzik@pobox.com>.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/libata-core.c | 1 +
drivers/scsi/libata-scsi.c | 41 +++++++++++++++++++++++++++++++++++++++++
include/linux/libata.h | 1 +
3 files changed, 43 insertions(+), 0 deletions(-)
0421953f2a2dee014a3e288c523129a3c602e3ae
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 977a53d..d53e0bc 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -4913,6 +4913,7 @@ EXPORT_SYMBOL_GPL(ata_ratelimit);
EXPORT_SYMBOL_GPL(ata_busy_sleep);
EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
+EXPORT_SYMBOL_GPL(ata_scsi_timed_out);
EXPORT_SYMBOL_GPL(ata_scsi_error);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
EXPORT_SYMBOL_GPL(ata_scsi_release);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 1df468e..d67cc2f 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -717,6 +717,47 @@ int ata_scsi_slave_config(struct scsi_de
}
/**
+ * ata_scsi_timed_out - SCSI layer time out callback
+ * @cmd: timed out SCSI command
+ *
+ * Handles SCSI layer timeout. We race with normal completion of
+ * the qc for @cmd. If the qc is already gone, we lose and let
+ * the scsi command finish (EH_HANDLED). Otherwise, the qc has
+ * timed out and EH should be invoked. Prevent ata_qc_complete()
+ * from finishing it by setting EH_SCHEDULED and return
+ * EH_NOT_HANDLED.
+ *
+ * LOCKING:
+ * Called from timer context
+ *
+ * RETURNS:
+ * EH_HANDLED or EH_NOT_HANDLED
+ */
+enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct ata_port *ap = (struct ata_port *) &host->hostdata[0];
+ unsigned long flags;
+ struct ata_queued_cmd *qc;
+ enum scsi_eh_timer_return ret = EH_HANDLED;
+
+ DPRINTK("ENTER\n");
+
+ spin_lock_irqsave(&ap->host_set->lock, flags);
+ qc = ata_qc_from_tag(ap, ap->active_tag);
+ if (qc) {
+ assert(qc->scsicmd == cmd);
+ qc->flags |= ATA_QCFLAG_EH_SCHEDULED;
+ qc->err_mask |= AC_ERR_TIMEOUT;
+ ret = EH_NOT_HANDLED;
+ }
+ spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+ DPRINTK("EXIT, ret=%d\n", ret);
+ return ret;
+}
+
+/**
* ata_scsi_error - SCSI layer error handler callback
* @host: SCSI host on which error occurred
*
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 5c70a57..c1e1986 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -509,6 +509,7 @@ extern void ata_host_set_remove(struct a
extern int ata_scsi_detect(struct scsi_host_template *sht);
extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
+extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
extern int ata_scsi_error(struct Scsi_Host *host);
extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
--
1.1.5
next prev parent reply other threads:[~2006-02-10 6:10 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-02-10 6:10 [PATCHSET] libata: various fixes related to EH, take #4 Tejun Heo
2006-02-10 6:10 ` [PATCH 4/4] libata: kill NULL qc handling from ->eng_timeout callbacks Tejun Heo
2006-02-10 6:10 ` Tejun Heo [this message]
2006-02-10 6:10 ` [PATCH 1/4] libata: add ATA_QCFLAG_EH_SCHEDULED Tejun Heo
2006-02-10 6:10 ` [PATCH 3/4] libata: use ata_scsi_timed_out() Tejun Heo
2006-02-10 12:00 ` [PATCHSET] libata: various fixes related to EH, take #4 Jeff Garzik
2006-02-10 12:16 ` Tejun Heo
2006-02-11 6:13 ` [PATCH] libata: inline ata_qc_complete() Tejun Heo
2006-02-11 22:53 ` Jeff Garzik
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=11395518483886-git-send-email-htejun@gmail.com \
--to=htejun@gmail.com \
--cc=albertcc@tw.ibm.com \
--cc=jgarzik@pobox.com \
--cc=linux-ide@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).