All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dan Williams <dan.j.williams@intel.com>
To: linux-scsi@vger.kernel.org
Cc: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Subject: [isci-rnc PATCH v1 05/37] isci: Manage device suspensions during TC terminations.
Date: Thu, 22 Mar 2012 17:28:19 -0700	[thread overview]
Message-ID: <20120323002814.18065.46456.stgit@dwillia2-linux.jf.intel.com> (raw)
In-Reply-To: <20120323002504.18065.45709.stgit@dwillia2-linux.jf.intel.com>

From: Jeff Skirvin <jeffrey.d.skirvin@intel.com>

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>
---
 drivers/scsi/isci/remote_device.c |   90 ++++++++++++++++++++++++++++++-------
 drivers/scsi/isci/remote_device.h |   33 ++++++++++++++
 drivers/scsi/isci/task.c          |   80 ++++++++++++++++++++-------------
 3 files changed, 154 insertions(+), 49 deletions(-)

diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c
index 9f03877..4f76dcd 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;
+}
+
diff --git a/drivers/scsi/isci/remote_device.h b/drivers/scsi/isci/remote_device.h
index ae508ee..a6a376e 100644
--- a/drivers/scsi/isci/remote_device.h
+++ b/drivers/scsi/isci/remote_device.h
@@ -106,6 +106,16 @@ struct isci_remote_device {
 #define ISCI_REMOTE_DEVICE_START_TIMEOUT 5000
 
 /* device reference routines must be called under sci_lock */
+static inline struct isci_remote_device *isci_get_device(
+	struct domain_device *dev)
+{
+	struct isci_remote_device *idev = dev->lldd_dev;
+
+	if (idev)
+		kref_get(&idev->kref);
+	return idev;
+}
+
 static inline struct isci_remote_device *isci_lookup_device(struct domain_device *dev)
 {
 	struct isci_remote_device *idev = dev->lldd_dev;
@@ -345,4 +355,27 @@ int isci_remote_device_is_safe_to_abort(
 enum sci_status
 sci_remote_device_abort_requests_pending_abort(
 	struct isci_remote_device *idev);
+
+enum sci_status isci_remote_device_suspend(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev);
+
+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 isci_remote_device_resume(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev,
+	scics_sds_remote_node_context_callback cb_fn,
+	void *cb_p);
+
+enum sci_status isci_remote_device_reset(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev);
+
+enum sci_status isci_remote_device_reset_complete(
+	struct isci_host *ihost,
+	struct isci_remote_device *idev);
 #endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 374254e..9b8632f 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -716,6 +716,8 @@ void isci_terminate_pending_requests(struct isci_host *ihost,
 	unsigned long flags;
 	LIST_HEAD(list);
 
+	isci_remote_device_suspend(ihost, idev);
+
 	spin_lock_irqsave(&ihost->scic_lock, flags);
 	list_splice_init(&idev->reqs_in_process, &list);
 
@@ -826,40 +828,47 @@ static int isci_task_send_lu_reset_sas(
 
 int isci_task_lu_reset(struct domain_device *dev, u8 *lun)
 {
-	struct isci_host *isci_host = dev_to_ihost(dev);
+	struct isci_host *ihost = dev_to_ihost(dev);
 	struct isci_remote_device *isci_device;
 	unsigned long flags;
 	int ret;
 
-	spin_lock_irqsave(&isci_host->scic_lock, flags);
+	spin_lock_irqsave(&ihost->scic_lock, flags);
 	isci_device = isci_lookup_device(dev);
-	spin_unlock_irqrestore(&isci_host->scic_lock, flags);
+	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
-	dev_dbg(&isci_host->pdev->dev,
+	dev_dbg(&ihost->pdev->dev,
 		"%s: domain_device=%p, isci_host=%p; isci_device=%p\n",
-		 __func__, dev, isci_host, isci_device);
+		__func__, dev, ihost, isci_device);
 
 	if (!isci_device) {
 		/* If the device is gone, stop the escalations. */
-		dev_dbg(&isci_host->pdev->dev, "%s: No dev\n", __func__);
+		dev_dbg(&ihost->pdev->dev, "%s: No dev\n", __func__);
 
 		ret = TMF_RESP_FUNC_COMPLETE;
 		goto out;
 	}
+	if (isci_remote_device_suspend(ihost, isci_device) != SCI_SUCCESS) {
+		dev_dbg(&ihost->pdev->dev,
+			"%s:  device = %p; failed to suspend\n",
+			__func__, isci_device);
+		ret = TMF_RESP_FUNC_FAILED;
+		goto out;
+	}
 
 	/* Send the task management part of the reset. */
 	if (dev_is_sata(dev)) {
 		sas_ata_schedule_reset(dev);
 		ret = TMF_RESP_FUNC_COMPLETE;
 	} else
-		ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun);
+		ret = isci_task_send_lu_reset_sas(ihost, isci_device, lun);
 
 	/* If the LUN reset worked, all the I/O can now be terminated. */
-	if (ret == TMF_RESP_FUNC_COMPLETE)
+	if (ret == TMF_RESP_FUNC_COMPLETE) {
 		/* Terminate all I/O now. */
-		isci_terminate_pending_requests(isci_host,
-						isci_device);
-
+		isci_terminate_pending_requests(ihost, isci_device);
+		isci_remote_device_resume(ihost, isci_device, NULL, NULL);
+	}
  out:
 	isci_put_device(isci_device);
 	return ret;
@@ -976,7 +985,7 @@ int isci_task_abort_task(struct sas_task *task)
 	spin_unlock(&task->task_state_lock);
 	spin_unlock_irqrestore(&isci_host->scic_lock, flags);
 
-	dev_dbg(&isci_host->pdev->dev,
+	dev_warn(&isci_host->pdev->dev,
 		"%s: dev = %p, task = %p, old_request == %p\n",
 		__func__, isci_device, task, old_request);
 
@@ -998,7 +1007,7 @@ int isci_task_abort_task(struct sas_task *task)
 
 		ret = TMF_RESP_FUNC_COMPLETE;
 
-		dev_dbg(&isci_host->pdev->dev,
+		dev_warn(&isci_host->pdev->dev,
 			"%s: abort task not needed for %p\n",
 			__func__, task);
 		goto out;
@@ -1022,7 +1031,7 @@ int isci_task_abort_task(struct sas_task *task)
 		/* The request was already being handled by someone else (because
 		* they got to set the state away from started).
 		*/
-		dev_dbg(&isci_host->pdev->dev,
+		dev_warn(&isci_host->pdev->dev,
 			"%s:  device = %p; old_request %p already being aborted\n",
 			__func__,
 			isci_device, old_request);
@@ -1035,7 +1044,7 @@ int isci_task_abort_task(struct sas_task *task)
 
 		spin_unlock_irqrestore(&isci_host->scic_lock, flags);
 
-		dev_dbg(&isci_host->pdev->dev,
+		dev_warn(&isci_host->pdev->dev,
 			"%s: %s request"
 			" or complete_in_target (%d), thus no TMF\n",
 			__func__,
@@ -1068,6 +1077,15 @@ int isci_task_abort_task(struct sas_task *task)
 		 */
 		perform_termination = 1;
 
+		if (isci_device && !test_bit(IDEV_GONE, &isci_device->flags) &&
+		    (isci_remote_device_suspend(isci_host, isci_device)
+		     != SCI_SUCCESS)) {
+			dev_warn(&isci_host->pdev->dev,
+				"%s:  device = %p; failed to suspend\n",
+				__func__, isci_device);
+			goto out;
+		}
+
 	} else {
 		/* Fill in the tmf stucture */
 		isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort,
@@ -1076,6 +1094,14 @@ int isci_task_abort_task(struct sas_task *task)
 
 		spin_unlock_irqrestore(&isci_host->scic_lock, flags);
 
+		if (isci_remote_device_suspend(isci_host, isci_device)
+		    != SCI_SUCCESS) {
+			dev_warn(&isci_host->pdev->dev,
+				"%s:  device = %p; failed to suspend\n",
+				__func__, isci_device);
+			goto out;
+		}
+
 		#define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */
 		ret = isci_task_execute_tmf(isci_host, isci_device, &tmf,
 					    ISCI_ABORT_TASK_TIMEOUT_MS);
@@ -1083,7 +1109,7 @@ int isci_task_abort_task(struct sas_task *task)
 		if (ret == TMF_RESP_FUNC_COMPLETE)
 			perform_termination = 1;
 		else
-			dev_dbg(&isci_host->pdev->dev,
+			dev_warn(&isci_host->pdev->dev,
 				"%s: isci_task_send_tmf failed\n", __func__);
 	}
 	if (perform_termination) {
@@ -1094,6 +1120,7 @@ int isci_task_abort_task(struct sas_task *task)
 		 */
 		isci_terminate_request_core(isci_host, isci_device,
 					    old_request);
+		isci_remote_device_resume(isci_host, isci_device, NULL, NULL);
 	}
 
 	/* Make sure we do not leave a reference to aborted_io_completion */
@@ -1251,21 +1278,13 @@ static int isci_reset_device(struct isci_host *ihost,
 			     struct isci_remote_device *idev)
 {
 	int rc;
-	unsigned long flags;
 	enum sci_status status;
 	struct sas_phy *phy = sas_get_local_phy(dev);
 	struct isci_port *iport = dev->port->lldd_port;
 
 	dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev);
 
-	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: sci_remote_device_reset(%p) returned %d!\n",
-			 __func__, idev, status);
+	if (isci_remote_device_reset(ihost, idev) != SCI_SUCCESS) {
 		rc = TMF_RESP_FUNC_FAILED;
 		goto out;
 	}
@@ -1281,15 +1300,12 @@ static int isci_reset_device(struct isci_host *ihost,
 	isci_remote_device_nuke_requests(ihost, idev);
 
 	/* Since all pending TCs have been cleaned, resume the RNC. */
-	spin_lock_irqsave(&ihost->scic_lock, flags);
-	status = sci_remote_device_reset_complete(idev);
-	spin_unlock_irqrestore(&ihost->scic_lock, flags);
+	status = isci_remote_device_reset_complete(ihost, idev);
 
-	if (status != SCI_SUCCESS) {
+	if (status != SCI_SUCCESS)
 		dev_dbg(&ihost->pdev->dev,
-			 "%s: sci_remote_device_reset_complete(%p) "
+			 "%s: isci_remote_device_reset_complete(%p) "
 			 "returned %d!\n", __func__, idev, status);
-	}
 
 	dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev);
  out:
@@ -1305,7 +1321,7 @@ int isci_task_I_T_nexus_reset(struct domain_device *dev)
 	int ret;
 
 	spin_lock_irqsave(&ihost->scic_lock, flags);
-	idev = isci_lookup_device(dev);
+	idev = isci_get_device(dev);
 	spin_unlock_irqrestore(&ihost->scic_lock, flags);
 
 	if (!idev) {


  parent reply	other threads:[~2012-03-23  0:12 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-03-23  0:27 [isci-rnc PATCH v1 00/37] remote node context rework Dan Williams
2012-03-23  0:27 ` [isci-rnc PATCH v1 01/37] isci: Manage the link layer hang detect timer for RNC suspensions Dan Williams
2012-03-23  0:27 ` [isci-rnc PATCH v1 02/37] isci: Fixed bug in resumption from RNC Tx/Rx suspend state Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 03/37] isci: Handle all suspending TC completions Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 04/37] isci: Terminate outstanding TCs on TX/RX RNC suspensions Dan Williams
2012-03-23  0:28 ` Dan Williams [this message]
2012-03-23  0:28 ` [isci-rnc PATCH v1 06/37] isci: Remote device must be suspended for NCQ cleanup Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 07/37] isci: Remote device stop also suspends the RNC and terminates I/O Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 08/37] isci: Escalate to I_T_Nexus_Reset when the device is gone Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 09/37] isci: Redesign device suspension, abort, cleanup Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 10/37] isci: Add suspension cases for RNC INVALIDATING, POSTING states Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 11/37] isci: Device access in the error path does not depend on IDEV_GONE Dan Williams
2012-03-23  0:28 ` [isci-rnc PATCH v1 12/37] isci: All pending TCs are terminated when the RNC is invalidated Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 13/37] isci: Only set IDEV_GONE in the device stop path Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 14/37] isci: Remove isci_device reqs_in_process and dev_node from isci_device Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 15/37] isci: Distinguish between remote device suspension cases Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 16/37] isci: Fix the terminated I/O to not call sas_task_abort() Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 17/37] isci: Save the suspension hint for upcoming suspensions Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 18/37] isci: Manage the LLHANG timer enable/disable per-device Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 19/37] isci: Make sure all TCs are terminated and cleaned in LUN reset Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 20/37] isci: Implement waiting for suspend in the abort path Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 21/37] isci: When in the abort path, defeat other resume calls until done Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 22/37] isci: Callbacks to libsas occur under scic_lock and are synchronized Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 23/37] isci: Manage tag releases differently when aborting tasks Dan Williams
2012-03-23  0:29 ` [isci-rnc PATCH v1 24/37] isci: Fix RNC suspend call for SCI_RESUMING state Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 25/37] isci: Wait for RNC resumption before leaving the abort path Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 26/37] isci: Directly control IREQ_ABORT_PATH_ACTIVE when completing TMFs Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 27/37] isci: Add protocol indicator for TMF requests Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 28/37] isci: Added timeouts to RNC suspensions in the abort path Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 29/37] isci: Change the phy control and link reset interface for HW reasons Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 30/37] isci: Don't wait for an RNC suspend if it's being destroyed Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 31/37] isci: Restore the ATAPI device RNC management code Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 32/37] isci: Check IDEV_GONE before performing abort path operations Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 33/37] isci: Remove obviated host callback list Dan Williams
2012-03-23  0:30 ` [isci-rnc PATCH v1 34/37] isci: Manage the IREQ_NO_AUTO_FREE_TAG under scic_lock Dan Williams
2012-03-23  0:31 ` [isci-rnc PATCH v1 35/37] isci: Fix RNC AWAIT_SUSPENSION->INVALIDATING transition Dan Williams
2012-03-23  0:31 ` [isci-rnc PATCH v1 36/37] isci: Fixed RNC bug that lost the suspension or resumption during destroy Dan Williams
2012-03-23  0:31 ` [isci-rnc PATCH v1 37/37] isci: End the RNC resumption wait when the RNC is destroyed Dan Williams

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=20120323002814.18065.46456.stgit@dwillia2-linux.jf.intel.com \
    --to=dan.j.williams@intel.com \
    --cc=jeffrey.d.skirvin@intel.com \
    --cc=linux-scsi@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 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.