summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci/remote_device.c
diff options
context:
space:
mode:
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;
+}
+