diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 65 |
1 files changed, 41 insertions, 24 deletions
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index f869fba86807..9c96d1bd36e2 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -51,10 +51,14 @@ static void sas_scsi_task_done(struct sas_task *task) | |||
51 | { | 51 | { |
52 | struct task_status_struct *ts = &task->task_status; | 52 | struct task_status_struct *ts = &task->task_status; |
53 | struct scsi_cmnd *sc = task->uldd_task; | 53 | struct scsi_cmnd *sc = task->uldd_task; |
54 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(sc->device->host); | ||
55 | unsigned ts_flags = task->task_state_flags; | ||
56 | int hs = 0, stat = 0; | 54 | int hs = 0, stat = 0; |
57 | 55 | ||
56 | if (unlikely(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { | ||
57 | /* Aborted tasks will be completed by the error handler */ | ||
58 | SAS_DPRINTK("task done but aborted\n"); | ||
59 | return; | ||
60 | } | ||
61 | |||
58 | if (unlikely(!sc)) { | 62 | if (unlikely(!sc)) { |
59 | SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n"); | 63 | SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n"); |
60 | list_del_init(&task->list); | 64 | list_del_init(&task->list); |
@@ -120,11 +124,7 @@ static void sas_scsi_task_done(struct sas_task *task) | |||
120 | sc->result = (hs << 16) | stat; | 124 | sc->result = (hs << 16) | stat; |
121 | list_del_init(&task->list); | 125 | list_del_init(&task->list); |
122 | sas_free_task(task); | 126 | sas_free_task(task); |
123 | /* This is very ugly but this is how SCSI Core works. */ | 127 | sc->scsi_done(sc); |
124 | if (ts_flags & SAS_TASK_STATE_ABORTED) | ||
125 | scsi_eh_finish_cmd(sc, &sas_ha->eh_done_q); | ||
126 | else | ||
127 | sc->scsi_done(sc); | ||
128 | } | 128 | } |
129 | 129 | ||
130 | static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd) | 130 | static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd) |
@@ -255,13 +255,33 @@ out: | |||
255 | return res; | 255 | return res; |
256 | } | 256 | } |
257 | 257 | ||
258 | static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) | ||
259 | { | ||
260 | struct sas_task *task = TO_SAS_TASK(cmd); | ||
261 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host); | ||
262 | |||
263 | /* remove the aborted task flag to allow the task to be | ||
264 | * completed now. At this point, we only get called following | ||
265 | * an actual abort of the task, so we should be guaranteed not | ||
266 | * to be racing with any completions from the LLD (hence we | ||
267 | * don't need the task state lock to clear the flag) */ | ||
268 | task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; | ||
269 | /* Now call task_done. However, task will be free'd after | ||
270 | * this */ | ||
271 | task->task_done(task); | ||
272 | /* now finish the command and move it on to the error | ||
273 | * handler done list, this also takes it off the | ||
274 | * error handler pending list */ | ||
275 | scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q); | ||
276 | } | ||
277 | |||
258 | static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) | 278 | static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) |
259 | { | 279 | { |
260 | struct scsi_cmnd *cmd, *n; | 280 | struct scsi_cmnd *cmd, *n; |
261 | 281 | ||
262 | list_for_each_entry_safe(cmd, n, error_q, eh_entry) { | 282 | list_for_each_entry_safe(cmd, n, error_q, eh_entry) { |
263 | if (cmd == my_cmd) | 283 | if (cmd == my_cmd) |
264 | list_del_init(&cmd->eh_entry); | 284 | sas_eh_finish_cmd(cmd); |
265 | } | 285 | } |
266 | } | 286 | } |
267 | 287 | ||
@@ -274,7 +294,7 @@ static void sas_scsi_clear_queue_I_T(struct list_head *error_q, | |||
274 | struct domain_device *x = cmd_to_domain_dev(cmd); | 294 | struct domain_device *x = cmd_to_domain_dev(cmd); |
275 | 295 | ||
276 | if (x == dev) | 296 | if (x == dev) |
277 | list_del_init(&cmd->eh_entry); | 297 | sas_eh_finish_cmd(cmd); |
278 | } | 298 | } |
279 | } | 299 | } |
280 | 300 | ||
@@ -288,7 +308,7 @@ static void sas_scsi_clear_queue_port(struct list_head *error_q, | |||
288 | struct asd_sas_port *x = dev->port; | 308 | struct asd_sas_port *x = dev->port; |
289 | 309 | ||
290 | if (x == port) | 310 | if (x == port) |
291 | list_del_init(&cmd->eh_entry); | 311 | sas_eh_finish_cmd(cmd); |
292 | } | 312 | } |
293 | } | 313 | } |
294 | 314 | ||
@@ -528,14 +548,14 @@ Again: | |||
528 | case TASK_IS_DONE: | 548 | case TASK_IS_DONE: |
529 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, | 549 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, |
530 | task); | 550 | task); |
531 | task->task_done(task); | 551 | sas_eh_finish_cmd(cmd); |
532 | if (need_reset) | 552 | if (need_reset) |
533 | try_to_reset_cmd_device(shost, cmd); | 553 | try_to_reset_cmd_device(shost, cmd); |
534 | continue; | 554 | continue; |
535 | case TASK_IS_ABORTED: | 555 | case TASK_IS_ABORTED: |
536 | SAS_DPRINTK("%s: task 0x%p is aborted\n", | 556 | SAS_DPRINTK("%s: task 0x%p is aborted\n", |
537 | __FUNCTION__, task); | 557 | __FUNCTION__, task); |
538 | task->task_done(task); | 558 | sas_eh_finish_cmd(cmd); |
539 | if (need_reset) | 559 | if (need_reset) |
540 | try_to_reset_cmd_device(shost, cmd); | 560 | try_to_reset_cmd_device(shost, cmd); |
541 | continue; | 561 | continue; |
@@ -547,7 +567,7 @@ Again: | |||
547 | "recovered\n", | 567 | "recovered\n", |
548 | SAS_ADDR(task->dev), | 568 | SAS_ADDR(task->dev), |
549 | cmd->device->lun); | 569 | cmd->device->lun); |
550 | task->task_done(task); | 570 | sas_eh_finish_cmd(cmd); |
551 | if (need_reset) | 571 | if (need_reset) |
552 | try_to_reset_cmd_device(shost, cmd); | 572 | try_to_reset_cmd_device(shost, cmd); |
553 | sas_scsi_clear_queue_lu(work_q, cmd); | 573 | sas_scsi_clear_queue_lu(work_q, cmd); |
@@ -562,7 +582,7 @@ Again: | |||
562 | if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { | 582 | if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { |
563 | SAS_DPRINTK("I_T %016llx recovered\n", | 583 | SAS_DPRINTK("I_T %016llx recovered\n", |
564 | SAS_ADDR(task->dev->sas_addr)); | 584 | SAS_ADDR(task->dev->sas_addr)); |
565 | task->task_done(task); | 585 | sas_eh_finish_cmd(cmd); |
566 | if (need_reset) | 586 | if (need_reset) |
567 | try_to_reset_cmd_device(shost, cmd); | 587 | try_to_reset_cmd_device(shost, cmd); |
568 | sas_scsi_clear_queue_I_T(work_q, task->dev); | 588 | sas_scsi_clear_queue_I_T(work_q, task->dev); |
@@ -577,7 +597,7 @@ Again: | |||
577 | if (res == TMF_RESP_FUNC_COMPLETE) { | 597 | if (res == TMF_RESP_FUNC_COMPLETE) { |
578 | SAS_DPRINTK("clear nexus port:%d " | 598 | SAS_DPRINTK("clear nexus port:%d " |
579 | "succeeded\n", port->id); | 599 | "succeeded\n", port->id); |
580 | task->task_done(task); | 600 | sas_eh_finish_cmd(cmd); |
581 | if (need_reset) | 601 | if (need_reset) |
582 | try_to_reset_cmd_device(shost, cmd); | 602 | try_to_reset_cmd_device(shost, cmd); |
583 | sas_scsi_clear_queue_port(work_q, | 603 | sas_scsi_clear_queue_port(work_q, |
@@ -591,10 +611,10 @@ Again: | |||
591 | if (res == TMF_RESP_FUNC_COMPLETE) { | 611 | if (res == TMF_RESP_FUNC_COMPLETE) { |
592 | SAS_DPRINTK("clear nexus ha " | 612 | SAS_DPRINTK("clear nexus ha " |
593 | "succeeded\n"); | 613 | "succeeded\n"); |
594 | task->task_done(task); | 614 | sas_eh_finish_cmd(cmd); |
595 | if (need_reset) | 615 | if (need_reset) |
596 | try_to_reset_cmd_device(shost, cmd); | 616 | try_to_reset_cmd_device(shost, cmd); |
597 | goto out; | 617 | goto clear_q; |
598 | } | 618 | } |
599 | } | 619 | } |
600 | /* If we are here -- this means that no amount | 620 | /* If we are here -- this means that no amount |
@@ -606,21 +626,18 @@ Again: | |||
606 | SAS_ADDR(task->dev->sas_addr), | 626 | SAS_ADDR(task->dev->sas_addr), |
607 | cmd->device->lun); | 627 | cmd->device->lun); |
608 | 628 | ||
609 | task->task_done(task); | 629 | sas_eh_finish_cmd(cmd); |
610 | if (need_reset) | 630 | if (need_reset) |
611 | try_to_reset_cmd_device(shost, cmd); | 631 | try_to_reset_cmd_device(shost, cmd); |
612 | goto clear_q; | 632 | goto clear_q; |
613 | } | 633 | } |
614 | } | 634 | } |
615 | out: | ||
616 | return list_empty(work_q); | 635 | return list_empty(work_q); |
617 | clear_q: | 636 | clear_q: |
618 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); | 637 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); |
619 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { | 638 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) |
620 | struct sas_task *task = TO_SAS_TASK(cmd); | 639 | sas_eh_finish_cmd(cmd); |
621 | list_del_init(&cmd->eh_entry); | 640 | |
622 | task->task_done(task); | ||
623 | } | ||
624 | return list_empty(work_q); | 641 | return list_empty(work_q); |
625 | } | 642 | } |
626 | 643 | ||