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; |