diff options
author | Dan Williams <dan.j.williams@intel.com> | 2011-05-12 15:27:29 +0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2011-07-03 15:04:48 +0400 |
commit | 23506a69e2ee761824c266f6e2cd541a7287c2a5 (patch) | |
tree | 91d6769163a741a238c66848241690fab34873d0 /drivers/scsi/isci/phy.c | |
parent | c4441abc25a33ab259f01dce4b4d63721013f86d (diff) | |
download | linux-23506a69e2ee761824c266f6e2cd541a7287c2a5.tar.xz |
isci: unify phy event handlers
Unify the implementations in scic_sds_phy_event_handler(), and kill the state handler
Reported-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/phy.c')
-rw-r--r-- | drivers/scsi/isci/phy.c | 1021 |
1 files changed, 384 insertions, 637 deletions
diff --git a/drivers/scsi/isci/phy.c b/drivers/scsi/isci/phy.c index 433ea605f70b..0ffb5d5a860e 100644 --- a/drivers/scsi/isci/phy.c +++ b/drivers/scsi/isci/phy.c @@ -506,116 +506,6 @@ enum sci_status scic_sds_phy_reset(struct scic_sds_phy *sci_phy) } /** - * This method will process the event code received. - * @sci_phy: - * @event_code: - * - * enum sci_status - */ -enum sci_status scic_sds_phy_event_handler( - struct scic_sds_phy *sci_phy, - u32 event_code) -{ - return sci_phy->state_handlers->event_handler(sci_phy, event_code); -} - -enum sci_status scic_sds_phy_frame_handler(struct scic_sds_phy *sci_phy, - u32 frame_index) -{ - enum scic_sds_phy_states state = sci_phy->state_machine.current_state_id; - struct scic_sds_controller *scic = sci_phy->owning_port->owning_controller; - enum sci_status result; - - switch (state) { - case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF: { - u32 *frame_words; - struct sas_identify_frame iaf; - struct isci_phy *iphy = sci_phy_to_iphy(sci_phy); - - result = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, - frame_index, - (void **)&frame_words); - - if (result != SCI_SUCCESS) - return result; - - sci_swab32_cpy(&iaf, frame_words, sizeof(iaf) / sizeof(u32)); - if (iaf.frame_type == 0) { - u32 state; - - memcpy(&iphy->frame_rcvd.iaf, &iaf, sizeof(iaf)); - if (iaf.smp_tport) { - /* We got the IAF for an expander PHY go to the final - * state since there are no power requirements for - * expander phys. - */ - state = SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL; - } else { - /* We got the IAF we can now go to the await spinup - * semaphore state - */ - state = SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER; - } - sci_base_state_machine_change_state(&sci_phy->state_machine, - state); - result = SCI_SUCCESS; - } else - dev_warn(sciphy_to_dev(sci_phy), - "%s: PHY starting substate machine received " - "unexpected frame id %x\n", - __func__, frame_index); - - scic_sds_controller_release_frame(scic, frame_index); - return result; - } - case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF: { - struct dev_to_host_fis *frame_header; - u32 *fis_frame_data; - struct isci_phy *iphy = sci_phy_to_iphy(sci_phy); - - result = scic_sds_unsolicited_frame_control_get_header( - &(scic_sds_phy_get_controller(sci_phy)->uf_control), - frame_index, - (void **)&frame_header); - - if (result != SCI_SUCCESS) - return result; - - if ((frame_header->fis_type == FIS_REGD2H) && - !(frame_header->status & ATA_BUSY)) { - scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, - frame_index, - (void **)&fis_frame_data); - - scic_sds_controller_copy_sata_response(&iphy->frame_rcvd.fis, - frame_header, - fis_frame_data); - - /* got IAF we can now go to the await spinup semaphore state */ - sci_base_state_machine_change_state(&sci_phy->state_machine, - SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL); - - result = SCI_SUCCESS; - } else - dev_warn(sciphy_to_dev(sci_phy), - "%s: PHY starting substate machine received " - "unexpected frame id %x\n", - __func__, frame_index); - - /* Regardless of the result we are done with this frame with it */ - scic_sds_controller_release_frame(scic, frame_index); - - return result; - } - default: - dev_dbg(sciphy_to_dev(sci_phy), - "%s: in wrong state: %d\n", __func__, state); - return SCI_FAILURE_INVALID_STATE; - } - -} - -/** * This method will give the phy permission to consume power * @sci_phy: * @@ -702,455 +592,6 @@ static void scic_sds_phy_complete_link_training( next_state); } -static void scic_sds_phy_restart_starting_state( - struct scic_sds_phy *sci_phy) -{ - /* Re-enter the base state machine starting state */ - sci_base_state_machine_change_state(&sci_phy->state_machine, - SCI_BASE_PHY_STATE_STARTING); -} - -/** - * - * @phy: This struct scic_sds_phy object which has received an event. - * @event_code: This is the event code which the phy object is to decode. - * - * This method is called when an event notification is received for the phy - * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SPEED_EN. - - * decode the event - sas phy detected causes a state transition to the wait - * for speed event notification. - any other events log a warning message and - * set a failure status enum sci_status SCI_SUCCESS on any valid event notification - * SCI_FAILURE on any unexpected event notifation - */ -static enum sci_status scic_sds_phy_starting_substate_await_ossp_event_handler( - struct scic_sds_phy *sci_phy, - u32 event_code) -{ - u32 result = SCI_SUCCESS; - - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_SAS_PHY_DETECTED: - scic_sds_phy_start_sas_link_training(sci_phy); - sci_phy->is_in_link_training = true; - break; - - case SCU_EVENT_SATA_SPINUP_HOLD: - scic_sds_phy_start_sata_link_training(sci_phy); - sci_phy->is_in_link_training = true; - break; - - default: - dev_dbg(sciphy_to_dev(sci_phy), - "%s: PHY starting substate machine received " - "unexpected event_code %x\n", - __func__, - event_code); - - result = SCI_FAILURE; - break; - } - - return result; -} - -/** - * - * @phy: This struct scic_sds_phy object which has received an event. - * @event_code: This is the event code which the phy object is to decode. - * - * This method is called when an event notification is received for the phy - * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SPEED_EN. - - * decode the event - sas phy detected returns us back to this state. - speed - * event detected causes a state transition to the wait for iaf. - identify - * timeout is an un-expected event and the state machine is restarted. - link - * failure events restart the starting state machine - any other events log a - * warning message and set a failure status enum sci_status SCI_SUCCESS on any valid - * event notification SCI_FAILURE on any unexpected event notifation - */ -static enum sci_status scic_sds_phy_starting_substate_await_sas_phy_speed_event_handler( - struct scic_sds_phy *sci_phy, - u32 event_code) -{ - u32 result = SCI_SUCCESS; - - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_SAS_PHY_DETECTED: - /* - * Why is this being reported again by the controller? - * We would re-enter this state so just stay here */ - break; - - case SCU_EVENT_SAS_15: - case SCU_EVENT_SAS_15_SSC: - scic_sds_phy_complete_link_training( - sci_phy, - SAS_LINK_RATE_1_5_GBPS, - SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF); - break; - - case SCU_EVENT_SAS_30: - case SCU_EVENT_SAS_30_SSC: - scic_sds_phy_complete_link_training( - sci_phy, - SAS_LINK_RATE_3_0_GBPS, - SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF); - break; - - case SCU_EVENT_SAS_60: - case SCU_EVENT_SAS_60_SSC: - scic_sds_phy_complete_link_training( - sci_phy, - SAS_LINK_RATE_6_0_GBPS, - SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF); - break; - - case SCU_EVENT_SATA_SPINUP_HOLD: - /* - * We were doing SAS PHY link training and received a SATA PHY event - * continue OOB/SN as if this were a SATA PHY */ - scic_sds_phy_start_sata_link_training(sci_phy); - break; - - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - scic_sds_phy_restart_starting_state(sci_phy); - break; - - default: - dev_warn(sciphy_to_dev(sci_phy), - "%s: PHY starting substate machine received " - "unexpected event_code %x\n", - __func__, - event_code); - - result = SCI_FAILURE; - break; - } - - return result; -} - -/** - * - * @phy: This struct scic_sds_phy object which has received an event. - * @event_code: This is the event code which the phy object is to decode. - * - * This method is called when an event notification is received for the phy - * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF. - - * decode the event - sas phy detected event backs up the state machine to the - * await speed notification. - identify timeout is an un-expected event and the - * state machine is restarted. - link failure events restart the starting state - * machine - any other events log a warning message and set a failure status - * enum sci_status SCI_SUCCESS on any valid event notification SCI_FAILURE on any - * unexpected event notifation - */ -static enum sci_status scic_sds_phy_starting_substate_await_iaf_uf_event_handler( - struct scic_sds_phy *sci_phy, - u32 event_code) -{ - u32 result = SCI_SUCCESS; - - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_SAS_PHY_DETECTED: - /* Backup the state machine */ - scic_sds_phy_start_sas_link_training(sci_phy); - break; - - case SCU_EVENT_SATA_SPINUP_HOLD: - /* - * We were doing SAS PHY link training and received a SATA PHY event - * continue OOB/SN as if this were a SATA PHY */ - scic_sds_phy_start_sata_link_training(sci_phy); - break; - - case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: - case SCU_EVENT_LINK_FAILURE: - case SCU_EVENT_HARD_RESET_RECEIVED: - /* Start the oob/sn state machine over again */ - scic_sds_phy_restart_starting_state(sci_phy); - break; - - default: - dev_warn(sciphy_to_dev(sci_phy), - "%s: PHY starting substate machine received " - "unexpected event_code %x\n", - __func__, - event_code); - - result = SCI_FAILURE; - break; - } - - return result; -} - -/** - * - * @phy: This struct scic_sds_phy object which has received an event. - * @event_code: This is the event code which the phy object is to decode. - * - * This method is called when an event notification is received for the phy - * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_POWER. - - * decode the event - link failure events restart the starting state machine - - * any other events log a warning message and set a failure status enum sci_status - * SCI_SUCCESS on a link failure event SCI_FAILURE on any unexpected event - * notifation - */ -static enum sci_status scic_sds_phy_starting_substate_await_sas_power_event_handler( - struct scic_sds_phy *sci_phy, - u32 event_code) -{ - u32 result = SCI_SUCCESS; - - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - scic_sds_phy_restart_starting_state(sci_phy); - break; - - default: - dev_warn(sciphy_to_dev(sci_phy), - "%s: PHY starting substate machine received unexpected " - "event_code %x\n", - __func__, - event_code); - - result = SCI_FAILURE; - break; - } - - return result; -} - -/** - * - * @phy: This struct scic_sds_phy object which has received an event. - * @event_code: This is the event code which the phy object is to decode. - * - * This method is called when an event notification is received for the phy - * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER. - - * decode the event - link failure events restart the starting state machine - - * sata spinup hold events are ignored since they are expected - any other - * events log a warning message and set a failure status enum sci_status SCI_SUCCESS - * on a link failure event SCI_FAILURE on any unexpected event notifation - */ -static enum sci_status scic_sds_phy_starting_substate_await_sata_power_event_handler( - struct scic_sds_phy *sci_phy, - u32 event_code) -{ - u32 result = SCI_SUCCESS; - - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - scic_sds_phy_restart_starting_state(sci_phy); - break; - - case SCU_EVENT_SATA_SPINUP_HOLD: - /* These events are received every 10ms and are expected while in this state */ - break; - - case SCU_EVENT_SAS_PHY_DETECTED: - /* - * There has been a change in the phy type before OOB/SN for the - * SATA finished start down the SAS link traning path. */ - scic_sds_phy_start_sas_link_training(sci_phy); - break; - - default: - dev_warn(sciphy_to_dev(sci_phy), - "%s: PHY starting substate machine received " - "unexpected event_code %x\n", - __func__, - event_code); - - result = SCI_FAILURE; - break; - } - - return result; -} - -/** - * scic_sds_phy_starting_substate_await_sata_phy_event_handler - - * @phy: This struct scic_sds_phy object which has received an event. - * @event_code: This is the event code which the phy object is to decode. - * - * This method is called when an event notification is received for the phy - * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN. - - * decode the event - link failure events restart the starting state machine - - * sata spinup hold events are ignored since they are expected - sata phy - * detected event change to the wait speed event - any other events log a - * warning message and set a failure status enum sci_status SCI_SUCCESS on a link - * failure event SCI_FAILURE on any unexpected event notifation - */ -static enum sci_status scic_sds_phy_starting_substate_await_sata_phy_event_handler( - struct scic_sds_phy *sci_phy, u32 event_code) -{ - u32 result = SCI_SUCCESS; - - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - scic_sds_phy_restart_starting_state(sci_phy); - break; - - case SCU_EVENT_SATA_SPINUP_HOLD: - /* These events might be received since we dont know how many may be in - * the completion queue while waiting for power - */ - break; - - case SCU_EVENT_SATA_PHY_DETECTED: - sci_phy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA; - - /* We have received the SATA PHY notification change state */ - sci_base_state_machine_change_state(&sci_phy->state_machine, - SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN); - break; - - case SCU_EVENT_SAS_PHY_DETECTED: - /* There has been a change in the phy type before OOB/SN for the - * SATA finished start down the SAS link traning path. - */ - scic_sds_phy_start_sas_link_training(sci_phy); - break; - - default: - dev_warn(sciphy_to_dev(sci_phy), - "%s: PHY starting substate machine received " - "unexpected event_code %x\n", - __func__, - event_code); - - result = SCI_FAILURE; - break; - } - - return result; -} - -/** - * - * @phy: This struct scic_sds_phy object which has received an event. - * @event_code: This is the event code which the phy object is to decode. - * - * This method is called when an event notification is received for the phy - * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN. - * - decode the event - sata phy detected returns us back to this state. - - * speed event detected causes a state transition to the wait for signature. - - * link failure events restart the starting state machine - any other events - * log a warning message and set a failure status enum sci_status SCI_SUCCESS on any - * valid event notification SCI_FAILURE on any unexpected event notifation - */ -static enum sci_status scic_sds_phy_starting_substate_await_sata_speed_event_handler( - struct scic_sds_phy *sci_phy, - u32 event_code) -{ - u32 result = SCI_SUCCESS; - - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_SATA_PHY_DETECTED: - /* - * The hardware reports multiple SATA PHY detected events - * ignore the extras */ - break; - - case SCU_EVENT_SATA_15: - case SCU_EVENT_SATA_15_SSC: - scic_sds_phy_complete_link_training( - sci_phy, - SAS_LINK_RATE_1_5_GBPS, - SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF); - break; - - case SCU_EVENT_SATA_30: - case SCU_EVENT_SATA_30_SSC: - scic_sds_phy_complete_link_training( - sci_phy, - SAS_LINK_RATE_3_0_GBPS, - SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF); - break; - - case SCU_EVENT_SATA_60: - case SCU_EVENT_SATA_60_SSC: - scic_sds_phy_complete_link_training( - sci_phy, - SAS_LINK_RATE_6_0_GBPS, - SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF); - break; - - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - scic_sds_phy_restart_starting_state(sci_phy); - break; - - case SCU_EVENT_SAS_PHY_DETECTED: - /* - * There has been a change in the phy type before OOB/SN for the - * SATA finished start down the SAS link traning path. */ - scic_sds_phy_start_sas_link_training(sci_phy); - break; - - default: - dev_warn(sciphy_to_dev(sci_phy), - "%s: PHY starting substate machine received " - "unexpected event_code %x\n", - __func__, - event_code); - - result = SCI_FAILURE; - break; - } - - return result; -} - -/** - * scic_sds_phy_starting_substate_await_sig_fis_event_handler - - * @phy: This struct scic_sds_phy object which has received an event. - * @event_code: This is the event code which the phy object is to decode. - * - * This method is called when an event notification is received for the phy - * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF. - - * decode the event - sas phy detected event backs up the state machine to the - * await speed notification. - identify timeout is an un-expected event and the - * state machine is restarted. - link failure events restart the starting state - * machine - any other events log a warning message and set a failure status - * enum sci_status SCI_SUCCESS on any valid event notification SCI_FAILURE on any - * unexpected event notifation - */ -static enum sci_status scic_sds_phy_starting_substate_await_sig_fis_event_handler( - struct scic_sds_phy *sci_phy, u32 event_code) -{ - u32 result = SCI_SUCCESS; - - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_SATA_PHY_DETECTED: - /* Backup the state machine */ - sci_base_state_machine_change_state(&sci_phy->state_machine, - SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN); - break; - - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - scic_sds_phy_restart_starting_state(sci_phy); - break; - - default: - dev_warn(sciphy_to_dev(sci_phy), - "%s: PHY starting substate machine received " - "unexpected event_code %x\n", - __func__, - event_code); - - result = SCI_FAILURE; - break; - } - - return result; -} - /* * This method is called by the struct scic_sds_controller when the phy object is * granted power. - The notify enable spinups are turned on for this phy object @@ -1215,154 +656,460 @@ static enum sci_status default_phy_handler(struct scic_sds_phy *sci_phy, } static enum sci_status -scic_sds_phy_default_event_handler(struct scic_sds_phy *sci_phy, - u32 event_code) -{ - return default_phy_handler(sci_phy, __func__); -} - -static enum sci_status scic_sds_phy_default_consume_power_handler(struct scic_sds_phy *sci_phy) { return default_phy_handler(sci_phy, __func__); } -/** - * scic_sds_phy_ready_state_event_handler - - * @phy: This is the struct scic_sds_phy object which has received the event. - * - * This method request the struct scic_sds_phy handle the received event. The only - * event that we are interested in while in the ready state is the link failure - * event. - decoded event is a link failure - transition the struct scic_sds_phy back - * to the SCI_BASE_PHY_STATE_STARTING state. - any other event received will - * report a warning message enum sci_status SCI_SUCCESS if the event received is a - * link failure SCI_FAILURE_INVALID_STATE for any other event received. - */ -static enum sci_status scic_sds_phy_ready_state_event_handler(struct scic_sds_phy *sci_phy, - u32 event_code) + +enum sci_status scic_sds_phy_event_handler(struct scic_sds_phy *sci_phy, + u32 event_code) { - enum sci_status result = SCI_FAILURE; + enum scic_sds_phy_states state = sci_phy->state_machine.current_state_id; - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - sci_base_state_machine_change_state(&sci_phy->state_machine, - SCI_BASE_PHY_STATE_STARTING); - result = SCI_SUCCESS; - break; + switch (state) { + case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN: + switch (scu_get_event_code(event_code)) { + case SCU_EVENT_SAS_PHY_DETECTED: + scic_sds_phy_start_sas_link_training(sci_phy); + sci_phy->is_in_link_training = true; + break; + case SCU_EVENT_SATA_SPINUP_HOLD: + scic_sds_phy_start_sata_link_training(sci_phy); + sci_phy->is_in_link_training = true; + break; + default: + dev_dbg(sciphy_to_dev(sci_phy), + "%s: PHY starting substate machine received " + "unexpected event_code %x\n", + __func__, + event_code); + return SCI_FAILURE; + } + return SCI_SUCCESS; + case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN: + switch (scu_get_event_code(event_code)) { + case SCU_EVENT_SAS_PHY_DETECTED: + /* + * Why is this being reported again by the controller? + * We would re-enter this state so just stay here */ + break; + case SCU_EVENT_SAS_15: + case SCU_EVENT_SAS_15_SSC: + scic_sds_phy_complete_link_training( + sci_phy, + SAS_LINK_RATE_1_5_GBPS, + SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF); + break; + case SCU_EVENT_SAS_30: + case SCU_EVENT_SAS_30_SSC: + scic_sds_phy_complete_link_training( + sci_phy, + SAS_LINK_RATE_3_0_GBPS, + SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF); + break; + case SCU_EVENT_SAS_60: + case SCU_EVENT_SAS_60_SSC: + scic_sds_phy_complete_link_training( + sci_phy, + SAS_LINK_RATE_6_0_GBPS, + SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF); + break; + case SCU_EVENT_SATA_SPINUP_HOLD: + /* + * We were doing SAS PHY link training and received a SATA PHY event + * continue OOB/SN as if this were a SATA PHY */ + scic_sds_phy_start_sata_link_training(sci_phy); + break; + case SCU_EVENT_LINK_FAILURE: + /* Link failure change state back to the starting state */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCI_BASE_PHY_STATE_STARTING); + break; + default: + dev_warn(sciphy_to_dev(sci_phy), + "%s: PHY starting substate machine received " + "unexpected event_code %x\n", + __func__, event_code); + + return SCI_FAILURE; + break; + } + return SCI_SUCCESS; + case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF: + switch (scu_get_event_code(event_code)) { + case SCU_EVENT_SAS_PHY_DETECTED: + /* Backup the state machine */ + scic_sds_phy_start_sas_link_training(sci_phy); + break; + case SCU_EVENT_SATA_SPINUP_HOLD: + /* We were doing SAS PHY link training and received a + * SATA PHY event continue OOB/SN as if this were a + * SATA PHY + */ + scic_sds_phy_start_sata_link_training(sci_phy); + break; + case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: + case SCU_EVENT_LINK_FAILURE: + case SCU_EVENT_HARD_RESET_RECEIVED: + /* Start the oob/sn state machine over again */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCI_BASE_PHY_STATE_STARTING); + break; + default: + dev_warn(sciphy_to_dev(sci_phy), + "%s: PHY starting substate machine received " + "unexpected event_code %x\n", + __func__, event_code); + return SCI_FAILURE; + } + return SCI_SUCCESS; + case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER: + switch (scu_get_event_code(event_code)) { + case SCU_EVENT_LINK_FAILURE: + /* Link failure change state back to the starting state */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCI_BASE_PHY_STATE_STARTING); + break; + default: + dev_warn(sciphy_to_dev(sci_phy), + "%s: PHY starting substate machine received unexpected " + "event_code %x\n", + __func__, + event_code); + return SCI_FAILURE; + } + return SCI_SUCCESS; + case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER: + switch (scu_get_event_code(event_code)) { + case SCU_EVENT_LINK_FAILURE: + /* Link failure change state back to the starting state */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCI_BASE_PHY_STATE_STARTING); + break; + case SCU_EVENT_SATA_SPINUP_HOLD: + /* These events are received every 10ms and are + * expected while in this state + */ + break; + + case SCU_EVENT_SAS_PHY_DETECTED: + /* There has been a change in the phy type before OOB/SN for the + * SATA finished start down the SAS link traning path. + */ + scic_sds_phy_start_sas_link_training(sci_phy); + break; + + default: + dev_warn(sciphy_to_dev(sci_phy), + "%s: PHY starting substate machine received " + "unexpected event_code %x\n", + __func__, event_code); - case SCU_EVENT_BROADCAST_CHANGE: - /* Broadcast change received. Notify the port. */ - if (scic_sds_phy_get_port(sci_phy) != NULL) - scic_sds_port_broadcast_change_received(sci_phy->owning_port, sci_phy); - else - sci_phy->bcn_received_while_port_unassigned = true; - break; + return SCI_FAILURE; + } + return SCI_SUCCESS; + case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN: + switch (scu_get_event_code(event_code)) { + case SCU_EVENT_LINK_FAILURE: + /* Link failure change state back to the starting state */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCI_BASE_PHY_STATE_STARTING); + break; + case SCU_EVENT_SATA_SPINUP_HOLD: + /* These events might be received since we dont know how many may be in + * the completion queue while waiting for power + */ + break; + case SCU_EVENT_SATA_PHY_DETECTED: + sci_phy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA; + + /* We have received the SATA PHY notification change state */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN); + break; + case SCU_EVENT_SAS_PHY_DETECTED: + /* There has been a change in the phy type before OOB/SN for the + * SATA finished start down the SAS link traning path. + */ + scic_sds_phy_start_sas_link_training(sci_phy); + break; + default: + dev_warn(sciphy_to_dev(sci_phy), + "%s: PHY starting substate machine received " + "unexpected event_code %x\n", + __func__, + event_code); - default: - dev_warn(sciphy_to_dev(sci_phy), - "%sP SCIC PHY 0x%p ready state machine received " - "unexpected event_code %x\n", - __func__, sci_phy, event_code); + return SCI_FAILURE;; + } + return SCI_SUCCESS; + case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN: + switch (scu_get_event_code(event_code)) { + case SCU_EVENT_SATA_PHY_DETECTED: + /* + * The hardware reports multiple SATA PHY detected events + * ignore the extras */ + break; + case SCU_EVENT_SATA_15: + case SCU_EVENT_SATA_15_SSC: + scic_sds_phy_complete_link_training( + sci_phy, + SAS_LINK_RATE_1_5_GBPS, + SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF); + break; + case SCU_EVENT_SATA_30: + case SCU_EVENT_SATA_30_SSC: + scic_sds_phy_complete_link_training( + sci_phy, + SAS_LINK_RATE_3_0_GBPS, + SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF); + break; + case SCU_EVENT_SATA_60: + case SCU_EVENT_SATA_60_SSC: + scic_sds_phy_complete_link_training( + sci_phy, + SAS_LINK_RATE_6_0_GBPS, + SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF); + break; + case SCU_EVENT_LINK_FAILURE: + /* Link failure change state back to the starting state */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCI_BASE_PHY_STATE_STARTING); + break; + case SCU_EVENT_SAS_PHY_DETECTED: + /* + * There has been a change in the phy type before OOB/SN for the + * SATA finished start down the SAS link traning path. */ + scic_sds_phy_start_sas_link_training(sci_phy); + break; + default: + dev_warn(sciphy_to_dev(sci_phy), + "%s: PHY starting substate machine received " + "unexpected event_code %x\n", + __func__, event_code); - result = SCI_FAILURE_INVALID_STATE; - break; - } + return SCI_FAILURE; + } + + return SCI_SUCCESS; + case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF: + switch (scu_get_event_code(event_code)) { + case SCU_EVENT_SATA_PHY_DETECTED: + /* Backup the state machine */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN); + break; + + case SCU_EVENT_LINK_FAILURE: + /* Link failure change state back to the starting state */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCI_BASE_PHY_STATE_STARTING); + break; - return result; + default: + dev_warn(sciphy_to_dev(sci_phy), + "%s: PHY starting substate machine received " + "unexpected event_code %x\n", + __func__, + event_code); + + return SCI_FAILURE; + } + return SCI_SUCCESS; + case SCI_BASE_PHY_STATE_READY: + switch (scu_get_event_code(event_code)) { + case SCU_EVENT_LINK_FAILURE: + /* Link failure change state back to the starting state */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCI_BASE_PHY_STATE_STARTING); + break; + case SCU_EVENT_BROADCAST_CHANGE: + /* Broadcast change received. Notify the port. */ + if (scic_sds_phy_get_port(sci_phy) != NULL) + scic_sds_port_broadcast_change_received(sci_phy->owning_port, sci_phy); + else + sci_phy->bcn_received_while_port_unassigned = true; + break; + default: + dev_warn(sciphy_to_dev(sci_phy), + "%sP SCIC PHY 0x%p ready state machine received " + "unexpected event_code %x\n", + __func__, sci_phy, event_code); + return SCI_FAILURE_INVALID_STATE; + } + return SCI_SUCCESS; + case SCI_BASE_PHY_STATE_RESETTING: + switch (scu_get_event_code(event_code)) { + case SCU_EVENT_HARD_RESET_TRANSMITTED: + /* Link failure change state back to the starting state */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCI_BASE_PHY_STATE_STARTING); + break; + default: + dev_warn(sciphy_to_dev(sci_phy), + "%s: SCIC PHY 0x%p resetting state machine received " + "unexpected event_code %x\n", + __func__, sci_phy, event_code); + + return SCI_FAILURE_INVALID_STATE; + break; + } + return SCI_SUCCESS; + default: + dev_dbg(sciphy_to_dev(sci_phy), + "%s: in wrong state: %d\n", __func__, state); + return SCI_FAILURE_INVALID_STATE; + } } -static enum sci_status scic_sds_phy_resetting_state_event_handler(struct scic_sds_phy *sci_phy, - u32 event_code) +enum sci_status scic_sds_phy_frame_handler(struct scic_sds_phy *sci_phy, + u32 frame_index) { - enum sci_status result = SCI_FAILURE; + enum scic_sds_phy_states state = sci_phy->state_machine.current_state_id; + struct scic_sds_controller *scic = sci_phy->owning_port->owning_controller; + enum sci_status result; - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_HARD_RESET_TRANSMITTED: - /* Link failure change state back to the starting state */ - sci_base_state_machine_change_state(&sci_phy->state_machine, - SCI_BASE_PHY_STATE_STARTING); - result = SCI_SUCCESS; - break; + switch (state) { + case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF: { + u32 *frame_words; + struct sas_identify_frame iaf; + struct isci_phy *iphy = sci_phy_to_iphy(sci_phy); - default: - dev_warn(sciphy_to_dev(sci_phy), - "%s: SCIC PHY 0x%p resetting state machine received " - "unexpected event_code %x\n", - __func__, sci_phy, event_code); + result = scic_sds_unsolicited_frame_control_get_header(&scic->uf_control, + frame_index, + (void **)&frame_words); - result = SCI_FAILURE_INVALID_STATE; - break; + if (result != SCI_SUCCESS) + return result; + + sci_swab32_cpy(&iaf, frame_words, sizeof(iaf) / sizeof(u32)); + if (iaf.frame_type == 0) { + u32 state; + + memcpy(&iphy->frame_rcvd.iaf, &iaf, sizeof(iaf)); + if (iaf.smp_tport) { + /* We got the IAF for an expander PHY go to the final + * state since there are no power requirements for + * expander phys. + */ + state = SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL; + } else { + /* We got the IAF we can now go to the await spinup + * semaphore state + */ + state = SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER; + } + sci_base_state_machine_change_state(&sci_phy->state_machine, + state); + result = SCI_SUCCESS; + } else + dev_warn(sciphy_to_dev(sci_phy), + "%s: PHY starting substate machine received " + "unexpected frame id %x\n", + __func__, frame_index); + + scic_sds_controller_release_frame(scic, frame_index); + return result; } + case SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF: { + struct dev_to_host_fis *frame_header; + u32 *fis_frame_data; + struct isci_phy *iphy = sci_phy_to_iphy(sci_phy); + + result = scic_sds_unsolicited_frame_control_get_header( + &(scic_sds_phy_get_controller(sci_phy)->uf_control), + frame_index, + (void **)&frame_header); + + if (result != SCI_SUCCESS) + return result; - return result; + if ((frame_header->fis_type == FIS_REGD2H) && + !(frame_header->status & ATA_BUSY)) { + scic_sds_unsolicited_frame_control_get_buffer(&scic->uf_control, + frame_index, + (void **)&fis_frame_data); + + scic_sds_controller_copy_sata_response(&iphy->frame_rcvd.fis, + frame_header, + fis_frame_data); + + /* got IAF we can now go to the await spinup semaphore state */ + sci_base_state_machine_change_state(&sci_phy->state_machine, + SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL); + + result = SCI_SUCCESS; + } else + dev_warn(sciphy_to_dev(sci_phy), + "%s: PHY starting substate machine received " + "unexpected frame id %x\n", + __func__, frame_index); + + /* Regardless of the result we are done with this frame with it */ + scic_sds_controller_release_frame(scic, frame_index); + + return result; + } + default: + dev_dbg(sciphy_to_dev(sci_phy), + "%s: in wrong state: %d\n", __func__, state); + return SCI_FAILURE_INVALID_STATE; + } + } + + /* --------------------------------------------------------------------------- */ static const struct scic_sds_phy_state_handler scic_sds_phy_state_handler_table[] = { [SCI_BASE_PHY_STATE_INITIAL] = { - .event_handler = scic_sds_phy_default_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCI_BASE_PHY_STATE_STOPPED] = { - .event_handler = scic_sds_phy_default_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCI_BASE_PHY_STATE_STARTING] = { - .event_handler = scic_sds_phy_default_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL] = { - .event_handler = scic_sds_phy_default_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN] = { - .event_handler = scic_sds_phy_starting_substate_await_ossp_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN] = { - .event_handler = scic_sds_phy_starting_substate_await_sas_phy_speed_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF] = { - .event_handler = scic_sds_phy_starting_substate_await_iaf_uf_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER] = { - .event_handler = scic_sds_phy_starting_substate_await_sas_power_event_handler, .consume_power_handler = scic_sds_phy_starting_substate_await_sas_power_consume_power_handler }, [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER] = { - .event_handler = scic_sds_phy_starting_substate_await_sata_power_event_handler, .consume_power_handler = scic_sds_phy_starting_substate_await_sata_power_consume_power_handler }, [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN] = { - .event_handler = scic_sds_phy_starting_substate_await_sata_phy_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN] = { - .event_handler = scic_sds_phy_starting_substate_await_sata_speed_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF] = { - .event_handler = scic_sds_phy_starting_substate_await_sig_fis_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL] = { - .event_handler = scic_sds_phy_default_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCI_BASE_PHY_STATE_READY] = { - .event_handler = scic_sds_phy_ready_state_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCI_BASE_PHY_STATE_RESETTING] = { - .event_handler = scic_sds_phy_resetting_state_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler }, [SCI_BASE_PHY_STATE_FINAL] = { - .event_handler = scic_sds_phy_default_event_handler, .consume_power_handler = scic_sds_phy_default_consume_power_handler } }; |