aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-11-17 20:59:50 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-19 14:50:12 -0500
commit312d3e56119a4bc5c36a96818f87f650c069ddc2 (patch)
treed8cf7586656301ff1c4e5a49f9cbddde61e3e561
parentb1124cd3ec97406c767b90bf7e93ecd2d2915592 (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.c3
-rw-r--r--drivers/scsi/isci/task.c6
-rw-r--r--drivers/scsi/isci/task.h36
-rw-r--r--drivers/scsi/libsas/sas_ata.c36
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c6
-rw-r--r--drivers/scsi/mvsas/mv_sas.c6
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c6
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*/
338static 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
167static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) 167static 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
247static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) 257static 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,