1230557Sjimharris/*- 2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license. When using or 3230557Sjimharris * redistributing this file, you may do so under either license. 4230557Sjimharris * 5230557Sjimharris * GPL LICENSE SUMMARY 6230557Sjimharris * 7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 8230557Sjimharris * 9230557Sjimharris * This program is free software; you can redistribute it and/or modify 10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as 11230557Sjimharris * published by the Free Software Foundation. 12230557Sjimharris * 13230557Sjimharris * This program is distributed in the hope that it will be useful, but 14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of 15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16230557Sjimharris * General Public License for more details. 17230557Sjimharris * 18230557Sjimharris * You should have received a copy of the GNU General Public License 19230557Sjimharris * along with this program; if not, write to the Free Software 20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 21230557Sjimharris * The full GNU General Public License is included in this distribution 22230557Sjimharris * in the file called LICENSE.GPL. 23230557Sjimharris * 24230557Sjimharris * BSD LICENSE 25230557Sjimharris * 26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 27230557Sjimharris * All rights reserved. 28230557Sjimharris * 29230557Sjimharris * Redistribution and use in source and binary forms, with or without 30230557Sjimharris * modification, are permitted provided that the following conditions 31230557Sjimharris * are met: 32230557Sjimharris * 33230557Sjimharris * * Redistributions of source code must retain the above copyright 34230557Sjimharris * notice, this list of conditions and the following disclaimer. 35230557Sjimharris * * Redistributions in binary form must reproduce the above copyright 36230557Sjimharris * notice, this list of conditions and the following disclaimer in 37230557Sjimharris * the documentation and/or other materials provided with the 38230557Sjimharris * distribution. 39230557Sjimharris * 40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51230557Sjimharris */ 52230557Sjimharris 53230557Sjimharris#include <sys/cdefs.h> 54230557Sjimharris__FBSDID("$FreeBSD: releng/10.3/sys/dev/isci/scil/scic_sds_port_configuration_agent.c 249586 2013-04-17 11:47:32Z gabor $"); 55230557Sjimharris 56230557Sjimharris/** 57230557Sjimharris * @file 58230557Sjimharris * 59230557Sjimharris * @brief This file contains the implementation for the public and protected 60230557Sjimharris * methods for the port configuration agent. 61230557Sjimharris */ 62230557Sjimharris 63230557Sjimharris#include <dev/isci/scil/scic_controller.h> 64230557Sjimharris#include <dev/isci/scil/scic_sds_logger.h> 65230557Sjimharris#include <dev/isci/scil/scic_sds_controller.h> 66230557Sjimharris#include <dev/isci/scil/scic_sds_port_configuration_agent.h> 67230557Sjimharris 68230557Sjimharris#define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10) 69230557Sjimharris#define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10) 70230557Sjimharris#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (250) 71230557Sjimharris 72230557Sjimharrisenum SCIC_SDS_APC_ACTIVITY 73230557Sjimharris{ 74230557Sjimharris SCIC_SDS_APC_SKIP_PHY, 75230557Sjimharris SCIC_SDS_APC_ADD_PHY, 76230557Sjimharris SCIC_SDS_APC_START_TIMER, 77230557Sjimharris 78230557Sjimharris SCIC_SDS_APC_ACTIVITY_MAX 79230557Sjimharris}; 80230557Sjimharris 81230557Sjimharris//****************************************************************************** 82230557Sjimharris// General port configuration agent routines 83230557Sjimharris//****************************************************************************** 84230557Sjimharris 85230557Sjimharris/** 86230557Sjimharris * Compare the two SAS Address and 87230557Sjimharris * if SAS Address One is greater than SAS Address Two then return > 0 88230557Sjimharris * else if SAS Address One is less than SAS Address Two return < 0 89230557Sjimharris * Otherwise they are the same return 0 90230557Sjimharris * 91230557Sjimharris * @param[in] address_one A SAS Address to be compared. 92230557Sjimharris * @param[in] address_two A SAS Address to be compared. 93230557Sjimharris * 94230557Sjimharris * @return A signed value of x > 0 > y where 95230557Sjimharris * x is returned for Address One > Address Two 96230557Sjimharris * y is returned for Address One < Address Two 97230557Sjimharris * 0 is returned ofr Address One = Address Two 98230557Sjimharris */ 99230557Sjimharrisstatic 100230557SjimharrisS32 sci_sas_address_compare( 101230557Sjimharris SCI_SAS_ADDRESS_T address_one, 102230557Sjimharris SCI_SAS_ADDRESS_T address_two 103230557Sjimharris) 104230557Sjimharris{ 105230557Sjimharris if (address_one.high > address_two.high) 106230557Sjimharris { 107230557Sjimharris return 1; 108230557Sjimharris } 109230557Sjimharris else if (address_one.high < address_two.high) 110230557Sjimharris { 111230557Sjimharris return -1; 112230557Sjimharris } 113230557Sjimharris else if (address_one.low > address_two.low) 114230557Sjimharris { 115230557Sjimharris return 1; 116230557Sjimharris } 117230557Sjimharris else if (address_one.low < address_two.low) 118230557Sjimharris { 119230557Sjimharris return -1; 120230557Sjimharris } 121230557Sjimharris 122230557Sjimharris // The two SAS Address must be identical 123230557Sjimharris return 0; 124230557Sjimharris} 125230557Sjimharris 126230557Sjimharris/** 127230557Sjimharris * This routine will find a matching port for the phy. This means that the 128230557Sjimharris * port and phy both have the same broadcast sas address and same received 129230557Sjimharris * sas address. 130230557Sjimharris * 131230557Sjimharris * @param[in] controller The controller object used for the port search. 132230557Sjimharris * @param[in] phy The phy object to match. 133230557Sjimharris * 134230557Sjimharris * @return The port address or the SCI_INVALID_HANDLE if there is no matching 135230557Sjimharris * port. 136230557Sjimharris * 137230557Sjimharris * @retvalue port address if the port can be found to match the phy. 138230557Sjimharris * @retvalue SCI_INVALID_HANDLE if there is no matching port for the phy. 139230557Sjimharris */ 140230557Sjimharrisstatic 141230557SjimharrisSCIC_SDS_PORT_T * scic_sds_port_configuration_agent_find_port( 142230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 143230557Sjimharris SCIC_SDS_PHY_T * phy 144230557Sjimharris) 145230557Sjimharris{ 146230557Sjimharris U8 port_index; 147230557Sjimharris SCI_PORT_HANDLE_T port_handle; 148230557Sjimharris SCI_SAS_ADDRESS_T port_sas_address; 149230557Sjimharris SCI_SAS_ADDRESS_T port_attached_device_address; 150230557Sjimharris SCI_SAS_ADDRESS_T phy_sas_address; 151230557Sjimharris SCI_SAS_ADDRESS_T phy_attached_device_address; 152230557Sjimharris 153230557Sjimharris SCIC_LOG_TRACE(( 154230557Sjimharris sci_base_object_get_logger(controller), 155230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 156230557Sjimharris "scic_sds_port_confgiruation_agent_find_port(0x%08x, 0x%08x) enter\n", 157230557Sjimharris controller, phy 158230557Sjimharris )); 159230557Sjimharris 160230557Sjimharris // Since this phy can be a member of a wide port check to see if one or 161230557Sjimharris // more phys match the sent and received SAS address as this phy in which 162230557Sjimharris // case it should participate in the same port. 163230557Sjimharris scic_sds_phy_get_sas_address(phy, &phy_sas_address); 164230557Sjimharris scic_sds_phy_get_attached_sas_address(phy, &phy_attached_device_address); 165230557Sjimharris 166230557Sjimharris for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) 167230557Sjimharris { 168230557Sjimharris if (scic_controller_get_port_handle(controller, port_index, &port_handle) == SCI_SUCCESS) 169230557Sjimharris { 170230557Sjimharris SCIC_SDS_PORT_T * port = (SCIC_SDS_PORT_T *)port_handle; 171230557Sjimharris 172230557Sjimharris scic_sds_port_get_sas_address(port, &port_sas_address); 173230557Sjimharris scic_sds_port_get_attached_sas_address(port, &port_attached_device_address); 174230557Sjimharris 175230557Sjimharris if ( 176230557Sjimharris (sci_sas_address_compare(port_sas_address, phy_sas_address) == 0) 177230557Sjimharris && (sci_sas_address_compare(port_attached_device_address, phy_attached_device_address) == 0) 178230557Sjimharris ) 179230557Sjimharris { 180230557Sjimharris return port; 181230557Sjimharris } 182230557Sjimharris } 183230557Sjimharris } 184230557Sjimharris 185230557Sjimharris return SCI_INVALID_HANDLE; 186230557Sjimharris} 187230557Sjimharris 188230557Sjimharris/** 189230557Sjimharris * This routine will validate the port configuration is correct for the SCU 190230557Sjimharris * hardware. The SCU hardware allows for port configurations as follows. 191230557Sjimharris * LP0 -> (PE0), (PE0, PE1), (PE0, PE1, PE2, PE3) 192230557Sjimharris * LP1 -> (PE1) 193230557Sjimharris * LP2 -> (PE2), (PE2, PE3) 194230557Sjimharris * LP3 -> (PE3) 195230557Sjimharris * 196230557Sjimharris * @param[in] controller This is the controller object that contains the 197230557Sjimharris * port agent 198230557Sjimharris * @param[in] port_agent This is the port configruation agent for 199230557Sjimharris * the controller. 200230557Sjimharris * 201230557Sjimharris * @return SCI_STATUS 202230557Sjimharris * @retval SCI_SUCCESS the port configuration is valid for this 203230557Sjimharris * port configuration agent. 204230557Sjimharris * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION the port configuration 205230557Sjimharris * is not valid for this port configuration agent. 206230557Sjimharris */ 207230557Sjimharrisstatic 208230557SjimharrisSCI_STATUS scic_sds_port_configuration_agent_validate_ports( 209230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 210230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 211230557Sjimharris) 212230557Sjimharris{ 213230557Sjimharris#if !defined(ARLINGTON_BUILD) 214230557Sjimharris SCI_SAS_ADDRESS_T first_address; 215230557Sjimharris SCI_SAS_ADDRESS_T second_address; 216230557Sjimharris 217230557Sjimharris SCIC_LOG_TRACE(( 218230557Sjimharris sci_base_object_get_logger(controller), 219230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 220230557Sjimharris "scic_sds_port_configuration_agent_validate_ports(0x%08x, 0x%08x) enter\n", 221230557Sjimharris controller, port_agent 222230557Sjimharris )); 223230557Sjimharris 224230557Sjimharris // Sanity check the max ranges for all the phys the max index 225230557Sjimharris // is always equal to the port range index 226230557Sjimharris if ( 227230557Sjimharris (port_agent->phy_valid_port_range[0].max_index != 0) 228230557Sjimharris || (port_agent->phy_valid_port_range[1].max_index != 1) 229230557Sjimharris || (port_agent->phy_valid_port_range[2].max_index != 2) 230230557Sjimharris || (port_agent->phy_valid_port_range[3].max_index != 3) 231230557Sjimharris ) 232230557Sjimharris { 233230557Sjimharris return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 234230557Sjimharris } 235230557Sjimharris 236230557Sjimharris // This is a request to configure a single x4 port or at least attempt 237230557Sjimharris // to make all the phys into a single port 238230557Sjimharris if ( 239230557Sjimharris (port_agent->phy_valid_port_range[0].min_index == 0) 240230557Sjimharris && (port_agent->phy_valid_port_range[1].min_index == 0) 241230557Sjimharris && (port_agent->phy_valid_port_range[2].min_index == 0) 242230557Sjimharris && (port_agent->phy_valid_port_range[3].min_index == 0) 243230557Sjimharris ) 244230557Sjimharris { 245230557Sjimharris return SCI_SUCCESS; 246230557Sjimharris } 247230557Sjimharris 248230557Sjimharris // This is a degenerate case where phy 1 and phy 2 are assigned 249230557Sjimharris // to the same port this is explicitly disallowed by the hardware 250230557Sjimharris // unless they are part of the same x4 port and this condition was 251230557Sjimharris // already checked above. 252230557Sjimharris if (port_agent->phy_valid_port_range[2].min_index == 1) 253230557Sjimharris { 254230557Sjimharris return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 255230557Sjimharris } 256230557Sjimharris 257230557Sjimharris // PE0 and PE3 can never have the same SAS Address unless they 258230557Sjimharris // are part of the same x4 wide port and we have already checked 259230557Sjimharris // for this condition. 260230557Sjimharris scic_sds_phy_get_sas_address(&controller->phy_table[0], &first_address); 261230557Sjimharris scic_sds_phy_get_sas_address(&controller->phy_table[3], &second_address); 262230557Sjimharris 263230557Sjimharris if (sci_sas_address_compare(first_address, second_address) == 0) 264230557Sjimharris { 265230557Sjimharris return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 266230557Sjimharris } 267230557Sjimharris 268230557Sjimharris // PE0 and PE1 are configured into a 2x1 ports make sure that the 269230557Sjimharris // SAS Address for PE0 and PE2 are different since they can not be 270230557Sjimharris // part of the same port. 271230557Sjimharris if ( 272230557Sjimharris (port_agent->phy_valid_port_range[0].min_index == 0) 273230557Sjimharris && (port_agent->phy_valid_port_range[1].min_index == 1) 274230557Sjimharris ) 275230557Sjimharris { 276230557Sjimharris scic_sds_phy_get_sas_address(&controller->phy_table[0], &first_address); 277230557Sjimharris scic_sds_phy_get_sas_address(&controller->phy_table[2], &second_address); 278230557Sjimharris 279230557Sjimharris if (sci_sas_address_compare(first_address, second_address) == 0) 280230557Sjimharris { 281230557Sjimharris return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 282230557Sjimharris } 283230557Sjimharris } 284230557Sjimharris 285230557Sjimharris // PE2 and PE3 are configured into a 2x1 ports make sure that the 286230557Sjimharris // SAS Address for PE1 and PE3 are different since they can not be 287230557Sjimharris // part of the same port. 288230557Sjimharris if ( 289230557Sjimharris (port_agent->phy_valid_port_range[2].min_index == 2) 290230557Sjimharris && (port_agent->phy_valid_port_range[3].min_index == 3) 291230557Sjimharris ) 292230557Sjimharris { 293230557Sjimharris scic_sds_phy_get_sas_address(&controller->phy_table[1], &first_address); 294230557Sjimharris scic_sds_phy_get_sas_address(&controller->phy_table[3], &second_address); 295230557Sjimharris 296230557Sjimharris if (sci_sas_address_compare(first_address, second_address) == 0) 297230557Sjimharris { 298230557Sjimharris return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 299230557Sjimharris } 300230557Sjimharris } 301230557Sjimharris#endif // !defined(ARLINGTON_BUILD) 302230557Sjimharris 303230557Sjimharris return SCI_SUCCESS; 304230557Sjimharris} 305230557Sjimharris 306230557Sjimharris//****************************************************************************** 307230557Sjimharris// Manual port configuration agent routines 308230557Sjimharris//****************************************************************************** 309230557Sjimharris 310230557Sjimharris/** 311230557Sjimharris * This routine will verify that all of the phys in the same port are using 312230557Sjimharris * the same SAS address. 313230557Sjimharris * 314230557Sjimharris * @param[in] controller This is the controller that contains the PHYs to 315230557Sjimharris * be verified. 316230557Sjimharris */ 317230557Sjimharrisstatic 318230557SjimharrisSCI_STATUS scic_sds_mpc_agent_validate_phy_configuration( 319230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 320230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 321230557Sjimharris) 322230557Sjimharris{ 323230557Sjimharris U32 phy_mask; 324230557Sjimharris U32 assigned_phy_mask; 325230557Sjimharris SCI_SAS_ADDRESS_T sas_address; 326230557Sjimharris SCI_SAS_ADDRESS_T phy_assigned_address; 327230557Sjimharris U8 port_index; 328230557Sjimharris U8 phy_index; 329230557Sjimharris 330230557Sjimharris assigned_phy_mask = 0; 331230557Sjimharris sas_address.high = 0; 332230557Sjimharris sas_address.low = 0; 333230557Sjimharris 334230557Sjimharris SCIC_LOG_TRACE(( 335230557Sjimharris sci_base_object_get_logger(controller), 336230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 337230557Sjimharris "scic_sds_mpc_agent_validate_phy_configuration(0x%08x, 0x%08x) enter\n", 338230557Sjimharris controller, port_agent 339230557Sjimharris )); 340230557Sjimharris 341230557Sjimharris for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) 342230557Sjimharris { 343230557Sjimharris phy_mask = controller->oem_parameters.sds1.ports[port_index].phy_mask; 344230557Sjimharris 345230557Sjimharris if (phy_mask != 0) 346230557Sjimharris { 347230557Sjimharris // Make sure that one or more of the phys were not already assinged to 348230557Sjimharris // a different port. 349230557Sjimharris if ((phy_mask & ~assigned_phy_mask) == 0) 350230557Sjimharris { 351230557Sjimharris return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 352230557Sjimharris } 353230557Sjimharris 354230557Sjimharris // Find the starting phy index for this round through the loop 355230557Sjimharris for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) 356230557Sjimharris { 357230557Sjimharris if ((1 << phy_index) & phy_mask) 358230557Sjimharris { 359230557Sjimharris scic_sds_phy_get_sas_address( 360230557Sjimharris &controller->phy_table[phy_index], &sas_address 361230557Sjimharris ); 362230557Sjimharris 363230557Sjimharris // The phy_index can be used as the starting point for the 364230557Sjimharris // port range since the hardware starts all logical ports 365230557Sjimharris // the same as the PE index. 366230557Sjimharris port_agent->phy_valid_port_range[phy_index].min_index = port_index; 367230557Sjimharris port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 368230557Sjimharris 369230557Sjimharris if (phy_index != port_index) 370230557Sjimharris { 371230557Sjimharris return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 372230557Sjimharris } 373230557Sjimharris 374230557Sjimharris break; 375230557Sjimharris } 376230557Sjimharris } 377230557Sjimharris 378230557Sjimharris // See how many additional phys are being added to this logical port. 379230557Sjimharris // Note: We have not moved the current phy_index so we will actually 380230557Sjimharris // compare the startting phy with itself. 381230557Sjimharris // This is expected and required to add the phy to the port. 382230557Sjimharris while (phy_index < SCI_MAX_PHYS) 383230557Sjimharris { 384230557Sjimharris if ((1 << phy_index) & phy_mask) 385230557Sjimharris { 386230557Sjimharris scic_sds_phy_get_sas_address( 387230557Sjimharris &controller->phy_table[phy_index], &phy_assigned_address 388230557Sjimharris ); 389230557Sjimharris 390230557Sjimharris if (sci_sas_address_compare(sas_address, phy_assigned_address) != 0) 391230557Sjimharris { 392230557Sjimharris // The phy mask specified that this phy is part of the same port 393230557Sjimharris // as the starting phy and it is not so fail this configuration 394230557Sjimharris return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 395230557Sjimharris } 396230557Sjimharris 397230557Sjimharris port_agent->phy_valid_port_range[phy_index].min_index = port_index; 398230557Sjimharris port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 399230557Sjimharris 400230557Sjimharris scic_sds_port_add_phy( 401230557Sjimharris &controller->port_table[port_index], 402230557Sjimharris &controller->phy_table[phy_index] 403230557Sjimharris ); 404230557Sjimharris 405230557Sjimharris assigned_phy_mask |= (1 << phy_index); 406230557Sjimharris } 407230557Sjimharris 408230557Sjimharris phy_index++; 409230557Sjimharris } 410230557Sjimharris } 411230557Sjimharris } 412230557Sjimharris 413230557Sjimharris return scic_sds_port_configuration_agent_validate_ports(controller, port_agent); 414230557Sjimharris} 415230557Sjimharris 416230557Sjimharris/** 417230557Sjimharris * This timer routine is used to allow the SCI User to rediscover or change 418230557Sjimharris * device objects before a new series of link up notifications because a 419230557Sjimharris * link down has allowed a better port configuration. 420230557Sjimharris * 421230557Sjimharris * @param[in] controller This is the core controller object which is used 422230557Sjimharris * to obtain the port configuration agent. 423230557Sjimharris */ 424230557Sjimharrisstatic 425230557Sjimharrisvoid scic_sds_mpc_agent_timeout_handler( 426230557Sjimharris void * object 427230557Sjimharris) 428230557Sjimharris{ 429230557Sjimharris U8 index; 430230557Sjimharris SCIC_SDS_CONTROLLER_T * controller = (SCIC_SDS_CONTROLLER_T *)object; 431230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent = &controller->port_agent; 432230557Sjimharris U16 configure_phy_mask; 433230557Sjimharris 434230557Sjimharris SCIC_LOG_TRACE(( 435230557Sjimharris sci_base_object_get_logger(controller), 436230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 437230557Sjimharris "scic_sds_mpc_agent_timeout_handler(0x%08x) enter\n", 438230557Sjimharris controller 439230557Sjimharris )); 440230557Sjimharris 441230557Sjimharris port_agent->timer_pending = FALSE; 442230557Sjimharris 443230557Sjimharris // Find the mask of phys that are reported read but as yet unconfigured into a port 444230557Sjimharris configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask; 445230557Sjimharris 446230557Sjimharris for (index = 0; index < SCI_MAX_PHYS; index++) 447230557Sjimharris { 448230557Sjimharris if (configure_phy_mask & (1 << index)) 449230557Sjimharris { 450230557Sjimharris port_agent->link_up_handler( 451230557Sjimharris controller, 452230557Sjimharris port_agent, 453230557Sjimharris scic_sds_phy_get_port(&controller->phy_table[index]), 454230557Sjimharris &controller->phy_table[index] 455230557Sjimharris ); 456230557Sjimharris } 457230557Sjimharris } 458230557Sjimharris} 459230557Sjimharris 460230557Sjimharris/** 461230557Sjimharris * This method handles the manual port configuration link up notifications. 462230557Sjimharris * Since all ports and phys are associate at initialization time we just turn 463230557Sjimharris * around and notifiy the port object that there is a link up. If this PHY is 464230557Sjimharris * not associated with a port there is no action taken. 465230557Sjimharris * 466230557Sjimharris * @param[in] controller This is the controller object that receives the 467230557Sjimharris * link up notification. 468230557Sjimharris * @param[in] port This is the port object associated with the phy. If the 469230557Sjimharris * is no associated port this is an SCI_INVALID_HANDLE. 470230557Sjimharris * @param[in] phy This is the phy object which has gone ready. 471230557Sjimharris * 472230557Sjimharris * @note Is it possible to get a link up notification from a phy that has 473230557Sjimharris * no assocoated port? 474230557Sjimharris */ 475230557Sjimharrisstatic 476230557Sjimharrisvoid scic_sds_mpc_agent_link_up( 477230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 478230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 479230557Sjimharris SCIC_SDS_PORT_T * port, 480230557Sjimharris SCIC_SDS_PHY_T * phy 481230557Sjimharris) 482230557Sjimharris{ 483230557Sjimharris SCIC_LOG_TRACE(( 484230557Sjimharris sci_base_object_get_logger(controller), 485230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 486230557Sjimharris "scic_sds_mpc_agent_link_up(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 487230557Sjimharris controller, port_agent, port, phy 488230557Sjimharris )); 489230557Sjimharris 490230557Sjimharris // If the port has an invalid handle then the phy was not assigned to 491230557Sjimharris // a port. This is because the phy was not given the same SAS Address 492230557Sjimharris // as the other PHYs in the port. 493230557Sjimharris if (port != SCI_INVALID_HANDLE) 494230557Sjimharris { 495230557Sjimharris port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy)); 496230557Sjimharris 497230557Sjimharris scic_sds_port_link_up(port, phy); 498230557Sjimharris 499230557Sjimharris if ((port->active_phy_mask & (1 << scic_sds_phy_get_index(phy))) != 0) 500230557Sjimharris { 501230557Sjimharris port_agent->phy_configured_mask |= (1 << scic_sds_phy_get_index(phy)); 502230557Sjimharris } 503230557Sjimharris } 504230557Sjimharris} 505230557Sjimharris 506230557Sjimharris/** 507230557Sjimharris * This method handles the manual port configuration link down notifications. 508230557Sjimharris * Since all ports and phys are associated at initialization time we just turn 509230557Sjimharris * around and notifiy the port object of the link down event. If this PHY is 510230557Sjimharris * not associated with a port there is no action taken. 511230557Sjimharris * 512230557Sjimharris * @param[in] controller This is the controller object that receives the 513230557Sjimharris * link down notification. 514230557Sjimharris * @param[in] port This is the port object associated with the phy. If the 515230557Sjimharris * is no associated port this is an SCI_INVALID_HANDLE. The port 516230557Sjimharris * is an invalid handle only if the phy was never port of this 517230557Sjimharris * port. This happens when the phy is not broadcasting the same 518230557Sjimharris * SAS address as the other phys in the assigned port. 519230557Sjimharris * @param[in] phy This is the phy object which has gone link down. 520230557Sjimharris * 521230557Sjimharris * @note Is it possible to get a link down notification from a phy that has 522230557Sjimharris * no assocoated port? 523230557Sjimharris */ 524230557Sjimharrisstatic 525230557Sjimharrisvoid scic_sds_mpc_agent_link_down( 526230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 527230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 528230557Sjimharris SCIC_SDS_PORT_T * port, 529230557Sjimharris SCIC_SDS_PHY_T * phy 530230557Sjimharris) 531230557Sjimharris{ 532230557Sjimharris SCIC_LOG_TRACE(( 533230557Sjimharris sci_base_object_get_logger(controller), 534230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 535230557Sjimharris "scic_sds_mpc_agent_link_down(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 536230557Sjimharris controller, port_agent, port, phy 537230557Sjimharris )); 538230557Sjimharris 539230557Sjimharris if (port != SCI_INVALID_HANDLE) 540230557Sjimharris { 541230557Sjimharris // If we can form a new port from the remainder of the phys then we want 542230557Sjimharris // to start the timer to allow the SCI User to cleanup old devices and 543230557Sjimharris // rediscover the port before rebuilding the port with the phys that 544230557Sjimharris // remain in the ready state. 545230557Sjimharris port_agent->phy_ready_mask &= ~(1 << scic_sds_phy_get_index(phy)); 546230557Sjimharris port_agent->phy_configured_mask &= ~(1 << scic_sds_phy_get_index(phy)); 547230557Sjimharris 548230557Sjimharris // Check to see if there are more phys waiting to be configured into a port. 549230557Sjimharris // If there are allow the SCI User to tear down this port, if necessary, and 550230557Sjimharris // then reconstruc the port after the timeout. 551230557Sjimharris if ( 552230557Sjimharris (port_agent->phy_configured_mask == 0x0000) 553230557Sjimharris && (port_agent->phy_ready_mask != 0x0000) 554230557Sjimharris && !port_agent->timer_pending 555230557Sjimharris ) 556230557Sjimharris { 557230557Sjimharris port_agent->timer_pending = TRUE; 558230557Sjimharris 559230557Sjimharris scic_cb_timer_start( 560230557Sjimharris controller, 561230557Sjimharris port_agent->timer, 562230557Sjimharris SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT 563230557Sjimharris ); 564230557Sjimharris } 565230557Sjimharris 566230557Sjimharris scic_sds_port_link_down(port, phy); 567230557Sjimharris } 568230557Sjimharris} 569230557Sjimharris 570230557Sjimharris//****************************************************************************** 571230557Sjimharris// Automatic port configuration agent routines 572230557Sjimharris//****************************************************************************** 573230557Sjimharris 574230557Sjimharris/** 575230557Sjimharris * This routine will verify that the phys are assigned a valid SAS address for 576230557Sjimharris * automatic port configuration mode. 577230557Sjimharris */ 578230557Sjimharrisstatic 579230557SjimharrisSCI_STATUS scic_sds_apc_agent_validate_phy_configuration( 580230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 581230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 582230557Sjimharris) 583230557Sjimharris{ 584230557Sjimharris U8 phy_index; 585230557Sjimharris U8 port_index; 586230557Sjimharris SCI_SAS_ADDRESS_T sas_address; 587230557Sjimharris SCI_SAS_ADDRESS_T phy_assigned_address; 588230557Sjimharris 589230557Sjimharris SCIC_LOG_TRACE(( 590230557Sjimharris sci_base_object_get_logger(controller), 591230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 592230557Sjimharris "scic_sds_apc_agent_validate_phy_configuration(0x%08x, 0x%08x) enter\n", 593230557Sjimharris controller, port_agent 594230557Sjimharris )); 595230557Sjimharris 596230557Sjimharris phy_index = 0; 597230557Sjimharris 598230557Sjimharris while (phy_index < SCI_MAX_PHYS) 599230557Sjimharris { 600230557Sjimharris port_index = phy_index; 601230557Sjimharris 602230557Sjimharris // Get the assigned SAS Address for the first PHY on the controller. 603230557Sjimharris scic_sds_phy_get_sas_address( 604230557Sjimharris &controller->phy_table[phy_index], &sas_address 605230557Sjimharris ); 606230557Sjimharris 607230557Sjimharris while (++phy_index < SCI_MAX_PHYS) 608230557Sjimharris { 609230557Sjimharris scic_sds_phy_get_sas_address( 610230557Sjimharris &controller->phy_table[phy_index], &phy_assigned_address 611230557Sjimharris ); 612230557Sjimharris 613230557Sjimharris // Verify each of the SAS address are all the same for every PHY 614230557Sjimharris if (sci_sas_address_compare(sas_address, phy_assigned_address) == 0) 615230557Sjimharris { 616230557Sjimharris port_agent->phy_valid_port_range[phy_index].min_index = port_index; 617230557Sjimharris port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 618230557Sjimharris } 619230557Sjimharris else 620230557Sjimharris { 621230557Sjimharris port_agent->phy_valid_port_range[phy_index].min_index = phy_index; 622230557Sjimharris port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 623230557Sjimharris break; 624230557Sjimharris } 625230557Sjimharris } 626230557Sjimharris } 627230557Sjimharris 628230557Sjimharris return scic_sds_port_configuration_agent_validate_ports(controller, port_agent); 629230557Sjimharris} 630230557Sjimharris 631230557Sjimharris/** 632230557Sjimharris * This routine will restart the automatic port configuration timeout 633230557Sjimharris * timer for the next time period. This could be caused by either a 634230557Sjimharris * link down event or a link up event where we can not yet tell to which 635230557Sjimharris * port a phy belongs. 636230557Sjimharris * 637230557Sjimharris * @param[in] controller This is the controller that to which the port 638230557Sjimharris * agent is assigned. 639230557Sjimharris * @param[in] port_agent This is the port agent that is requesting the 640230557Sjimharris * timer start operation. 641230557Sjimharris * @param[in] phy This is the phy that has caused the timer operation to 642230557Sjimharris * be scheduled. 643230557Sjimharris * @param[in] timeout This is the timeout in ms. 644230557Sjimharris */ 645230557Sjimharrisstatic 646230557Sjimharrisvoid scic_sds_apc_agent_start_timer( 647230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 648230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 649230557Sjimharris SCIC_SDS_PHY_T * phy, 650230557Sjimharris U32 timeout 651230557Sjimharris) 652230557Sjimharris{ 653230557Sjimharris SCIC_LOG_TRACE(( 654230557Sjimharris sci_base_object_get_logger(controller), 655230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 656230557Sjimharris "scic_sds_apc_agent_start_timer(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 657230557Sjimharris controller, port_agent, phy, timeout 658230557Sjimharris )); 659230557Sjimharris 660230557Sjimharris if (port_agent->timer_pending) 661230557Sjimharris { 662230557Sjimharris scic_cb_timer_stop(controller, port_agent->timer); 663230557Sjimharris } 664230557Sjimharris 665230557Sjimharris port_agent->timer_pending = TRUE; 666230557Sjimharris 667230557Sjimharris scic_cb_timer_start(controller, port_agent->timer, timeout); 668230557Sjimharris} 669230557Sjimharris 670230557Sjimharris/** 671230557Sjimharris * This method handles the automatic port configuration for link up notifications. 672230557Sjimharris * 673230557Sjimharris * @param[in] controller This is the controller object that receives the 674230557Sjimharris * link up notification. 675230557Sjimharris * @param[in] phy This is the phy object which has gone link up. 676230557Sjimharris * @param[in] start_timer This tells the routine if it should start the timer for 677230557Sjimharris * any phys that might be added to a port in the future. 678230557Sjimharris */ 679230557Sjimharrisstatic 680230557Sjimharrisvoid scic_sds_apc_agent_configure_ports( 681230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 682230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 683230557Sjimharris SCIC_SDS_PHY_T * phy, 684230557Sjimharris BOOL start_timer 685230557Sjimharris) 686230557Sjimharris{ 687230557Sjimharris U8 port_index; 688230557Sjimharris SCI_STATUS status; 689230557Sjimharris SCIC_SDS_PORT_T * port; 690230557Sjimharris SCI_PORT_HANDLE_T port_handle; 691230557Sjimharris enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY; 692230557Sjimharris 693230557Sjimharris SCIC_LOG_TRACE(( 694230557Sjimharris sci_base_object_get_logger(controller), 695230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 696230557Sjimharris "scic_sds_apc_agent_configure_ports(0x%08x, 0x%08x, 0x%08x, %d) enter\n", 697230557Sjimharris controller, port_agent, phy, start_timer 698230557Sjimharris )); 699230557Sjimharris 700230557Sjimharris port = scic_sds_port_configuration_agent_find_port(controller, phy); 701230557Sjimharris 702230557Sjimharris if (port != SCI_INVALID_HANDLE) 703230557Sjimharris { 704230557Sjimharris if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)) 705230557Sjimharris apc_activity = SCIC_SDS_APC_ADD_PHY; 706230557Sjimharris else 707230557Sjimharris apc_activity = SCIC_SDS_APC_SKIP_PHY; 708230557Sjimharris } 709230557Sjimharris else 710230557Sjimharris { 711230557Sjimharris // There is no matching Port for this PHY so lets search through the 712230557Sjimharris // Ports and see if we can add the PHY to its own port or maybe start 713230557Sjimharris // the timer and wait to see if a wider port can be made. 714230557Sjimharris // 715230557Sjimharris // Note the break when we reach the condition of the port id == phy id 716230557Sjimharris for ( 717230557Sjimharris port_index = port_agent->phy_valid_port_range[phy->phy_index].min_index; 718230557Sjimharris port_index <= port_agent->phy_valid_port_range[phy->phy_index].max_index; 719230557Sjimharris port_index++ 720230557Sjimharris ) 721230557Sjimharris { 722230557Sjimharris scic_controller_get_port_handle(controller, port_index, &port_handle); 723230557Sjimharris 724230557Sjimharris port = (SCIC_SDS_PORT_T *)port_handle; 725230557Sjimharris 726230557Sjimharris // First we must make sure that this PHY can be added to this Port. 727230557Sjimharris if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)) 728230557Sjimharris { 729230557Sjimharris // Port contains a PHY with a greater PHY ID than the current 730230557Sjimharris // PHY that has gone link up. This phy can not be part of any 731230557Sjimharris // port so skip it and move on. 732230557Sjimharris if (port->active_phy_mask > (1 << phy->phy_index)) 733230557Sjimharris { 734230557Sjimharris apc_activity = SCIC_SDS_APC_SKIP_PHY; 735230557Sjimharris break; 736230557Sjimharris } 737230557Sjimharris 738230557Sjimharris // We have reached the end of our Port list and have not found 739230557Sjimharris // any reason why we should not either add the PHY to the port 740230557Sjimharris // or wait for more phys to become active. 741230557Sjimharris if (port->physical_port_index == phy->phy_index) 742230557Sjimharris { 743230557Sjimharris // The Port either has no active PHYs. 744230557Sjimharris // Consider that if the port had any active PHYs we would have 745230557Sjimharris // or active PHYs with 746230557Sjimharris // a lower PHY Id than this PHY. 747230557Sjimharris if (apc_activity != SCIC_SDS_APC_START_TIMER) 748230557Sjimharris { 749230557Sjimharris apc_activity = SCIC_SDS_APC_ADD_PHY; 750230557Sjimharris } 751230557Sjimharris 752230557Sjimharris break; 753230557Sjimharris } 754230557Sjimharris 755230557Sjimharris // The current Port has no active PHYs and this PHY could be part 756230557Sjimharris // of this Port. Since we dont know as yet setup to start the 757230557Sjimharris // timer and see if there is a better configuration. 758230557Sjimharris if (port->active_phy_mask == 0) 759230557Sjimharris { 760230557Sjimharris apc_activity = SCIC_SDS_APC_START_TIMER; 761230557Sjimharris } 762230557Sjimharris } 763230557Sjimharris else if (port->active_phy_mask != 0) 764230557Sjimharris { 765230557Sjimharris // The Port has an active phy and the current Phy can not 766230557Sjimharris // participate in this port so skip the PHY and see if 767230557Sjimharris // there is a better configuration. 768230557Sjimharris apc_activity = SCIC_SDS_APC_SKIP_PHY; 769230557Sjimharris } 770230557Sjimharris } 771230557Sjimharris } 772230557Sjimharris 773230557Sjimharris // Check to see if the start timer operations should instead map to an 774230557Sjimharris // add phy operation. This is caused because we have been waiting to 775230557Sjimharris // add a phy to a port but could not becuase the automatic port 776230557Sjimharris // configuration engine had a choice of possible ports for the phy. 777230557Sjimharris // Since we have gone through a timeout we are going to restrict the 778230557Sjimharris // choice to the smallest possible port. 779230557Sjimharris if ( 780230557Sjimharris (start_timer == FALSE) 781230557Sjimharris && (apc_activity == SCIC_SDS_APC_START_TIMER) 782230557Sjimharris ) 783230557Sjimharris { 784230557Sjimharris apc_activity = SCIC_SDS_APC_ADD_PHY; 785230557Sjimharris } 786230557Sjimharris 787230557Sjimharris switch (apc_activity) 788230557Sjimharris { 789230557Sjimharris case SCIC_SDS_APC_ADD_PHY: 790230557Sjimharris status = scic_sds_port_add_phy(port, phy); 791230557Sjimharris 792230557Sjimharris if (status == SCI_SUCCESS) 793230557Sjimharris { 794230557Sjimharris port_agent->phy_configured_mask |= (1 << phy->phy_index); 795230557Sjimharris } 796230557Sjimharris break; 797230557Sjimharris 798230557Sjimharris case SCIC_SDS_APC_START_TIMER: 799230557Sjimharris scic_sds_apc_agent_start_timer( 800230557Sjimharris controller, port_agent, phy, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION 801230557Sjimharris ); 802230557Sjimharris break; 803230557Sjimharris 804230557Sjimharris case SCIC_SDS_APC_SKIP_PHY: 805230557Sjimharris default: 806230557Sjimharris // do nothing the PHY can not be made part of a port at this time. 807230557Sjimharris break; 808230557Sjimharris } 809230557Sjimharris} 810230557Sjimharris 811230557Sjimharris/** 812230557Sjimharris * This method handles the automatic port configuration for link up notifications. 813230557Sjimharris * 814230557Sjimharris * @param[in] controller This is the controller object that receives the 815230557Sjimharris * link up notification. 816230557Sjimharris * @param[in] port This is the port object associated with the phy. If the 817230557Sjimharris * is no associated port this is an SCI_INVALID_HANDLE. 818230557Sjimharris * @param[in] phy This is the phy object which has gone link up. 819230557Sjimharris * 820230557Sjimharris * @note Is it possible to get a link down notification from a phy that has 821230557Sjimharris * no assocoated port? 822230557Sjimharris */ 823230557Sjimharrisstatic 824230557Sjimharrisvoid scic_sds_apc_agent_link_up( 825230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 826230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 827230557Sjimharris SCIC_SDS_PORT_T * port, 828230557Sjimharris SCIC_SDS_PHY_T * phy 829230557Sjimharris) 830230557Sjimharris{ 831230557Sjimharris SCIC_LOG_TRACE(( 832230557Sjimharris sci_base_object_get_logger(controller), 833230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 834230557Sjimharris "scic_sds_apc_agent_link_up(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 835230557Sjimharris controller, port_agent, port, phy 836230557Sjimharris )); 837230557Sjimharris 838230557Sjimharris //the phy is not the part of this port, configure the port with this phy 839230557Sjimharris if (port == SCI_INVALID_HANDLE) 840230557Sjimharris { 841230557Sjimharris port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy)); 842230557Sjimharris 843230557Sjimharris scic_sds_apc_agent_start_timer( 844230557Sjimharris controller, port_agent, phy, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION 845230557Sjimharris ); 846230557Sjimharris } 847230557Sjimharris else 848230557Sjimharris { 849230557Sjimharris //the phy is already the part of the port 850230557Sjimharris 851230557Sjimharris //if the PORT'S state is resetting then the link up is from port hard reset 852230557Sjimharris //in this case, we need to tell the port that link up is recieved 853230557Sjimharris if ( SCI_BASE_PORT_STATE_RESETTING 854230557Sjimharris == port->parent.state_machine.current_state_id 855230557Sjimharris ) 856230557Sjimharris { 857230557Sjimharris //notify the port that port needs to be ready 858230557Sjimharris port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy)); 859230557Sjimharris scic_sds_port_link_up(port, phy); 860230557Sjimharris } 861230557Sjimharris else 862230557Sjimharris { 863230557Sjimharris ASSERT (0); 864230557Sjimharris } 865230557Sjimharris } 866230557Sjimharris} 867230557Sjimharris 868230557Sjimharris/** 869230557Sjimharris * This method handles the automatic port configuration link down notifications. 870230557Sjimharris * If this PHY is * not associated with a port there is no action taken. 871230557Sjimharris * 872230557Sjimharris * @param[in] controller This is the controller object that receives the 873230557Sjimharris * link down notification. 874230557Sjimharris * @param[in] port This is the port object associated with the phy. If the 875230557Sjimharris * is no associated port this is an SCI_INVALID_HANDLE. 876230557Sjimharris * @param[in] phy This is the phy object which has gone link down. 877230557Sjimharris * 878230557Sjimharris * @note Is it possible to get a link down notification from a phy that has 879230557Sjimharris * no assocoated port? 880230557Sjimharris */ 881230557Sjimharrisstatic 882230557Sjimharrisvoid scic_sds_apc_agent_link_down( 883230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 884230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 885230557Sjimharris SCIC_SDS_PORT_T * port, 886230557Sjimharris SCIC_SDS_PHY_T * phy 887230557Sjimharris) 888230557Sjimharris{ 889230557Sjimharris SCIC_LOG_TRACE(( 890230557Sjimharris sci_base_object_get_logger(controller), 891230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 892230557Sjimharris "scic_sds_apc_agent_link_down(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 893230557Sjimharris controller, port_agent, port, phy 894230557Sjimharris )); 895230557Sjimharris 896230557Sjimharris port_agent->phy_ready_mask &= ~(1 << scic_sds_phy_get_index(phy)); 897230557Sjimharris 898230557Sjimharris if (port != SCI_INVALID_HANDLE) 899230557Sjimharris { 900230557Sjimharris if (port_agent->phy_configured_mask & (1 << phy->phy_index)) 901230557Sjimharris { 902230557Sjimharris SCI_STATUS status; 903230557Sjimharris 904230557Sjimharris status = scic_sds_port_remove_phy(port, phy); 905230557Sjimharris 906230557Sjimharris if (status == SCI_SUCCESS) 907230557Sjimharris { 908230557Sjimharris port_agent->phy_configured_mask &= ~(1 << phy->phy_index); 909230557Sjimharris } 910230557Sjimharris } 911230557Sjimharris } 912230557Sjimharris} 913230557Sjimharris 914230557Sjimharris/** 915230557Sjimharris * This routine will try to configure the phys into ports when the timer fires. 916230557Sjimharris * 917230557Sjimharris * @param[in] object This is actually the controller that needs to have the 918230557Sjimharris * pending phys configured. 919230557Sjimharris */ 920230557Sjimharrisstatic 921230557Sjimharrisvoid scic_sds_apc_agent_timeout_handler( 922230557Sjimharris void * object 923230557Sjimharris) 924230557Sjimharris{ 925230557Sjimharris U32 index; 926230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent; 927230557Sjimharris SCIC_SDS_CONTROLLER_T * controller = (SCIC_SDS_CONTROLLER_T *)object; 928230557Sjimharris U16 configure_phy_mask; 929230557Sjimharris 930230557Sjimharris port_agent = scic_sds_controller_get_port_configuration_agent(controller); 931230557Sjimharris 932230557Sjimharris SCIC_LOG_TRACE(( 933230557Sjimharris sci_base_object_get_logger(controller), 934230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 935230557Sjimharris "scic_sds_apc_agent_timeout_handler(0x%08x) enter\n", 936230557Sjimharris controller 937230557Sjimharris )); 938230557Sjimharris 939230557Sjimharris port_agent->timer_pending = FALSE; 940230557Sjimharris 941230557Sjimharris configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask; 942230557Sjimharris 943230557Sjimharris if (configure_phy_mask != 0x00) 944230557Sjimharris { 945230557Sjimharris for (index = 0; index < SCI_MAX_PHYS; index++) 946230557Sjimharris { 947230557Sjimharris if (configure_phy_mask & (1 << index)) 948230557Sjimharris { 949230557Sjimharris scic_sds_apc_agent_configure_ports( 950230557Sjimharris controller, port_agent, &controller->phy_table[index], FALSE 951230557Sjimharris ); 952230557Sjimharris } 953230557Sjimharris } 954230557Sjimharris 955230557Sjimharris //Notify the controller ports are configured. 956230557Sjimharris if ( 957230557Sjimharris (port_agent->phy_ready_mask == port_agent->phy_configured_mask) && 958230557Sjimharris (controller->next_phy_to_start == SCI_MAX_PHYS) && 959230557Sjimharris (controller->phy_startup_timer_pending == FALSE) 960230557Sjimharris ) 961230557Sjimharris { 962230557Sjimharris // The controller has successfully finished the start process. 963230557Sjimharris // Inform the SCI Core user and transition to the READY state. 964230557Sjimharris if (scic_sds_controller_is_start_complete(controller) == TRUE) 965230557Sjimharris { 966230557Sjimharris scic_sds_controller_port_agent_configured_ports(controller); 967230557Sjimharris } 968230557Sjimharris } 969230557Sjimharris } 970230557Sjimharris} 971230557Sjimharris 972230557Sjimharris//****************************************************************************** 973230557Sjimharris// Public port configuration agent routines 974230557Sjimharris//****************************************************************************** 975230557Sjimharris 976230557Sjimharris/** 977230557Sjimharris * This method will construct the port configuration agent for operation. 978230557Sjimharris * This call is universal for both manual port configuration and automatic 979230557Sjimharris * port configuration modes. 980230557Sjimharris * 981230557Sjimharris * @param[in] port_agent This is the port configuration agent for this 982230557Sjimharris * controller object. 983230557Sjimharris */ 984230557Sjimharrisvoid scic_sds_port_configuration_agent_construct( 985230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 986230557Sjimharris) 987230557Sjimharris{ 988230557Sjimharris U32 index; 989230557Sjimharris 990230557Sjimharris port_agent->phy_configured_mask = 0x00; 991230557Sjimharris port_agent->phy_ready_mask = 0x00; 992230557Sjimharris 993230557Sjimharris port_agent->link_up_handler = NULL; 994230557Sjimharris port_agent->link_down_handler = NULL; 995230557Sjimharris 996230557Sjimharris port_agent->timer_pending = FALSE; 997230557Sjimharris port_agent->timer = NULL; 998230557Sjimharris 999230557Sjimharris for (index = 0; index < SCI_MAX_PORTS; index++) 1000230557Sjimharris { 1001230557Sjimharris port_agent->phy_valid_port_range[index].min_index = 0; 1002230557Sjimharris port_agent->phy_valid_port_range[index].max_index = 0; 1003230557Sjimharris } 1004230557Sjimharris} 1005230557Sjimharris 1006230557Sjimharris/** 1007230557Sjimharris * This method will construct the port configuration agent for this controller. 1008230557Sjimharris * 1009230557Sjimharris * @param[in] controller This is the controller object for which the port 1010230557Sjimharris * agent is being initialized. 1011230557Sjimharris * 1012230557Sjimharris * @param[in] port_agent This is the port configuration agent that is being 1013230557Sjimharris * initialized. The initialization path is handled differntly 1014230557Sjimharris * for the automatic port configuration agent and the manual port 1015230557Sjimharris * configuration agent. 1016230557Sjimharris * 1017230557Sjimharris * @return 1018230557Sjimharris */ 1019230557SjimharrisSCI_STATUS scic_sds_port_configuration_agent_initialize( 1020230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 1021230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 1022230557Sjimharris) 1023230557Sjimharris{ 1024230557Sjimharris SCI_STATUS status = SCI_SUCCESS; 1025230557Sjimharris enum SCIC_PORT_CONFIGURATION_MODE mode; 1026230557Sjimharris 1027230557Sjimharris SCIC_LOG_TRACE(( 1028230557Sjimharris sci_base_object_get_logger(controller), 1029230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 1030230557Sjimharris "scic_sds_port_configuration_agent_initialize(0x%08x, 0x%08x) enter\n", 1031230557Sjimharris controller, port_agent 1032230557Sjimharris )); 1033230557Sjimharris 1034230557Sjimharris mode = controller->oem_parameters.sds1.controller.mode_type; 1035230557Sjimharris 1036230557Sjimharris if (mode == SCIC_PORT_MANUAL_CONFIGURATION_MODE) 1037230557Sjimharris { 1038230557Sjimharris status = scic_sds_mpc_agent_validate_phy_configuration(controller, port_agent); 1039230557Sjimharris 1040230557Sjimharris port_agent->link_up_handler = scic_sds_mpc_agent_link_up; 1041230557Sjimharris port_agent->link_down_handler = scic_sds_mpc_agent_link_down; 1042230557Sjimharris 1043230557Sjimharris port_agent->timer = scic_cb_timer_create( 1044230557Sjimharris controller, 1045230557Sjimharris scic_sds_mpc_agent_timeout_handler, 1046230557Sjimharris controller 1047230557Sjimharris ); 1048230557Sjimharris } 1049230557Sjimharris else 1050230557Sjimharris { 1051230557Sjimharris status = scic_sds_apc_agent_validate_phy_configuration(controller, port_agent); 1052230557Sjimharris 1053230557Sjimharris port_agent->link_up_handler = scic_sds_apc_agent_link_up; 1054230557Sjimharris port_agent->link_down_handler = scic_sds_apc_agent_link_down; 1055230557Sjimharris 1056230557Sjimharris port_agent->timer = scic_cb_timer_create( 1057230557Sjimharris controller, 1058230557Sjimharris scic_sds_apc_agent_timeout_handler, 1059230557Sjimharris controller 1060230557Sjimharris ); 1061230557Sjimharris } 1062230557Sjimharris 1063230557Sjimharris // Make sure we have actually gotten a timer 1064230557Sjimharris if (status == SCI_SUCCESS && port_agent->timer == NULL) 1065230557Sjimharris { 1066230557Sjimharris SCIC_LOG_ERROR(( 1067230557Sjimharris sci_base_object_get_logger(controller), 1068230557Sjimharris SCIC_LOG_OBJECT_CONTROLLER, 1069230557Sjimharris "Controller 0x%x automatic port configuration agent could not get timer.\n", 1070230557Sjimharris controller 1071230557Sjimharris )); 1072230557Sjimharris 1073230557Sjimharris status = SCI_FAILURE; 1074230557Sjimharris } 1075230557Sjimharris 1076230557Sjimharris return status; 1077230557Sjimharris} 1078230557Sjimharris 1079230557Sjimharris/** 1080230557Sjimharris * This method will destroy the port configuration agent for this controller. 1081230557Sjimharris * 1082230557Sjimharris * @param[in] controller This is the controller object for which the port 1083230557Sjimharris * agent is being destroyed. 1084230557Sjimharris * 1085230557Sjimharris * @param[in] port_agent This is the port configuration agent that is being 1086230557Sjimharris * destroyed. 1087230557Sjimharris * 1088230557Sjimharris * @return 1089230557Sjimharris */ 1090230557Sjimharrisvoid scic_sds_port_configuration_agent_destroy( 1091230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 1092230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 1093230557Sjimharris) 1094230557Sjimharris{ 1095230557Sjimharris if (port_agent->timer_pending == TRUE) 1096230557Sjimharris { 1097230557Sjimharris scic_cb_timer_stop(controller, port_agent->timer); 1098230557Sjimharris } 1099230557Sjimharris 1100230557Sjimharris scic_cb_timer_destroy(controller, port_agent->timer); 1101230557Sjimharris 1102230557Sjimharris port_agent->timer_pending = FALSE; 1103230557Sjimharris port_agent->timer = NULL; 1104230557Sjimharris} 1105230557Sjimharris 1106230557Sjimharris 1107230557Sjimharris/** 1108230557Sjimharris * @brief This method release resources in for a scic port configuration agent. 1109230557Sjimharris * 1110230557Sjimharris * @param[in] controller This parameter specifies the core controller, one of 1111230557Sjimharris * its phy's resources are to be released. 1112249586Sgabor * @param[in] this_phy This parameter specifies the phy whose resource is to 1113230557Sjimharris * be released. 1114230557Sjimharris */ 1115230557Sjimharrisvoid scic_sds_port_configuration_agent_release_resource( 1116230557Sjimharris SCIC_SDS_CONTROLLER_T * controller, 1117230557Sjimharris SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 1118230557Sjimharris) 1119230557Sjimharris{ 1120230557Sjimharris SCIC_LOG_TRACE(( 1121230557Sjimharris sci_base_object_get_logger(controller), 1122230557Sjimharris SCIC_LOG_OBJECT_PORT, 1123230557Sjimharris "scic_sds_port_configuration_agent_release_resource(0x%x, 0x%x)\n", 1124230557Sjimharris controller, port_agent 1125230557Sjimharris )); 1126230557Sjimharris 1127230557Sjimharris //Currently, the only resource to be released is a timer. 1128230557Sjimharris if (port_agent->timer != NULL) 1129230557Sjimharris { 1130230557Sjimharris scic_cb_timer_destroy(controller, port_agent->timer); 1131230557Sjimharris port_agent->timer = NULL; 1132230557Sjimharris } 1133230557Sjimharris} 1134