[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 @@ qc_already_gone:
|
||||||
|
|
||||||
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,
|
||||||
|
|
Reference in a new issue