scic_sds_port_configuration_agent.c revision 298955
1130561Sobrien/*- 2130561Sobrien * This file is provided under a dual BSD/GPLv2 license. When using or 3130561Sobrien * redistributing this file, you may do so under either license. 4130561Sobrien * 5130561Sobrien * GPL LICENSE SUMMARY 6130561Sobrien * 7130561Sobrien * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 8130561Sobrien * 9130561Sobrien * This program is free software; you can redistribute it and/or modify 10130561Sobrien * it under the terms of version 2 of the GNU General Public License as 11130561Sobrien * published by the Free Software Foundation. 12130561Sobrien * 13130561Sobrien * This program is distributed in the hope that it will be useful, but 14130561Sobrien * WITHOUT ANY WARRANTY; without even the implied warranty of 15130561Sobrien * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16130561Sobrien * General Public License for more details. 17130561Sobrien * 18130561Sobrien * You should have received a copy of the GNU General Public License 19130561Sobrien * along with this program; if not, write to the Free Software 20130561Sobrien * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 21130561Sobrien * The full GNU General Public License is included in this distribution 22130561Sobrien * in the file called LICENSE.GPL. 23130561Sobrien * 24130561Sobrien * BSD LICENSE 25130561Sobrien * 26130561Sobrien * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 27130561Sobrien * All rights reserved. 28130561Sobrien * 29130561Sobrien * Redistribution and use in source and binary forms, with or without 30130561Sobrien * modification, are permitted provided that the following conditions 31130561Sobrien * are met: 32130561Sobrien * 33130561Sobrien * * Redistributions of source code must retain the above copyright 34130561Sobrien * notice, this list of conditions and the following disclaimer. 35130561Sobrien * * Redistributions in binary form must reproduce the above copyright 36130561Sobrien * notice, this list of conditions and the following disclaimer in 37130561Sobrien * the documentation and/or other materials provided with the 38130561Sobrien * distribution. 39130561Sobrien * 40130561Sobrien * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 41130561Sobrien * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 42130561Sobrien * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 43130561Sobrien * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 44130561Sobrien * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45130561Sobrien * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46130561Sobrien * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47130561Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48130561Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49130561Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 50130561Sobrien * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51130561Sobrien */ 52130561Sobrien 53130561Sobrien#include <sys/cdefs.h> 54130561Sobrien__FBSDID("$FreeBSD: head/sys/dev/isci/scil/scic_sds_port_configuration_agent.c 298955 2016-05-03 03:41:25Z pfg $"); 55130561Sobrien 56130561Sobrien/** 57130561Sobrien * @file 58130561Sobrien * 59130561Sobrien * @brief This file contains the implementation for the public and protected 60130561Sobrien * methods for the port configuration agent. 61130561Sobrien */ 62130561Sobrien 63130561Sobrien#include <dev/isci/scil/scic_controller.h> 64130561Sobrien#include <dev/isci/scil/scic_sds_logger.h> 65130561Sobrien#include <dev/isci/scil/scic_sds_controller.h> 66130561Sobrien#include <dev/isci/scil/scic_sds_port_configuration_agent.h> 67130561Sobrien 68130561Sobrien#define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10) 69130561Sobrien#define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10) 70130561Sobrien#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (250) 71130561Sobrien 72130561Sobrienenum SCIC_SDS_APC_ACTIVITY 73130561Sobrien{ 74130561Sobrien SCIC_SDS_APC_SKIP_PHY, 75130561Sobrien SCIC_SDS_APC_ADD_PHY, 76130561Sobrien SCIC_SDS_APC_START_TIMER, 77130561Sobrien 78130561Sobrien SCIC_SDS_APC_ACTIVITY_MAX 79130561Sobrien}; 80130561Sobrien 81130561Sobrien//****************************************************************************** 82130561Sobrien// General port configuration agent routines 83130561Sobrien//****************************************************************************** 84130561Sobrien 85130561Sobrien/** 86130561Sobrien * Compare the two SAS Address and 87130561Sobrien * if SAS Address One is greater than SAS Address Two then return > 0 88130561Sobrien * else if SAS Address One is less than SAS Address Two return < 0 89130561Sobrien * Otherwise they are the same return 0 90130561Sobrien * 91130561Sobrien * @param[in] address_one A SAS Address to be compared. 92130561Sobrien * @param[in] address_two A SAS Address to be compared. 93130561Sobrien * 94130561Sobrien * @return A signed value of x > 0 > y where 95130561Sobrien * x is returned for Address One > Address Two 96130561Sobrien * y is returned for Address One < Address Two 97130561Sobrien * 0 is returned ofr Address One = Address Two 98130561Sobrien */ 99130561Sobrienstatic 100130561SobrienS32 sci_sas_address_compare( 101130561Sobrien SCI_SAS_ADDRESS_T address_one, 102130561Sobrien SCI_SAS_ADDRESS_T address_two 103130561Sobrien) 104130561Sobrien{ 105130561Sobrien if (address_one.high > address_two.high) 106130561Sobrien { 107130561Sobrien return 1; 108130561Sobrien } 109130561Sobrien else if (address_one.high < address_two.high) 110130561Sobrien { 111130561Sobrien return -1; 112130561Sobrien } 113130561Sobrien else if (address_one.low > address_two.low) 114130561Sobrien { 115130561Sobrien return 1; 116130561Sobrien } 117130561Sobrien else if (address_one.low < address_two.low) 118130561Sobrien { 119130561Sobrien return -1; 120130561Sobrien } 121130561Sobrien 122130561Sobrien // The two SAS Address must be identical 123130561Sobrien return 0; 124130561Sobrien} 125130561Sobrien 126130561Sobrien/** 127130561Sobrien * This routine will find a matching port for the phy. This means that the 128130561Sobrien * port and phy both have the same broadcast sas address and same received 129130561Sobrien * sas address. 130130561Sobrien * 131130561Sobrien * @param[in] controller The controller object used for the port search. 132130561Sobrien * @param[in] phy The phy object to match. 133130561Sobrien * 134130561Sobrien * @return The port address or the SCI_INVALID_HANDLE if there is no matching 135130561Sobrien * port. 136130561Sobrien * 137130561Sobrien * @retvalue port address if the port can be found to match the phy. 138130561Sobrien * @retvalue SCI_INVALID_HANDLE if there is no matching port for the phy. 139130561Sobrien */ 140130561Sobrienstatic 141130561SobrienSCIC_SDS_PORT_T * scic_sds_port_configuration_agent_find_port( 142130561Sobrien SCIC_SDS_CONTROLLER_T * controller, 143130561Sobrien SCIC_SDS_PHY_T * phy 144130561Sobrien) 145130561Sobrien{ 146130561Sobrien U8 port_index; 147130561Sobrien SCI_PORT_HANDLE_T port_handle; 148130561Sobrien SCI_SAS_ADDRESS_T port_sas_address; 149130561Sobrien SCI_SAS_ADDRESS_T port_attached_device_address; 150130561Sobrien SCI_SAS_ADDRESS_T phy_sas_address; 151130561Sobrien SCI_SAS_ADDRESS_T phy_attached_device_address; 152130561Sobrien 153130561Sobrien SCIC_LOG_TRACE(( 154130561Sobrien sci_base_object_get_logger(controller), 155130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 156130561Sobrien "scic_sds_port_confgiruation_agent_find_port(0x%08x, 0x%08x) enter\n", 157130561Sobrien controller, phy 158130561Sobrien )); 159130561Sobrien 160130561Sobrien // Since this phy can be a member of a wide port check to see if one or 161130561Sobrien // more phys match the sent and received SAS address as this phy in which 162130561Sobrien // case it should participate in the same port. 163130561Sobrien scic_sds_phy_get_sas_address(phy, &phy_sas_address); 164130561Sobrien scic_sds_phy_get_attached_sas_address(phy, &phy_attached_device_address); 165130561Sobrien 166130561Sobrien for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) 167130561Sobrien { 168130561Sobrien if (scic_controller_get_port_handle(controller, port_index, &port_handle) == SCI_SUCCESS) 169130561Sobrien { 170130561Sobrien SCIC_SDS_PORT_T * port = (SCIC_SDS_PORT_T *)port_handle; 171130561Sobrien 172130561Sobrien scic_sds_port_get_sas_address(port, &port_sas_address); 173130561Sobrien scic_sds_port_get_attached_sas_address(port, &port_attached_device_address); 174130561Sobrien 175130561Sobrien if ( 176130561Sobrien (sci_sas_address_compare(port_sas_address, phy_sas_address) == 0) 177130561Sobrien && (sci_sas_address_compare(port_attached_device_address, phy_attached_device_address) == 0) 178130561Sobrien ) 179130561Sobrien { 180130561Sobrien return port; 181130561Sobrien } 182130561Sobrien } 183130561Sobrien } 184130561Sobrien 185130561Sobrien return SCI_INVALID_HANDLE; 186130561Sobrien} 187130561Sobrien 188130561Sobrien/** 189130561Sobrien * This routine will validate the port configuration is correct for the SCU 190130561Sobrien * hardware. The SCU hardware allows for port configurations as follows. 191130561Sobrien * LP0 -> (PE0), (PE0, PE1), (PE0, PE1, PE2, PE3) 192130561Sobrien * LP1 -> (PE1) 193130561Sobrien * LP2 -> (PE2), (PE2, PE3) 194130561Sobrien * LP3 -> (PE3) 195130561Sobrien * 196130561Sobrien * @param[in] controller This is the controller object that contains the 197130561Sobrien * port agent 198130561Sobrien * @param[in] port_agent This is the port configruation agent for 199130561Sobrien * the controller. 200130561Sobrien * 201130561Sobrien * @return SCI_STATUS 202130561Sobrien * @retval SCI_SUCCESS the port configuration is valid for this 203130561Sobrien * port configuration agent. 204130561Sobrien * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION the port configuration 205130561Sobrien * is not valid for this port configuration agent. 206130561Sobrien */ 207130561Sobrienstatic 208130561SobrienSCI_STATUS scic_sds_port_configuration_agent_validate_ports( 209130561Sobrien SCIC_SDS_CONTROLLER_T * controller, 210130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 211130561Sobrien) 212130561Sobrien{ 213130561Sobrien#if !defined(ARLINGTON_BUILD) 214130561Sobrien SCI_SAS_ADDRESS_T first_address; 215130561Sobrien SCI_SAS_ADDRESS_T second_address; 216130561Sobrien 217130561Sobrien SCIC_LOG_TRACE(( 218130561Sobrien sci_base_object_get_logger(controller), 219130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 220130561Sobrien "scic_sds_port_configuration_agent_validate_ports(0x%08x, 0x%08x) enter\n", 221130561Sobrien controller, port_agent 222130561Sobrien )); 223130561Sobrien 224130561Sobrien // Sanity check the max ranges for all the phys the max index 225130561Sobrien // is always equal to the port range index 226130561Sobrien if ( 227130561Sobrien (port_agent->phy_valid_port_range[0].max_index != 0) 228130561Sobrien || (port_agent->phy_valid_port_range[1].max_index != 1) 229130561Sobrien || (port_agent->phy_valid_port_range[2].max_index != 2) 230130561Sobrien || (port_agent->phy_valid_port_range[3].max_index != 3) 231130561Sobrien ) 232130561Sobrien { 233130561Sobrien return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 234130561Sobrien } 235130561Sobrien 236130561Sobrien // This is a request to configure a single x4 port or at least attempt 237130561Sobrien // to make all the phys into a single port 238130561Sobrien if ( 239130561Sobrien (port_agent->phy_valid_port_range[0].min_index == 0) 240130561Sobrien && (port_agent->phy_valid_port_range[1].min_index == 0) 241130561Sobrien && (port_agent->phy_valid_port_range[2].min_index == 0) 242130561Sobrien && (port_agent->phy_valid_port_range[3].min_index == 0) 243130561Sobrien ) 244130561Sobrien { 245130561Sobrien return SCI_SUCCESS; 246130561Sobrien } 247130561Sobrien 248130561Sobrien // This is a degenerate case where phy 1 and phy 2 are assigned 249130561Sobrien // to the same port this is explicitly disallowed by the hardware 250130561Sobrien // unless they are part of the same x4 port and this condition was 251130561Sobrien // already checked above. 252130561Sobrien if (port_agent->phy_valid_port_range[2].min_index == 1) 253130561Sobrien { 254130561Sobrien return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 255130561Sobrien } 256130561Sobrien 257130561Sobrien // PE0 and PE3 can never have the same SAS Address unless they 258130561Sobrien // are part of the same x4 wide port and we have already checked 259130561Sobrien // for this condition. 260130561Sobrien scic_sds_phy_get_sas_address(&controller->phy_table[0], &first_address); 261130561Sobrien scic_sds_phy_get_sas_address(&controller->phy_table[3], &second_address); 262130561Sobrien 263130561Sobrien if (sci_sas_address_compare(first_address, second_address) == 0) 264130561Sobrien { 265130561Sobrien return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 266130561Sobrien } 267130561Sobrien 268130561Sobrien // PE0 and PE1 are configured into a 2x1 ports make sure that the 269130561Sobrien // SAS Address for PE0 and PE2 are different since they can not be 270130561Sobrien // part of the same port. 271130561Sobrien if ( 272130561Sobrien (port_agent->phy_valid_port_range[0].min_index == 0) 273130561Sobrien && (port_agent->phy_valid_port_range[1].min_index == 1) 274130561Sobrien ) 275130561Sobrien { 276130561Sobrien scic_sds_phy_get_sas_address(&controller->phy_table[0], &first_address); 277130561Sobrien scic_sds_phy_get_sas_address(&controller->phy_table[2], &second_address); 278130561Sobrien 279130561Sobrien if (sci_sas_address_compare(first_address, second_address) == 0) 280130561Sobrien { 281130561Sobrien return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 282130561Sobrien } 283130561Sobrien } 284130561Sobrien 285130561Sobrien // PE2 and PE3 are configured into a 2x1 ports make sure that the 286130561Sobrien // SAS Address for PE1 and PE3 are different since they can not be 287130561Sobrien // part of the same port. 288130561Sobrien if ( 289130561Sobrien (port_agent->phy_valid_port_range[2].min_index == 2) 290130561Sobrien && (port_agent->phy_valid_port_range[3].min_index == 3) 291130561Sobrien ) 292130561Sobrien { 293130561Sobrien scic_sds_phy_get_sas_address(&controller->phy_table[1], &first_address); 294130561Sobrien scic_sds_phy_get_sas_address(&controller->phy_table[3], &second_address); 295130561Sobrien 296130561Sobrien if (sci_sas_address_compare(first_address, second_address) == 0) 297130561Sobrien { 298130561Sobrien return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 299130561Sobrien } 300130561Sobrien } 301130561Sobrien#endif // !defined(ARLINGTON_BUILD) 302130561Sobrien 303130561Sobrien return SCI_SUCCESS; 304130561Sobrien} 305130561Sobrien 306130561Sobrien//****************************************************************************** 307130561Sobrien// Manual port configuration agent routines 308130561Sobrien//****************************************************************************** 309130561Sobrien 310130561Sobrien/** 311130561Sobrien * This routine will verify that all of the phys in the same port are using 312130561Sobrien * the same SAS address. 313130561Sobrien * 314130561Sobrien * @param[in] controller This is the controller that contains the PHYs to 315130561Sobrien * be verified. 316130561Sobrien */ 317130561Sobrienstatic 318130561SobrienSCI_STATUS scic_sds_mpc_agent_validate_phy_configuration( 319130561Sobrien SCIC_SDS_CONTROLLER_T * controller, 320130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 321130561Sobrien) 322130561Sobrien{ 323130561Sobrien U32 phy_mask; 324130561Sobrien U32 assigned_phy_mask; 325130561Sobrien SCI_SAS_ADDRESS_T sas_address; 326130561Sobrien SCI_SAS_ADDRESS_T phy_assigned_address; 327130561Sobrien U8 port_index; 328130561Sobrien U8 phy_index; 329130561Sobrien 330130561Sobrien assigned_phy_mask = 0; 331130561Sobrien sas_address.high = 0; 332130561Sobrien sas_address.low = 0; 333130561Sobrien 334130561Sobrien SCIC_LOG_TRACE(( 335130561Sobrien sci_base_object_get_logger(controller), 336130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 337130561Sobrien "scic_sds_mpc_agent_validate_phy_configuration(0x%08x, 0x%08x) enter\n", 338130561Sobrien controller, port_agent 339130561Sobrien )); 340130561Sobrien 341130561Sobrien for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) 342130561Sobrien { 343130561Sobrien phy_mask = controller->oem_parameters.sds1.ports[port_index].phy_mask; 344130561Sobrien 345130561Sobrien if (phy_mask != 0) 346130561Sobrien { 347130561Sobrien // Make sure that one or more of the phys were not already assinged to 348130561Sobrien // a different port. 349130561Sobrien if ((phy_mask & ~assigned_phy_mask) == 0) 350130561Sobrien { 351130561Sobrien return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 352130561Sobrien } 353130561Sobrien 354130561Sobrien // Find the starting phy index for this round through the loop 355130561Sobrien for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) 356130561Sobrien { 357130561Sobrien if ((1 << phy_index) & phy_mask) 358130561Sobrien { 359130561Sobrien scic_sds_phy_get_sas_address( 360130561Sobrien &controller->phy_table[phy_index], &sas_address 361130561Sobrien ); 362130561Sobrien 363130561Sobrien // The phy_index can be used as the starting point for the 364130561Sobrien // port range since the hardware starts all logical ports 365130561Sobrien // the same as the PE index. 366130561Sobrien port_agent->phy_valid_port_range[phy_index].min_index = port_index; 367130561Sobrien port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 368130561Sobrien 369130561Sobrien if (phy_index != port_index) 370130561Sobrien { 371130561Sobrien return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 372130561Sobrien } 373130561Sobrien 374130561Sobrien break; 375130561Sobrien } 376130561Sobrien } 377130561Sobrien 378130561Sobrien // See how many additional phys are being added to this logical port. 379130561Sobrien // Note: We have not moved the current phy_index so we will actually 380130561Sobrien // compare the startting phy with itself. 381130561Sobrien // This is expected and required to add the phy to the port. 382130561Sobrien while (phy_index < SCI_MAX_PHYS) 383130561Sobrien { 384130561Sobrien if ((1 << phy_index) & phy_mask) 385130561Sobrien { 386130561Sobrien scic_sds_phy_get_sas_address( 387130561Sobrien &controller->phy_table[phy_index], &phy_assigned_address 388130561Sobrien ); 389130561Sobrien 390130561Sobrien if (sci_sas_address_compare(sas_address, phy_assigned_address) != 0) 391130561Sobrien { 392130561Sobrien // The phy mask specified that this phy is part of the same port 393130561Sobrien // as the starting phy and it is not so fail this configuration 394130561Sobrien return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 395130561Sobrien } 396130561Sobrien 397130561Sobrien port_agent->phy_valid_port_range[phy_index].min_index = port_index; 398130561Sobrien port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 399130561Sobrien 400130561Sobrien scic_sds_port_add_phy( 401130561Sobrien &controller->port_table[port_index], 402130561Sobrien &controller->phy_table[phy_index] 403130561Sobrien ); 404130561Sobrien 405130561Sobrien assigned_phy_mask |= (1 << phy_index); 406130561Sobrien } 407130561Sobrien 408130561Sobrien phy_index++; 409130561Sobrien } 410130561Sobrien } 411130561Sobrien } 412130561Sobrien 413130561Sobrien return scic_sds_port_configuration_agent_validate_ports(controller, port_agent); 414130561Sobrien} 415130561Sobrien 416130561Sobrien/** 417130561Sobrien * This timer routine is used to allow the SCI User to rediscover or change 418130561Sobrien * device objects before a new series of link up notifications because a 419130561Sobrien * link down has allowed a better port configuration. 420130561Sobrien * 421130561Sobrien * @param[in] controller This is the core controller object which is used 422130561Sobrien * to obtain the port configuration agent. 423130561Sobrien */ 424130561Sobrienstatic 425130561Sobrienvoid scic_sds_mpc_agent_timeout_handler( 426130561Sobrien void * object 427130561Sobrien) 428130561Sobrien{ 429130561Sobrien U8 index; 430130561Sobrien SCIC_SDS_CONTROLLER_T * controller = (SCIC_SDS_CONTROLLER_T *)object; 431130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent = &controller->port_agent; 432130561Sobrien U16 configure_phy_mask; 433130561Sobrien 434130561Sobrien SCIC_LOG_TRACE(( 435130561Sobrien sci_base_object_get_logger(controller), 436130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 437130561Sobrien "scic_sds_mpc_agent_timeout_handler(0x%08x) enter\n", 438130561Sobrien controller 439130561Sobrien )); 440130561Sobrien 441130561Sobrien port_agent->timer_pending = FALSE; 442130561Sobrien 443130561Sobrien // Find the mask of phys that are reported read but as yet unconfigured into a port 444130561Sobrien configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask; 445130561Sobrien 446130561Sobrien for (index = 0; index < SCI_MAX_PHYS; index++) 447130561Sobrien { 448130561Sobrien if (configure_phy_mask & (1 << index)) 449130561Sobrien { 450130561Sobrien port_agent->link_up_handler( 451130561Sobrien controller, 452130561Sobrien port_agent, 453130561Sobrien scic_sds_phy_get_port(&controller->phy_table[index]), 454130561Sobrien &controller->phy_table[index] 455130561Sobrien ); 456130561Sobrien } 457130561Sobrien } 458130561Sobrien} 459130561Sobrien 460130561Sobrien/** 461130561Sobrien * This method handles the manual port configuration link up notifications. 462130561Sobrien * Since all ports and phys are associate at initialization time we just turn 463130561Sobrien * around and notifiy the port object that there is a link up. If this PHY is 464130561Sobrien * not associated with a port there is no action taken. 465130561Sobrien * 466130561Sobrien * @param[in] controller This is the controller object that receives the 467130561Sobrien * link up notification. 468130561Sobrien * @param[in] port This is the port object associated with the phy. If the 469130561Sobrien * is no associated port this is an SCI_INVALID_HANDLE. 470130561Sobrien * @param[in] phy This is the phy object which has gone ready. 471130561Sobrien * 472130561Sobrien * @note Is it possible to get a link up notification from a phy that has 473130561Sobrien * no assocoated port? 474130561Sobrien */ 475130561Sobrienstatic 476130561Sobrienvoid scic_sds_mpc_agent_link_up( 477130561Sobrien SCIC_SDS_CONTROLLER_T * controller, 478130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 479130561Sobrien SCIC_SDS_PORT_T * port, 480130561Sobrien SCIC_SDS_PHY_T * phy 481130561Sobrien) 482130561Sobrien{ 483130561Sobrien SCIC_LOG_TRACE(( 484130561Sobrien sci_base_object_get_logger(controller), 485130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 486130561Sobrien "scic_sds_mpc_agent_link_up(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 487130561Sobrien controller, port_agent, port, phy 488130561Sobrien )); 489130561Sobrien 490130561Sobrien // If the port has an invalid handle then the phy was not assigned to 491130561Sobrien // a port. This is because the phy was not given the same SAS Address 492130561Sobrien // as the other PHYs in the port. 493130561Sobrien if (port != SCI_INVALID_HANDLE) 494130561Sobrien { 495130561Sobrien port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy)); 496130561Sobrien 497130561Sobrien scic_sds_port_link_up(port, phy); 498130561Sobrien 499130561Sobrien if ((port->active_phy_mask & (1 << scic_sds_phy_get_index(phy))) != 0) 500130561Sobrien { 501130561Sobrien port_agent->phy_configured_mask |= (1 << scic_sds_phy_get_index(phy)); 502130561Sobrien } 503130561Sobrien } 504130561Sobrien} 505130561Sobrien 506130561Sobrien/** 507130561Sobrien * This method handles the manual port configuration link down notifications. 508130561Sobrien * Since all ports and phys are associated at initialization time we just turn 509130561Sobrien * around and notifiy the port object of the link down event. If this PHY is 510130561Sobrien * not associated with a port there is no action taken. 511130561Sobrien * 512130561Sobrien * @param[in] controller This is the controller object that receives the 513130561Sobrien * link down notification. 514130561Sobrien * @param[in] port This is the port object associated with the phy. If the 515130561Sobrien * is no associated port this is an SCI_INVALID_HANDLE. The port 516130561Sobrien * is an invalid handle only if the phy was never port of this 517130561Sobrien * port. This happens when the phy is not broadcasting the same 518130561Sobrien * SAS address as the other phys in the assigned port. 519130561Sobrien * @param[in] phy This is the phy object which has gone link down. 520130561Sobrien * 521130561Sobrien * @note Is it possible to get a link down notification from a phy that has 522130561Sobrien * no assocoated port? 523130561Sobrien */ 524130561Sobrienstatic 525130561Sobrienvoid scic_sds_mpc_agent_link_down( 526130561Sobrien SCIC_SDS_CONTROLLER_T * controller, 527130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 528130561Sobrien SCIC_SDS_PORT_T * port, 529130561Sobrien SCIC_SDS_PHY_T * phy 530130561Sobrien) 531130561Sobrien{ 532130561Sobrien SCIC_LOG_TRACE(( 533130561Sobrien sci_base_object_get_logger(controller), 534130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 535130561Sobrien "scic_sds_mpc_agent_link_down(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 536130561Sobrien controller, port_agent, port, phy 537130561Sobrien )); 538130561Sobrien 539130561Sobrien if (port != SCI_INVALID_HANDLE) 540130561Sobrien { 541130561Sobrien // If we can form a new port from the remainder of the phys then we want 542130561Sobrien // to start the timer to allow the SCI User to cleanup old devices and 543130561Sobrien // rediscover the port before rebuilding the port with the phys that 544130561Sobrien // remain in the ready state. 545130561Sobrien port_agent->phy_ready_mask &= ~(1 << scic_sds_phy_get_index(phy)); 546130561Sobrien port_agent->phy_configured_mask &= ~(1 << scic_sds_phy_get_index(phy)); 547130561Sobrien 548130561Sobrien // Check to see if there are more phys waiting to be configured into a port. 549130561Sobrien // If there are allow the SCI User to tear down this port, if necessary, and 550130561Sobrien // then reconstruc the port after the timeout. 551130561Sobrien if ( 552130561Sobrien (port_agent->phy_configured_mask == 0x0000) 553130561Sobrien && (port_agent->phy_ready_mask != 0x0000) 554130561Sobrien && !port_agent->timer_pending 555130561Sobrien ) 556130561Sobrien { 557130561Sobrien port_agent->timer_pending = TRUE; 558130561Sobrien 559130561Sobrien scic_cb_timer_start( 560130561Sobrien controller, 561130561Sobrien port_agent->timer, 562130561Sobrien SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT 563130561Sobrien ); 564130561Sobrien } 565130561Sobrien 566130561Sobrien scic_sds_port_link_down(port, phy); 567130561Sobrien } 568130561Sobrien} 569130561Sobrien 570130561Sobrien//****************************************************************************** 571130561Sobrien// Automatic port configuration agent routines 572130561Sobrien//****************************************************************************** 573130561Sobrien 574130561Sobrien/** 575130561Sobrien * This routine will verify that the phys are assigned a valid SAS address for 576130561Sobrien * automatic port configuration mode. 577130561Sobrien */ 578130561Sobrienstatic 579130561SobrienSCI_STATUS scic_sds_apc_agent_validate_phy_configuration( 580130561Sobrien SCIC_SDS_CONTROLLER_T * controller, 581130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 582130561Sobrien) 583130561Sobrien{ 584130561Sobrien U8 phy_index; 585130561Sobrien U8 port_index; 586130561Sobrien SCI_SAS_ADDRESS_T sas_address; 587130561Sobrien SCI_SAS_ADDRESS_T phy_assigned_address; 588130561Sobrien 589130561Sobrien SCIC_LOG_TRACE(( 590130561Sobrien sci_base_object_get_logger(controller), 591130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 592130561Sobrien "scic_sds_apc_agent_validate_phy_configuration(0x%08x, 0x%08x) enter\n", 593130561Sobrien controller, port_agent 594130561Sobrien )); 595130561Sobrien 596130561Sobrien phy_index = 0; 597130561Sobrien 598130561Sobrien while (phy_index < SCI_MAX_PHYS) 599130561Sobrien { 600130561Sobrien port_index = phy_index; 601130561Sobrien 602130561Sobrien // Get the assigned SAS Address for the first PHY on the controller. 603130561Sobrien scic_sds_phy_get_sas_address( 604130561Sobrien &controller->phy_table[phy_index], &sas_address 605130561Sobrien ); 606130561Sobrien 607130561Sobrien while (++phy_index < SCI_MAX_PHYS) 608130561Sobrien { 609130561Sobrien scic_sds_phy_get_sas_address( 610130561Sobrien &controller->phy_table[phy_index], &phy_assigned_address 611130561Sobrien ); 612130561Sobrien 613130561Sobrien // Verify each of the SAS address are all the same for every PHY 614130561Sobrien if (sci_sas_address_compare(sas_address, phy_assigned_address) == 0) 615130561Sobrien { 616130561Sobrien port_agent->phy_valid_port_range[phy_index].min_index = port_index; 617130561Sobrien port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 618130561Sobrien } 619130561Sobrien else 620130561Sobrien { 621130561Sobrien port_agent->phy_valid_port_range[phy_index].min_index = phy_index; 622130561Sobrien port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 623130561Sobrien break; 624130561Sobrien } 625130561Sobrien } 626130561Sobrien } 627130561Sobrien 628130561Sobrien return scic_sds_port_configuration_agent_validate_ports(controller, port_agent); 629130561Sobrien} 630130561Sobrien 631130561Sobrien/** 632130561Sobrien * This routine will restart the automatic port configuration timeout 633130561Sobrien * timer for the next time period. This could be caused by either a 634130561Sobrien * link down event or a link up event where we can not yet tell to which 635130561Sobrien * port a phy belongs. 636130561Sobrien * 637130561Sobrien * @param[in] controller This is the controller that to which the port 638130561Sobrien * agent is assigned. 639130561Sobrien * @param[in] port_agent This is the port agent that is requesting the 640130561Sobrien * timer start operation. 641130561Sobrien * @param[in] phy This is the phy that has caused the timer operation to 642130561Sobrien * be scheduled. 643130561Sobrien * @param[in] timeout This is the timeout in ms. 644130561Sobrien */ 645130561Sobrienstatic 646130561Sobrienvoid scic_sds_apc_agent_start_timer( 647130561Sobrien SCIC_SDS_CONTROLLER_T * controller, 648130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 649130561Sobrien SCIC_SDS_PHY_T * phy, 650130561Sobrien U32 timeout 651130561Sobrien) 652130561Sobrien{ 653130561Sobrien SCIC_LOG_TRACE(( 654130561Sobrien sci_base_object_get_logger(controller), 655130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 656130561Sobrien "scic_sds_apc_agent_start_timer(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 657130561Sobrien controller, port_agent, phy, timeout 658130561Sobrien )); 659130561Sobrien 660130561Sobrien if (port_agent->timer_pending) 661130561Sobrien { 662130561Sobrien scic_cb_timer_stop(controller, port_agent->timer); 663130561Sobrien } 664130561Sobrien 665130561Sobrien port_agent->timer_pending = TRUE; 666130561Sobrien 667130561Sobrien scic_cb_timer_start(controller, port_agent->timer, timeout); 668130561Sobrien} 669130561Sobrien 670130561Sobrien/** 671130561Sobrien * This method handles the automatic port configuration for link up notifications. 672130561Sobrien * 673130561Sobrien * @param[in] controller This is the controller object that receives the 674130561Sobrien * link up notification. 675130561Sobrien * @param[in] phy This is the phy object which has gone link up. 676130561Sobrien * @param[in] start_timer This tells the routine if it should start the timer for 677130561Sobrien * any phys that might be added to a port in the future. 678130561Sobrien */ 679130561Sobrienstatic 680130561Sobrienvoid scic_sds_apc_agent_configure_ports( 681130561Sobrien SCIC_SDS_CONTROLLER_T * controller, 682130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 683130561Sobrien SCIC_SDS_PHY_T * phy, 684130561Sobrien BOOL start_timer 685130561Sobrien) 686130561Sobrien{ 687130561Sobrien U8 port_index; 688130561Sobrien SCI_STATUS status; 689130561Sobrien SCIC_SDS_PORT_T * port; 690130561Sobrien SCI_PORT_HANDLE_T port_handle; 691130561Sobrien enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY; 692130561Sobrien 693130561Sobrien SCIC_LOG_TRACE(( 694130561Sobrien sci_base_object_get_logger(controller), 695130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 696130561Sobrien "scic_sds_apc_agent_configure_ports(0x%08x, 0x%08x, 0x%08x, %d) enter\n", 697130561Sobrien controller, port_agent, phy, start_timer 698130561Sobrien )); 699130561Sobrien 700130561Sobrien port = scic_sds_port_configuration_agent_find_port(controller, phy); 701130561Sobrien 702130561Sobrien if (port != SCI_INVALID_HANDLE) 703130561Sobrien { 704130561Sobrien if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)) 705130561Sobrien apc_activity = SCIC_SDS_APC_ADD_PHY; 706130561Sobrien else 707130561Sobrien apc_activity = SCIC_SDS_APC_SKIP_PHY; 708130561Sobrien } 709130561Sobrien else 710130561Sobrien { 711130561Sobrien // There is no matching Port for this PHY so lets search through the 712130561Sobrien // Ports and see if we can add the PHY to its own port or maybe start 713130561Sobrien // the timer and wait to see if a wider port can be made. 714130561Sobrien // 715130561Sobrien // Note the break when we reach the condition of the port id == phy id 716130561Sobrien for ( 717130561Sobrien port_index = port_agent->phy_valid_port_range[phy->phy_index].min_index; 718130561Sobrien port_index <= port_agent->phy_valid_port_range[phy->phy_index].max_index; 719130561Sobrien port_index++ 720130561Sobrien ) 721130561Sobrien { 722130561Sobrien scic_controller_get_port_handle(controller, port_index, &port_handle); 723130561Sobrien 724130561Sobrien port = (SCIC_SDS_PORT_T *)port_handle; 725130561Sobrien 726130561Sobrien // First we must make sure that this PHY can be added to this Port. 727130561Sobrien if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)) 728130561Sobrien { 729130561Sobrien // Port contains a PHY with a greater PHY ID than the current 730130561Sobrien // PHY that has gone link up. This phy can not be part of any 731130561Sobrien // port so skip it and move on. 732130561Sobrien if (port->active_phy_mask > (1 << phy->phy_index)) 733130561Sobrien { 734130561Sobrien apc_activity = SCIC_SDS_APC_SKIP_PHY; 735130561Sobrien break; 736130561Sobrien } 737130561Sobrien 738130561Sobrien // We have reached the end of our Port list and have not found 739130561Sobrien // any reason why we should not either add the PHY to the port 740130561Sobrien // or wait for more phys to become active. 741130561Sobrien if (port->physical_port_index == phy->phy_index) 742130561Sobrien { 743130561Sobrien // The Port either has no active PHYs. 744130561Sobrien // Consider that if the port had any active PHYs we would have 745130561Sobrien // or active PHYs with 746130561Sobrien // a lower PHY Id than this PHY. 747130561Sobrien if (apc_activity != SCIC_SDS_APC_START_TIMER) 748130561Sobrien { 749130561Sobrien apc_activity = SCIC_SDS_APC_ADD_PHY; 750130561Sobrien } 751130561Sobrien 752130561Sobrien break; 753130561Sobrien } 754130561Sobrien 755130561Sobrien // The current Port has no active PHYs and this PHY could be part 756130561Sobrien // of this Port. Since we dont know as yet setup to start the 757130561Sobrien // timer and see if there is a better configuration. 758130561Sobrien if (port->active_phy_mask == 0) 759130561Sobrien { 760130561Sobrien apc_activity = SCIC_SDS_APC_START_TIMER; 761130561Sobrien } 762130561Sobrien } 763130561Sobrien else if (port->active_phy_mask != 0) 764130561Sobrien { 765130561Sobrien // The Port has an active phy and the current Phy can not 766130561Sobrien // participate in this port so skip the PHY and see if 767130561Sobrien // there is a better configuration. 768130561Sobrien apc_activity = SCIC_SDS_APC_SKIP_PHY; 769130561Sobrien } 770130561Sobrien } 771130561Sobrien } 772130561Sobrien 773130561Sobrien // Check to see if the start timer operations should instead map to an 774130561Sobrien // add phy operation. This is caused because we have been waiting to 775130561Sobrien // add a phy to a port but could not because the automatic port 776130561Sobrien // configuration engine had a choice of possible ports for the phy. 777130561Sobrien // Since we have gone through a timeout we are going to restrict the 778130561Sobrien // choice to the smallest possible port. 779130561Sobrien if ( 780130561Sobrien (start_timer == FALSE) 781130561Sobrien && (apc_activity == SCIC_SDS_APC_START_TIMER) 782130561Sobrien ) 783130561Sobrien { 784130561Sobrien apc_activity = SCIC_SDS_APC_ADD_PHY; 785130561Sobrien } 786130561Sobrien 787130561Sobrien switch (apc_activity) 788130561Sobrien { 789130561Sobrien case SCIC_SDS_APC_ADD_PHY: 790130561Sobrien status = scic_sds_port_add_phy(port, phy); 791130561Sobrien 792130561Sobrien if (status == SCI_SUCCESS) 793130561Sobrien { 794130561Sobrien port_agent->phy_configured_mask |= (1 << phy->phy_index); 795130561Sobrien } 796130561Sobrien break; 797130561Sobrien 798130561Sobrien case SCIC_SDS_APC_START_TIMER: 799130561Sobrien scic_sds_apc_agent_start_timer( 800130561Sobrien controller, port_agent, phy, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION 801130561Sobrien ); 802130561Sobrien break; 803130561Sobrien 804130561Sobrien case SCIC_SDS_APC_SKIP_PHY: 805130561Sobrien default: 806130561Sobrien // do nothing the PHY can not be made part of a port at this time. 807130561Sobrien break; 808130561Sobrien } 809130561Sobrien} 810130561Sobrien 811130561Sobrien/** 812130561Sobrien * This method handles the automatic port configuration for link up notifications. 813130561Sobrien * 814130561Sobrien * @param[in] controller This is the controller object that receives the 815130561Sobrien * link up notification. 816130561Sobrien * @param[in] port This is the port object associated with the phy. If the 817130561Sobrien * is no associated port this is an SCI_INVALID_HANDLE. 818130561Sobrien * @param[in] phy This is the phy object which has gone link up. 819130561Sobrien * 820130561Sobrien * @note Is it possible to get a link down notification from a phy that has 821130561Sobrien * no assocoated port? 822130561Sobrien */ 823130561Sobrienstatic 824130561Sobrienvoid scic_sds_apc_agent_link_up( 825130561Sobrien SCIC_SDS_CONTROLLER_T * controller, 826130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 827130561Sobrien SCIC_SDS_PORT_T * port, 828130561Sobrien SCIC_SDS_PHY_T * phy 829130561Sobrien) 830130561Sobrien{ 831130561Sobrien SCIC_LOG_TRACE(( 832130561Sobrien sci_base_object_get_logger(controller), 833130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 834130561Sobrien "scic_sds_apc_agent_link_up(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 835130561Sobrien controller, port_agent, port, phy 836130561Sobrien )); 837130561Sobrien 838130561Sobrien //the phy is not the part of this port, configure the port with this phy 839130561Sobrien if (port == SCI_INVALID_HANDLE) 840130561Sobrien { 841130561Sobrien port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy)); 842130561Sobrien 843130561Sobrien scic_sds_apc_agent_start_timer( 844130561Sobrien controller, port_agent, phy, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION 845130561Sobrien ); 846130561Sobrien } 847130561Sobrien else 848130561Sobrien { 849130561Sobrien //the phy is already the part of the port 850130561Sobrien 851130561Sobrien //if the PORT'S state is resetting then the link up is from port hard reset 852130561Sobrien //in this case, we need to tell the port that link up is received 853130561Sobrien if ( SCI_BASE_PORT_STATE_RESETTING 854130561Sobrien == port->parent.state_machine.current_state_id 855130561Sobrien ) 856130561Sobrien { 857130561Sobrien //notify the port that port needs to be ready 858130561Sobrien port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy)); 859130561Sobrien scic_sds_port_link_up(port, phy); 860130561Sobrien } 861130561Sobrien else 862130561Sobrien { 863130561Sobrien ASSERT (0); 864130561Sobrien } 865130561Sobrien } 866130561Sobrien} 867130561Sobrien 868130561Sobrien/** 869130561Sobrien * This method handles the automatic port configuration link down notifications. 870130561Sobrien * If this PHY is * not associated with a port there is no action taken. 871130561Sobrien * 872130561Sobrien * @param[in] controller This is the controller object that receives the 873130561Sobrien * link down notification. 874130561Sobrien * @param[in] port This is the port object associated with the phy. If the 875130561Sobrien * is no associated port this is an SCI_INVALID_HANDLE. 876130561Sobrien * @param[in] phy This is the phy object which has gone link down. 877130561Sobrien * 878130561Sobrien * @note Is it possible to get a link down notification from a phy that has 879130561Sobrien * no assocoated port? 880130561Sobrien */ 881130561Sobrienstatic 882130561Sobrienvoid scic_sds_apc_agent_link_down( 883130561Sobrien SCIC_SDS_CONTROLLER_T * controller, 884130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 885130561Sobrien SCIC_SDS_PORT_T * port, 886130561Sobrien SCIC_SDS_PHY_T * phy 887130561Sobrien) 888130561Sobrien{ 889130561Sobrien SCIC_LOG_TRACE(( 890130561Sobrien sci_base_object_get_logger(controller), 891130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 892130561Sobrien "scic_sds_apc_agent_link_down(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 893130561Sobrien controller, port_agent, port, phy 894130561Sobrien )); 895130561Sobrien 896130561Sobrien port_agent->phy_ready_mask &= ~(1 << scic_sds_phy_get_index(phy)); 897130561Sobrien 898130561Sobrien if (port != SCI_INVALID_HANDLE) 899130561Sobrien { 900130561Sobrien if (port_agent->phy_configured_mask & (1 << phy->phy_index)) 901130561Sobrien { 902130561Sobrien SCI_STATUS status; 903130561Sobrien 904130561Sobrien status = scic_sds_port_remove_phy(port, phy); 905130561Sobrien 906130561Sobrien if (status == SCI_SUCCESS) 907130561Sobrien { 908130561Sobrien port_agent->phy_configured_mask &= ~(1 << phy->phy_index); 909130561Sobrien } 910130561Sobrien } 911130561Sobrien } 912130561Sobrien} 913130561Sobrien 914130561Sobrien/** 915130561Sobrien * This routine will try to configure the phys into ports when the timer fires. 916130561Sobrien * 917130561Sobrien * @param[in] object This is actually the controller that needs to have the 918130561Sobrien * pending phys configured. 919130561Sobrien */ 920130561Sobrienstatic 921130561Sobrienvoid scic_sds_apc_agent_timeout_handler( 922130561Sobrien void * object 923130561Sobrien) 924130561Sobrien{ 925130561Sobrien U32 index; 926130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent; 927130561Sobrien SCIC_SDS_CONTROLLER_T * controller = (SCIC_SDS_CONTROLLER_T *)object; 928130561Sobrien U16 configure_phy_mask; 929130561Sobrien 930130561Sobrien port_agent = scic_sds_controller_get_port_configuration_agent(controller); 931130561Sobrien 932130561Sobrien SCIC_LOG_TRACE(( 933130561Sobrien sci_base_object_get_logger(controller), 934130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 935130561Sobrien "scic_sds_apc_agent_timeout_handler(0x%08x) enter\n", 936130561Sobrien controller 937130561Sobrien )); 938130561Sobrien 939130561Sobrien port_agent->timer_pending = FALSE; 940130561Sobrien 941130561Sobrien configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask; 942130561Sobrien 943130561Sobrien if (configure_phy_mask != 0x00) 944130561Sobrien { 945130561Sobrien for (index = 0; index < SCI_MAX_PHYS; index++) 946130561Sobrien { 947130561Sobrien if (configure_phy_mask & (1 << index)) 948130561Sobrien { 949130561Sobrien scic_sds_apc_agent_configure_ports( 950130561Sobrien controller, port_agent, &controller->phy_table[index], FALSE 951130561Sobrien ); 952130561Sobrien } 953130561Sobrien } 954130561Sobrien 955130561Sobrien //Notify the controller ports are configured. 956130561Sobrien if ( 957130561Sobrien (port_agent->phy_ready_mask == port_agent->phy_configured_mask) && 958130561Sobrien (controller->next_phy_to_start == SCI_MAX_PHYS) && 959130561Sobrien (controller->phy_startup_timer_pending == FALSE) 960130561Sobrien ) 961130561Sobrien { 962130561Sobrien // The controller has successfully finished the start process. 963130561Sobrien // Inform the SCI Core user and transition to the READY state. 964130561Sobrien if (scic_sds_controller_is_start_complete(controller) == TRUE) 965130561Sobrien { 966130561Sobrien scic_sds_controller_port_agent_configured_ports(controller); 967130561Sobrien } 968130561Sobrien } 969130561Sobrien } 970130561Sobrien} 971130561Sobrien 972130561Sobrien//****************************************************************************** 973130561Sobrien// Public port configuration agent routines 974130561Sobrien//****************************************************************************** 975130561Sobrien 976130561Sobrien/** 977130561Sobrien * This method will construct the port configuration agent for operation. 978130561Sobrien * This call is universal for both manual port configuration and automatic 979130561Sobrien * port configuration modes. 980130561Sobrien * 981130561Sobrien * @param[in] port_agent This is the port configuration agent for this 982130561Sobrien * controller object. 983130561Sobrien */ 984130561Sobrienvoid scic_sds_port_configuration_agent_construct( 985130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 986130561Sobrien) 987130561Sobrien{ 988130561Sobrien U32 index; 989130561Sobrien 990130561Sobrien port_agent->phy_configured_mask = 0x00; 991130561Sobrien port_agent->phy_ready_mask = 0x00; 992130561Sobrien 993130561Sobrien port_agent->link_up_handler = NULL; 994130561Sobrien port_agent->link_down_handler = NULL; 995130561Sobrien 996130561Sobrien port_agent->timer_pending = FALSE; 997130561Sobrien port_agent->timer = NULL; 998130561Sobrien 999130561Sobrien for (index = 0; index < SCI_MAX_PORTS; index++) 1000130561Sobrien { 1001130561Sobrien port_agent->phy_valid_port_range[index].min_index = 0; 1002130561Sobrien port_agent->phy_valid_port_range[index].max_index = 0; 1003130561Sobrien } 1004130561Sobrien} 1005130561Sobrien 1006130561Sobrien/** 1007130561Sobrien * This method will construct the port configuration agent for this controller. 1008130561Sobrien * 1009130561Sobrien * @param[in] controller This is the controller object for which the port 1010130561Sobrien * agent is being initialized. 1011130561Sobrien * 1012130561Sobrien * @param[in] port_agent This is the port configuration agent that is being 1013130561Sobrien * initialized. The initialization path is handled differntly 1014130561Sobrien * for the automatic port configuration agent and the manual port 1015130561Sobrien * configuration agent. 1016130561Sobrien * 1017130561Sobrien * @return 1018130561Sobrien */ 1019130561SobrienSCI_STATUS scic_sds_port_configuration_agent_initialize( 1020130561Sobrien SCIC_SDS_CONTROLLER_T * controller, 1021130561Sobrien SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 1022130561Sobrien) 1023130561Sobrien{ 1024130561Sobrien SCI_STATUS status = SCI_SUCCESS; 1025130561Sobrien enum SCIC_PORT_CONFIGURATION_MODE mode; 1026130561Sobrien 1027130561Sobrien SCIC_LOG_TRACE(( 1028130561Sobrien sci_base_object_get_logger(controller), 1029130561Sobrien SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 1030130561Sobrien "scic_sds_port_configuration_agent_initialize(0x%08x, 0x%08x) enter\n", 1031130561Sobrien controller, port_agent 1032130561Sobrien )); 1033130561Sobrien 1034130561Sobrien mode = controller->oem_parameters.sds1.controller.mode_type; 1035130561Sobrien 1036130561Sobrien if (mode == SCIC_PORT_MANUAL_CONFIGURATION_MODE) 1037130561Sobrien { 1038130561Sobrien status = scic_sds_mpc_agent_validate_phy_configuration(controller, port_agent); 1039130561Sobrien 1040130561Sobrien port_agent->link_up_handler = scic_sds_mpc_agent_link_up; 1041130561Sobrien port_agent->link_down_handler = scic_sds_mpc_agent_link_down; 1042130561Sobrien 1043 port_agent->timer = scic_cb_timer_create( 1044 controller, 1045 scic_sds_mpc_agent_timeout_handler, 1046 controller 1047 ); 1048 } 1049 else 1050 { 1051 status = scic_sds_apc_agent_validate_phy_configuration(controller, port_agent); 1052 1053 port_agent->link_up_handler = scic_sds_apc_agent_link_up; 1054 port_agent->link_down_handler = scic_sds_apc_agent_link_down; 1055 1056 port_agent->timer = scic_cb_timer_create( 1057 controller, 1058 scic_sds_apc_agent_timeout_handler, 1059 controller 1060 ); 1061 } 1062 1063 // Make sure we have actually gotten a timer 1064 if (status == SCI_SUCCESS && port_agent->timer == NULL) 1065 { 1066 SCIC_LOG_ERROR(( 1067 sci_base_object_get_logger(controller), 1068 SCIC_LOG_OBJECT_CONTROLLER, 1069 "Controller 0x%x automatic port configuration agent could not get timer.\n", 1070 controller 1071 )); 1072 1073 status = SCI_FAILURE; 1074 } 1075 1076 return status; 1077} 1078 1079/** 1080 * This method will destroy the port configuration agent for this controller. 1081 * 1082 * @param[in] controller This is the controller object for which the port 1083 * agent is being destroyed. 1084 * 1085 * @param[in] port_agent This is the port configuration agent that is being 1086 * destroyed. 1087 * 1088 * @return 1089 */ 1090void scic_sds_port_configuration_agent_destroy( 1091 SCIC_SDS_CONTROLLER_T * controller, 1092 SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 1093) 1094{ 1095 if (port_agent->timer_pending == TRUE) 1096 { 1097 scic_cb_timer_stop(controller, port_agent->timer); 1098 } 1099 1100 scic_cb_timer_destroy(controller, port_agent->timer); 1101 1102 port_agent->timer_pending = FALSE; 1103 port_agent->timer = NULL; 1104} 1105 1106 1107/** 1108 * @brief This method release resources in for a scic port configuration agent. 1109 * 1110 * @param[in] controller This parameter specifies the core controller, one of 1111 * its phy's resources are to be released. 1112 * @param[in] this_phy This parameter specifies the phy whose resource is to 1113 * be released. 1114 */ 1115void scic_sds_port_configuration_agent_release_resource( 1116 SCIC_SDS_CONTROLLER_T * controller, 1117 SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 1118) 1119{ 1120 SCIC_LOG_TRACE(( 1121 sci_base_object_get_logger(controller), 1122 SCIC_LOG_OBJECT_PORT, 1123 "scic_sds_port_configuration_agent_release_resource(0x%x, 0x%x)\n", 1124 controller, port_agent 1125 )); 1126 1127 //Currently, the only resource to be released is a timer. 1128 if (port_agent->timer != NULL) 1129 { 1130 scic_cb_timer_destroy(controller, port_agent->timer); 1131 port_agent->timer = NULL; 1132 } 1133} 1134