/* * This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license. * * GPL LICENSE SUMMARY * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * BSD LICENSE * * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* * Hardware team recommends that we enable the STP prefetch for all * transports
*/
tl_control = readl(&iphy->transport_layer_registers->control);
tl_control |= SCU_TLCR_GEN_BIT(STP_WRITE_DATA_PREFETCH);
writel(tl_control, &iphy->transport_layer_registers->control);
/* Write the device SAS Address */
writel(0xFEDCBA98, &llr->sas_device_name_high);
writel(phy_idx, &llr->sas_device_name_low);
/* Write the source SAS Address */
writel(phy_oem->sas_address.high, &llr->source_sas_address_high);
writel(phy_oem->sas_address.low, &llr->source_sas_address_low);
/* Clear and Set the PHY Identifier */
writel(0, &llr->identify_frame_phy_id);
writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx), &llr->identify_frame_phy_id);
/* Change the initial state of the phy configuration register */
phy_configuration = readl(&llr->phy_configuration);
/* Hold OOB state machine in reset */
phy_configuration |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
writel(phy_configuration, &llr->phy_configuration);
/* The SAS specification indicates that the phy_capabilities that * are transmitted shall have an even parity. Calculate the parity.
*/
parity_check = phy_cap.all; while (parity_check != 0) { if (parity_check & 0x1)
parity_count++;
parity_check >>= 1;
}
/* If parity indicates there are an odd number of bits set, then * set the parity bit to 1 in the phy capabilities.
*/ if ((parity_count % 2) != 0)
phy_cap.parity = 1;
writel(phy_cap.all, &llr->phy_capabilities);
/* Set the enable spinup period but disable the ability to send * notify enable spinup
*/
writel(SCU_ENSPINUP_GEN_VAL(COUNT,
phy_user->notify_enable_spin_up_insertion_frequency),
&llr->notify_enable_spinup_control);
/* Write the ALIGN Insertion Ferequency for connected phy and * inpendent of connected state
*/
clksm_value = SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(CONNECTED,
phy_user->in_connection_align_insertion_frequency);
/* Set RATE_CHANGE timeout value to 0x3B (59us). This ensures SCU can * lock with 3Gb drive when SCU max rate is set to 1.5Gb.
*/
sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B);
writel(sp_timeouts, &llr->sas_phy_timeouts);
if (is_a2(ihost->pdev)) { /* Program the max ARB time for the PHY to 700us so we * inter-operate with the PMC expander which shuts down * PHYs if the expander PHY generates too many breaks. * This time value will guarantee that the initiator PHY * will generate the break.
*/
writel(SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME,
&llr->maximum_arbitration_wait_timer_timeout);
}
/* Disable link layer hang detection, rely on the OS timeout for * I/O timeouts.
*/
writel(0, &llr->link_layer_hang_detection_timeout);
/* We can exit the initial state to the stopped state */
sci_change_state(&iphy->sm, SCI_PHY_STOPPED);
/** * phy_get_non_dummy_port() - This method returns the port currently containing * this phy. If the phy is currently contained by the dummy port, then the phy * is considered to not be part of a port. * * @iphy: This parameter specifies the phy for which to retrieve the * containing port. * * This method returns a handle to a port that contains the supplied phy. * NULL This value is returned if the phy is not part of a real * port (i.e. it's contained in the dummy port). !NULL All other * values indicate a handle/pointer to the port containing the phy.
*/ struct isci_port *phy_get_non_dummy_port(struct isci_phy *iphy)
{ struct isci_port *iport = iphy->owning_port;
if (iport->physical_port_index == SCIC_SDS_DUMMY_PORT) return NULL;
return iphy->owning_port;
}
/* * sci_phy_set_port() - This method will assign a port to the phy object.
*/ void sci_phy_set_port( struct isci_phy *iphy, struct isci_port *iport)
{
iphy->owning_port = iport;
if (iphy->bcn_received_while_port_unassigned) {
iphy->bcn_received_while_port_unassigned = false;
sci_port_broadcast_change_received(iphy->owning_port, iphy);
}
}
enum sci_status sci_phy_initialize(struct isci_phy *iphy, struct scu_transport_layer_registers __iomem *tl, struct scu_link_layer_registers __iomem *ll)
{ /* Perfrom the initialization of the TL hardware */
sci_phy_transport_layer_initialization(iphy, tl);
/* Perofrm the initialization of the PE hardware */
sci_phy_link_layer_initialization(iphy, ll);
/* There is nothing that needs to be done in this state just * transition to the stopped state
*/
sci_change_state(&iphy->sm, SCI_PHY_STOPPED);
return SCI_SUCCESS;
}
/** * sci_phy_setup_transport() - This method assigns the direct attached device ID for this phy. * * @iphy: The phy for which the direct attached device id is to * be assigned. * @device_id: The direct attached device ID to assign to the phy. * This will either be the RNi for the device or an invalid RNi if there * is no current device assigned to the phy.
*/ void sci_phy_setup_transport(struct isci_phy *iphy, u32 device_id)
{
u32 tl_control;
/* * The read should guarantee that the first write gets posted * before the next write
*/
tl_control = readl(&iphy->transport_layer_registers->control);
tl_control |= SCU_TLCR_GEN_BIT(CLEAR_TCI_NCQ_MAPPING_TABLE);
writel(tl_control, &iphy->transport_layer_registers->control);
}
switch (state) { case SCI_PHY_SUB_INITIAL: case SCI_PHY_SUB_AWAIT_OSSP_EN: case SCI_PHY_SUB_AWAIT_SAS_SPEED_EN: case SCI_PHY_SUB_AWAIT_SAS_POWER: case SCI_PHY_SUB_AWAIT_SATA_POWER: case SCI_PHY_SUB_AWAIT_SATA_PHY_EN: case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN: case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: case SCI_PHY_SUB_FINAL: case SCI_PHY_READY: break; default:
dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
__func__, phy_state_name(state)); return SCI_FAILURE_INVALID_STATE;
}
/* Change state to the final state this substate machine has run to completion */
sci_change_state(&iphy->sm, SCI_PHY_SUB_FINAL);
return SCI_SUCCESS;
} case SCI_PHY_SUB_AWAIT_SATA_POWER: {
u32 scu_sas_pcfg_value;
/* Release the spinup hold state and reset the OOB state machine */
scu_sas_pcfg_value =
readl(&iphy->link_layer_registers->phy_configuration);
scu_sas_pcfg_value &=
~(SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD) | SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE));
scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
writel(scu_sas_pcfg_value,
&iphy->link_layer_registers->phy_configuration);
/* Now restart the OOB operation */
scu_sas_pcfg_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
writel(scu_sas_pcfg_value,
&iphy->link_layer_registers->phy_configuration);
/* Change state to the final state this substate machine has run to completion */
sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_PHY_EN);
staticvoid sci_phy_start_sas_link_training(struct isci_phy *iphy)
{ /* continue the link training for the phy as if it were a SAS PHY * instead of a SATA PHY. This is done because the completion queue had a SAS * PHY DETECTED event when the state machine was expecting a SATA PHY event.
*/
u32 phy_control;
staticvoid sci_phy_start_sata_link_training(struct isci_phy *iphy)
{ /* This method continues the link training for the phy as if it were a SATA PHY * instead of a SAS PHY. This is done because the completion queue had a SATA * SPINUP HOLD event when the state machine was expecting a SAS PHY event. none
*/
sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_POWER);
iphy->protocol = SAS_PROTOCOL_SATA;
}
/** * sci_phy_complete_link_training - perform processing common to * all protocols upon completion of link training. * @iphy: This parameter specifies the phy object for which link training * has completed. * @max_link_rate: This parameter specifies the maximum link rate to be * associated with this phy. * @next_state: This parameter specifies the next state for the phy's starting * sub-state machine. *
*/ staticvoid sci_phy_complete_link_training(struct isci_phy *iphy, enum sas_linkrate max_link_rate,
u32 next_state)
{
iphy->max_negotiated_speed = max_link_rate;
sci_change_state(&iphy->sm, next_state);
}
staticconstchar *phy_event_name(u32 event_code)
{ switch (scu_get_event_code(event_code)) { case SCU_EVENT_PORT_SELECTOR_DETECTED: return"port selector"; case SCU_EVENT_SENT_PORT_SELECTION: return"port selection"; case SCU_EVENT_HARD_RESET_TRANSMITTED: return"tx hard reset"; case SCU_EVENT_HARD_RESET_RECEIVED: return"rx hard reset"; case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: return"identify timeout"; case SCU_EVENT_LINK_FAILURE: return"link fail"; case SCU_EVENT_SATA_SPINUP_HOLD: return"sata spinup hold"; case SCU_EVENT_SAS_15_SSC: case SCU_EVENT_SAS_15: return"sas 1.5"; case SCU_EVENT_SAS_30_SSC: case SCU_EVENT_SAS_30: return"sas 3.0"; case SCU_EVENT_SAS_60_SSC: case SCU_EVENT_SAS_60: return"sas 6.0"; case SCU_EVENT_SATA_15_SSC: case SCU_EVENT_SATA_15: return"sata 1.5"; case SCU_EVENT_SATA_30_SSC: case SCU_EVENT_SATA_30: return"sata 3.0"; case SCU_EVENT_SATA_60_SSC: case SCU_EVENT_SATA_60: return"sata 6.0"; case SCU_EVENT_SAS_PHY_DETECTED: return"sas detect"; case SCU_EVENT_SATA_PHY_DETECTED: return"sata detect"; default: return"unknown";
}
}
/* Extend timeout */
val = readl(&iphy->link_layer_registers->transmit_comsas_signal);
val &= ~SCU_SAS_LLTXCOMSAS_GEN_VAL(NEGTIME, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_MASK);
val |= SCU_SAS_LLTXCOMSAS_GEN_VAL(NEGTIME, timeout);
switch (state) { case SCI_PHY_SUB_AWAIT_OSSP_EN: switch (scu_get_event_code(event_code)) { case SCU_EVENT_SAS_PHY_DETECTED:
sci_phy_start_sas_link_training(iphy);
iphy->is_in_link_training = true; break; case SCU_EVENT_SATA_SPINUP_HOLD:
sci_phy_start_sata_link_training(iphy);
iphy->is_in_link_training = true; break; case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: /* Extend timeout value */
scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED);
/* Start the oob/sn state machine over again */
sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; default:
phy_event_dbg(iphy, state, event_code); return SCI_FAILURE;
} return SCI_SUCCESS; case SCI_PHY_SUB_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:
sci_phy_complete_link_training(iphy, SAS_LINK_RATE_1_5_GBPS,
SCI_PHY_SUB_AWAIT_IAF_UF); break; case SCU_EVENT_SAS_30: case SCU_EVENT_SAS_30_SSC:
sci_phy_complete_link_training(iphy, SAS_LINK_RATE_3_0_GBPS,
SCI_PHY_SUB_AWAIT_IAF_UF); break; case SCU_EVENT_SAS_60: case SCU_EVENT_SAS_60_SSC:
sci_phy_complete_link_training(iphy, SAS_LINK_RATE_6_0_GBPS,
SCI_PHY_SUB_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 */
sci_phy_start_sata_link_training(iphy); break; case SCU_EVENT_LINK_FAILURE: /* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: /* Extend the timeout value */
scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED);
/* Start the oob/sn state machine over again */
sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; default:
phy_event_warn(iphy, state, event_code); return SCI_FAILURE;
} return SCI_SUCCESS; case SCI_PHY_SUB_AWAIT_IAF_UF: switch (scu_get_event_code(event_code)) { case SCU_EVENT_SAS_PHY_DETECTED: /* Backup the state machine */
sci_phy_start_sas_link_training(iphy); 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
*/
sci_phy_start_sata_link_training(iphy); break; case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: /* Extend the timeout value */
scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_EXTENDED);
/* Start the oob/sn state machine over again */
sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; case SCU_EVENT_LINK_FAILURE:
scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
fallthrough; case SCU_EVENT_HARD_RESET_RECEIVED: /* Start the oob/sn state machine over again */
sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; default:
phy_event_warn(iphy, state, event_code); return SCI_FAILURE;
} return SCI_SUCCESS; case SCI_PHY_SUB_AWAIT_SAS_POWER: switch (scu_get_event_code(event_code)) { case SCU_EVENT_LINK_FAILURE: /* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; default:
phy_event_warn(iphy, state, event_code); return SCI_FAILURE;
} return SCI_SUCCESS; case SCI_PHY_SUB_AWAIT_SATA_POWER: switch (scu_get_event_code(event_code)) { case SCU_EVENT_LINK_FAILURE: /* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_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.
*/
sci_phy_start_sas_link_training(iphy); break;
default:
phy_event_warn(iphy, state, event_code); return SCI_FAILURE;
} return SCI_SUCCESS; case SCI_PHY_SUB_AWAIT_SATA_PHY_EN: switch (scu_get_event_code(event_code)) { case SCU_EVENT_LINK_FAILURE: /* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_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:
iphy->protocol = SAS_PROTOCOL_SATA;
/* We have received the SATA PHY notification change state */
sci_change_state(&iphy->sm, SCI_PHY_SUB_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.
*/
sci_phy_start_sas_link_training(iphy); break; default:
phy_event_warn(iphy, state, event_code); return SCI_FAILURE;
} return SCI_SUCCESS; case SCI_PHY_SUB_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:
sci_phy_complete_link_training(iphy, SAS_LINK_RATE_1_5_GBPS,
SCI_PHY_SUB_AWAIT_SIG_FIS_UF); break; case SCU_EVENT_SATA_30: case SCU_EVENT_SATA_30_SSC:
sci_phy_complete_link_training(iphy, SAS_LINK_RATE_3_0_GBPS,
SCI_PHY_SUB_AWAIT_SIG_FIS_UF); break; case SCU_EVENT_SATA_60: case SCU_EVENT_SATA_60_SSC:
sci_phy_complete_link_training(iphy, SAS_LINK_RATE_6_0_GBPS,
SCI_PHY_SUB_AWAIT_SIG_FIS_UF); break; case SCU_EVENT_LINK_FAILURE: /* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_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. */
sci_phy_start_sas_link_training(iphy); break; default:
phy_event_warn(iphy, state, event_code); return SCI_FAILURE;
}
return SCI_SUCCESS; case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: switch (scu_get_event_code(event_code)) { case SCU_EVENT_SATA_PHY_DETECTED: /* Backup the state machine */
sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_SPEED_EN); break;
case SCU_EVENT_LINK_FAILURE: /* Change the timeout value to default */
scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING); break;
default:
phy_event_warn(iphy, state, event_code); return SCI_FAILURE;
} return SCI_SUCCESS; case SCI_PHY_READY: switch (scu_get_event_code(event_code)) { case SCU_EVENT_LINK_FAILURE: /* Set default timeout */
scu_link_layer_set_txcomsas_timeout(iphy, SCU_SAS_LINK_LAYER_TXCOMSAS_NEGTIME_DEFAULT);
/* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; case SCU_EVENT_BROADCAST_CHANGE: case SCU_EVENT_BROADCAST_SES: case SCU_EVENT_BROADCAST_RESERVED0: case SCU_EVENT_BROADCAST_RESERVED1: case SCU_EVENT_BROADCAST_EXPANDER: case SCU_EVENT_BROADCAST_AEN: /* Broadcast change received. Notify the port. */ if (phy_get_non_dummy_port(iphy) != NULL)
sci_port_broadcast_change_received(iphy->owning_port, iphy); else
iphy->bcn_received_while_port_unassigned = true; break; case SCU_EVENT_BROADCAST_RESERVED3: case SCU_EVENT_BROADCAST_RESERVED4: default:
phy_event_warn(iphy, state, event_code); return SCI_FAILURE_INVALID_STATE;
} return SCI_SUCCESS; case SCI_PHY_RESETTING: switch (scu_get_event_code(event_code)) { case SCU_EVENT_HARD_RESET_TRANSMITTED: /* Link failure change state back to the starting state */
sci_change_state(&iphy->sm, SCI_PHY_STARTING); break; default:
phy_event_warn(iphy, state, event_code); return SCI_FAILURE_INVALID_STATE;
} return SCI_SUCCESS; default:
dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n",
__func__, phy_state_name(state)); return SCI_FAILURE_INVALID_STATE;
}
}
spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags);
memcpy(&iphy->frame_rcvd.iaf, &iaf, sizeof(iaf));
spin_unlock_irqrestore(&iphy->sas_phy.frame_rcvd_lock, flags); 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 = SCI_PHY_SUB_FINAL;
} else { /* We got the IAF we can now go to the await spinup * semaphore state
*/
state = SCI_PHY_SUB_AWAIT_SAS_POWER;
}
sci_change_state(&iphy->sm, state);
result = SCI_SUCCESS;
} else
dev_warn(sciphy_to_dev(iphy), "%s: PHY starting substate machine received " "unexpected frame id %x\n",
__func__, frame_index);
if (sci_port_link_detected(iphy->owning_port, iphy)) {
/* * Clear the PE suspend condition so we can actually * receive SIG FIS * The hardware will not respond to the XRDY until the PE * suspend condition is cleared.
*/
sci_phy_resume(iphy);
/* State machine has run to completion so exit out and change * the base state machine to the ready state
*/
sci_change_state(&iphy->sm, SCI_PHY_READY);
}
/** * scu_link_layer_stop_protocol_engine() * @iphy: This is the struct isci_phy object to stop. * * This method will stop the struct isci_phy object. This does not reset the * protocol engine it just suspends it and places it in a state where it will * not cause the end device to power up. none
*/ staticvoid scu_link_layer_stop_protocol_engine( struct isci_phy *iphy)
{
u32 scu_sas_pcfg_value;
u32 enable_spinup_value;
/* Suspend the protocol engine and place it in a sata spinup hold state */
scu_sas_pcfg_value =
readl(&iphy->link_layer_registers->phy_configuration);
scu_sas_pcfg_value |=
(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) |
SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE) |
SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD));
writel(scu_sas_pcfg_value,
&iphy->link_layer_registers->phy_configuration);
/** Reset OOB sequence - start */
val = readl(&ll->phy_configuration);
val &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) |
SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE) |
SCU_SAS_PCFG_GEN_BIT(HARD_RESET));
writel(val, &ll->phy_configuration);
readl(&ll->phy_configuration); /* flush */ /** Reset OOB sequence - end */
/** Start OOB sequence - start */
val = readl(&ll->phy_configuration);
val |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
writel(val, &ll->phy_configuration);
readl(&ll->phy_configuration); /* flush */ /** Start OOB sequence - end */
}
/** * scu_link_layer_tx_hard_reset() * @iphy: This is the struct isci_phy object to stop. * * This method will transmit a hard reset request on the specified phy. The SCU * hardware requires that we reset the OOB state machine and set the hard reset * bit in the phy configuration register. We then must start OOB over with the * hard reset bit set.
*/ staticvoid scu_link_layer_tx_hard_reset( struct isci_phy *iphy)
{
u32 phy_configuration_value;
/* * SAS Phys must wait for the HARD_RESET_TX event notification to transition
* to the starting state. */
phy_configuration_value =
readl(&iphy->link_layer_registers->phy_configuration);
phy_configuration_value &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE));
phy_configuration_value |=
(SCU_SAS_PCFG_GEN_BIT(HARD_RESET) |
SCU_SAS_PCFG_GEN_BIT(OOB_RESET));
writel(phy_configuration_value,
&iphy->link_layer_registers->phy_configuration);
/* Now take the OOB state machine out of reset */
phy_configuration_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
phy_configuration_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
writel(phy_configuration_value,
&iphy->link_layer_registers->phy_configuration);
}
/* The phy is being reset, therefore deactivate it from the port. In * the resetting state we don't notify the user regarding link up and * link down notifications
*/
sci_port_deactivate_phy(iphy->owning_port, iphy, false);
if (iphy->protocol == SAS_PROTOCOL_SSP) {
scu_link_layer_tx_hard_reset(iphy);
} else { /* The SCU does not need to have a discrete reset state so * just go back to the starting state.
*/
sci_change_state(&iphy->sm, SCI_PHY_STARTING);
}
}
/** * isci_phy_control() - This function is one of the SAS Domain Template * functions. This is a phy management function. * @sas_phy: This parameter specifies the sphy being controlled. * @func: This parameter specifies the phy control function being invoked. * @buf: This parameter is specific to the phy function being invoked. * * status, zero indicates success.
*/ int isci_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, void *buf)
{ int ret = 0; struct isci_phy *iphy = sas_phy->lldd_phy; struct asd_sas_port *port = sas_phy->port; struct isci_host *ihost = sas_phy->ha->lldd_ha; unsignedlong flags;
default:
dev_dbg(&ihost->pdev->dev, "%s: phy %p; func %d NOT IMPLEMENTED!\n",
__func__, sas_phy, func);
ret = -ENOSYS; break;
} return ret;
}
Messung V0.5
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.23Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.