diff options
Diffstat (limited to 'drivers/scsi/libsas/sas_scsi_host.c')
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 258 |
1 files changed, 183 insertions, 75 deletions
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 22672d54aa27..cd2378010c7e 100644 --- a/drivers/scsi/libsas/sas_scsi_host.c +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <scsi/scsi_transport_sas.h> | 34 | #include <scsi/scsi_transport_sas.h> |
35 | #include "../scsi_sas_internal.h" | 35 | #include "../scsi_sas_internal.h" |
36 | #include "../scsi_transport_api.h" | 36 | #include "../scsi_transport_api.h" |
37 | #include "../scsi_priv.h" | ||
37 | 38 | ||
38 | #include <linux/err.h> | 39 | #include <linux/err.h> |
39 | #include <linux/blkdev.h> | 40 | #include <linux/blkdev.h> |
@@ -130,7 +131,7 @@ static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd) | |||
130 | if (cmd->request && blk_rq_tagged(cmd->request)) { | 131 | if (cmd->request && blk_rq_tagged(cmd->request)) { |
131 | if (cmd->device->ordered_tags && | 132 | if (cmd->device->ordered_tags && |
132 | (cmd->request->cmd_flags & REQ_HARDBARRIER)) | 133 | (cmd->request->cmd_flags & REQ_HARDBARRIER)) |
133 | ta = TASK_ATTR_HOQ; | 134 | ta = TASK_ATTR_ORDERED; |
134 | } | 135 | } |
135 | return ta; | 136 | return ta; |
136 | } | 137 | } |
@@ -281,6 +282,7 @@ enum task_disposition { | |||
281 | TASK_IS_ABORTED, | 282 | TASK_IS_ABORTED, |
282 | TASK_IS_AT_LU, | 283 | TASK_IS_AT_LU, |
283 | TASK_IS_NOT_AT_LU, | 284 | TASK_IS_NOT_AT_LU, |
285 | TASK_ABORT_FAILED, | ||
284 | }; | 286 | }; |
285 | 287 | ||
286 | static enum task_disposition sas_scsi_find_task(struct sas_task *task) | 288 | static enum task_disposition sas_scsi_find_task(struct sas_task *task) |
@@ -310,15 +312,6 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) | |||
310 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | 312 | spin_unlock_irqrestore(&core->task_queue_lock, flags); |
311 | } | 313 | } |
312 | 314 | ||
313 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
314 | if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) { | ||
315 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
316 | SAS_DPRINTK("%s: task 0x%p already aborted\n", | ||
317 | __FUNCTION__, task); | ||
318 | return TASK_IS_ABORTED; | ||
319 | } | ||
320 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
321 | |||
322 | for (i = 0; i < 5; i++) { | 315 | for (i = 0; i < 5; i++) { |
323 | SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task); | 316 | SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task); |
324 | res = si->dft->lldd_abort_task(task); | 317 | res = si->dft->lldd_abort_task(task); |
@@ -340,15 +333,21 @@ static enum task_disposition sas_scsi_find_task(struct sas_task *task) | |||
340 | SAS_DPRINTK("%s: querying task 0x%p\n", | 333 | SAS_DPRINTK("%s: querying task 0x%p\n", |
341 | __FUNCTION__, task); | 334 | __FUNCTION__, task); |
342 | res = si->dft->lldd_query_task(task); | 335 | res = si->dft->lldd_query_task(task); |
343 | if (res == TMF_RESP_FUNC_SUCC) { | 336 | switch (res) { |
337 | case TMF_RESP_FUNC_SUCC: | ||
344 | SAS_DPRINTK("%s: task 0x%p at LU\n", | 338 | SAS_DPRINTK("%s: task 0x%p at LU\n", |
345 | __FUNCTION__, task); | 339 | __FUNCTION__, task); |
346 | return TASK_IS_AT_LU; | 340 | return TASK_IS_AT_LU; |
347 | } else if (res == TMF_RESP_FUNC_COMPLETE) { | 341 | case TMF_RESP_FUNC_COMPLETE: |
348 | SAS_DPRINTK("%s: task 0x%p not at LU\n", | 342 | SAS_DPRINTK("%s: task 0x%p not at LU\n", |
349 | __FUNCTION__, task); | 343 | __FUNCTION__, task); |
350 | return TASK_IS_NOT_AT_LU; | 344 | return TASK_IS_NOT_AT_LU; |
351 | } | 345 | case TMF_RESP_FUNC_FAILED: |
346 | SAS_DPRINTK("%s: task 0x%p failed to abort\n", | ||
347 | __FUNCTION__, task); | ||
348 | return TASK_ABORT_FAILED; | ||
349 | } | ||
350 | |||
352 | } | 351 | } |
353 | } | 352 | } |
354 | return res; | 353 | return res; |
@@ -398,35 +397,82 @@ static int sas_recover_I_T(struct domain_device *dev) | |||
398 | return res; | 397 | return res; |
399 | } | 398 | } |
400 | 399 | ||
401 | void sas_scsi_recover_host(struct Scsi_Host *shost) | 400 | /* Find the sas_phy that's attached to this device */ |
401 | struct sas_phy *find_local_sas_phy(struct domain_device *dev) | ||
402 | { | ||
403 | struct domain_device *pdev = dev->parent; | ||
404 | struct ex_phy *exphy = NULL; | ||
405 | int i; | ||
406 | |||
407 | /* Directly attached device */ | ||
408 | if (!pdev) | ||
409 | return dev->port->phy; | ||
410 | |||
411 | /* Otherwise look in the expander */ | ||
412 | for (i = 0; i < pdev->ex_dev.num_phys; i++) | ||
413 | if (!memcmp(dev->sas_addr, | ||
414 | pdev->ex_dev.ex_phy[i].attached_sas_addr, | ||
415 | SAS_ADDR_SIZE)) { | ||
416 | exphy = &pdev->ex_dev.ex_phy[i]; | ||
417 | break; | ||
418 | } | ||
419 | |||
420 | BUG_ON(!exphy); | ||
421 | return exphy->phy; | ||
422 | } | ||
423 | |||
424 | /* Attempt to send a target reset message to a device */ | ||
425 | int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) | ||
426 | { | ||
427 | struct domain_device *dev = cmd_to_domain_dev(cmd); | ||
428 | struct sas_phy *phy = find_local_sas_phy(dev); | ||
429 | int res; | ||
430 | |||
431 | res = sas_phy_reset(phy, 1); | ||
432 | if (res) | ||
433 | SAS_DPRINTK("Device reset of %s failed 0x%x\n", | ||
434 | phy->dev.kobj.k_name, | ||
435 | res); | ||
436 | if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) | ||
437 | return SUCCESS; | ||
438 | |||
439 | return FAILED; | ||
440 | } | ||
441 | |||
442 | /* Try to reset a device */ | ||
443 | static int try_to_reset_cmd_device(struct Scsi_Host *shost, | ||
444 | struct scsi_cmnd *cmd) | ||
445 | { | ||
446 | if (!shost->hostt->eh_device_reset_handler) | ||
447 | return FAILED; | ||
448 | |||
449 | return shost->hostt->eh_device_reset_handler(cmd); | ||
450 | } | ||
451 | |||
452 | static int sas_eh_handle_sas_errors(struct Scsi_Host *shost, | ||
453 | struct list_head *work_q, | ||
454 | struct list_head *done_q) | ||
402 | { | 455 | { |
403 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | ||
404 | unsigned long flags; | ||
405 | LIST_HEAD(error_q); | ||
406 | struct scsi_cmnd *cmd, *n; | 456 | struct scsi_cmnd *cmd, *n; |
407 | enum task_disposition res = TASK_IS_DONE; | 457 | enum task_disposition res = TASK_IS_DONE; |
408 | int tmf_resp; | 458 | int tmf_resp, need_reset; |
409 | struct sas_internal *i = to_sas_internal(shost->transportt); | 459 | struct sas_internal *i = to_sas_internal(shost->transportt); |
460 | unsigned long flags; | ||
461 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | ||
410 | 462 | ||
411 | spin_lock_irqsave(shost->host_lock, flags); | ||
412 | list_splice_init(&shost->eh_cmd_q, &error_q); | ||
413 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
414 | |||
415 | SAS_DPRINTK("Enter %s\n", __FUNCTION__); | ||
416 | |||
417 | /* All tasks on this list were marked SAS_TASK_STATE_ABORTED | ||
418 | * by sas_scsi_timed_out() callback. | ||
419 | */ | ||
420 | Again: | 463 | Again: |
421 | SAS_DPRINTK("going over list...\n"); | 464 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { |
422 | list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { | ||
423 | struct sas_task *task = TO_SAS_TASK(cmd); | 465 | struct sas_task *task = TO_SAS_TASK(cmd); |
424 | list_del_init(&cmd->eh_entry); | ||
425 | 466 | ||
426 | if (!task) { | 467 | if (!task) |
427 | SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__); | ||
428 | continue; | 468 | continue; |
429 | } | 469 | |
470 | list_del_init(&cmd->eh_entry); | ||
471 | |||
472 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
473 | need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET; | ||
474 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
475 | |||
430 | SAS_DPRINTK("trying to find task 0x%p\n", task); | 476 | SAS_DPRINTK("trying to find task 0x%p\n", task); |
431 | res = sas_scsi_find_task(task); | 477 | res = sas_scsi_find_task(task); |
432 | 478 | ||
@@ -437,11 +483,15 @@ Again: | |||
437 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, | 483 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, |
438 | task); | 484 | task); |
439 | task->task_done(task); | 485 | task->task_done(task); |
486 | if (need_reset) | ||
487 | try_to_reset_cmd_device(shost, cmd); | ||
440 | continue; | 488 | continue; |
441 | case TASK_IS_ABORTED: | 489 | case TASK_IS_ABORTED: |
442 | SAS_DPRINTK("%s: task 0x%p is aborted\n", | 490 | SAS_DPRINTK("%s: task 0x%p is aborted\n", |
443 | __FUNCTION__, task); | 491 | __FUNCTION__, task); |
444 | task->task_done(task); | 492 | task->task_done(task); |
493 | if (need_reset) | ||
494 | try_to_reset_cmd_device(shost, cmd); | ||
445 | continue; | 495 | continue; |
446 | case TASK_IS_AT_LU: | 496 | case TASK_IS_AT_LU: |
447 | SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); | 497 | SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); |
@@ -452,11 +502,14 @@ Again: | |||
452 | SAS_ADDR(task->dev), | 502 | SAS_ADDR(task->dev), |
453 | cmd->device->lun); | 503 | cmd->device->lun); |
454 | task->task_done(task); | 504 | task->task_done(task); |
455 | sas_scsi_clear_queue_lu(&error_q, cmd); | 505 | if (need_reset) |
506 | try_to_reset_cmd_device(shost, cmd); | ||
507 | sas_scsi_clear_queue_lu(work_q, cmd); | ||
456 | goto Again; | 508 | goto Again; |
457 | } | 509 | } |
458 | /* fallthrough */ | 510 | /* fallthrough */ |
459 | case TASK_IS_NOT_AT_LU: | 511 | case TASK_IS_NOT_AT_LU: |
512 | case TASK_ABORT_FAILED: | ||
460 | SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n", | 513 | SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n", |
461 | task); | 514 | task); |
462 | tmf_resp = sas_recover_I_T(task->dev); | 515 | tmf_resp = sas_recover_I_T(task->dev); |
@@ -464,7 +517,9 @@ Again: | |||
464 | SAS_DPRINTK("I_T %016llx recovered\n", | 517 | SAS_DPRINTK("I_T %016llx recovered\n", |
465 | SAS_ADDR(task->dev->sas_addr)); | 518 | SAS_ADDR(task->dev->sas_addr)); |
466 | task->task_done(task); | 519 | task->task_done(task); |
467 | sas_scsi_clear_queue_I_T(&error_q, task->dev); | 520 | if (need_reset) |
521 | try_to_reset_cmd_device(shost, cmd); | ||
522 | sas_scsi_clear_queue_I_T(work_q, task->dev); | ||
468 | goto Again; | 523 | goto Again; |
469 | } | 524 | } |
470 | /* Hammer time :-) */ | 525 | /* Hammer time :-) */ |
@@ -477,7 +532,9 @@ Again: | |||
477 | SAS_DPRINTK("clear nexus port:%d " | 532 | SAS_DPRINTK("clear nexus port:%d " |
478 | "succeeded\n", port->id); | 533 | "succeeded\n", port->id); |
479 | task->task_done(task); | 534 | task->task_done(task); |
480 | sas_scsi_clear_queue_port(&error_q, | 535 | if (need_reset) |
536 | try_to_reset_cmd_device(shost, cmd); | ||
537 | sas_scsi_clear_queue_port(work_q, | ||
481 | port); | 538 | port); |
482 | goto Again; | 539 | goto Again; |
483 | } | 540 | } |
@@ -489,6 +546,8 @@ Again: | |||
489 | SAS_DPRINTK("clear nexus ha " | 546 | SAS_DPRINTK("clear nexus ha " |
490 | "succeeded\n"); | 547 | "succeeded\n"); |
491 | task->task_done(task); | 548 | task->task_done(task); |
549 | if (need_reset) | ||
550 | try_to_reset_cmd_device(shost, cmd); | ||
492 | goto out; | 551 | goto out; |
493 | } | 552 | } |
494 | } | 553 | } |
@@ -502,20 +561,54 @@ Again: | |||
502 | cmd->device->lun); | 561 | cmd->device->lun); |
503 | 562 | ||
504 | task->task_done(task); | 563 | task->task_done(task); |
564 | if (need_reset) | ||
565 | try_to_reset_cmd_device(shost, cmd); | ||
505 | goto clear_q; | 566 | goto clear_q; |
506 | } | 567 | } |
507 | } | 568 | } |
508 | out: | 569 | out: |
509 | scsi_eh_flush_done_q(&ha->eh_done_q); | 570 | return list_empty(work_q); |
510 | SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); | ||
511 | return; | ||
512 | clear_q: | 571 | clear_q: |
513 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); | 572 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); |
514 | list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { | 573 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { |
515 | struct sas_task *task = TO_SAS_TASK(cmd); | 574 | struct sas_task *task = TO_SAS_TASK(cmd); |
516 | list_del_init(&cmd->eh_entry); | 575 | list_del_init(&cmd->eh_entry); |
517 | task->task_done(task); | 576 | task->task_done(task); |
518 | } | 577 | } |
578 | return list_empty(work_q); | ||
579 | } | ||
580 | |||
581 | void sas_scsi_recover_host(struct Scsi_Host *shost) | ||
582 | { | ||
583 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | ||
584 | unsigned long flags; | ||
585 | LIST_HEAD(eh_work_q); | ||
586 | |||
587 | spin_lock_irqsave(shost->host_lock, flags); | ||
588 | list_splice_init(&shost->eh_cmd_q, &eh_work_q); | ||
589 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
590 | |||
591 | SAS_DPRINTK("Enter %s\n", __FUNCTION__); | ||
592 | /* | ||
593 | * Deal with commands that still have SAS tasks (i.e. they didn't | ||
594 | * complete via the normal sas_task completion mechanism) | ||
595 | */ | ||
596 | if (sas_eh_handle_sas_errors(shost, &eh_work_q, &ha->eh_done_q)) | ||
597 | goto out; | ||
598 | |||
599 | /* | ||
600 | * Now deal with SCSI commands that completed ok but have a an error | ||
601 | * code (and hopefully sense data) attached. This is roughly what | ||
602 | * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any | ||
603 | * command we see here has no sas_task and is thus unknown to the HA. | ||
604 | */ | ||
605 | if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q)) | ||
606 | scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); | ||
607 | |||
608 | out: | ||
609 | scsi_eh_flush_done_q(&ha->eh_done_q); | ||
610 | SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); | ||
611 | return; | ||
519 | } | 612 | } |
520 | 613 | ||
521 | enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) | 614 | enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) |
@@ -524,24 +617,30 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) | |||
524 | unsigned long flags; | 617 | unsigned long flags; |
525 | 618 | ||
526 | if (!task) { | 619 | if (!task) { |
527 | SAS_DPRINTK("command 0x%p, task 0x%p, gone: EH_HANDLED\n", | 620 | cmd->timeout_per_command /= 2; |
528 | cmd, task); | 621 | SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n", |
529 | return EH_HANDLED; | 622 | cmd, task, (cmd->timeout_per_command ? |
623 | "EH_RESET_TIMER" : "EH_NOT_HANDLED")); | ||
624 | if (!cmd->timeout_per_command) | ||
625 | return EH_NOT_HANDLED; | ||
626 | return EH_RESET_TIMER; | ||
530 | } | 627 | } |
531 | 628 | ||
532 | spin_lock_irqsave(&task->task_state_lock, flags); | 629 | spin_lock_irqsave(&task->task_state_lock, flags); |
533 | if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) { | 630 | BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED); |
534 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
535 | SAS_DPRINTK("command 0x%p, task 0x%p, aborted by initiator: " | ||
536 | "EH_NOT_HANDLED\n", cmd, task); | ||
537 | return EH_NOT_HANDLED; | ||
538 | } | ||
539 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | 631 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { |
540 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 632 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
541 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", | 633 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", |
542 | cmd, task); | 634 | cmd, task); |
543 | return EH_HANDLED; | 635 | return EH_HANDLED; |
544 | } | 636 | } |
637 | if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) { | ||
638 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
639 | SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: " | ||
640 | "EH_RESET_TIMER\n", | ||
641 | cmd, task); | ||
642 | return EH_RESET_TIMER; | ||
643 | } | ||
545 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | 644 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; |
546 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 645 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
547 | 646 | ||
@@ -557,8 +656,9 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy) | |||
557 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | 656 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); |
558 | struct domain_device *found_dev = NULL; | 657 | struct domain_device *found_dev = NULL; |
559 | int i; | 658 | int i; |
659 | unsigned long flags; | ||
560 | 660 | ||
561 | spin_lock(&ha->phy_port_lock); | 661 | spin_lock_irqsave(&ha->phy_port_lock, flags); |
562 | for (i = 0; i < ha->num_phys; i++) { | 662 | for (i = 0; i < ha->num_phys; i++) { |
563 | struct asd_sas_port *port = ha->sas_port[i]; | 663 | struct asd_sas_port *port = ha->sas_port[i]; |
564 | struct domain_device *dev; | 664 | struct domain_device *dev; |
@@ -574,7 +674,7 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy) | |||
574 | spin_unlock(&port->dev_list_lock); | 674 | spin_unlock(&port->dev_list_lock); |
575 | } | 675 | } |
576 | found: | 676 | found: |
577 | spin_unlock(&ha->phy_port_lock); | 677 | spin_unlock_irqrestore(&ha->phy_port_lock, flags); |
578 | 678 | ||
579 | return found_dev; | 679 | return found_dev; |
580 | } | 680 | } |
@@ -623,6 +723,8 @@ int sas_slave_configure(struct scsi_device *scsi_dev) | |||
623 | scsi_deactivate_tcq(scsi_dev, 1); | 723 | scsi_deactivate_tcq(scsi_dev, 1); |
624 | } | 724 | } |
625 | 725 | ||
726 | scsi_dev->allow_restart = 1; | ||
727 | |||
626 | return 0; | 728 | return 0; |
627 | } | 729 | } |
628 | 730 | ||
@@ -799,46 +901,42 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha) | |||
799 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | 901 | spin_unlock_irqrestore(&core->task_queue_lock, flags); |
800 | } | 902 | } |
801 | 903 | ||
802 | static int do_sas_task_abort(struct sas_task *task) | 904 | /* |
905 | * Call the LLDD task abort routine directly. This function is intended for | ||
906 | * use by upper layers that need to tell the LLDD to abort a task. | ||
907 | */ | ||
908 | int __sas_task_abort(struct sas_task *task) | ||
803 | { | 909 | { |
804 | struct scsi_cmnd *sc = task->uldd_task; | ||
805 | struct sas_internal *si = | 910 | struct sas_internal *si = |
806 | to_sas_internal(task->dev->port->ha->core.shost->transportt); | 911 | to_sas_internal(task->dev->port->ha->core.shost->transportt); |
807 | unsigned long flags; | 912 | unsigned long flags; |
808 | int res; | 913 | int res; |
809 | 914 | ||
810 | spin_lock_irqsave(&task->task_state_lock, flags); | 915 | spin_lock_irqsave(&task->task_state_lock, flags); |
811 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { | 916 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED || |
917 | task->task_state_flags & SAS_TASK_STATE_DONE) { | ||
812 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 918 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
813 | SAS_DPRINTK("%s: Task %p already aborted.\n", __FUNCTION__, | 919 | SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__, |
814 | task); | 920 | task); |
815 | return 0; | 921 | return 0; |
816 | } | 922 | } |
817 | 923 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | |
818 | task->task_state_flags |= SAS_TASK_INITIATOR_ABORTED; | ||
819 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | ||
820 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | ||
821 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 924 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
822 | 925 | ||
823 | if (!si->dft->lldd_abort_task) | 926 | if (!si->dft->lldd_abort_task) |
824 | return -ENODEV; | 927 | return -ENODEV; |
825 | 928 | ||
826 | res = si->dft->lldd_abort_task(task); | 929 | res = si->dft->lldd_abort_task(task); |
930 | |||
931 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
827 | if ((task->task_state_flags & SAS_TASK_STATE_DONE) || | 932 | if ((task->task_state_flags & SAS_TASK_STATE_DONE) || |
828 | (res == TMF_RESP_FUNC_COMPLETE)) | 933 | (res == TMF_RESP_FUNC_COMPLETE)) |
829 | { | 934 | { |
830 | /* SMP commands don't have scsi_cmds(?) */ | 935 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
831 | if (!sc) { | 936 | task->task_done(task); |
832 | task->task_done(task); | ||
833 | return 0; | ||
834 | } | ||
835 | scsi_req_abort_cmd(sc); | ||
836 | scsi_schedule_eh(sc->device->host); | ||
837 | return 0; | 937 | return 0; |
838 | } | 938 | } |
839 | 939 | ||
840 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
841 | task->task_state_flags &= ~SAS_TASK_INITIATOR_ABORTED; | ||
842 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | 940 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) |
843 | task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; | 941 | task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; |
844 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 942 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
@@ -846,17 +944,24 @@ static int do_sas_task_abort(struct sas_task *task) | |||
846 | return -EAGAIN; | 944 | return -EAGAIN; |
847 | } | 945 | } |
848 | 946 | ||
849 | void sas_task_abort(struct work_struct *work) | 947 | /* |
948 | * Tell an upper layer that it needs to initiate an abort for a given task. | ||
949 | * This should only ever be called by an LLDD. | ||
950 | */ | ||
951 | void sas_task_abort(struct sas_task *task) | ||
850 | { | 952 | { |
851 | struct sas_task *task = | 953 | struct scsi_cmnd *sc = task->uldd_task; |
852 | container_of(work, struct sas_task, abort_work); | ||
853 | int i; | ||
854 | 954 | ||
855 | for (i = 0; i < 5; i++) | 955 | /* Escape for libsas internal commands */ |
856 | if (!do_sas_task_abort(task)) | 956 | if (!sc) { |
957 | if (!del_timer(&task->timer)) | ||
857 | return; | 958 | return; |
959 | task->timer.function(task->timer.data); | ||
960 | return; | ||
961 | } | ||
858 | 962 | ||
859 | SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__); | 963 | scsi_req_abort_cmd(sc); |
964 | scsi_schedule_eh(sc->device->host); | ||
860 | } | 965 | } |
861 | 966 | ||
862 | EXPORT_SYMBOL_GPL(sas_queuecommand); | 967 | EXPORT_SYMBOL_GPL(sas_queuecommand); |
@@ -866,5 +971,8 @@ EXPORT_SYMBOL_GPL(sas_slave_destroy); | |||
866 | EXPORT_SYMBOL_GPL(sas_change_queue_depth); | 971 | EXPORT_SYMBOL_GPL(sas_change_queue_depth); |
867 | EXPORT_SYMBOL_GPL(sas_change_queue_type); | 972 | EXPORT_SYMBOL_GPL(sas_change_queue_type); |
868 | EXPORT_SYMBOL_GPL(sas_bios_param); | 973 | EXPORT_SYMBOL_GPL(sas_bios_param); |
974 | EXPORT_SYMBOL_GPL(__sas_task_abort); | ||
869 | EXPORT_SYMBOL_GPL(sas_task_abort); | 975 | EXPORT_SYMBOL_GPL(sas_task_abort); |
870 | EXPORT_SYMBOL_GPL(sas_phy_reset); | 976 | EXPORT_SYMBOL_GPL(sas_phy_reset); |
977 | EXPORT_SYMBOL_GPL(sas_phy_enable); | ||
978 | EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); | ||