aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@us.ibm.com>2007-01-30 04:18:41 -0500
committerJames Bottomley <jejb@mulgrave.localdomain>2007-07-18 12:15:13 -0400
commit1c50dc83f9ca752b1e1b985f1ce33d2695103ffa (patch)
treefba4621565a87272d1232281b9457c297d53ea04
parent35a7f2f698d309cc50d98e56312dd907427b7ba4 (diff)
[SCSI] sas_ata: ata_post_internal should abort the sas_task
This patch adds a new field, lldd_task, to ata_queued_cmd so that libata users such as libsas can associate some data with a qc. The particular ambition with this patch is to associate a sas_task with a qc; that way, if libata decides to timeout a command, we can come back (in sas_ata_post_internal) and abort the sas task. One question remains: Is it necessary to reset the phy on error, or will the libata error handler take care of it? (Assuming that one is written, of course.) This patch, as it is today, works well enough to clean things up when an ATA device probe attempt fails halfway through the probe, though I'm not sure this is always the right thing to do. Signed-off-by: Darrick J. Wong <djwong@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r--drivers/scsi/libsas/sas_ata.c30
-rw-r--r--include/linux/libata.h1
2 files changed, 28 insertions, 3 deletions
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 46e1dbe1b843..c8af884abe18 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -88,12 +88,17 @@ static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts)
88static void sas_ata_task_done(struct sas_task *task) 88static void sas_ata_task_done(struct sas_task *task)
89{ 89{
90 struct ata_queued_cmd *qc = task->uldd_task; 90 struct ata_queued_cmd *qc = task->uldd_task;
91 struct domain_device *dev = qc->ap->private_data; 91 struct domain_device *dev;
92 struct task_status_struct *stat = &task->task_status; 92 struct task_status_struct *stat = &task->task_status;
93 struct ata_task_resp *resp = (struct ata_task_resp *)stat->buf; 93 struct ata_task_resp *resp = (struct ata_task_resp *)stat->buf;
94 enum ata_completion_errors ac; 94 enum ata_completion_errors ac;
95 unsigned long flags; 95 unsigned long flags;
96 96
97 if (!qc)
98 goto qc_already_gone;
99
100 dev = qc->ap->private_data;
101
97 spin_lock_irqsave(dev->sata_dev.ap->lock, flags); 102 spin_lock_irqsave(dev->sata_dev.ap->lock, flags);
98 if (stat->stat == SAS_PROTO_RESPONSE) { 103 if (stat->stat == SAS_PROTO_RESPONSE) {
99 ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf); 104 ata_tf_from_fis(resp->ending_fis, &dev->sata_dev.tf);
@@ -114,9 +119,11 @@ static void sas_ata_task_done(struct sas_task *task)
114 } 119 }
115 } 120 }
116 121
122 qc->lldd_task = NULL;
117 ata_qc_complete(qc); 123 ata_qc_complete(qc);
118 spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags); 124 spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags);
119 125
126qc_already_gone:
120 list_del_init(&task->list); 127 list_del_init(&task->list);
121 sas_free_task(task); 128 sas_free_task(task);
122} 129}
@@ -166,6 +173,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
166 task->scatter = qc->__sg; 173 task->scatter = qc->__sg;
167 task->ata_task.retry_count = 1; 174 task->ata_task.retry_count = 1;
168 task->task_state_flags = SAS_TASK_STATE_PENDING; 175 task->task_state_flags = SAS_TASK_STATE_PENDING;
176 qc->lldd_task = task;
169 177
170 switch (qc->tf.protocol) { 178 switch (qc->tf.protocol) {
171 case ATA_PROT_NCQ: 179 case ATA_PROT_NCQ:
@@ -237,8 +245,24 @@ static void sas_ata_post_internal(struct ata_queued_cmd *qc)
237 if (qc->flags & ATA_QCFLAG_FAILED) 245 if (qc->flags & ATA_QCFLAG_FAILED)
238 qc->err_mask |= AC_ERR_OTHER; 246 qc->err_mask |= AC_ERR_OTHER;
239 247
240 if (qc->err_mask) 248 if (qc->err_mask) {
241 SAS_DPRINTK("%s: Failure; reset phy!\n", __FUNCTION__); 249 /*
250 * Find the sas_task and kill it. By this point,
251 * libata has decided to kill the qc, so we needn't
252 * bother with sas_ata_task_done. But we still
253 * ought to abort the task.
254 */
255 struct sas_task *task = qc->lldd_task;
256 struct domain_device *dev = qc->ap->private_data;
257
258 qc->lldd_task = NULL;
259 if (task) {
260 task->uldd_task = NULL;
261 __sas_task_abort(task);
262 }
263
264 sas_phy_reset(dev->port->phy, 1);
265 }
242} 266}
243 267
244static void sas_ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) 268static void sas_ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 47cd2a1c5544..4abb758a0450 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -411,6 +411,7 @@ struct ata_queued_cmd {
411 ata_qc_cb_t complete_fn; 411 ata_qc_cb_t complete_fn;
412 412
413 void *private_data; 413 void *private_data;
414 void *lldd_task;
414}; 415};
415 416
416struct ata_port_stats { 417struct ata_port_stats {