aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic94xx/aic94xx_tmf.c
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2008-02-24 00:44:19 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-02-24 01:40:57 -0500
commite2396f1e4ecd438a15fa653a028b93e95013caa3 (patch)
tree8cc11b28b64fbf3a7a22d1636467d35174092e27 /drivers/scsi/aic94xx/aic94xx_tmf.c
parent8de3ef25a1fcd28d270b69417a41b424826d4f89 (diff)
[SCSI] aic94xx: fix TMF ascb handling to prevent sequencer panic
This is a particularly nasty bug. The problem is that if any internal ascb times out, currently we free it even though it's pending at the sequencer. This results in the sequencer getting terminally confused and the error message: BUG:sequencer:dl:no ascb Being returned when it comes back. The way to fix this is to manage freeing the ascb from the tasklet completion routine, so that we only free it when the sequencer actually returns it. The code is also altered to use on stack completions and transfer variables. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/aic94xx/aic94xx_tmf.c')
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c246
1 files changed, 135 insertions, 111 deletions
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;