mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	[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: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
		
							parent
							
								
									b1124cd3ec
								
							
						
					
					
						commit
						312d3e5611
					
				
					 7 changed files with 29 additions and 70 deletions
				
			
		| 
						 | 
					@ -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
 | 
							/* Cause this task to be scheduled in the SCSI error
 | 
				
			||||||
		 * handler thread.
 | 
							 * handler thread.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		isci_execpath_callback(ihost, task,
 | 
							sas_task_abort(task);
 | 
				
			||||||
				       sas_task_abort);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Change the status, since we are holding
 | 
							/* Change the status, since we are holding
 | 
				
			||||||
		 * the I/O until it is managed by the SCSI
 | 
							 * the I/O until it is managed by the SCSI
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,8 +96,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task,
 | 
				
			||||||
			__func__, task, response, status);
 | 
								__func__, task, response, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		task->lldd_task = NULL;
 | 
							task->lldd_task = NULL;
 | 
				
			||||||
 | 
							task->task_done(task);
 | 
				
			||||||
		isci_execpath_callback(ihost, task, task->task_done);
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case isci_perform_aborted_io_completion:
 | 
						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, "
 | 
								"%s: Error - task = %p, response=%d, "
 | 
				
			||||||
			"status=%d\n",
 | 
								"status=%d\n",
 | 
				
			||||||
			__func__, task, response, status);
 | 
								__func__, task, response, status);
 | 
				
			||||||
 | 
							sas_task_abort(task);
 | 
				
			||||||
		isci_execpath_callback(ihost, task, sas_task_abort);
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -321,40 +321,4 @@ isci_task_set_completion_status(
 | 
				
			||||||
	return task_notification_selection;
 | 
						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_) */
 | 
					#endif /* !defined(_SCI_TASK_H_) */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -166,23 +166,30 @@ static void sas_ata_task_done(struct sas_task *task)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
 | 
					static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int res;
 | 
						unsigned long flags;
 | 
				
			||||||
	struct sas_task *task;
 | 
						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 sas_ha_struct *sas_ha = dev->port->ha;
 | 
				
			||||||
	struct Scsi_Host *host = sas_ha->core.shost;
 | 
						struct Scsi_Host *host = sas_ha->core.shost;
 | 
				
			||||||
	struct sas_internal *i = to_sas_internal(host->transportt);
 | 
						struct sas_internal *i = to_sas_internal(host->transportt);
 | 
				
			||||||
	struct scatterlist *sg;
 | 
					
 | 
				
			||||||
	unsigned int xfer = 0;
 | 
						/* TODO: audit callers to ensure they are ready for qc_issue to
 | 
				
			||||||
	unsigned int si;
 | 
						 * unconditionally re-enable interrupts
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						local_irq_save(flags);
 | 
				
			||||||
 | 
						spin_unlock(ap->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* If the device fell off, no sense in issuing commands */
 | 
						/* If the device fell off, no sense in issuing commands */
 | 
				
			||||||
	if (dev->gone)
 | 
						if (dev->gone)
 | 
				
			||||||
		return AC_ERR_SYSTEM;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	task = sas_alloc_task(GFP_ATOMIC);
 | 
						task = sas_alloc_task(GFP_ATOMIC);
 | 
				
			||||||
	if (!task)
 | 
						if (!task)
 | 
				
			||||||
		return AC_ERR_SYSTEM;
 | 
							goto out;
 | 
				
			||||||
	task->dev = dev;
 | 
						task->dev = dev;
 | 
				
			||||||
	task->task_proto = SAS_PROTOCOL_STP;
 | 
						task->task_proto = SAS_PROTOCOL_STP;
 | 
				
			||||||
	task->task_done = sas_ata_task_done;
 | 
						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);
 | 
							ASSIGN_SAS_TASK(qc->scsicmd, task);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sas_ha->lldd_max_execute_num < 2)
 | 
						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
 | 
						else
 | 
				
			||||||
		res = sas_queue_up(task);
 | 
							ret = sas_queue_up(task);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Examine */
 | 
						/* Examine */
 | 
				
			||||||
	if (res) {
 | 
						if (ret) {
 | 
				
			||||||
		SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
 | 
							SAS_DPRINTK("lldd_execute_task returned: %d\n", ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (qc->scsicmd)
 | 
							if (qc->scsicmd)
 | 
				
			||||||
			ASSIGN_SAS_TASK(qc->scsicmd, NULL);
 | 
								ASSIGN_SAS_TASK(qc->scsicmd, NULL);
 | 
				
			||||||
		sas_free_task(task);
 | 
							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)
 | 
					static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -198,11 +198,9 @@ int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dev_is_sata(dev)) {
 | 
						if (dev_is_sata(dev)) {
 | 
				
			||||||
		unsigned long flags;
 | 
							spin_lock_irq(dev->sata_dev.ap->lock);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
 | 
					 | 
				
			||||||
		res = ata_sas_queuecmd(cmd, dev->sata_dev.ap);
 | 
							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;
 | 
							return res;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -893,9 +893,6 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info;
 | 
						mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
 | 
					 | 
				
			||||||
		spin_unlock_irq(dev->sata_dev.ap->lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	spin_lock_irqsave(&mvi->lock, flags);
 | 
						spin_lock_irqsave(&mvi->lock, flags);
 | 
				
			||||||
	rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass);
 | 
						rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass);
 | 
				
			||||||
	if (rc)
 | 
						if (rc)
 | 
				
			||||||
| 
						 | 
					@ -906,9 +903,6 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
 | 
				
			||||||
				(MVS_CHIP_SLOT_SZ - 1));
 | 
									(MVS_CHIP_SLOT_SZ - 1));
 | 
				
			||||||
	spin_unlock_irqrestore(&mvi->lock, flags);
 | 
						spin_unlock_irqrestore(&mvi->lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL))
 | 
					 | 
				
			||||||
		spin_lock_irq(dev->sata_dev.ap->lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -364,7 +364,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
 | 
				
			||||||
	struct pm8001_ccb_info *ccb;
 | 
						struct pm8001_ccb_info *ccb;
 | 
				
			||||||
	u32 tag = 0xdeadbeef, rc, n_elem = 0;
 | 
						u32 tag = 0xdeadbeef, rc, n_elem = 0;
 | 
				
			||||||
	u32 n = num;
 | 
						u32 n = num;
 | 
				
			||||||
	unsigned long flags = 0, flags_libsas = 0;
 | 
						unsigned long flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dev->port) {
 | 
						if (!dev->port) {
 | 
				
			||||||
		struct task_status_struct *tsm = &t->task_status;
 | 
							struct task_status_struct *tsm = &t->task_status;
 | 
				
			||||||
| 
						 | 
					@ -388,11 +388,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
 | 
				
			||||||
				ts->stat = SAS_PHY_DOWN;
 | 
									ts->stat = SAS_PHY_DOWN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 | 
									spin_unlock_irqrestore(&pm8001_ha->lock, flags);
 | 
				
			||||||
				spin_unlock_irqrestore(dev->sata_dev.ap->lock,
 | 
					 | 
				
			||||||
						flags_libsas);
 | 
					 | 
				
			||||||
				t->task_done(t);
 | 
									t->task_done(t);
 | 
				
			||||||
				spin_lock_irqsave(dev->sata_dev.ap->lock,
 | 
					 | 
				
			||||||
					flags_libsas);
 | 
					 | 
				
			||||||
				spin_lock_irqsave(&pm8001_ha->lock, flags);
 | 
									spin_lock_irqsave(&pm8001_ha->lock, flags);
 | 
				
			||||||
				if (n > 1)
 | 
									if (n > 1)
 | 
				
			||||||
					t = list_entry(t->list.next,
 | 
										t = list_entry(t->list.next,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue