diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-11-17 20:59:50 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-19 14:50:12 -0500 |
commit | 312d3e56119a4bc5c36a96818f87f650c069ddc2 (patch) | |
tree | d8cf7586656301ff1c4e5a49f9cbddde61e3e561 | |
parent | b1124cd3ec97406c767b90bf7e93ecd2d2915592 (diff) |
[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>
-rw-r--r-- | drivers/scsi/isci/request.c | 3 | ||||
-rw-r--r-- | drivers/scsi/isci/task.c | 6 | ||||
-rw-r--r-- | drivers/scsi/isci/task.h | 36 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 36 | ||||
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 6 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_sas.c | 6 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.c | 6 |
7 files changed, 29 insertions, 70 deletions
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index 751368b46b44..788daeedc89f 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c | |||
@@ -3796,8 +3796,7 @@ int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *ide | |||
3796 | /* Cause this task to be scheduled in the SCSI error | 3796 | /* Cause this task to be scheduled in the SCSI error |
3797 | * handler thread. | 3797 | * handler thread. |
3798 | */ | 3798 | */ |
3799 | isci_execpath_callback(ihost, task, | 3799 | sas_task_abort(task); |
3800 | sas_task_abort); | ||
3801 | 3800 | ||
3802 | /* Change the status, since we are holding | 3801 | /* Change the status, since we are holding |
3803 | * the I/O until it is managed by the SCSI | 3802 | * the I/O until it is managed by the SCSI |
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index f5a3f7d2bdab..4bd88ef83cdf 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c | |||
@@ -96,8 +96,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, | |||
96 | __func__, task, response, status); | 96 | __func__, task, response, status); |
97 | 97 | ||
98 | task->lldd_task = NULL; | 98 | task->lldd_task = NULL; |
99 | 99 | task->task_done(task); | |
100 | isci_execpath_callback(ihost, task, task->task_done); | ||
101 | break; | 100 | break; |
102 | 101 | ||
103 | case isci_perform_aborted_io_completion: | 102 | case isci_perform_aborted_io_completion: |
@@ -117,8 +116,7 @@ static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, | |||
117 | "%s: Error - task = %p, response=%d, " | 116 | "%s: Error - task = %p, response=%d, " |
118 | "status=%d\n", | 117 | "status=%d\n", |
119 | __func__, task, response, status); | 118 | __func__, task, response, status); |
120 | 119 | sas_task_abort(task); | |
121 | isci_execpath_callback(ihost, task, sas_task_abort); | ||
122 | break; | 120 | break; |
123 | 121 | ||
124 | default: | 122 | default: |
diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h index 1b27b3797c6c..bb472c339523 100644 --- a/drivers/scsi/isci/task.h +++ b/drivers/scsi/isci/task.h | |||
@@ -321,40 +321,4 @@ isci_task_set_completion_status( | |||
321 | return task_notification_selection; | 321 | return task_notification_selection; |
322 | 322 | ||
323 | } | 323 | } |
324 | /** | ||
325 | * isci_execpath_callback() - This function is called from the task | ||
326 | * execute path when the task needs to callback libsas about the submit-time | ||
327 | * task failure. The callback occurs either through the task's done function | ||
328 | * or through sas_task_abort. In the case of regular non-discovery SATA/STP I/O | ||
329 | * requests, libsas takes the host lock before calling execute task. Therefore | ||
330 | * in this situation the host lock must be managed before calling the func. | ||
331 | * | ||
332 | * @ihost: This parameter is the controller to which the I/O request was sent. | ||
333 | * @task: This parameter is the I/O request. | ||
334 | * @func: This parameter is the function to call in the correct context. | ||
335 | * @status: This parameter is the status code for the completed task. | ||
336 | * | ||
337 | */ | ||
338 | static inline void isci_execpath_callback(struct isci_host *ihost, | ||
339 | struct sas_task *task, | ||
340 | void (*func)(struct sas_task *)) | ||
341 | { | ||
342 | struct domain_device *dev = task->dev; | ||
343 | |||
344 | if (dev_is_sata(dev) && task->uldd_task) { | ||
345 | unsigned long flags; | ||
346 | |||
347 | /* Since we are still in the submit path, and since | ||
348 | * libsas takes the host lock on behalf of SATA | ||
349 | * devices before I/O starts (in the non-discovery case), | ||
350 | * we need to unlock before we can call the callback function. | ||
351 | */ | ||
352 | raw_local_irq_save(flags); | ||
353 | spin_unlock(dev->sata_dev.ap->lock); | ||
354 | func(task); | ||
355 | spin_lock(dev->sata_dev.ap->lock); | ||
356 | raw_local_irq_restore(flags); | ||
357 | } else | ||
358 | func(task); | ||
359 | } | ||
360 | #endif /* !defined(_SCI_TASK_H_) */ | 324 | #endif /* !defined(_SCI_TASK_H_) */ |
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c index 83118d0b6d0c..81ce39d166d1 100644 --- a/drivers/scsi/libsas/sas_ata.c +++ b/drivers/scsi/libsas/sas_ata.c | |||
@@ -166,23 +166,30 @@ qc_already_gone: | |||
166 | 166 | ||
167 | static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) | 167 | static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) |
168 | { | 168 | { |
169 | int res; | 169 | unsigned long flags; |
170 | struct sas_task *task; | 170 | struct sas_task *task; |
171 | struct domain_device *dev = qc->ap->private_data; | 171 | struct scatterlist *sg; |
172 | int ret = AC_ERR_SYSTEM; | ||
173 | unsigned int si, xfer = 0; | ||
174 | struct ata_port *ap = qc->ap; | ||
175 | struct domain_device *dev = ap->private_data; | ||
172 | struct sas_ha_struct *sas_ha = dev->port->ha; | 176 | struct sas_ha_struct *sas_ha = dev->port->ha; |
173 | struct Scsi_Host *host = sas_ha->core.shost; | 177 | struct Scsi_Host *host = sas_ha->core.shost; |
174 | struct sas_internal *i = to_sas_internal(host->transportt); | 178 | struct sas_internal *i = to_sas_internal(host->transportt); |
175 | struct scatterlist *sg; | 179 | |
176 | unsigned int xfer = 0; | 180 | /* TODO: audit callers to ensure they are ready for qc_issue to |
177 | unsigned int si; | 181 | * unconditionally re-enable interrupts |
182 | */ | ||
183 | local_irq_save(flags); | ||
184 | spin_unlock(ap->lock); | ||
178 | 185 | ||
179 | /* If the device fell off, no sense in issuing commands */ | 186 | /* If the device fell off, no sense in issuing commands */ |
180 | if (dev->gone) | 187 | if (dev->gone) |
181 | return AC_ERR_SYSTEM; | 188 | goto out; |
182 | 189 | ||
183 | task = sas_alloc_task(GFP_ATOMIC); | 190 | task = sas_alloc_task(GFP_ATOMIC); |
184 | if (!task) | 191 | if (!task) |
185 | return AC_ERR_SYSTEM; | 192 | goto out; |
186 | task->dev = dev; | 193 | task->dev = dev; |
187 | task->task_proto = SAS_PROTOCOL_STP; | 194 | task->task_proto = SAS_PROTOCOL_STP; |
188 | task->task_done = sas_ata_task_done; | 195 | task->task_done = sas_ata_task_done; |
@@ -227,21 +234,24 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) | |||
227 | ASSIGN_SAS_TASK(qc->scsicmd, task); | 234 | ASSIGN_SAS_TASK(qc->scsicmd, task); |
228 | 235 | ||
229 | if (sas_ha->lldd_max_execute_num < 2) | 236 | if (sas_ha->lldd_max_execute_num < 2) |
230 | res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC); | 237 | ret = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC); |
231 | else | 238 | else |
232 | res = sas_queue_up(task); | 239 | ret = sas_queue_up(task); |
233 | 240 | ||
234 | /* Examine */ | 241 | /* Examine */ |
235 | if (res) { | 242 | if (ret) { |
236 | SAS_DPRINTK("lldd_execute_task returned: %d\n", res); | 243 | SAS_DPRINTK("lldd_execute_task returned: %d\n", ret); |
237 | 244 | ||
238 | if (qc->scsicmd) | 245 | if (qc->scsicmd) |
239 | ASSIGN_SAS_TASK(qc->scsicmd, NULL); | 246 | ASSIGN_SAS_TASK(qc->scsicmd, NULL); |
240 | sas_free_task(task); | 247 | sas_free_task(task); |
241 | return AC_ERR_SYSTEM; | 248 | ret = AC_ERR_SYSTEM; |
242 | } | 249 | } |
243 | 250 | ||
244 | return 0; | 251 | out: |
252 | spin_lock(ap->lock); | ||
253 | local_irq_restore(flags); | ||
254 | return ret; | ||
245 | } | 255 | } |
246 | 256 | ||
247 | static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) | 257 | static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) |
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 2a163c73fd8b..fd60465d4b2d 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -198,11 +198,9 @@ int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) | |||
198 | } | 198 | } |
199 | 199 | ||
200 | if (dev_is_sata(dev)) { | 200 | if (dev_is_sata(dev)) { |
201 | unsigned long flags; | 201 | spin_lock_irq(dev->sata_dev.ap->lock); |
202 | |||
203 | spin_lock_irqsave(dev->sata_dev.ap->lock, flags); | ||
204 | res = ata_sas_queuecmd(cmd, dev->sata_dev.ap); | 202 | res = ata_sas_queuecmd(cmd, dev->sata_dev.ap); |
205 | spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags); | 203 | spin_unlock_irq(dev->sata_dev.ap->lock); |
206 | return res; | 204 | return res; |
207 | } | 205 | } |
208 | 206 | ||
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index b118e632bc7d..cd882230591f 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c | |||
@@ -893,9 +893,6 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, | |||
893 | 893 | ||
894 | mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info; | 894 | mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info; |
895 | 895 | ||
896 | if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL)) | ||
897 | spin_unlock_irq(dev->sata_dev.ap->lock); | ||
898 | |||
899 | spin_lock_irqsave(&mvi->lock, flags); | 896 | spin_lock_irqsave(&mvi->lock, flags); |
900 | rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass); | 897 | rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass); |
901 | if (rc) | 898 | if (rc) |
@@ -906,9 +903,6 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, | |||
906 | (MVS_CHIP_SLOT_SZ - 1)); | 903 | (MVS_CHIP_SLOT_SZ - 1)); |
907 | spin_unlock_irqrestore(&mvi->lock, flags); | 904 | spin_unlock_irqrestore(&mvi->lock, flags); |
908 | 905 | ||
909 | if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL)) | ||
910 | spin_lock_irq(dev->sata_dev.ap->lock); | ||
911 | |||
912 | return rc; | 906 | return rc; |
913 | } | 907 | } |
914 | 908 | ||
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 50837933a1e5..310860e37d98 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c | |||
@@ -364,7 +364,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num, | |||
364 | struct pm8001_ccb_info *ccb; | 364 | struct pm8001_ccb_info *ccb; |
365 | u32 tag = 0xdeadbeef, rc, n_elem = 0; | 365 | u32 tag = 0xdeadbeef, rc, n_elem = 0; |
366 | u32 n = num; | 366 | u32 n = num; |
367 | unsigned long flags = 0, flags_libsas = 0; | 367 | unsigned long flags = 0; |
368 | 368 | ||
369 | if (!dev->port) { | 369 | if (!dev->port) { |
370 | struct task_status_struct *tsm = &t->task_status; | 370 | struct task_status_struct *tsm = &t->task_status; |
@@ -388,11 +388,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num, | |||
388 | ts->stat = SAS_PHY_DOWN; | 388 | ts->stat = SAS_PHY_DOWN; |
389 | 389 | ||
390 | spin_unlock_irqrestore(&pm8001_ha->lock, flags); | 390 | spin_unlock_irqrestore(&pm8001_ha->lock, flags); |
391 | spin_unlock_irqrestore(dev->sata_dev.ap->lock, | ||
392 | flags_libsas); | ||
393 | t->task_done(t); | 391 | t->task_done(t); |
394 | spin_lock_irqsave(dev->sata_dev.ap->lock, | ||
395 | flags_libsas); | ||
396 | spin_lock_irqsave(&pm8001_ha->lock, flags); | 392 | spin_lock_irqsave(&pm8001_ha->lock, flags); |
397 | if (n > 1) | 393 | if (n > 1) |
398 | t = list_entry(t->list.next, | 394 | t = list_entry(t->list.next, |