diff options
| -rw-r--r-- | drivers/scsi/isci/port.c | 101 | ||||
| -rw-r--r-- | drivers/scsi/isci/port.h | 1 |
2 files changed, 60 insertions, 42 deletions
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c index 8e59c8865dcd..bfeb87905aaf 100644 --- a/drivers/scsi/isci/port.c +++ b/drivers/scsi/isci/port.c | |||
| @@ -350,6 +350,34 @@ static void isci_port_stop_complete(struct isci_host *ihost, | |||
| 350 | dev_dbg(&ihost->pdev->dev, "Port stop complete\n"); | 350 | dev_dbg(&ihost->pdev->dev, "Port stop complete\n"); |
| 351 | } | 351 | } |
| 352 | 352 | ||
| 353 | |||
| 354 | static bool is_port_ready_state(enum sci_port_states state) | ||
| 355 | { | ||
| 356 | switch (state) { | ||
| 357 | case SCI_PORT_READY: | ||
| 358 | case SCI_PORT_SUB_WAITING: | ||
| 359 | case SCI_PORT_SUB_OPERATIONAL: | ||
| 360 | case SCI_PORT_SUB_CONFIGURING: | ||
| 361 | return true; | ||
| 362 | default: | ||
| 363 | return false; | ||
| 364 | } | ||
| 365 | } | ||
| 366 | |||
| 367 | /* flag dummy rnc hanling when exiting a ready state */ | ||
| 368 | static void port_state_machine_change(struct isci_port *iport, | ||
| 369 | enum sci_port_states state) | ||
| 370 | { | ||
| 371 | struct sci_base_state_machine *sm = &iport->sm; | ||
| 372 | enum sci_port_states old_state = sm->current_state_id; | ||
| 373 | |||
| 374 | if (is_port_ready_state(old_state) && !is_port_ready_state(state)) | ||
| 375 | iport->ready_exit = true; | ||
| 376 | |||
| 377 | sci_change_state(sm, state); | ||
| 378 | iport->ready_exit = false; | ||
| 379 | } | ||
| 380 | |||
| 353 | /** | 381 | /** |
| 354 | * isci_port_hard_reset_complete() - This function is called by the sci core | 382 | * isci_port_hard_reset_complete() - This function is called by the sci core |
| 355 | * when the hard reset complete notification has been received. | 383 | * when the hard reset complete notification has been received. |
| @@ -368,6 +396,26 @@ static void isci_port_hard_reset_complete(struct isci_port *isci_port, | |||
| 368 | /* Save the status of the hard reset from the port. */ | 396 | /* Save the status of the hard reset from the port. */ |
| 369 | isci_port->hard_reset_status = completion_status; | 397 | isci_port->hard_reset_status = completion_status; |
| 370 | 398 | ||
| 399 | if (completion_status != SCI_SUCCESS) { | ||
| 400 | |||
| 401 | /* The reset failed. The port state is now SCI_PORT_FAILED. */ | ||
| 402 | if (isci_port->active_phy_mask == 0) { | ||
| 403 | |||
| 404 | /* Generate the link down now to the host, since it | ||
| 405 | * was intercepted by the hard reset state machine when | ||
| 406 | * it really happened. | ||
| 407 | */ | ||
| 408 | isci_port_link_down(isci_port->isci_host, | ||
| 409 | &isci_port->isci_host->phys[ | ||
| 410 | isci_port->last_active_phy], | ||
| 411 | isci_port); | ||
| 412 | } | ||
| 413 | /* Advance the port state so that link state changes will be | ||
| 414 | * noticed. | ||
| 415 | */ | ||
| 416 | port_state_machine_change(isci_port, SCI_PORT_SUB_WAITING); | ||
| 417 | |||
| 418 | } | ||
| 371 | complete_all(&isci_port->hard_reset_complete); | 419 | complete_all(&isci_port->hard_reset_complete); |
| 372 | } | 420 | } |
| 373 | 421 | ||
| @@ -657,6 +705,8 @@ void sci_port_deactivate_phy(struct isci_port *iport, struct isci_phy *iphy, | |||
| 657 | struct isci_host *ihost = iport->owning_controller; | 705 | struct isci_host *ihost = iport->owning_controller; |
| 658 | 706 | ||
| 659 | iport->active_phy_mask &= ~(1 << iphy->phy_index); | 707 | iport->active_phy_mask &= ~(1 << iphy->phy_index); |
| 708 | if (!iport->active_phy_mask) | ||
| 709 | iport->last_active_phy = iphy->phy_index; | ||
| 660 | 710 | ||
| 661 | iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; | 711 | iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; |
| 662 | 712 | ||
| @@ -683,33 +733,6 @@ static void sci_port_invalid_link_up(struct isci_port *iport, struct isci_phy *i | |||
| 683 | } | 733 | } |
| 684 | } | 734 | } |
| 685 | 735 | ||
| 686 | static bool is_port_ready_state(enum sci_port_states state) | ||
| 687 | { | ||
| 688 | switch (state) { | ||
| 689 | case SCI_PORT_READY: | ||
| 690 | case SCI_PORT_SUB_WAITING: | ||
| 691 | case SCI_PORT_SUB_OPERATIONAL: | ||
| 692 | case SCI_PORT_SUB_CONFIGURING: | ||
| 693 | return true; | ||
| 694 | default: | ||
| 695 | return false; | ||
| 696 | } | ||
| 697 | } | ||
| 698 | |||
| 699 | /* flag dummy rnc hanling when exiting a ready state */ | ||
| 700 | static void port_state_machine_change(struct isci_port *iport, | ||
| 701 | enum sci_port_states state) | ||
| 702 | { | ||
| 703 | struct sci_base_state_machine *sm = &iport->sm; | ||
| 704 | enum sci_port_states old_state = sm->current_state_id; | ||
| 705 | |||
| 706 | if (is_port_ready_state(old_state) && !is_port_ready_state(state)) | ||
| 707 | iport->ready_exit = true; | ||
| 708 | |||
| 709 | sci_change_state(sm, state); | ||
| 710 | iport->ready_exit = false; | ||
| 711 | } | ||
| 712 | |||
| 713 | /** | 736 | /** |
| 714 | * sci_port_general_link_up_handler - phy can be assigned to port? | 737 | * sci_port_general_link_up_handler - phy can be assigned to port? |
| 715 | * @sci_port: sci_port object for which has a phy that has gone link up. | 738 | * @sci_port: sci_port object for which has a phy that has gone link up. |
| @@ -1622,7 +1645,8 @@ void sci_port_construct(struct isci_port *iport, u8 index, | |||
| 1622 | iport->logical_port_index = SCIC_SDS_DUMMY_PORT; | 1645 | iport->logical_port_index = SCIC_SDS_DUMMY_PORT; |
| 1623 | iport->physical_port_index = index; | 1646 | iport->physical_port_index = index; |
| 1624 | iport->active_phy_mask = 0; | 1647 | iport->active_phy_mask = 0; |
| 1625 | iport->ready_exit = false; | 1648 | iport->last_active_phy = 0; |
| 1649 | iport->ready_exit = false; | ||
| 1626 | 1650 | ||
| 1627 | iport->owning_controller = ihost; | 1651 | iport->owning_controller = ihost; |
| 1628 | 1652 | ||
| @@ -1676,7 +1700,7 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor | |||
| 1676 | { | 1700 | { |
| 1677 | unsigned long flags; | 1701 | unsigned long flags; |
| 1678 | enum sci_status status; | 1702 | enum sci_status status; |
| 1679 | int idx, ret = TMF_RESP_FUNC_COMPLETE; | 1703 | int ret = TMF_RESP_FUNC_COMPLETE; |
| 1680 | 1704 | ||
| 1681 | dev_dbg(&ihost->pdev->dev, "%s: iport = %p\n", | 1705 | dev_dbg(&ihost->pdev->dev, "%s: iport = %p\n", |
| 1682 | __func__, iport); | 1706 | __func__, iport); |
| @@ -1697,8 +1721,13 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor | |||
| 1697 | "%s: iport = %p; hard reset completion\n", | 1721 | "%s: iport = %p; hard reset completion\n", |
| 1698 | __func__, iport); | 1722 | __func__, iport); |
| 1699 | 1723 | ||
| 1700 | if (iport->hard_reset_status != SCI_SUCCESS) | 1724 | if (iport->hard_reset_status != SCI_SUCCESS) { |
| 1701 | ret = TMF_RESP_FUNC_FAILED; | 1725 | ret = TMF_RESP_FUNC_FAILED; |
| 1726 | |||
| 1727 | dev_err(&ihost->pdev->dev, | ||
| 1728 | "%s: iport = %p; hard reset failed (0x%x)\n", | ||
| 1729 | __func__, iport, iport->hard_reset_status); | ||
| 1730 | } | ||
| 1702 | } else { | 1731 | } else { |
| 1703 | ret = TMF_RESP_FUNC_FAILED; | 1732 | ret = TMF_RESP_FUNC_FAILED; |
| 1704 | 1733 | ||
| @@ -1718,18 +1747,6 @@ int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *ipor | |||
| 1718 | "%s: iport = %p; hard reset failed " | 1747 | "%s: iport = %p; hard reset failed " |
| 1719 | "(0x%x) - driving explicit link fail for all phys\n", | 1748 | "(0x%x) - driving explicit link fail for all phys\n", |
| 1720 | __func__, iport, iport->hard_reset_status); | 1749 | __func__, iport, iport->hard_reset_status); |
| 1721 | |||
| 1722 | /* Down all phys in the port. */ | ||
| 1723 | spin_lock_irqsave(&ihost->scic_lock, flags); | ||
| 1724 | for (idx = 0; idx < SCI_MAX_PHYS; ++idx) { | ||
| 1725 | struct isci_phy *iphy = iport->phy_table[idx]; | ||
| 1726 | |||
| 1727 | if (!iphy) | ||
| 1728 | continue; | ||
| 1729 | sci_phy_stop(iphy); | ||
| 1730 | sci_phy_start(iphy); | ||
| 1731 | } | ||
| 1732 | spin_unlock_irqrestore(&ihost->scic_lock, flags); | ||
| 1733 | } | 1750 | } |
| 1734 | return ret; | 1751 | return ret; |
| 1735 | } | 1752 | } |
diff --git a/drivers/scsi/isci/port.h b/drivers/scsi/isci/port.h index b50ecd4e8f9c..e84d22a309e3 100644 --- a/drivers/scsi/isci/port.h +++ b/drivers/scsi/isci/port.h | |||
| @@ -109,6 +109,7 @@ struct isci_port { | |||
| 109 | u8 logical_port_index; | 109 | u8 logical_port_index; |
| 110 | u8 physical_port_index; | 110 | u8 physical_port_index; |
| 111 | u8 active_phy_mask; | 111 | u8 active_phy_mask; |
| 112 | u8 last_active_phy; | ||
| 112 | u16 reserved_rni; | 113 | u16 reserved_rni; |
| 113 | u16 reserved_tag; | 114 | u16 reserved_tag; |
| 114 | u32 started_request_count; | 115 | u32 started_request_count; |
