Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 312d3e56 authored by Dan Williams's avatar Dan Williams Committed by James Bottomley
Browse files

[SCSI] libsas: remove ata_port.lock management duties from lldds



Each libsas driver (mvsas, pm8001, and isci) has invented a different
method for managing the ap->lock.  The lock is held by the ata
->queuecommand() path.  mvsas drops it prior to acquiring any internal
locks which allows it to hold its internal lock across calls to
task->task_done().  This capability is important as it is the only way
the driver can flush task->task_done() instances to guarantee that it no
longer has any in-flight references to a domain_device at
->lldd_dev_gone() time.

Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent b1124cd3
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -3796,8 +3796,7 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide
		/* Cause this task to be scheduled in the SCSI error
		 * handler thread.
		 */
		isci_execpath_callback(ihost, task,
				       sas_task_abort);
		sas_task_abort(task);

		/* Change the status, since we are holding
		 * the I/O until it is managed by the SCSI
+2 −4
Original line number Diff line number Diff line
@@ -96,8 +96,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task,
			__func__, task, response, status);

		task->lldd_task = NULL;

		isci_execpath_callback(ihost, task, task->task_done);
		task->task_done(task);
		break;

	case isci_perform_aborted_io_completion:
@@ -117,8 +116,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task,
			"%s: Error - task = %p, response=%d, "
			"status=%d\n",
			__func__, task, response, status);

		isci_execpath_callback(ihost, task, sas_task_abort);
		sas_task_abort(task);
		break;

	default:
+0 −36
Original line number Diff line number Diff line
@@ -321,40 +321,4 @@ isci_task_set_completion_status(
	return task_notification_selection;

}
/**
* isci_execpath_callback() - This function is called from the task
* execute path when the task needs to callback libsas about the submit-time
* task failure.  The callback occurs either through the task's done function
* or through sas_task_abort.  In the case of regular non-discovery SATA/STP I/O
* requests, libsas takes the host lock before calling execute task.  Therefore
* in this situation the host lock must be managed before calling the func.
*
* @ihost: This parameter is the controller to which the I/O request was sent.
* @task: This parameter is the I/O request.
* @func: This parameter is the function to call in the correct context.
* @status: This parameter is the status code for the completed task.
*
*/
static inline void isci_execpath_callback(struct isci_host *ihost,
					  struct sas_task  *task,
					  void (*func)(struct sas_task *))
{
	struct domain_device *dev = task->dev;

	if (dev_is_sata(dev) && task->uldd_task) {
		unsigned long flags;

		/* Since we are still in the submit path, and since
		 * libsas takes the host lock on behalf of SATA
		 * devices before I/O starts (in the non-discovery case),
		 * we need to unlock before we can call the callback function.
		 */
		raw_local_irq_save(flags);
		spin_unlock(dev->sata_dev.ap->lock);
		func(task);
		spin_lock(dev->sata_dev.ap->lock);
		raw_local_irq_restore(flags);
	} else
		func(task);
}
#endif /* !defined(_SCI_TASK_H_) */
+23 −13
Original line number Diff line number Diff line
@@ -166,23 +166,30 @@ qc_already_gone:

static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
{
	int res;
	unsigned long flags;
	struct sas_task *task;
	struct domain_device *dev = qc->ap->private_data;
	struct scatterlist *sg;
	int ret = AC_ERR_SYSTEM;
	unsigned int si, xfer = 0;
	struct ata_port *ap = qc->ap;
	struct domain_device *dev = ap->private_data;
	struct sas_ha_struct *sas_ha = dev->port->ha;
	struct Scsi_Host *host = sas_ha->core.shost;
	struct sas_internal *i = to_sas_internal(host->transportt);
	struct scatterlist *sg;
	unsigned int xfer = 0;
	unsigned int si;

	/* TODO: audit callers to ensure they are ready for qc_issue to
	 * unconditionally re-enable interrupts
	 */
	local_irq_save(flags);
	spin_unlock(ap->lock);

	/* If the device fell off, no sense in issuing commands */
	if (dev->gone)
		return AC_ERR_SYSTEM;
		goto out;

	task = sas_alloc_task(GFP_ATOMIC);
	if (!task)
		return AC_ERR_SYSTEM;
		goto out;
	task->dev = dev;
	task->task_proto = SAS_PROTOCOL_STP;
	task->task_done = sas_ata_task_done;
@@ -227,21 +234,24 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
		ASSIGN_SAS_TASK(qc->scsicmd, task);

	if (sas_ha->lldd_max_execute_num < 2)
		res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
		ret = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
	else
		res = sas_queue_up(task);
		ret = sas_queue_up(task);

	/* Examine */
	if (res) {
		SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
	if (ret) {
		SAS_DPRINTK("lldd_execute_task returned: %d\n", ret);

		if (qc->scsicmd)
			ASSIGN_SAS_TASK(qc->scsicmd, NULL);
		sas_free_task(task);
		return AC_ERR_SYSTEM;
		ret = AC_ERR_SYSTEM;
	}

	return 0;
 out:
	spin_lock(ap->lock);
	local_irq_restore(flags);
	return ret;
}

static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
+2 −4
Original line number Diff line number Diff line
@@ -198,11 +198,9 @@ int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
	}

	if (dev_is_sata(dev)) {
		unsigned long flags;

		spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
		spin_lock_irq(dev->sata_dev.ap->lock);
		res = ata_sas_queuecmd(cmd, dev->sata_dev.ap);
		spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
		spin_unlock_irq(dev->sata_dev.ap->lock);
		return res;
	}

Loading