diff options
Diffstat (limited to 'drivers/scsi/libsas/sas_ata.c')
-rw-r--r-- | drivers/scsi/libsas/sas_ata.c | 30 |
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) | |||
88 | static void sas_ata_task_done(struct sas_task *task) | 88 | static 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 | ||
126 | qc_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 | ||
244 | static void sas_ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) | 268 | static void sas_ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) |