aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2011-11-28 15:08:22 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-19 14:58:38 -0500
commit3dff5721e4f67e6231dfc419d30aaa7563bfffd4 (patch)
tree752102ef79f985f4d153b4791461404f67cdf467 /drivers/scsi/libsas
parente500a34b0257def5b9ec07563afeeada1ead87bb (diff)
[SCSI] libsas: close error handling vs sas_ata_task_done() race
Since sas_ata does not implement ->freeze(), completions for scmds and internal commands can still arrive concurrent with ata_scsi_cmd_error_handler() and sas_ata_post_internal() respectively. By the time either of those is called libata has committed to completing the qc, and the ATA_PFLAG_FROZEN flag tells sas_ata_task_done() it has lost the race. In the sas_ata_post_internal() case we take on the additional responsibility of freeing the sas_task to close the race with sas_ata_task_done() freeing the the task while sas_ata_post_internal() is in the process of invoking ->lldd_abort_task(). Signed-off-by: Dan Williams <dan.j.williams@intel.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/libsas')
-rw-r--r--drivers/scsi/libsas/sas_ata.c84
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c44
2 files changed, 75 insertions, 53 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 5cb0a2ae5924..903bb441b9f9 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -100,15 +100,31 @@ static void sas_ata_task_done(struct sas_task *task)
100 enum ata_completion_errors ac; 100 enum ata_completion_errors ac;
101 unsigned long flags; 101 unsigned long flags;
102 struct ata_link *link; 102 struct ata_link *link;
103 struct ata_port *ap;
103 104
104 if (!qc) 105 if (!qc)
105 goto qc_already_gone; 106 goto qc_already_gone;
106 107
107 dev = qc->ap->private_data; 108 ap = qc->ap;
109 dev = ap->private_data;
108 sas_ha = dev->port->ha; 110 sas_ha = dev->port->ha;
109 link = &dev->sata_dev.ap->link; 111 link = &ap->link;
112
113 spin_lock_irqsave(ap->lock, flags);
114 /* check if we lost the race with libata/sas_ata_post_internal() */
115 if (unlikely(ap->pflags & ATA_PFLAG_FROZEN)) {
116 spin_unlock_irqrestore(ap->lock, flags);
117 if (qc->scsicmd)
118 goto qc_already_gone;
119 else {
120 /* if eh is not involved and the port is frozen then the
121 * ata internal abort process has taken responsibility
122 * for this sas_task
123 */
124 return;
125 }
126 }
110 127
111 spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
112 if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD || 128 if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD ||
113 ((stat->stat == SAM_STAT_CHECK_CONDITION && 129 ((stat->stat == SAM_STAT_CHECK_CONDITION &&
114 dev->sata_dev.command_set == ATAPI_COMMAND_SET))) { 130 dev->sata_dev.command_set == ATAPI_COMMAND_SET))) {
@@ -143,7 +159,7 @@ static void sas_ata_task_done(struct sas_task *task)
143 if (qc->scsicmd) 159 if (qc->scsicmd)
144 ASSIGN_SAS_TASK(qc->scsicmd, NULL); 160 ASSIGN_SAS_TASK(qc->scsicmd, NULL);
145 ata_qc_complete(qc); 161 ata_qc_complete(qc);
146 spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags); 162 spin_unlock_irqrestore(ap->lock, flags);
147 163
148qc_already_gone: 164qc_already_gone:
149 list_del_init(&task->list); 165 list_del_init(&task->list);
@@ -325,6 +341,54 @@ static int sas_ata_soft_reset(struct ata_link *link, unsigned int *class,
325 return ret; 341 return ret;
326} 342}
327 343
344/*
345 * notify the lldd to forget the sas_task for this internal ata command
346 * that bypasses scsi-eh
347 */
348static void sas_ata_internal_abort(struct sas_task *task)
349{
350 struct sas_internal *si =
351 to_sas_internal(task->dev->port->ha->core.shost->transportt);
352 unsigned long flags;
353 int res;
354
355 spin_lock_irqsave(&task->task_state_lock, flags);
356 if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
357 task->task_state_flags & SAS_TASK_STATE_DONE) {
358 spin_unlock_irqrestore(&task->task_state_lock, flags);
359 SAS_DPRINTK("%s: Task %p already finished.\n", __func__,
360 task);
361 goto out;
362 }
363 task->task_state_flags |= SAS_TASK_STATE_ABORTED;
364 spin_unlock_irqrestore(&task->task_state_lock, flags);
365
366 res = si->dft->lldd_abort_task(task);
367
368 spin_lock_irqsave(&task->task_state_lock, flags);
369 if (task->task_state_flags & SAS_TASK_STATE_DONE ||
370 res == TMF_RESP_FUNC_COMPLETE) {
371 spin_unlock_irqrestore(&task->task_state_lock, flags);
372 goto out;
373 }
374
375 /* XXX we are not prepared to deal with ->lldd_abort_task()
376 * failures. TODO: lldds need to unconditionally forget about
377 * aborted ata tasks, otherwise we (likely) leak the sas task
378 * here
379 */
380 SAS_DPRINTK("%s: Task %p leaked.\n", __func__, task);
381
382 if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
383 task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
384 spin_unlock_irqrestore(&task->task_state_lock, flags);
385
386 return;
387 out:
388 list_del_init(&task->list);
389 sas_free_task(task);
390}
391
328static void sas_ata_post_internal(struct ata_queued_cmd *qc) 392static void sas_ata_post_internal(struct ata_queued_cmd *qc)
329{ 393{
330 if (qc->flags & ATA_QCFLAG_FAILED) 394 if (qc->flags & ATA_QCFLAG_FAILED)
@@ -332,10 +396,12 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc)
332 396
333 if (qc->err_mask) { 397 if (qc->err_mask) {
334 /* 398 /*
335 * Find the sas_task and kill it. By this point, 399 * Find the sas_task and kill it. By this point, libata
336 * libata has decided to kill the qc, so we needn't 400 * has decided to kill the qc and has frozen the port.
337 * bother with sas_ata_task_done. But we still 401 * In this state sas_ata_task_done() will no longer free
338 * ought to abort the task. 402 * the sas_task, so we need to notify the lldd (via
403 * ->lldd_abort_task) that the task is dead and free it
404 * ourselves.
339 */ 405 */
340 struct sas_task *task = qc->lldd_task; 406 struct sas_task *task = qc->lldd_task;
341 unsigned long flags; 407 unsigned long flags;
@@ -348,7 +414,7 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc)
348 spin_unlock_irqrestore(&task->task_state_lock, flags); 414 spin_unlock_irqrestore(&task->task_state_lock, flags);
349 415
350 task->uldd_task = NULL; 416 task->uldd_task = NULL;
351 __sas_task_abort(task); 417 sas_ata_internal_abort(task);
352 } 418 }
353 } 419 }
354} 420}
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 15533a17eb97..ba5876ccd29a 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -957,49 +957,6 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
957} 957}
958 958
959/* 959/*
960 * Call the LLDD task abort routine directly. This function is intended for
961 * use by upper layers that need to tell the LLDD to abort a task.
962 */
963int __sas_task_abort(struct sas_task *task)
964{
965 struct sas_internal *si =
966 to_sas_internal(task->dev->port->ha->core.shost->transportt);
967 unsigned long flags;
968 int res;
969
970 spin_lock_irqsave(&task->task_state_lock, flags);
971 if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
972 task->task_state_flags & SAS_TASK_STATE_DONE) {
973 spin_unlock_irqrestore(&task->task_state_lock, flags);
974 SAS_DPRINTK("%s: Task %p already finished.\n", __func__,
975 task);
976 return 0;
977 }
978 task->task_state_flags |= SAS_TASK_STATE_ABORTED;
979 spin_unlock_irqrestore(&task->task_state_lock, flags);
980
981 if (!si->dft->lldd_abort_task)
982 return -ENODEV;
983
984 res = si->dft->lldd_abort_task(task);
985
986 spin_lock_irqsave(&task->task_state_lock, flags);
987 if ((task->task_state_flags & SAS_TASK_STATE_DONE) ||
988 (res == TMF_RESP_FUNC_COMPLETE))
989 {
990 spin_unlock_irqrestore(&task->task_state_lock, flags);
991 task->task_done(task);
992 return 0;
993 }
994
995 if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
996 task->task_state_flags &= ~SAS_TASK_STATE_ABORTED;
997 spin_unlock_irqrestore(&task->task_state_lock, flags);
998
999 return -EAGAIN;
1000}
1001
1002/*
1003 * Tell an upper layer that it needs to initiate an abort for a given task. 960 * Tell an upper layer that it needs to initiate an abort for a given task.
1004 * This should only ever be called by an LLDD. 961 * This should only ever be called by an LLDD.
1005 */ 962 */
@@ -1097,7 +1054,6 @@ EXPORT_SYMBOL_GPL(sas_slave_configure);
1097EXPORT_SYMBOL_GPL(sas_change_queue_depth); 1054EXPORT_SYMBOL_GPL(sas_change_queue_depth);
1098EXPORT_SYMBOL_GPL(sas_change_queue_type); 1055EXPORT_SYMBOL_GPL(sas_change_queue_type);
1099EXPORT_SYMBOL_GPL(sas_bios_param); 1056EXPORT_SYMBOL_GPL(sas_bios_param);
1100EXPORT_SYMBOL_GPL(__sas_task_abort);
1101EXPORT_SYMBOL_GPL(sas_task_abort); 1057EXPORT_SYMBOL_GPL(sas_task_abort);
1102EXPORT_SYMBOL_GPL(sas_phy_reset); 1058EXPORT_SYMBOL_GPL(sas_phy_reset);
1103EXPORT_SYMBOL_GPL(sas_phy_enable); 1059EXPORT_SYMBOL_GPL(sas_phy_enable);