diff options
Diffstat (limited to 'drivers/scsi/libsas/sas_scsi_host.c')
-rw-r--r-- | drivers/scsi/libsas/sas_scsi_host.c | 290 |
1 files changed, 215 insertions, 75 deletions
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c index 22672d54aa27..897a5e2c55e4 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,113 @@ 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 LUN 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_internal *i = | ||
429 | to_sas_internal(dev->port->ha->core.shost->transportt); | ||
430 | struct scsi_lun lun; | ||
431 | int res; | ||
432 | |||
433 | int_to_scsilun(cmd->device->lun, &lun); | ||
434 | |||
435 | if (!i->dft->lldd_lu_reset) | ||
436 | return FAILED; | ||
437 | |||
438 | res = i->dft->lldd_lu_reset(dev, lun.scsi_lun); | ||
439 | if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) | ||
440 | return SUCCESS; | ||
441 | |||
442 | return FAILED; | ||
443 | } | ||
444 | |||
445 | /* Attempt to send a phy (bus) reset */ | ||
446 | int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd) | ||
447 | { | ||
448 | struct domain_device *dev = cmd_to_domain_dev(cmd); | ||
449 | struct sas_phy *phy = find_local_sas_phy(dev); | ||
450 | int res; | ||
451 | |||
452 | res = sas_phy_reset(phy, 1); | ||
453 | if (res) | ||
454 | SAS_DPRINTK("Bus reset of %s failed 0x%x\n", | ||
455 | phy->dev.kobj.k_name, | ||
456 | res); | ||
457 | if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) | ||
458 | return SUCCESS; | ||
459 | |||
460 | return FAILED; | ||
461 | } | ||
462 | |||
463 | /* Try to reset a device */ | ||
464 | static int try_to_reset_cmd_device(struct Scsi_Host *shost, | ||
465 | struct scsi_cmnd *cmd) | ||
466 | { | ||
467 | int res; | ||
468 | |||
469 | if (!shost->hostt->eh_device_reset_handler) | ||
470 | goto try_bus_reset; | ||
471 | |||
472 | res = shost->hostt->eh_device_reset_handler(cmd); | ||
473 | if (res == SUCCESS) | ||
474 | return res; | ||
475 | |||
476 | try_bus_reset: | ||
477 | if (shost->hostt->eh_bus_reset_handler) | ||
478 | return shost->hostt->eh_bus_reset_handler(cmd); | ||
479 | |||
480 | return FAILED; | ||
481 | } | ||
482 | |||
483 | static int sas_eh_handle_sas_errors(struct Scsi_Host *shost, | ||
484 | struct list_head *work_q, | ||
485 | struct list_head *done_q) | ||
402 | { | 486 | { |
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; | 487 | struct scsi_cmnd *cmd, *n; |
407 | enum task_disposition res = TASK_IS_DONE; | 488 | enum task_disposition res = TASK_IS_DONE; |
408 | int tmf_resp; | 489 | int tmf_resp, need_reset; |
409 | struct sas_internal *i = to_sas_internal(shost->transportt); | 490 | struct sas_internal *i = to_sas_internal(shost->transportt); |
491 | unsigned long flags; | ||
492 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | ||
410 | 493 | ||
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: | 494 | Again: |
421 | SAS_DPRINTK("going over list...\n"); | 495 | 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); | 496 | struct sas_task *task = TO_SAS_TASK(cmd); |
424 | list_del_init(&cmd->eh_entry); | ||
425 | 497 | ||
426 | if (!task) { | 498 | if (!task) |
427 | SAS_DPRINTK("%s: taskless cmd?!\n", __FUNCTION__); | ||
428 | continue; | 499 | continue; |
429 | } | 500 | |
501 | list_del_init(&cmd->eh_entry); | ||
502 | |||
503 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
504 | need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET; | ||
505 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
506 | |||
430 | SAS_DPRINTK("trying to find task 0x%p\n", task); | 507 | SAS_DPRINTK("trying to find task 0x%p\n", task); |
431 | res = sas_scsi_find_task(task); | 508 | res = sas_scsi_find_task(task); |
432 | 509 | ||
@@ -437,11 +514,15 @@ Again: | |||
437 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, | 514 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, |
438 | task); | 515 | task); |
439 | task->task_done(task); | 516 | task->task_done(task); |
517 | if (need_reset) | ||
518 | try_to_reset_cmd_device(shost, cmd); | ||
440 | continue; | 519 | continue; |
441 | case TASK_IS_ABORTED: | 520 | case TASK_IS_ABORTED: |
442 | SAS_DPRINTK("%s: task 0x%p is aborted\n", | 521 | SAS_DPRINTK("%s: task 0x%p is aborted\n", |
443 | __FUNCTION__, task); | 522 | __FUNCTION__, task); |
444 | task->task_done(task); | 523 | task->task_done(task); |
524 | if (need_reset) | ||
525 | try_to_reset_cmd_device(shost, cmd); | ||
445 | continue; | 526 | continue; |
446 | case TASK_IS_AT_LU: | 527 | case TASK_IS_AT_LU: |
447 | SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); | 528 | SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); |
@@ -452,11 +533,14 @@ Again: | |||
452 | SAS_ADDR(task->dev), | 533 | SAS_ADDR(task->dev), |
453 | cmd->device->lun); | 534 | cmd->device->lun); |
454 | task->task_done(task); | 535 | task->task_done(task); |
455 | sas_scsi_clear_queue_lu(&error_q, cmd); | 536 | if (need_reset) |
537 | try_to_reset_cmd_device(shost, cmd); | ||
538 | sas_scsi_clear_queue_lu(work_q, cmd); | ||
456 | goto Again; | 539 | goto Again; |
457 | } | 540 | } |
458 | /* fallthrough */ | 541 | /* fallthrough */ |
459 | case TASK_IS_NOT_AT_LU: | 542 | case TASK_IS_NOT_AT_LU: |
543 | case TASK_ABORT_FAILED: | ||
460 | SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n", | 544 | SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n", |
461 | task); | 545 | task); |
462 | tmf_resp = sas_recover_I_T(task->dev); | 546 | tmf_resp = sas_recover_I_T(task->dev); |
@@ -464,7 +548,9 @@ Again: | |||
464 | SAS_DPRINTK("I_T %016llx recovered\n", | 548 | SAS_DPRINTK("I_T %016llx recovered\n", |
465 | SAS_ADDR(task->dev->sas_addr)); | 549 | SAS_ADDR(task->dev->sas_addr)); |
466 | task->task_done(task); | 550 | task->task_done(task); |
467 | sas_scsi_clear_queue_I_T(&error_q, task->dev); | 551 | if (need_reset) |
552 | try_to_reset_cmd_device(shost, cmd); | ||
553 | sas_scsi_clear_queue_I_T(work_q, task->dev); | ||
468 | goto Again; | 554 | goto Again; |
469 | } | 555 | } |
470 | /* Hammer time :-) */ | 556 | /* Hammer time :-) */ |
@@ -477,7 +563,9 @@ Again: | |||
477 | SAS_DPRINTK("clear nexus port:%d " | 563 | SAS_DPRINTK("clear nexus port:%d " |
478 | "succeeded\n", port->id); | 564 | "succeeded\n", port->id); |
479 | task->task_done(task); | 565 | task->task_done(task); |
480 | sas_scsi_clear_queue_port(&error_q, | 566 | if (need_reset) |
567 | try_to_reset_cmd_device(shost, cmd); | ||
568 | sas_scsi_clear_queue_port(work_q, | ||
481 | port); | 569 | port); |
482 | goto Again; | 570 | goto Again; |
483 | } | 571 | } |
@@ -489,6 +577,8 @@ Again: | |||
489 | SAS_DPRINTK("clear nexus ha " | 577 | SAS_DPRINTK("clear nexus ha " |
490 | "succeeded\n"); | 578 | "succeeded\n"); |
491 | task->task_done(task); | 579 | task->task_done(task); |
580 | if (need_reset) | ||
581 | try_to_reset_cmd_device(shost, cmd); | ||
492 | goto out; | 582 | goto out; |
493 | } | 583 | } |
494 | } | 584 | } |
@@ -502,20 +592,54 @@ Again: | |||
502 | cmd->device->lun); | 592 | cmd->device->lun); |
503 | 593 | ||
504 | task->task_done(task); | 594 | task->task_done(task); |
595 | if (need_reset) | ||
596 | try_to_reset_cmd_device(shost, cmd); | ||
505 | goto clear_q; | 597 | goto clear_q; |
506 | } | 598 | } |
507 | } | 599 | } |
508 | out: | 600 | out: |
509 | scsi_eh_flush_done_q(&ha->eh_done_q); | 601 | return list_empty(work_q); |
510 | SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); | ||
511 | return; | ||
512 | clear_q: | 602 | clear_q: |
513 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); | 603 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); |
514 | list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { | 604 | list_for_each_entry_safe(cmd, n, work_q, eh_entry) { |
515 | struct sas_task *task = TO_SAS_TASK(cmd); | 605 | struct sas_task *task = TO_SAS_TASK(cmd); |
516 | list_del_init(&cmd->eh_entry); | 606 | list_del_init(&cmd->eh_entry); |
517 | task->task_done(task); | 607 | task->task_done(task); |
518 | } | 608 | } |
609 | return list_empty(work_q); | ||
610 | } | ||
611 | |||
612 | void sas_scsi_recover_host(struct Scsi_Host *shost) | ||
613 | { | ||
614 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | ||
615 | unsigned long flags; | ||
616 | LIST_HEAD(eh_work_q); | ||
617 | |||
618 | spin_lock_irqsave(shost->host_lock, flags); | ||
619 | list_splice_init(&shost->eh_cmd_q, &eh_work_q); | ||
620 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
621 | |||
622 | SAS_DPRINTK("Enter %s\n", __FUNCTION__); | ||
623 | /* | ||
624 | * Deal with commands that still have SAS tasks (i.e. they didn't | ||
625 | * complete via the normal sas_task completion mechanism) | ||
626 | */ | ||
627 | if (sas_eh_handle_sas_errors(shost, &eh_work_q, &ha->eh_done_q)) | ||
628 | goto out; | ||
629 | |||
630 | /* | ||
631 | * Now deal with SCSI commands that completed ok but have a an error | ||
632 | * code (and hopefully sense data) attached. This is roughly what | ||
633 | * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any | ||
634 | * command we see here has no sas_task and is thus unknown to the HA. | ||
635 | */ | ||
636 | if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q)) | ||
637 | scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); | ||
638 | |||
639 | out: | ||
640 | scsi_eh_flush_done_q(&ha->eh_done_q); | ||
641 | SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); | ||
642 | return; | ||
519 | } | 643 | } |
520 | 644 | ||
521 | enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) | 645 | enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) |
@@ -524,24 +648,30 @@ enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) | |||
524 | unsigned long flags; | 648 | unsigned long flags; |
525 | 649 | ||
526 | if (!task) { | 650 | if (!task) { |
527 | SAS_DPRINTK("command 0x%p, task 0x%p, gone: EH_HANDLED\n", | 651 | cmd->timeout_per_command /= 2; |
528 | cmd, task); | 652 | SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n", |
529 | return EH_HANDLED; | 653 | cmd, task, (cmd->timeout_per_command ? |
654 | "EH_RESET_TIMER" : "EH_NOT_HANDLED")); | ||
655 | if (!cmd->timeout_per_command) | ||
656 | return EH_NOT_HANDLED; | ||
657 | return EH_RESET_TIMER; | ||
530 | } | 658 | } |
531 | 659 | ||
532 | spin_lock_irqsave(&task->task_state_lock, flags); | 660 | spin_lock_irqsave(&task->task_state_lock, flags); |
533 | if (task->task_state_flags & SAS_TASK_INITIATOR_ABORTED) { | 661 | 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) { | 662 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { |
540 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 663 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
541 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", | 664 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", |
542 | cmd, task); | 665 | cmd, task); |
543 | return EH_HANDLED; | 666 | return EH_HANDLED; |
544 | } | 667 | } |
668 | if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) { | ||
669 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
670 | SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: " | ||
671 | "EH_RESET_TIMER\n", | ||
672 | cmd, task); | ||
673 | return EH_RESET_TIMER; | ||
674 | } | ||
545 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | 675 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; |
546 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 676 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
547 | 677 | ||
@@ -557,8 +687,9 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy) | |||
557 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | 687 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); |
558 | struct domain_device *found_dev = NULL; | 688 | struct domain_device *found_dev = NULL; |
559 | int i; | 689 | int i; |
690 | unsigned long flags; | ||
560 | 691 | ||
561 | spin_lock(&ha->phy_port_lock); | 692 | spin_lock_irqsave(&ha->phy_port_lock, flags); |
562 | for (i = 0; i < ha->num_phys; i++) { | 693 | for (i = 0; i < ha->num_phys; i++) { |
563 | struct asd_sas_port *port = ha->sas_port[i]; | 694 | struct asd_sas_port *port = ha->sas_port[i]; |
564 | struct domain_device *dev; | 695 | struct domain_device *dev; |
@@ -574,7 +705,7 @@ struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy) | |||
574 | spin_unlock(&port->dev_list_lock); | 705 | spin_unlock(&port->dev_list_lock); |
575 | } | 706 | } |
576 | found: | 707 | found: |
577 | spin_unlock(&ha->phy_port_lock); | 708 | spin_unlock_irqrestore(&ha->phy_port_lock, flags); |
578 | 709 | ||
579 | return found_dev; | 710 | return found_dev; |
580 | } | 711 | } |
@@ -623,6 +754,8 @@ int sas_slave_configure(struct scsi_device *scsi_dev) | |||
623 | scsi_deactivate_tcq(scsi_dev, 1); | 754 | scsi_deactivate_tcq(scsi_dev, 1); |
624 | } | 755 | } |
625 | 756 | ||
757 | scsi_dev->allow_restart = 1; | ||
758 | |||
626 | return 0; | 759 | return 0; |
627 | } | 760 | } |
628 | 761 | ||
@@ -799,46 +932,42 @@ void sas_shutdown_queue(struct sas_ha_struct *sas_ha) | |||
799 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | 932 | spin_unlock_irqrestore(&core->task_queue_lock, flags); |
800 | } | 933 | } |
801 | 934 | ||
802 | static int do_sas_task_abort(struct sas_task *task) | 935 | /* |
936 | * Call the LLDD task abort routine directly. This function is intended for | ||
937 | * use by upper layers that need to tell the LLDD to abort a task. | ||
938 | */ | ||
939 | int __sas_task_abort(struct sas_task *task) | ||
803 | { | 940 | { |
804 | struct scsi_cmnd *sc = task->uldd_task; | ||
805 | struct sas_internal *si = | 941 | struct sas_internal *si = |
806 | to_sas_internal(task->dev->port->ha->core.shost->transportt); | 942 | to_sas_internal(task->dev->port->ha->core.shost->transportt); |
807 | unsigned long flags; | 943 | unsigned long flags; |
808 | int res; | 944 | int res; |
809 | 945 | ||
810 | spin_lock_irqsave(&task->task_state_lock, flags); | 946 | spin_lock_irqsave(&task->task_state_lock, flags); |
811 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { | 947 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED || |
948 | task->task_state_flags & SAS_TASK_STATE_DONE) { | ||
812 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 949 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
813 | SAS_DPRINTK("%s: Task %p already aborted.\n", __FUNCTION__, | 950 | SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__, |
814 | task); | 951 | task); |
815 | return 0; | 952 | return 0; |
816 | } | 953 | } |
817 | 954 | 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); | 955 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
822 | 956 | ||
823 | if (!si->dft->lldd_abort_task) | 957 | if (!si->dft->lldd_abort_task) |
824 | return -ENODEV; | 958 | return -ENODEV; |
825 | 959 | ||
826 | res = si->dft->lldd_abort_task(task); | 960 | res = si->dft->lldd_abort_task(task); |
961 | |||
962 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
827 | if ((task->task_state_flags & SAS_TASK_STATE_DONE) || | 963 | if ((task->task_state_flags & SAS_TASK_STATE_DONE) || |
828 | (res == TMF_RESP_FUNC_COMPLETE)) | 964 | (res == TMF_RESP_FUNC_COMPLETE)) |
829 | { | 965 | { |
830 | /* SMP commands don't have scsi_cmds(?) */ | 966 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
831 | if (!sc) { | 967 | 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; | 968 | return 0; |
838 | } | 969 | } |
839 | 970 | ||
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)) | 971 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) |
843 | task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; | 972 | task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; |
844 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 973 | spin_unlock_irqrestore(&task->task_state_lock, flags); |
@@ -846,17 +975,24 @@ static int do_sas_task_abort(struct sas_task *task) | |||
846 | return -EAGAIN; | 975 | return -EAGAIN; |
847 | } | 976 | } |
848 | 977 | ||
849 | void sas_task_abort(struct work_struct *work) | 978 | /* |
979 | * Tell an upper layer that it needs to initiate an abort for a given task. | ||
980 | * This should only ever be called by an LLDD. | ||
981 | */ | ||
982 | void sas_task_abort(struct sas_task *task) | ||
850 | { | 983 | { |
851 | struct sas_task *task = | 984 | struct scsi_cmnd *sc = task->uldd_task; |
852 | container_of(work, struct sas_task, abort_work); | ||
853 | int i; | ||
854 | 985 | ||
855 | for (i = 0; i < 5; i++) | 986 | /* Escape for libsas internal commands */ |
856 | if (!do_sas_task_abort(task)) | 987 | if (!sc) { |
988 | if (!del_timer(&task->timer)) | ||
857 | return; | 989 | return; |
990 | task->timer.function(task->timer.data); | ||
991 | return; | ||
992 | } | ||
858 | 993 | ||
859 | SAS_DPRINTK("%s: Could not kill task!\n", __FUNCTION__); | 994 | scsi_req_abort_cmd(sc); |
995 | scsi_schedule_eh(sc->device->host); | ||
860 | } | 996 | } |
861 | 997 | ||
862 | EXPORT_SYMBOL_GPL(sas_queuecommand); | 998 | EXPORT_SYMBOL_GPL(sas_queuecommand); |
@@ -866,5 +1002,9 @@ EXPORT_SYMBOL_GPL(sas_slave_destroy); | |||
866 | EXPORT_SYMBOL_GPL(sas_change_queue_depth); | 1002 | EXPORT_SYMBOL_GPL(sas_change_queue_depth); |
867 | EXPORT_SYMBOL_GPL(sas_change_queue_type); | 1003 | EXPORT_SYMBOL_GPL(sas_change_queue_type); |
868 | EXPORT_SYMBOL_GPL(sas_bios_param); | 1004 | EXPORT_SYMBOL_GPL(sas_bios_param); |
1005 | EXPORT_SYMBOL_GPL(__sas_task_abort); | ||
869 | EXPORT_SYMBOL_GPL(sas_task_abort); | 1006 | EXPORT_SYMBOL_GPL(sas_task_abort); |
870 | EXPORT_SYMBOL_GPL(sas_phy_reset); | 1007 | EXPORT_SYMBOL_GPL(sas_phy_reset); |
1008 | EXPORT_SYMBOL_GPL(sas_phy_enable); | ||
1009 | EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); | ||
1010 | EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler); | ||