From: Dan Williams <dan.j.williams@intel.com>
To: linux-scsi@vger.kernel.org
Cc: Tejun Heo <tj@kernel.org>, linux-ide@vger.kernel.org
Subject: [PATCH 24/24] libsas: poll for ata device readiness after reset
Date: Fri, 16 Dec 2011 18:35:12 -0800 [thread overview]
Message-ID: <20111217023512.15036.97516.stgit@localhost6.localdomain6> (raw)
In-Reply-To: <20111217022912.15036.85808.stgit@localhost6.localdomain6>
Use ata_wait_after_reset() to poll for link recovery after a reset.
This combined with sas_ha->eh_mutex prevents expander rediscovery from
probing phys in an intermediate state. Local discovery does not have a
mechanism to filter link status changes during this timeout, so it
remains the responsibility of lldds to prevent premature port teardown.
Although once all lldd's support ->lldd_ata_check_ready() that could be
used as a gate to local port teardown.
The signature fis is re-transmitted when the link comes back so we
should be revalidating the ata device class, but that is left to a future
patch.
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
drivers/scsi/libsas/sas_ata.c | 104 +++++++++++++++++++++++++-----------
drivers/scsi/libsas/sas_expander.c | 10 ++-
drivers/scsi/libsas/sas_internal.h | 3 +
include/scsi/libsas.h | 1
4 files changed, 83 insertions(+), 35 deletions(-)
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 773e010..a5a7184 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -267,39 +267,84 @@ static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
return true;
}
-static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
+static struct sas_internal *dev_to_sas_internal(struct domain_device *dev)
+{
+ return to_sas_internal(dev->port->ha->core.shost->transportt);
+}
+
+static int smp_ata_check_ready(struct ata_link *link)
{
+ int res;
+ u8 addr[8];
struct ata_port *ap = link->ap;
struct domain_device *dev = ap->private_data;
- struct sas_internal *i =
- to_sas_internal(dev->port->ha->core.shost->transportt);
- int res = TMF_RESP_FUNC_FAILED;
- int ret = 0;
+ struct domain_device *ex_dev = dev->parent;
+ struct sas_phy *phy = sas_find_local_phy(dev);
- if (i->dft->lldd_I_T_nexus_reset)
- res = i->dft->lldd_I_T_nexus_reset(dev);
+ res = sas_get_phy_attached_sas_addr(ex_dev, phy->number, addr);
+ /* break the wait early if the expander is unreachable,
+ * otherwise keep polling
+ */
+ if (res == -ECOMM)
+ return res;
+ if (res != SMP_RESP_FUNC_ACC || SAS_ADDR(addr) == 0)
+ return 0;
+ else
+ return 1;
+}
- if (res != TMF_RESP_FUNC_COMPLETE) {
- SAS_DPRINTK("%s: Unable to reset I T nexus?\n", __func__);
- ret = -EAGAIN;
+static int local_ata_check_ready(struct ata_link *link)
+{
+ struct ata_port *ap = link->ap;
+ struct domain_device *dev = ap->private_data;
+ struct sas_internal *i = dev_to_sas_internal(dev);
+
+ if (i->dft->lldd_ata_check_ready)
+ return i->dft->lldd_ata_check_ready(dev);
+ else {
+ /* lldd's that don't implement 'ready' checking get the
+ * old default behavior of not coordinating reset
+ * recovery with libata
+ */
+ return 1;
}
+}
+static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int ret = 0, res;
+ struct ata_port *ap = link->ap;
+ int (*check_ready)(struct ata_link *link);
+ struct domain_device *dev = ap->private_data;
+ struct sas_phy *phy = sas_find_local_phy(dev);
+ struct sas_internal *i = dev_to_sas_internal(dev);
+
+ res = i->dft->lldd_I_T_nexus_reset(dev);
+
+ if (res != TMF_RESP_FUNC_COMPLETE)
+ SAS_DPRINTK("%s: Unable to reset ata device?\n", __func__);
+
+ if (scsi_is_sas_phy_local(phy))
+ check_ready = local_ata_check_ready;
+ else
+ check_ready = smp_ata_check_ready;
+
+ ret = ata_wait_after_reset(link, deadline, check_ready);
+ if (ret && ret != -EAGAIN)
+ ata_link_err(link, "COMRESET failed (errno=%d)\n", ret);
+
+ /* XXX: if the class changes during the reset the upper layer
+ * should be informed, if the device has gone away we assume
+ * libsas will eventually delete it
+ */
switch (dev->sata_dev.command_set) {
- case ATA_COMMAND_SET:
- SAS_DPRINTK("%s: Found ATA device.\n", __func__);
- *class = ATA_DEV_ATA;
- break;
- case ATAPI_COMMAND_SET:
- SAS_DPRINTK("%s: Found ATAPI device.\n", __func__);
- *class = ATA_DEV_ATAPI;
- break;
- default:
- SAS_DPRINTK("%s: Unknown SATA command set: %d.\n",
- __func__,
- dev->sata_dev.command_set);
- *class = ATA_DEV_UNKNOWN;
- break;
+ case ATA_COMMAND_SET:
+ *class = ATA_DEV_ATA;
+ break;
+ case ATAPI_COMMAND_SET:
+ *class = ATA_DEV_ATAPI;
+ break;
}
ap->cbl = ATA_CBL_SATA;
@@ -311,8 +356,7 @@ static int sas_ata_soft_reset(struct ata_link *link, unsigned int *class,
{
struct ata_port *ap = link->ap;
struct domain_device *dev = ap->private_data;
- struct sas_internal *i =
- to_sas_internal(dev->port->ha->core.shost->transportt);
+ struct sas_internal *i = dev_to_sas_internal(dev);
int res = TMF_RESP_FUNC_FAILED;
int ret = 0;
@@ -350,8 +394,7 @@ static int sas_ata_soft_reset(struct ata_link *link, unsigned int *class,
*/
static void sas_ata_internal_abort(struct sas_task *task)
{
- struct sas_internal *si =
- to_sas_internal(task->dev->port->ha->core.shost->transportt);
+ struct sas_internal *si = dev_to_sas_internal(task->dev);
unsigned long flags;
int res;
@@ -421,8 +464,7 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc)
static void sas_ata_set_dmamode(struct ata_port *ap, struct ata_device *ata_dev)
{
struct domain_device *dev = ap->private_data;
- struct sas_internal *i =
- to_sas_internal(dev->port->ha->core.shost->transportt);
+ struct sas_internal *i = dev_to_sas_internal(dev);
if (i->dft->lldd_ata_set_dmamode)
i->dft->lldd_ata_set_dmamode(dev);
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index fd77ea3..5e1eec9 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -125,7 +125,11 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
task->task_status.stat == SAS_DATA_OVERRUN) {
res = -EMSGSIZE;
break;
- } else {
+ }
+ if (task->task_status.resp == SAS_TASK_UNDELIVERED &&
+ task->task_status.stat == SAS_DEVICE_UNKNOWN)
+ break;
+ else {
SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
"status 0x%x\n", __func__,
SAS_ADDR(dev->sas_addr),
@@ -1648,8 +1652,8 @@ static int sas_get_phy_change_count(struct domain_device *dev,
return res;
}
-static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
- int phy_id, u8 *attached_sas_addr)
+int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id,
+ u8 *attached_sas_addr)
{
int res;
struct smp_resp *disc_resp;
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 5879e72..dde4f29 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -74,7 +74,8 @@ int sas_smp_get_phy_events(struct sas_phy *phy);
struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
-
+int sas_get_phy_attached_sas_addr(struct domain_device *dev, int phy_id,
+ u8 *attached_sas_addr);
void sas_hae_reset(struct work_struct *work);
void sas_free_device(struct kref *kref);
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index a8159f9..42110f9 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -605,6 +605,7 @@ struct sas_domain_function_template {
int (*lldd_clear_task_set)(struct domain_device *, u8 *lun);
int (*lldd_I_T_nexus_reset)(struct domain_device *);
int (*lldd_ata_soft_reset)(struct domain_device *);
+ int (*lldd_ata_check_ready)(struct domain_device *);
void (*lldd_ata_set_dmamode)(struct domain_device *);
int (*lldd_lu_reset)(struct domain_device *, u8 *lun);
int (*lldd_query_task)(struct sas_task *);
next prev parent reply other threads:[~2011-12-17 2:35 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-17 2:33 [PATCH 00/24] libsas: eh reworks (ata-eh vs discovery, races, ...) Dan Williams
2011-12-17 2:33 ` [PATCH 01/24] workqueue: promote workqueue_lock to hard-irq safe Dan Williams
2011-12-17 2:33 ` [PATCH 02/24] workqueue: defer work to a draining queue Dan Williams
2011-12-19 21:49 ` Tejun Heo
2011-12-19 22:01 ` Dan Williams
2011-12-19 22:08 ` Tejun Heo
2011-12-19 22:25 ` Williams, Dan J
2011-12-17 2:33 ` [PATCH 03/24] scsi: use drain_workqueue Dan Williams
2011-12-17 2:33 ` [PATCH 04/24] libsas: remove unused ata_task_resp fields Dan Williams
2011-12-17 12:51 ` Sergei Shtylyov
2011-12-19 1:38 ` Jack Wang
2011-12-17 2:33 ` [PATCH 05/24] libsas: kill sas_slave_destroy Dan Williams
2011-12-17 2:33 ` [PATCH 06/24] libsas: fix domain_device leak Dan Williams
2011-12-19 2:32 ` Jack Wang
2011-12-17 2:33 ` [PATCH 07/24] libsas: fix leak of dev->sata_dev.identify_[packet_]device Dan Williams
2011-12-19 2:38 ` Jack Wang
2011-12-17 2:33 ` [PATCH 08/24] libsas: replace event locks with atomic bitops Dan Williams
2011-12-17 2:33 ` [PATCH 09/24] libsas: remove ata_port.lock management duties from lldds Dan Williams
2011-12-17 2:33 ` [PATCH 10/24] libsas: prevent domain rediscovery competing with ata error handling Dan Williams
2011-12-17 2:34 ` [PATCH 11/24] libsas: use ->set_dmamode to notify lldds of NCQ parameters Dan Williams
2011-12-17 2:34 ` [PATCH 12/24] libsas: kill invocation of scsi_eh_finish_cmd from sas_ata_task_done Dan Williams
2011-12-17 2:34 ` [PATCH 13/24] libsas: close error handling vs sas_ata_task_done() race Dan Williams
2011-12-17 2:34 ` [PATCH 14/24] libsas: prevent double completion of scmds from eh Dan Williams
2011-12-17 13:08 ` Sergei Shtylyov
2011-12-18 19:19 ` Dan Williams
2011-12-17 13:13 ` Sergei Shtylyov
2011-12-18 19:24 ` Dan Williams
2011-12-17 2:34 ` [PATCH 15/24] libsas: fix timeout vs completion race Dan Williams
2011-12-17 2:34 ` [PATCH 16/24] libsas: let libata handle command timeouts Dan Williams
2011-12-17 2:34 ` [PATCH 17/24] libsas: defer SAS_TASK_NEED_DEV_RESET commands to libata Dan Williams
2011-12-17 2:34 ` [PATCH 18/24] libsas: use libata-eh-reset for sata rediscovery fis transmit failures Dan Williams
2011-12-17 2:34 ` [PATCH 19/24] libsas: execute transport link resets with libata-eh via host workqueue Dan Williams
2011-12-17 2:34 ` [PATCH 20/24] libsas: sas_phy_enable via transport_sas_phy_reset Dan Williams
2011-12-17 2:34 ` [PATCH 21/24] libsas: Remove redundant phy state notification calls Dan Williams
2011-12-17 2:35 ` [PATCH 22/24] libsas: add mutex for SMP task execution Dan Williams
2011-12-17 2:35 ` [PATCH 23/24] libsas: async ata-eh Dan Williams
2011-12-17 2:35 ` Dan Williams [this message]
2011-12-20 6:18 ` [PATCH 24/24] libsas: poll for ata device readiness after reset Jack Wang
2011-12-20 7:08 ` Williams, Dan J
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=20111217023512.15036.97516.stgit@localhost6.localdomain6 \
--to=dan.j.williams@intel.com \
--cc=linux-ide@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=tj@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.