Commit 50e7f9b5 authored by Dan Williams's avatar Dan Williams
Browse files

isci: Errors in the submit path for SATA devices manage the ap lock.



Since libsas takes the domain device sata_dev.ap->lock before submitting
a task, error completions in the submit path for SATA devices must
unlock/relock when completing the sas_task back to libsas.

Signed-off-by: default avatarJeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent 70957a94
Loading
Loading
Loading
Loading
+87 −0
Original line number Diff line number Diff line
@@ -54,6 +54,8 @@
 */

#include <linux/completion.h>
#include <linux/irqflags.h>
#include <scsi/sas_ata.h>
#include "scic_task_request.h"
#include "scic_remote_device.h"
#include "scic_io_request.h"
@@ -64,6 +66,91 @@
#include "sata.h"
#include "task.h"

/**
* isci_task_complete_for_upper_layer() - This function completes the request
*    to the upper layer driver in the case where an I/O needs to be completed
*    back in the submit path.
* @host: This parameter is a pointer to the host on which the the request
*    should be queued (either as an error or success).
* @task: This parameter is the completed request.
* @response: This parameter is the response code for the completed task.
* @status: This parameter is the status code for the completed task.
*
* none.
*/
static void isci_task_complete_for_upper_layer(struct sas_task *task,
					       enum service_response response,
					       enum exec_status status,
					       enum isci_completion_selection task_notification_selection)
{
	unsigned long    flags = 0;
	struct Scsi_Host *host = NULL;

	task_notification_selection
		= isci_task_set_completion_status(task, response, status,
						  task_notification_selection);

	/* Tasks aborted specifically by a call to the lldd_abort_task
	* function should not be completed to the host in the regular path.
	*/
	switch (task_notification_selection) {
		case isci_perform_normal_io_completion:
			/* Normal notification (task_done) */
			dev_dbg(task->dev->port->ha->dev,
				"%s: Normal - task = %p, response=%d, status=%d\n",
				__func__, task, response, status);

			if (dev_is_sata(task->dev)) {
				/* Since we are still in the submit path, and since
				* libsas takes the host lock on behalf of SATA
				* devices before I/O starts, we need to unlock
				* before we can call back and report the I/O
				* submission error.
				*/
				if (task->dev
				    && task->dev->port
				    && task->dev->port->ha) {

					host = task->dev->port->ha->core.shost;
					raw_local_irq_save(flags);
					spin_unlock(host->host_lock);
				}
				task->task_done(task);
				if (host) {
					spin_lock(host->host_lock);
					raw_local_irq_restore(flags);
				}
			} else
				task->task_done(task);

			task->lldd_task = NULL;
			break;

		case isci_perform_aborted_io_completion:
			/* No notification because this request is already in the
			* abort path.
			*/
			dev_warn(task->dev->port->ha->dev,
				 "%s: Aborted - task = %p, response=%d, status=%d\n",
				 __func__, task, response, status);
			break;

		case isci_perform_error_io_completion:
			/* Use sas_task_abort */
			dev_warn(task->dev->port->ha->dev,
				 "%s: Error - task = %p, response=%d, status=%d\n",
				 __func__, task, response, status);
			sas_task_abort(task);
			break;

		default:
			dev_warn(task->dev->port->ha->dev,
				 "%s: isci task notification default case!",
				 __func__);
			sas_task_abort(task);
			break;
	}
}

/**
 * isci_task_execute_task() - This function is one of the SAS Domain Template
+0 −59
Original line number Diff line number Diff line
@@ -341,64 +341,5 @@ isci_task_set_completion_status(
	return task_notification_selection;

}
/**
 * isci_task_complete_for_upper_layer() - This function completes the request
 *    to the upper layer driver.
 * @host: This parameter is a pointer to the host on which the the request
 *    should be queued (either as an error or success).
 * @request: This parameter is the completed request.
 * @response: This parameter is the response code for the completed task.
 * @status: This parameter is the status code for the completed task.
 *
 * none.
 */
static inline void isci_task_complete_for_upper_layer(
	struct sas_task *task,
	enum service_response response,
	enum exec_status status,
	enum isci_completion_selection task_notification_selection)
{
	task_notification_selection
		= isci_task_set_completion_status(task, response, status,
						  task_notification_selection);

	/* Tasks aborted specifically by a call to the lldd_abort_task
	 * function should not be completed to the host in the regular path.
	 */
	switch (task_notification_selection) {
	case isci_perform_normal_io_completion:
		/* Normal notification (task_done) */
		dev_dbg(task->dev->port->ha->dev,
			"%s: Normal - task = %p, response=%d, status=%d\n",
			__func__, task, response, status);
		task->task_done(task);
		task->lldd_task = NULL;
		break;

	case isci_perform_aborted_io_completion:
		/* No notification because this request is already in the
		 * abort path.
		 */
		dev_warn(task->dev->port->ha->dev,
			 "%s: Aborted - task = %p, response=%d, status=%d\n",
			 __func__, task, response, status);
		break;

	case isci_perform_error_io_completion:
		/* Use sas_task_abort */
		dev_warn(task->dev->port->ha->dev,
			 "%s: Error - task = %p, response=%d, status=%d\n",
			 __func__, task, response, status);
		sas_task_abort(task);
		break;

	default:
		dev_warn(task->dev->port->ha->dev,
			 "%s: isci task notification default case!",
			 __func__);
		sas_task_abort(task);
		break;
	}
}

#endif /* !defined(_SCI_TASK_H_) */