aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libsas/sas_ata.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libsas/sas_ata.c')
-rw-r--r--drivers/scsi/libsas/sas_ata.c30
1 files changed, 27 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)