aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic94xx
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/aic94xx')
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.h3
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c4
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c246
3 files changed, 139 insertions, 114 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
index 150f6706d23f..abc757559c1a 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.h
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
@@ -140,7 +140,7 @@ struct asd_ascb {
140 140
141 /* internally generated command */ 141 /* internally generated command */
142 struct timer_list timer; 142 struct timer_list timer;
143 struct completion completion; 143 struct completion *completion;
144 u8 tag_valid:1; 144 u8 tag_valid:1;
145 __be16 tag; /* error recovery only */ 145 __be16 tag; /* error recovery only */
146 146
@@ -294,7 +294,6 @@ static inline void asd_init_ascb(struct asd_ha_struct *asd_ha,
294 ascb->timer.function = NULL; 294 ascb->timer.function = NULL;
295 init_timer(&ascb->timer); 295 init_timer(&ascb->timer);
296 ascb->tc_index = -1; 296 ascb->tc_index = -1;
297 init_completion(&ascb->completion);
298} 297}
299 298
300/* Must be called with the tc_index_lock held! 299/* Must be called with the tc_index_lock held!
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index 965d4bb999d9..008df9ab92a5 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -343,11 +343,13 @@ Again:
343 task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; 343 task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
344 task->task_state_flags |= SAS_TASK_STATE_DONE; 344 task->task_state_flags |= SAS_TASK_STATE_DONE;
345 if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) { 345 if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) {
346 struct completion *completion = ascb->completion;
346 spin_unlock_irqrestore(&task->task_state_lock, flags); 347 spin_unlock_irqrestore(&task->task_state_lock, flags);
347 ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x " 348 ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x "
348 "stat 0x%x but aborted by upper layer!\n", 349 "stat 0x%x but aborted by upper layer!\n",
349 task, opcode, ts->resp, ts->stat); 350 task, opcode, ts->resp, ts->stat);
350 complete(&ascb->completion); 351 if (completion)
352 complete(completion);
351 } else { 353 } else {
352 spin_unlock_irqrestore(&task->task_state_lock, flags); 354 spin_unlock_irqrestore(&task->task_state_lock, flags);
353 task->lldd_task = NULL; 355 task->lldd_task = NULL;
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
index d684c7432e63..b9ac8f703a1d 100644
--- a/drivers/scsi/aic94xx/aic94xx_tmf.c
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -53,50 +53,64 @@ static int asd_enqueue_internal(struct asd_ascb *ascb,
53 return res; 53 return res;
54} 54}
55 55
56static inline void asd_timedout_common(unsigned long data) 56/* ---------- CLEAR NEXUS ---------- */
57{
58 struct asd_ascb *ascb = (void *) data;
59 struct asd_seq_data *seq = &ascb->ha->seq;
60 unsigned long flags;
61 57
62 spin_lock_irqsave(&seq->pend_q_lock, flags); 58struct tasklet_completion_status {
63 seq->pending--; 59 int dl_opcode;
64 list_del_init(&ascb->list); 60 int tmf_state;
65 spin_unlock_irqrestore(&seq->pend_q_lock, flags); 61 u8 tag_valid:1;
66} 62 __be16 tag;
63};
64
65#define DECLARE_TCS(tcs) \
66 struct tasklet_completion_status tcs = { \
67 .dl_opcode = 0, \
68 .tmf_state = 0, \
69 .tag_valid = 0, \
70 .tag = 0, \
71 }
67 72
68/* ---------- CLEAR NEXUS ---------- */
69 73
70static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb, 74static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
71 struct done_list_struct *dl) 75 struct done_list_struct *dl)
72{ 76{
77 struct tasklet_completion_status *tcs = ascb->uldd_task;
73 ASD_DPRINTK("%s: here\n", __FUNCTION__); 78 ASD_DPRINTK("%s: here\n", __FUNCTION__);
74 if (!del_timer(&ascb->timer)) { 79 if (!del_timer(&ascb->timer)) {
75 ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__); 80 ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__);
76 return; 81 return;
77 } 82 }
78 ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode); 83 ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode);
79 ascb->uldd_task = (void *) (unsigned long) dl->opcode; 84 tcs->dl_opcode = dl->opcode;
80 complete(&ascb->completion); 85 complete(ascb->completion);
86 asd_ascb_free(ascb);
81} 87}
82 88
83static void asd_clear_nexus_timedout(unsigned long data) 89static void asd_clear_nexus_timedout(unsigned long data)
84{ 90{
85 struct asd_ascb *ascb = (void *) data; 91 struct asd_ascb *ascb = (void *)data;
92 struct tasklet_completion_status *tcs = ascb->uldd_task;
86 93
87 ASD_DPRINTK("%s: here\n", __FUNCTION__); 94 ASD_DPRINTK("%s: here\n", __FUNCTION__);
88 asd_timedout_common(data); 95 tcs->dl_opcode = TMF_RESP_FUNC_FAILED;
89 ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED; 96 complete(ascb->completion);
90 complete(&ascb->completion);
91} 97}
92 98
93#define CLEAR_NEXUS_PRE \ 99#define CLEAR_NEXUS_PRE \
100 struct asd_ascb *ascb; \
101 struct scb *scb; \
102 int res; \
103 DECLARE_COMPLETION_ONSTACK(completion); \
104 DECLARE_TCS(tcs); \
105 \
94 ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \ 106 ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \
95 res = 1; \ 107 res = 1; \
96 ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \ 108 ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
97 if (!ascb) \ 109 if (!ascb) \
98 return -ENOMEM; \ 110 return -ENOMEM; \
99 \ 111 \
112 ascb->completion = &completion; \
113 ascb->uldd_task = &tcs; \
100 scb = ascb->scb; \ 114 scb = ascb->scb; \
101 scb->header.opcode = CLEAR_NEXUS 115 scb->header.opcode = CLEAR_NEXUS
102 116
@@ -107,10 +121,11 @@ static void asd_clear_nexus_timedout(unsigned long data)
107 if (res) \ 121 if (res) \
108 goto out_err; \ 122 goto out_err; \
109 ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \ 123 ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \
110 wait_for_completion(&ascb->completion); \ 124 wait_for_completion(&completion); \
111 res = (int) (unsigned long) ascb->uldd_task; \ 125 res = tcs.dl_opcode; \
112 if (res == TC_NO_ERROR) \ 126 if (res == TC_NO_ERROR) \
113 res = TMF_RESP_FUNC_COMPLETE; \ 127 res = TMF_RESP_FUNC_COMPLETE; \
128 return res; \
114out_err: \ 129out_err: \
115 asd_ascb_free(ascb); \ 130 asd_ascb_free(ascb); \
116 return res 131 return res
@@ -118,9 +133,6 @@ out_err: \
118int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha) 133int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha)
119{ 134{
120 struct asd_ha_struct *asd_ha = sas_ha->lldd_ha; 135 struct asd_ha_struct *asd_ha = sas_ha->lldd_ha;
121 struct asd_ascb *ascb;
122 struct scb *scb;
123 int res;
124 136
125 CLEAR_NEXUS_PRE; 137 CLEAR_NEXUS_PRE;
126 scb->clear_nexus.nexus = NEXUS_ADAPTER; 138 scb->clear_nexus.nexus = NEXUS_ADAPTER;
@@ -130,9 +142,6 @@ int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha)
130int asd_clear_nexus_port(struct asd_sas_port *port) 142int asd_clear_nexus_port(struct asd_sas_port *port)
131{ 143{
132 struct asd_ha_struct *asd_ha = port->ha->lldd_ha; 144 struct asd_ha_struct *asd_ha = port->ha->lldd_ha;
133 struct asd_ascb *ascb;
134 struct scb *scb;
135 int res;
136 145
137 CLEAR_NEXUS_PRE; 146 CLEAR_NEXUS_PRE;
138 scb->clear_nexus.nexus = NEXUS_PORT; 147 scb->clear_nexus.nexus = NEXUS_PORT;
@@ -150,9 +159,6 @@ static int asd_clear_nexus_I_T(struct domain_device *dev,
150 enum clear_nexus_phase phase) 159 enum clear_nexus_phase phase)
151{ 160{
152 struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; 161 struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
153 struct asd_ascb *ascb;
154 struct scb *scb;
155 int res;
156 162
157 CLEAR_NEXUS_PRE; 163 CLEAR_NEXUS_PRE;
158 scb->clear_nexus.nexus = NEXUS_I_T; 164 scb->clear_nexus.nexus = NEXUS_I_T;
@@ -210,9 +216,6 @@ int asd_I_T_nexus_reset(struct domain_device *dev)
210static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun) 216static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
211{ 217{
212 struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; 218 struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
213 struct asd_ascb *ascb;
214 struct scb *scb;
215 int res;
216 219
217 CLEAR_NEXUS_PRE; 220 CLEAR_NEXUS_PRE;
218 scb->clear_nexus.nexus = NEXUS_I_T_L; 221 scb->clear_nexus.nexus = NEXUS_I_T_L;
@@ -227,9 +230,6 @@ static int asd_clear_nexus_tag(struct sas_task *task)
227{ 230{
228 struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; 231 struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
229 struct asd_ascb *tascb = task->lldd_task; 232 struct asd_ascb *tascb = task->lldd_task;
230 struct asd_ascb *ascb;
231 struct scb *scb;
232 int res;
233 233
234 CLEAR_NEXUS_PRE; 234 CLEAR_NEXUS_PRE;
235 scb->clear_nexus.nexus = NEXUS_TAG; 235 scb->clear_nexus.nexus = NEXUS_TAG;
@@ -245,9 +245,6 @@ static int asd_clear_nexus_index(struct sas_task *task)
245{ 245{
246 struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; 246 struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
247 struct asd_ascb *tascb = task->lldd_task; 247 struct asd_ascb *tascb = task->lldd_task;
248 struct asd_ascb *ascb;
249 struct scb *scb;
250 int res;
251 248
252 CLEAR_NEXUS_PRE; 249 CLEAR_NEXUS_PRE;
253 scb->clear_nexus.nexus = NEXUS_TRANS_CX; 250 scb->clear_nexus.nexus = NEXUS_TRANS_CX;
@@ -263,11 +260,11 @@ static int asd_clear_nexus_index(struct sas_task *task)
263static void asd_tmf_timedout(unsigned long data) 260static void asd_tmf_timedout(unsigned long data)
264{ 261{
265 struct asd_ascb *ascb = (void *) data; 262 struct asd_ascb *ascb = (void *) data;
263 struct tasklet_completion_status *tcs = ascb->uldd_task;
266 264
267 ASD_DPRINTK("tmf timed out\n"); 265 ASD_DPRINTK("tmf timed out\n");
268 asd_timedout_common(data); 266 tcs->tmf_state = TMF_RESP_FUNC_FAILED;
269 ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED; 267 complete(ascb->completion);
270 complete(&ascb->completion);
271} 268}
272 269
273static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb, 270static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
@@ -319,18 +316,24 @@ static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
319static void asd_tmf_tasklet_complete(struct asd_ascb *ascb, 316static void asd_tmf_tasklet_complete(struct asd_ascb *ascb,
320 struct done_list_struct *dl) 317 struct done_list_struct *dl)
321{ 318{
319 struct tasklet_completion_status *tcs;
320
322 if (!del_timer(&ascb->timer)) 321 if (!del_timer(&ascb->timer))
323 return; 322 return;
324 323
324 tcs = ascb->uldd_task;
325 ASD_DPRINTK("tmf tasklet complete\n"); 325 ASD_DPRINTK("tmf tasklet complete\n");
326 326
327 if (dl->opcode == TC_SSP_RESP) 327 tcs->dl_opcode = dl->opcode;
328 ascb->uldd_task = (void *) (unsigned long)
329 asd_get_tmf_resp_tasklet(ascb, dl);
330 else
331 ascb->uldd_task = (void *) 0xFF00 + (unsigned long) dl->opcode;
332 328
333 complete(&ascb->completion); 329 if (dl->opcode == TC_SSP_RESP) {
330 tcs->tmf_state = asd_get_tmf_resp_tasklet(ascb, dl);
331 tcs->tag_valid = ascb->tag_valid;
332 tcs->tag = ascb->tag;
333 }
334
335 complete(ascb->completion);
336 asd_ascb_free(ascb);
334} 337}
335 338
336static inline int asd_clear_nexus(struct sas_task *task) 339static inline int asd_clear_nexus(struct sas_task *task)
@@ -338,15 +341,19 @@ static inline int asd_clear_nexus(struct sas_task *task)
338 int res = TMF_RESP_FUNC_FAILED; 341 int res = TMF_RESP_FUNC_FAILED;
339 int leftover; 342 int leftover;
340 struct asd_ascb *tascb = task->lldd_task; 343 struct asd_ascb *tascb = task->lldd_task;
344 DECLARE_COMPLETION_ONSTACK(completion);
341 unsigned long flags; 345 unsigned long flags;
342 346
347 tascb->completion = &completion;
348
343 ASD_DPRINTK("task not done, clearing nexus\n"); 349 ASD_DPRINTK("task not done, clearing nexus\n");
344 if (tascb->tag_valid) 350 if (tascb->tag_valid)
345 res = asd_clear_nexus_tag(task); 351 res = asd_clear_nexus_tag(task);
346 else 352 else
347 res = asd_clear_nexus_index(task); 353 res = asd_clear_nexus_index(task);
348 leftover = wait_for_completion_timeout(&tascb->completion, 354 leftover = wait_for_completion_timeout(&completion,
349 AIC94XX_SCB_TIMEOUT); 355 AIC94XX_SCB_TIMEOUT);
356 tascb->completion = NULL;
350 ASD_DPRINTK("came back from clear nexus\n"); 357 ASD_DPRINTK("came back from clear nexus\n");
351 spin_lock_irqsave(&task->task_state_lock, flags); 358 spin_lock_irqsave(&task->task_state_lock, flags);
352 if (leftover < 1) 359 if (leftover < 1)
@@ -400,6 +407,11 @@ int asd_abort_task(struct sas_task *task)
400 struct asd_ascb *ascb = NULL; 407 struct asd_ascb *ascb = NULL;
401 struct scb *scb; 408 struct scb *scb;
402 int leftover; 409 int leftover;
410 DECLARE_TCS(tcs);
411 DECLARE_COMPLETION_ONSTACK(completion);
412 DECLARE_COMPLETION_ONSTACK(tascb_completion);
413
414 tascb->completion = &tascb_completion;
403 415
404 spin_lock_irqsave(&task->task_state_lock, flags); 416 spin_lock_irqsave(&task->task_state_lock, flags);
405 if (task->task_state_flags & SAS_TASK_STATE_DONE) { 417 if (task->task_state_flags & SAS_TASK_STATE_DONE) {
@@ -413,8 +425,10 @@ int asd_abort_task(struct sas_task *task)
413 ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); 425 ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
414 if (!ascb) 426 if (!ascb)
415 return -ENOMEM; 427 return -ENOMEM;
416 scb = ascb->scb;
417 428
429 ascb->uldd_task = &tcs;
430 ascb->completion = &completion;
431 scb = ascb->scb;
418 scb->header.opcode = SCB_ABORT_TASK; 432 scb->header.opcode = SCB_ABORT_TASK;
419 433
420 switch (task->task_proto) { 434 switch (task->task_proto) {
@@ -456,13 +470,12 @@ int asd_abort_task(struct sas_task *task)
456 res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete, 470 res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
457 asd_tmf_timedout); 471 asd_tmf_timedout);
458 if (res) 472 if (res)
459 goto out; 473 goto out_free;
460 wait_for_completion(&ascb->completion); 474 wait_for_completion(&completion);
461 ASD_DPRINTK("tmf came back\n"); 475 ASD_DPRINTK("tmf came back\n");
462 476
463 res = (int) (unsigned long) ascb->uldd_task; 477 tascb->tag = tcs.tag;
464 tascb->tag = ascb->tag; 478 tascb->tag_valid = tcs.tag_valid;
465 tascb->tag_valid = ascb->tag_valid;
466 479
467 spin_lock_irqsave(&task->task_state_lock, flags); 480 spin_lock_irqsave(&task->task_state_lock, flags);
468 if (task->task_state_flags & SAS_TASK_STATE_DONE) { 481 if (task->task_state_flags & SAS_TASK_STATE_DONE) {
@@ -473,63 +486,68 @@ int asd_abort_task(struct sas_task *task)
473 } 486 }
474 spin_unlock_irqrestore(&task->task_state_lock, flags); 487 spin_unlock_irqrestore(&task->task_state_lock, flags);
475 488
476 switch (res) { 489 if (tcs.dl_opcode == TC_SSP_RESP) {
477 /* The task to be aborted has been sent to the device. 490 /* The task to be aborted has been sent to the device.
478 * We got a Response IU for the ABORT TASK TMF. */ 491 * We got a Response IU for the ABORT TASK TMF. */
479 case TC_NO_ERROR + 0xFF00: 492 if (tcs.tmf_state == TMF_RESP_FUNC_COMPLETE)
480 case TMF_RESP_FUNC_COMPLETE: 493 res = asd_clear_nexus(task);
481 case TMF_RESP_FUNC_FAILED: 494 else
482 res = asd_clear_nexus(task); 495 res = tcs.tmf_state;
483 break; 496 } else if (tcs.dl_opcode == TC_NO_ERROR &&
484 case TMF_RESP_INVALID_FRAME: 497 tcs.tmf_state == TMF_RESP_FUNC_FAILED) {
485 case TMF_RESP_OVERLAPPED_TAG: 498 /* timeout */
486 case TMF_RESP_FUNC_ESUPP:
487 case TMF_RESP_NO_LUN:
488 goto out_done; break;
489 }
490 /* In the following we assume that the managing layer
491 * will _never_ make a mistake, when issuing ABORT TASK.
492 */
493 switch (res) {
494 default:
495 res = asd_clear_nexus(task);
496 /* fallthrough */
497 case TC_NO_ERROR + 0xFF00:
498 case TMF_RESP_FUNC_COMPLETE:
499 break;
500 /* The task hasn't been sent to the device xor we never got
501 * a (sane) Response IU for the ABORT TASK TMF.
502 */
503 case TF_NAK_RECV + 0xFF00:
504 res = TMF_RESP_INVALID_FRAME;
505 break;
506 case TF_TMF_TASK_DONE + 0xFF00: /* done but not reported yet */
507 res = TMF_RESP_FUNC_FAILED; 499 res = TMF_RESP_FUNC_FAILED;
508 leftover = wait_for_completion_timeout(&tascb->completion, 500 } else {
509 AIC94XX_SCB_TIMEOUT); 501 /* In the following we assume that the managing layer
510 spin_lock_irqsave(&task->task_state_lock, flags); 502 * will _never_ make a mistake, when issuing ABORT
511 if (leftover < 1) 503 * TASK.
504 */
505 switch (tcs.dl_opcode) {
506 default:
507 res = asd_clear_nexus(task);
508 /* fallthrough */
509 case TC_NO_ERROR:
510 break;
511 /* The task hasn't been sent to the device xor
512 * we never got a (sane) Response IU for the
513 * ABORT TASK TMF.
514 */
515 case TF_NAK_RECV:
516 res = TMF_RESP_INVALID_FRAME;
517 break;
518 case TF_TMF_TASK_DONE: /* done but not reported yet */
512 res = TMF_RESP_FUNC_FAILED; 519 res = TMF_RESP_FUNC_FAILED;
513 if (task->task_state_flags & SAS_TASK_STATE_DONE) 520 leftover =
521 wait_for_completion_timeout(&tascb_completion,
522 AIC94XX_SCB_TIMEOUT);
523 spin_lock_irqsave(&task->task_state_lock, flags);
524 if (leftover < 1)
525 res = TMF_RESP_FUNC_FAILED;
526 if (task->task_state_flags & SAS_TASK_STATE_DONE)
527 res = TMF_RESP_FUNC_COMPLETE;
528 spin_unlock_irqrestore(&task->task_state_lock, flags);
529 break;
530 case TF_TMF_NO_TAG:
531 case TF_TMF_TAG_FREE: /* the tag is in the free list */
532 case TF_TMF_NO_CONN_HANDLE: /* no such device */
514 res = TMF_RESP_FUNC_COMPLETE; 533 res = TMF_RESP_FUNC_COMPLETE;
515 spin_unlock_irqrestore(&task->task_state_lock, flags); 534 break;
516 goto out_done; 535 case TF_TMF_NO_CTX: /* not in seq, or proto != SSP */
517 case TF_TMF_NO_TAG + 0xFF00: 536 res = TMF_RESP_FUNC_ESUPP;
518 case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */ 537 break;
519 case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */ 538 }
520 res = TMF_RESP_FUNC_COMPLETE;
521 goto out_done;
522 case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */
523 res = TMF_RESP_FUNC_ESUPP;
524 goto out;
525 } 539 }
526out_done: 540 out_done:
541 tascb->completion = NULL;
527 if (res == TMF_RESP_FUNC_COMPLETE) { 542 if (res == TMF_RESP_FUNC_COMPLETE) {
528 task->lldd_task = NULL; 543 task->lldd_task = NULL;
529 mb(); 544 mb();
530 asd_ascb_free(tascb); 545 asd_ascb_free(tascb);
531 } 546 }
532out: 547 ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res);
548 return res;
549
550 out_free:
533 asd_ascb_free(ascb); 551 asd_ascb_free(ascb);
534 ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res); 552 ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res);
535 return res; 553 return res;
@@ -557,6 +575,8 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
557 struct asd_ascb *ascb; 575 struct asd_ascb *ascb;
558 int res = 1; 576 int res = 1;
559 struct scb *scb; 577 struct scb *scb;
578 DECLARE_COMPLETION_ONSTACK(completion);
579 DECLARE_TCS(tcs);
560 580
561 if (!(dev->tproto & SAS_PROTOCOL_SSP)) 581 if (!(dev->tproto & SAS_PROTOCOL_SSP))
562 return TMF_RESP_FUNC_ESUPP; 582 return TMF_RESP_FUNC_ESUPP;
@@ -564,6 +584,9 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
564 ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); 584 ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
565 if (!ascb) 585 if (!ascb)
566 return -ENOMEM; 586 return -ENOMEM;
587
588 ascb->completion = &completion;
589 ascb->uldd_task = &tcs;
567 scb = ascb->scb; 590 scb = ascb->scb;
568 591
569 if (tmf == TMF_QUERY_TASK) 592 if (tmf == TMF_QUERY_TASK)
@@ -596,31 +619,32 @@ static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
596 asd_tmf_timedout); 619 asd_tmf_timedout);
597 if (res) 620 if (res)
598 goto out_err; 621 goto out_err;
599 wait_for_completion(&ascb->completion); 622 wait_for_completion(&completion);
600 res = (int) (unsigned long) ascb->uldd_task;
601 623
602 switch (res) { 624 switch (tcs.dl_opcode) {
603 case TC_NO_ERROR + 0xFF00: 625 case TC_NO_ERROR:
604 res = TMF_RESP_FUNC_COMPLETE; 626 res = TMF_RESP_FUNC_COMPLETE;
605 break; 627 break;
606 case TF_NAK_RECV + 0xFF00: 628 case TF_NAK_RECV:
607 res = TMF_RESP_INVALID_FRAME; 629 res = TMF_RESP_INVALID_FRAME;
608 break; 630 break;
609 case TF_TMF_TASK_DONE + 0xFF00: 631 case TF_TMF_TASK_DONE:
610 res = TMF_RESP_FUNC_FAILED; 632 res = TMF_RESP_FUNC_FAILED;
611 break; 633 break;
612 case TF_TMF_NO_TAG + 0xFF00: 634 case TF_TMF_NO_TAG:
613 case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */ 635 case TF_TMF_TAG_FREE: /* the tag is in the free list */
614 case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */ 636 case TF_TMF_NO_CONN_HANDLE: /* no such device */
615 res = TMF_RESP_FUNC_COMPLETE; 637 res = TMF_RESP_FUNC_COMPLETE;
616 break; 638 break;
617 case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */ 639 case TF_TMF_NO_CTX: /* not in seq, or proto != SSP */
618 res = TMF_RESP_FUNC_ESUPP; 640 res = TMF_RESP_FUNC_ESUPP;
619 break; 641 break;
620 default: 642 default:
621 /* Allow TMF response codes to propagate upwards */ 643 /* Allow TMF response codes to propagate upwards */
644 res = tcs.dl_opcode;
622 break; 645 break;
623 } 646 }
647 return res;
624out_err: 648out_err:
625 asd_ascb_free(ascb); 649 asd_ascb_free(ascb);
626 return res; 650 return res;