summaryrefslogtreecommitdiff
path: root/drivers/scsi/isci/remote_device.c
diff options
context:
space:
mode:
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>2012-03-08 22:41:51 -0800
committerDan Williams <dan.j.williams@intel.com>2012-05-17 14:33:37 -0700
commit5b6bf225e7fc249c703e19bf2c983d1a59178874 (patch)
tree9c9b855474b77323c0d89b33ac224e0c1f016c73 /drivers/scsi/isci/remote_device.c
parent726980d56908f2e230624394f03743689db3110c (diff)
isci: Manage device suspensions during TC terminations.
TCs must be terminated only while the RNC is suspended. This commit adds remote device suspensions and resumptions in the abort, reset and termination paths. Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/remote_device.c')
-rw-r--r--drivers/scsi/isci/remote_device.c90
1 files changed, 73 insertions, 17 deletions
diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 9f03877534d2..4f76dcd1cec2 100644
--- a/drivers/scsi/isci/remote_device.c
+++ b/drivers/scsi/isci/remote_device.c
@@ -143,6 +143,12 @@ static enum sci_status sci_remote_device_suspend(
NULL, NULL);
}
+static int isci_remote_device_suspendcheck(struct isci_remote_device *idev)
+{
+ return test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
+ || !test_bit(IDEV_ALLOCATED, &idev->flags);
+}
+
enum sci_status isci_remote_device_suspend(
struct isci_host *ihost,
struct isci_remote_device *idev)
@@ -151,18 +157,18 @@ enum sci_status isci_remote_device_suspend(
unsigned long flags;
spin_lock_irqsave(&ihost->scic_lock, flags);
-
- if (isci_lookup_device(idev->domain_dev) == NULL) {
+ if (isci_get_device(idev->domain_dev) == NULL) {
spin_unlock_irqrestore(&ihost->scic_lock, flags);
status = SCI_FAILURE;
} else {
status = sci_remote_device_suspend(idev);
spin_unlock_irqrestore(&ihost->scic_lock, flags);
if (status == SCI_SUCCESS) {
+ dev_dbg(&ihost->pdev->dev,
+ "%s: idev=%p, about to wait\n",
+ __func__, idev);
wait_event(ihost->eventq,
- test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
- || !test_bit(IDEV_ALLOCATED, &idev->flags));
-
+ isci_remote_device_suspendcheck(idev));
status = test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
? SCI_SUCCESS : SCI_FAILURE;
dev_dbg(&ihost->pdev->dev,
@@ -171,7 +177,10 @@ enum sci_status isci_remote_device_suspend(
test_bit(IDEV_TXRX_SUSPENDED, &idev->flags)
? "<suspended>" : "<deallocated!>");
- }
+ } else
+ dev_dbg(scirdev_to_dev(idev),
+ "%s: sci_remote_device_suspend failed, "
+ "status = %d\n", __func__, status);
isci_put_device(idev);
}
return status;
@@ -1218,6 +1227,35 @@ static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport,
return SCI_SUCCESS;
}
+enum sci_status sci_remote_device_resume(
+ struct isci_remote_device *idev,
+ scics_sds_remote_node_context_callback cb_fn,
+ void *cb_p)
+{
+ enum sci_status status;
+
+ status = sci_remote_node_context_resume(&idev->rnc, cb_fn, cb_p);
+ if (status != SCI_SUCCESS)
+ dev_dbg(scirdev_to_dev(idev), "%s: failed to resume: %d\n",
+ __func__, status);
+ return status;
+}
+
+enum sci_status isci_remote_device_resume(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev,
+ scics_sds_remote_node_context_callback cb_fn,
+ void *cb_p)
+{
+ unsigned long flags;
+ enum sci_status status;
+
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ status = sci_remote_device_resume(idev, cb_fn, cb_p);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+ return status;
+}
/**
* sci_remote_device_start() - This method will start the supplied remote
* device. This method enables normal IO requests to flow through to the
@@ -1244,9 +1282,8 @@ static enum sci_status sci_remote_device_start(struct isci_remote_device *idev,
return SCI_FAILURE_INVALID_STATE;
}
- status = sci_remote_node_context_resume(&idev->rnc,
- remote_device_resume_done,
- idev);
+ status = sci_remote_device_resume(idev, remote_device_resume_done,
+ idev);
if (status != SCI_SUCCESS)
return status;
@@ -1461,26 +1498,29 @@ int isci_remote_device_found(struct domain_device *dev)
}
enum sci_status isci_remote_device_reset(
+ struct isci_host *ihost,
struct isci_remote_device *idev)
{
- struct isci_host *ihost = dev_to_ihost(idev->domain_dev);
unsigned long flags;
enum sci_status status;
- /* Wait for the device suspend. */
- status = isci_remote_device_suspend(ihost, idev);
+ /* Put the device into a reset state so the suspension will not
+ * automatically resume.
+ */
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ status = sci_remote_device_reset(idev);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
if (status != SCI_SUCCESS) {
dev_dbg(&ihost->pdev->dev,
- "%s: isci_remote_device_suspend(%p) returned %d!\n",
+ "%s: sci_remote_device_reset(%p) returned %d!\n",
__func__, idev, status);
return status;
}
- spin_lock_irqsave(&ihost->scic_lock, flags);
- status = sci_remote_device_reset(idev);
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
+ /* Wait for the device suspend. */
+ status = isci_remote_device_suspend(ihost, idev);
if (status != SCI_SUCCESS) {
dev_dbg(&ihost->pdev->dev,
- "%s: sci_remote_device_reset(%p) returned %d!\n",
+ "%s: isci_remote_device_suspend(%p) returned %d!\n",
__func__, idev, status);
}
return status;
@@ -1497,3 +1537,19 @@ enum sci_status sci_remote_device_abort_requests_pending_abort(
{
return sci_remote_device_terminate_requests_checkabort(idev, 1);
}
+
+enum sci_status isci_remote_device_reset_complete(
+ struct isci_host *ihost,
+ struct isci_remote_device *idev)
+{
+ unsigned long flags;
+ enum sci_status status;
+
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ status = sci_remote_device_reset_complete(idev);
+ sci_remote_device_resume(idev, NULL, NULL);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+
+ return status;
+}
+