scic_sds_port_configuration_agent.c revision 256281
1216115Slstewart/*- 2216115Slstewart * This file is provided under a dual BSD/GPLv2 license. When using or 3216115Slstewart * redistributing this file, you may do so under either license. 4216115Slstewart * 5216115Slstewart * GPL LICENSE SUMMARY 6216115Slstewart * 7216115Slstewart * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 8216115Slstewart * 9216115Slstewart * This program is free software; you can redistribute it and/or modify 10216115Slstewart * it under the terms of version 2 of the GNU General Public License as 11216115Slstewart * published by the Free Software Foundation. 12216115Slstewart * 13216115Slstewart * This program is distributed in the hope that it will be useful, but 14216115Slstewart * WITHOUT ANY WARRANTY; without even the implied warranty of 15216115Slstewart * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16216115Slstewart * General Public License for more details. 17216115Slstewart * 18216115Slstewart * You should have received a copy of the GNU General Public License 19216115Slstewart * along with this program; if not, write to the Free Software 20216115Slstewart * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 21216115Slstewart * The full GNU General Public License is included in this distribution 22216115Slstewart * in the file called LICENSE.GPL. 23216115Slstewart * 24216115Slstewart * BSD LICENSE 25216115Slstewart * 26216115Slstewart * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 27216115Slstewart * All rights reserved. 28216115Slstewart * 29216115Slstewart * Redistribution and use in source and binary forms, with or without 30216115Slstewart * modification, are permitted provided that the following conditions 31216115Slstewart * are met: 32216115Slstewart * 33216115Slstewart * * Redistributions of source code must retain the above copyright 34216115Slstewart * notice, this list of conditions and the following disclaimer. 35216115Slstewart * * Redistributions in binary form must reproduce the above copyright 36216115Slstewart * notice, this list of conditions and the following disclaimer in 37216115Slstewart * the documentation and/or other materials provided with the 38216115Slstewart * distribution. 39216115Slstewart * 40216115Slstewart * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 41216115Slstewart * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 42216115Slstewart * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 43216115Slstewart * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 44216115Slstewart * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45216115Slstewart * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46216115Slstewart * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47216115Slstewart * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48216115Slstewart * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49216115Slstewart * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 50216115Slstewart * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51216115Slstewart */ 52216115Slstewart 53216115Slstewart#include <sys/cdefs.h> 54216115Slstewart__FBSDID("$FreeBSD: stable/10/sys/dev/isci/scil/scic_sds_port_configuration_agent.c 249586 2013-04-17 11:47:32Z gabor $"); 55216115Slstewart 56216115Slstewart/** 57216115Slstewart * @file 58216115Slstewart * 59216115Slstewart * @brief This file contains the implementation for the public and protected 60216115Slstewart * methods for the port configuration agent. 61216115Slstewart */ 62216115Slstewart 63216115Slstewart#include <dev/isci/scil/scic_controller.h> 64216115Slstewart#include <dev/isci/scil/scic_sds_logger.h> 65216115Slstewart#include <dev/isci/scil/scic_sds_controller.h> 66216115Slstewart#include <dev/isci/scil/scic_sds_port_configuration_agent.h> 67216115Slstewart 68216115Slstewart#define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10) 69216115Slstewart#define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10) 70216115Slstewart#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (250) 71216115Slstewart 72216115Slstewartenum SCIC_SDS_APC_ACTIVITY 73216115Slstewart{ 74216115Slstewart SCIC_SDS_APC_SKIP_PHY, 75216115Slstewart SCIC_SDS_APC_ADD_PHY, 76216115Slstewart SCIC_SDS_APC_START_TIMER, 77216115Slstewart 78216115Slstewart SCIC_SDS_APC_ACTIVITY_MAX 79216115Slstewart}; 80216115Slstewart 81216115Slstewart//****************************************************************************** 82216115Slstewart// General port configuration agent routines 83216115Slstewart//****************************************************************************** 84216115Slstewart 85216115Slstewart/** 86216115Slstewart * Compare the two SAS Address and 87216115Slstewart * if SAS Address One is greater than SAS Address Two then return > 0 88216115Slstewart * else if SAS Address One is less than SAS Address Two return < 0 89216115Slstewart * Otherwise they are the same return 0 90216115Slstewart * 91216115Slstewart * @param[in] address_one A SAS Address to be compared. 92216115Slstewart * @param[in] address_two A SAS Address to be compared. 93216115Slstewart * 94216115Slstewart * @return A signed value of x > 0 > y where 95216115Slstewart * x is returned for Address One > Address Two 96216115Slstewart * y is returned for Address One < Address Two 97216115Slstewart * 0 is returned ofr Address One = Address Two 98216115Slstewart */ 99216115Slstewartstatic 100216115SlstewartS32 sci_sas_address_compare( 101216115Slstewart SCI_SAS_ADDRESS_T address_one, 102216115Slstewart SCI_SAS_ADDRESS_T address_two 103216115Slstewart) 104216115Slstewart{ 105216115Slstewart if (address_one.high > address_two.high) 106216115Slstewart { 107216115Slstewart return 1; 108216115Slstewart } 109216115Slstewart else if (address_one.high < address_two.high) 110216115Slstewart { 111216115Slstewart return -1; 112216115Slstewart } 113216115Slstewart else if (address_one.low > address_two.low) 114216115Slstewart { 115216115Slstewart return 1; 116216115Slstewart } 117216115Slstewart else if (address_one.low < address_two.low) 118216115Slstewart { 119216115Slstewart return -1; 120216115Slstewart } 121216115Slstewart 122216115Slstewart // The two SAS Address must be identical 123216115Slstewart return 0; 124216115Slstewart} 125216115Slstewart 126216115Slstewart/** 127216115Slstewart * This routine will find a matching port for the phy. This means that the 128216115Slstewart * port and phy both have the same broadcast sas address and same received 129216115Slstewart * sas address. 130216115Slstewart * 131216115Slstewart * @param[in] controller The controller object used for the port search. 132216115Slstewart * @param[in] phy The phy object to match. 133216115Slstewart * 134216115Slstewart * @return The port address or the SCI_INVALID_HANDLE if there is no matching 135216115Slstewart * port. 136216115Slstewart * 137216115Slstewart * @retvalue port address if the port can be found to match the phy. 138216115Slstewart * @retvalue SCI_INVALID_HANDLE if there is no matching port for the phy. 139216115Slstewart */ 140216115Slstewartstatic 141216115SlstewartSCIC_SDS_PORT_T * scic_sds_port_configuration_agent_find_port( 142216115Slstewart SCIC_SDS_CONTROLLER_T * controller, 143216115Slstewart SCIC_SDS_PHY_T * phy 144216115Slstewart) 145216115Slstewart{ 146216115Slstewart U8 port_index; 147216115Slstewart SCI_PORT_HANDLE_T port_handle; 148216115Slstewart SCI_SAS_ADDRESS_T port_sas_address; 149216115Slstewart SCI_SAS_ADDRESS_T port_attached_device_address; 150216115Slstewart SCI_SAS_ADDRESS_T phy_sas_address; 151216115Slstewart SCI_SAS_ADDRESS_T phy_attached_device_address; 152216115Slstewart 153216115Slstewart SCIC_LOG_TRACE(( 154216115Slstewart sci_base_object_get_logger(controller), 155216115Slstewart SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 156216115Slstewart "scic_sds_port_confgiruation_agent_find_port(0x%08x, 0x%08x) enter\n", 157216115Slstewart controller, phy 158216115Slstewart )); 159216115Slstewart 160216115Slstewart // Since this phy can be a member of a wide port check to see if one or 161216115Slstewart // more phys match the sent and received SAS address as this phy in which 162216115Slstewart // case it should participate in the same port. 163216115Slstewart scic_sds_phy_get_sas_address(phy, &phy_sas_address); 164216115Slstewart scic_sds_phy_get_attached_sas_address(phy, &phy_attached_device_address); 165216115Slstewart 166216115Slstewart for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) 167216115Slstewart { 168216115Slstewart if (scic_controller_get_port_handle(controller, port_index, &port_handle) == SCI_SUCCESS) 169216115Slstewart { 170216115Slstewart SCIC_SDS_PORT_T * port = (SCIC_SDS_PORT_T *)port_handle; 171217322Smdf 172217322Smdf scic_sds_port_get_sas_address(port, &port_sas_address); 173216115Slstewart scic_sds_port_get_attached_sas_address(port, &port_attached_device_address); 174216115Slstewart 175216115Slstewart if ( 176216115Slstewart (sci_sas_address_compare(port_sas_address, phy_sas_address) == 0) 177216115Slstewart && (sci_sas_address_compare(port_attached_device_address, phy_attached_device_address) == 0) 178216115Slstewart ) 179216115Slstewart { 180216115Slstewart return port; 181216115Slstewart } 182216115Slstewart } 183216115Slstewart } 184216115Slstewart 185216115Slstewart return SCI_INVALID_HANDLE; 186216115Slstewart} 187216115Slstewart 188216115Slstewart/** 189216115Slstewart * This routine will validate the port configuration is correct for the SCU 190216115Slstewart * hardware. The SCU hardware allows for port configurations as follows. 191216115Slstewart * LP0 -> (PE0), (PE0, PE1), (PE0, PE1, PE2, PE3) 192216115Slstewart * LP1 -> (PE1) 193216115Slstewart * LP2 -> (PE2), (PE2, PE3) 194216115Slstewart * LP3 -> (PE3) 195216115Slstewart * 196216115Slstewart * @param[in] controller This is the controller object that contains the 197216115Slstewart * port agent 198216115Slstewart * @param[in] port_agent This is the port configruation agent for 199216115Slstewart * the controller. 200216115Slstewart * 201216115Slstewart * @return SCI_STATUS 202216115Slstewart * @retval SCI_SUCCESS the port configuration is valid for this 203216115Slstewart * port configuration agent. 204216115Slstewart * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION the port configuration 205216115Slstewart * is not valid for this port configuration agent. 206216115Slstewart */ 207216115Slstewartstatic 208216115SlstewartSCI_STATUS scic_sds_port_configuration_agent_validate_ports( 209216115Slstewart SCIC_SDS_CONTROLLER_T * controller, 210216115Slstewart SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 211216115Slstewart) 212216115Slstewart{ 213216115Slstewart#if !defined(ARLINGTON_BUILD) 214216115Slstewart SCI_SAS_ADDRESS_T first_address; 215216115Slstewart SCI_SAS_ADDRESS_T second_address; 216216115Slstewart 217216115Slstewart SCIC_LOG_TRACE(( 218216115Slstewart sci_base_object_get_logger(controller), 219216115Slstewart SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 220216115Slstewart "scic_sds_port_configuration_agent_validate_ports(0x%08x, 0x%08x) enter\n", 221216115Slstewart controller, port_agent 222216115Slstewart )); 223216115Slstewart 224216115Slstewart // Sanity check the max ranges for all the phys the max index 225216115Slstewart // is always equal to the port range index 226216115Slstewart if ( 227216115Slstewart (port_agent->phy_valid_port_range[0].max_index != 0) 228216115Slstewart || (port_agent->phy_valid_port_range[1].max_index != 1) 229216115Slstewart || (port_agent->phy_valid_port_range[2].max_index != 2) 230216115Slstewart || (port_agent->phy_valid_port_range[3].max_index != 3) 231216115Slstewart ) 232216115Slstewart { 233216115Slstewart return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 234216115Slstewart } 235216115Slstewart 236216115Slstewart // This is a request to configure a single x4 port or at least attempt 237216115Slstewart // to make all the phys into a single port 238216115Slstewart if ( 239216115Slstewart (port_agent->phy_valid_port_range[0].min_index == 0) 240216115Slstewart && (port_agent->phy_valid_port_range[1].min_index == 0) 241216115Slstewart && (port_agent->phy_valid_port_range[2].min_index == 0) 242216115Slstewart && (port_agent->phy_valid_port_range[3].min_index == 0) 243216115Slstewart ) 244216115Slstewart { 245216115Slstewart return SCI_SUCCESS; 246216115Slstewart } 247216115Slstewart 248216115Slstewart // This is a degenerate case where phy 1 and phy 2 are assigned 249216115Slstewart // to the same port this is explicitly disallowed by the hardware 250216115Slstewart // unless they are part of the same x4 port and this condition was 251216115Slstewart // already checked above. 252216115Slstewart if (port_agent->phy_valid_port_range[2].min_index == 1) 253216115Slstewart { 254216115Slstewart return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 255216115Slstewart } 256216115Slstewart 257216115Slstewart // PE0 and PE3 can never have the same SAS Address unless they 258216115Slstewart // are part of the same x4 wide port and we have already checked 259216115Slstewart // for this condition. 260216115Slstewart scic_sds_phy_get_sas_address(&controller->phy_table[0], &first_address); 261216115Slstewart scic_sds_phy_get_sas_address(&controller->phy_table[3], &second_address); 262216115Slstewart 263216115Slstewart if (sci_sas_address_compare(first_address, second_address) == 0) 264216115Slstewart { 265216115Slstewart return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 266216115Slstewart } 267216115Slstewart 268216115Slstewart // PE0 and PE1 are configured into a 2x1 ports make sure that the 269216115Slstewart // SAS Address for PE0 and PE2 are different since they can not be 270216115Slstewart // part of the same port. 271216115Slstewart if ( 272216115Slstewart (port_agent->phy_valid_port_range[0].min_index == 0) 273216115Slstewart && (port_agent->phy_valid_port_range[1].min_index == 1) 274216115Slstewart ) 275216115Slstewart { 276216115Slstewart scic_sds_phy_get_sas_address(&controller->phy_table[0], &first_address); 277216115Slstewart scic_sds_phy_get_sas_address(&controller->phy_table[2], &second_address); 278216115Slstewart 279216115Slstewart if (sci_sas_address_compare(first_address, second_address) == 0) 280216115Slstewart { 281216115Slstewart return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 282216115Slstewart } 283216115Slstewart } 284216115Slstewart 285216115Slstewart // PE2 and PE3 are configured into a 2x1 ports make sure that the 286216115Slstewart // SAS Address for PE1 and PE3 are different since they can not be 287216115Slstewart // part of the same port. 288216115Slstewart if ( 289216115Slstewart (port_agent->phy_valid_port_range[2].min_index == 2) 290216115Slstewart && (port_agent->phy_valid_port_range[3].min_index == 3) 291216115Slstewart ) 292216115Slstewart { 293216115Slstewart scic_sds_phy_get_sas_address(&controller->phy_table[1], &first_address); 294216115Slstewart scic_sds_phy_get_sas_address(&controller->phy_table[3], &second_address); 295216115Slstewart 296216115Slstewart if (sci_sas_address_compare(first_address, second_address) == 0) 297216115Slstewart { 298216115Slstewart return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 299216115Slstewart } 300216115Slstewart } 301216115Slstewart#endif // !defined(ARLINGTON_BUILD) 302216115Slstewart 303216115Slstewart return SCI_SUCCESS; 304216115Slstewart} 305216115Slstewart 306216115Slstewart//****************************************************************************** 307216115Slstewart// Manual port configuration agent routines 308216115Slstewart//****************************************************************************** 309216115Slstewart 310216115Slstewart/** 311216115Slstewart * This routine will verify that all of the phys in the same port are using 312216115Slstewart * the same SAS address. 313216115Slstewart * 314216115Slstewart * @param[in] controller This is the controller that contains the PHYs to 315216115Slstewart * be verified. 316216115Slstewart */ 317216115Slstewartstatic 318216115SlstewartSCI_STATUS scic_sds_mpc_agent_validate_phy_configuration( 319216115Slstewart SCIC_SDS_CONTROLLER_T * controller, 320216115Slstewart SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 321216115Slstewart) 322216115Slstewart{ 323216115Slstewart U32 phy_mask; 324216115Slstewart U32 assigned_phy_mask; 325216115Slstewart SCI_SAS_ADDRESS_T sas_address; 326216115Slstewart SCI_SAS_ADDRESS_T phy_assigned_address; 327216115Slstewart U8 port_index; 328216115Slstewart U8 phy_index; 329216115Slstewart 330216115Slstewart assigned_phy_mask = 0; 331216115Slstewart sas_address.high = 0; 332216115Slstewart sas_address.low = 0; 333216115Slstewart 334216115Slstewart SCIC_LOG_TRACE(( 335216115Slstewart sci_base_object_get_logger(controller), 336216115Slstewart SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 337216115Slstewart "scic_sds_mpc_agent_validate_phy_configuration(0x%08x, 0x%08x) enter\n", 338216115Slstewart controller, port_agent 339216115Slstewart )); 340216115Slstewart 341216115Slstewart for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) 342216115Slstewart { 343216115Slstewart phy_mask = controller->oem_parameters.sds1.ports[port_index].phy_mask; 344216115Slstewart 345216115Slstewart if (phy_mask != 0) 346216115Slstewart { 347216115Slstewart // Make sure that one or more of the phys were not already assinged to 348216115Slstewart // a different port. 349216115Slstewart if ((phy_mask & ~assigned_phy_mask) == 0) 350216115Slstewart { 351216115Slstewart return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 352216115Slstewart } 353216115Slstewart 354216115Slstewart // Find the starting phy index for this round through the loop 355216115Slstewart for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) 356216115Slstewart { 357216115Slstewart if ((1 << phy_index) & phy_mask) 358216115Slstewart { 359216115Slstewart scic_sds_phy_get_sas_address( 360216115Slstewart &controller->phy_table[phy_index], &sas_address 361216115Slstewart ); 362216115Slstewart 363216115Slstewart // The phy_index can be used as the starting point for the 364216115Slstewart // port range since the hardware starts all logical ports 365216115Slstewart // the same as the PE index. 366216115Slstewart port_agent->phy_valid_port_range[phy_index].min_index = port_index; 367216115Slstewart port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 368216115Slstewart 369216115Slstewart if (phy_index != port_index) 370216115Slstewart { 371216115Slstewart return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 372216115Slstewart } 373216115Slstewart 374216115Slstewart break; 375216115Slstewart } 376216115Slstewart } 377216115Slstewart 378216115Slstewart // See how many additional phys are being added to this logical port. 379216115Slstewart // Note: We have not moved the current phy_index so we will actually 380216115Slstewart // compare the startting phy with itself. 381216115Slstewart // This is expected and required to add the phy to the port. 382216115Slstewart while (phy_index < SCI_MAX_PHYS) 383216115Slstewart { 384216115Slstewart if ((1 << phy_index) & phy_mask) 385216115Slstewart { 386216115Slstewart scic_sds_phy_get_sas_address( 387216115Slstewart &controller->phy_table[phy_index], &phy_assigned_address 388216115Slstewart ); 389216115Slstewart 390216115Slstewart if (sci_sas_address_compare(sas_address, phy_assigned_address) != 0) 391216115Slstewart { 392216115Slstewart // The phy mask specified that this phy is part of the same port 393216115Slstewart // as the starting phy and it is not so fail this configuration 394216115Slstewart return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 395216115Slstewart } 396216115Slstewart 397216115Slstewart port_agent->phy_valid_port_range[phy_index].min_index = port_index; 398216115Slstewart port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 399216115Slstewart 400216115Slstewart scic_sds_port_add_phy( 401216115Slstewart &controller->port_table[port_index], 402216115Slstewart &controller->phy_table[phy_index] 403216115Slstewart ); 404216115Slstewart 405216115Slstewart assigned_phy_mask |= (1 << phy_index); 406216115Slstewart } 407216115Slstewart 408216115Slstewart phy_index++; 409216115Slstewart } 410216115Slstewart } 411216115Slstewart } 412216115Slstewart 413216115Slstewart return scic_sds_port_configuration_agent_validate_ports(controller, port_agent); 414216115Slstewart} 415216115Slstewart 416216115Slstewart/** 417216115Slstewart * This timer routine is used to allow the SCI User to rediscover or change 418216115Slstewart * device objects before a new series of link up notifications because a 419216115Slstewart * link down has allowed a better port configuration. 420216115Slstewart * 421216115Slstewart * @param[in] controller This is the core controller object which is used 422216115Slstewart * to obtain the port configuration agent. 423216115Slstewart */ 424216115Slstewartstatic 425216115Slstewartvoid scic_sds_mpc_agent_timeout_handler( 426216115Slstewart void * object 427216115Slstewart) 428216115Slstewart{ 429216115Slstewart U8 index; 430216115Slstewart SCIC_SDS_CONTROLLER_T * controller = (SCIC_SDS_CONTROLLER_T *)object; 431216115Slstewart SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent = &controller->port_agent; 432216115Slstewart U16 configure_phy_mask; 433216115Slstewart 434216115Slstewart SCIC_LOG_TRACE(( 435216115Slstewart sci_base_object_get_logger(controller), 436216115Slstewart SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 437216115Slstewart "scic_sds_mpc_agent_timeout_handler(0x%08x) enter\n", 438216115Slstewart controller 439216115Slstewart )); 440216115Slstewart 441216115Slstewart port_agent->timer_pending = FALSE; 442216115Slstewart 443216115Slstewart // Find the mask of phys that are reported read but as yet unconfigured into a port 444216115Slstewart configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask; 445216115Slstewart 446216115Slstewart for (index = 0; index < SCI_MAX_PHYS; index++) 447216115Slstewart { 448216115Slstewart if (configure_phy_mask & (1 << index)) 449216115Slstewart { 450216115Slstewart port_agent->link_up_handler( 451216115Slstewart controller, 452216115Slstewart port_agent, 453216115Slstewart scic_sds_phy_get_port(&controller->phy_table[index]), 454216115Slstewart &controller->phy_table[index] 455216115Slstewart ); 456216115Slstewart } 457216115Slstewart } 458216115Slstewart} 459216115Slstewart 460216115Slstewart/** 461216115Slstewart * This method handles the manual port configuration link up notifications. 462216115Slstewart * Since all ports and phys are associate at initialization time we just turn 463216115Slstewart * around and notifiy the port object that there is a link up. If this PHY is 464216115Slstewart * not associated with a port there is no action taken. 465216115Slstewart * 466216115Slstewart * @param[in] controller This is the controller object that receives the 467216115Slstewart * link up notification. 468216115Slstewart * @param[in] port This is the port object associated with the phy. If the 469216115Slstewart * is no associated port this is an SCI_INVALID_HANDLE. 470216115Slstewart * @param[in] phy This is the phy object which has gone ready. 471216115Slstewart * 472216115Slstewart * @note Is it possible to get a link up notification from a phy that has 473216115Slstewart * no assocoated port? 474216115Slstewart */ 475216115Slstewartstatic 476216115Slstewartvoid scic_sds_mpc_agent_link_up( 477216115Slstewart SCIC_SDS_CONTROLLER_T * controller, 478216115Slstewart SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 479216115Slstewart SCIC_SDS_PORT_T * port, 480216115Slstewart SCIC_SDS_PHY_T * phy 481216115Slstewart) 482216115Slstewart{ 483216115Slstewart SCIC_LOG_TRACE(( 484216115Slstewart sci_base_object_get_logger(controller), 485216115Slstewart SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 486216115Slstewart "scic_sds_mpc_agent_link_up(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 487216115Slstewart controller, port_agent, port, phy 488216115Slstewart )); 489216115Slstewart 490216115Slstewart // If the port has an invalid handle then the phy was not assigned to 491216115Slstewart // a port. This is because the phy was not given the same SAS Address 492216115Slstewart // as the other PHYs in the port. 493216115Slstewart if (port != SCI_INVALID_HANDLE) 494216115Slstewart { 495216115Slstewart port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy)); 496216115Slstewart 497216115Slstewart scic_sds_port_link_up(port, phy); 498216115Slstewart 499216115Slstewart if ((port->active_phy_mask & (1 << scic_sds_phy_get_index(phy))) != 0) 500216115Slstewart { 501216115Slstewart port_agent->phy_configured_mask |= (1 << scic_sds_phy_get_index(phy)); 502216115Slstewart } 503216115Slstewart } 504216115Slstewart} 505216115Slstewart 506216115Slstewart/** 507216115Slstewart * This method handles the manual port configuration link down notifications. 508216115Slstewart * Since all ports and phys are associated at initialization time we just turn 509216115Slstewart * around and notifiy the port object of the link down event. If this PHY is 510216115Slstewart * not associated with a port there is no action taken. 511216115Slstewart * 512216115Slstewart * @param[in] controller This is the controller object that receives the 513216115Slstewart * link down notification. 514216115Slstewart * @param[in] port This is the port object associated with the phy. If the 515216115Slstewart * is no associated port this is an SCI_INVALID_HANDLE. The port 516216115Slstewart * is an invalid handle only if the phy was never port of this 517216115Slstewart * port. This happens when the phy is not broadcasting the same 518216115Slstewart * SAS address as the other phys in the assigned port. 519216115Slstewart * @param[in] phy This is the phy object which has gone link down. 520216115Slstewart * 521216115Slstewart * @note Is it possible to get a link down notification from a phy that has 522 * no assocoated port? 523 */ 524static 525void scic_sds_mpc_agent_link_down( 526 SCIC_SDS_CONTROLLER_T * controller, 527 SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 528 SCIC_SDS_PORT_T * port, 529 SCIC_SDS_PHY_T * phy 530) 531{ 532 SCIC_LOG_TRACE(( 533 sci_base_object_get_logger(controller), 534 SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 535 "scic_sds_mpc_agent_link_down(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 536 controller, port_agent, port, phy 537 )); 538 539 if (port != SCI_INVALID_HANDLE) 540 { 541 // If we can form a new port from the remainder of the phys then we want 542 // to start the timer to allow the SCI User to cleanup old devices and 543 // rediscover the port before rebuilding the port with the phys that 544 // remain in the ready state. 545 port_agent->phy_ready_mask &= ~(1 << scic_sds_phy_get_index(phy)); 546 port_agent->phy_configured_mask &= ~(1 << scic_sds_phy_get_index(phy)); 547 548 // Check to see if there are more phys waiting to be configured into a port. 549 // If there are allow the SCI User to tear down this port, if necessary, and 550 // then reconstruc the port after the timeout. 551 if ( 552 (port_agent->phy_configured_mask == 0x0000) 553 && (port_agent->phy_ready_mask != 0x0000) 554 && !port_agent->timer_pending 555 ) 556 { 557 port_agent->timer_pending = TRUE; 558 559 scic_cb_timer_start( 560 controller, 561 port_agent->timer, 562 SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT 563 ); 564 } 565 566 scic_sds_port_link_down(port, phy); 567 } 568} 569 570//****************************************************************************** 571// Automatic port configuration agent routines 572//****************************************************************************** 573 574/** 575 * This routine will verify that the phys are assigned a valid SAS address for 576 * automatic port configuration mode. 577 */ 578static 579SCI_STATUS scic_sds_apc_agent_validate_phy_configuration( 580 SCIC_SDS_CONTROLLER_T * controller, 581 SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 582) 583{ 584 U8 phy_index; 585 U8 port_index; 586 SCI_SAS_ADDRESS_T sas_address; 587 SCI_SAS_ADDRESS_T phy_assigned_address; 588 589 SCIC_LOG_TRACE(( 590 sci_base_object_get_logger(controller), 591 SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 592 "scic_sds_apc_agent_validate_phy_configuration(0x%08x, 0x%08x) enter\n", 593 controller, port_agent 594 )); 595 596 phy_index = 0; 597 598 while (phy_index < SCI_MAX_PHYS) 599 { 600 port_index = phy_index; 601 602 // Get the assigned SAS Address for the first PHY on the controller. 603 scic_sds_phy_get_sas_address( 604 &controller->phy_table[phy_index], &sas_address 605 ); 606 607 while (++phy_index < SCI_MAX_PHYS) 608 { 609 scic_sds_phy_get_sas_address( 610 &controller->phy_table[phy_index], &phy_assigned_address 611 ); 612 613 // Verify each of the SAS address are all the same for every PHY 614 if (sci_sas_address_compare(sas_address, phy_assigned_address) == 0) 615 { 616 port_agent->phy_valid_port_range[phy_index].min_index = port_index; 617 port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 618 } 619 else 620 { 621 port_agent->phy_valid_port_range[phy_index].min_index = phy_index; 622 port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 623 break; 624 } 625 } 626 } 627 628 return scic_sds_port_configuration_agent_validate_ports(controller, port_agent); 629} 630 631/** 632 * This routine will restart the automatic port configuration timeout 633 * timer for the next time period. This could be caused by either a 634 * link down event or a link up event where we can not yet tell to which 635 * port a phy belongs. 636 * 637 * @param[in] controller This is the controller that to which the port 638 * agent is assigned. 639 * @param[in] port_agent This is the port agent that is requesting the 640 * timer start operation. 641 * @param[in] phy This is the phy that has caused the timer operation to 642 * be scheduled. 643 * @param[in] timeout This is the timeout in ms. 644 */ 645static 646void scic_sds_apc_agent_start_timer( 647 SCIC_SDS_CONTROLLER_T * controller, 648 SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 649 SCIC_SDS_PHY_T * phy, 650 U32 timeout 651) 652{ 653 SCIC_LOG_TRACE(( 654 sci_base_object_get_logger(controller), 655 SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 656 "scic_sds_apc_agent_start_timer(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 657 controller, port_agent, phy, timeout 658 )); 659 660 if (port_agent->timer_pending) 661 { 662 scic_cb_timer_stop(controller, port_agent->timer); 663 } 664 665 port_agent->timer_pending = TRUE; 666 667 scic_cb_timer_start(controller, port_agent->timer, timeout); 668} 669 670/** 671 * This method handles the automatic port configuration for link up notifications. 672 * 673 * @param[in] controller This is the controller object that receives the 674 * link up notification. 675 * @param[in] phy This is the phy object which has gone link up. 676 * @param[in] start_timer This tells the routine if it should start the timer for 677 * any phys that might be added to a port in the future. 678 */ 679static 680void scic_sds_apc_agent_configure_ports( 681 SCIC_SDS_CONTROLLER_T * controller, 682 SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 683 SCIC_SDS_PHY_T * phy, 684 BOOL start_timer 685) 686{ 687 U8 port_index; 688 SCI_STATUS status; 689 SCIC_SDS_PORT_T * port; 690 SCI_PORT_HANDLE_T port_handle; 691 enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY; 692 693 SCIC_LOG_TRACE(( 694 sci_base_object_get_logger(controller), 695 SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 696 "scic_sds_apc_agent_configure_ports(0x%08x, 0x%08x, 0x%08x, %d) enter\n", 697 controller, port_agent, phy, start_timer 698 )); 699 700 port = scic_sds_port_configuration_agent_find_port(controller, phy); 701 702 if (port != SCI_INVALID_HANDLE) 703 { 704 if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)) 705 apc_activity = SCIC_SDS_APC_ADD_PHY; 706 else 707 apc_activity = SCIC_SDS_APC_SKIP_PHY; 708 } 709 else 710 { 711 // There is no matching Port for this PHY so lets search through the 712 // Ports and see if we can add the PHY to its own port or maybe start 713 // the timer and wait to see if a wider port can be made. 714 // 715 // Note the break when we reach the condition of the port id == phy id 716 for ( 717 port_index = port_agent->phy_valid_port_range[phy->phy_index].min_index; 718 port_index <= port_agent->phy_valid_port_range[phy->phy_index].max_index; 719 port_index++ 720 ) 721 { 722 scic_controller_get_port_handle(controller, port_index, &port_handle); 723 724 port = (SCIC_SDS_PORT_T *)port_handle; 725 726 // First we must make sure that this PHY can be added to this Port. 727 if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)) 728 { 729 // Port contains a PHY with a greater PHY ID than the current 730 // PHY that has gone link up. This phy can not be part of any 731 // port so skip it and move on. 732 if (port->active_phy_mask > (1 << phy->phy_index)) 733 { 734 apc_activity = SCIC_SDS_APC_SKIP_PHY; 735 break; 736 } 737 738 // We have reached the end of our Port list and have not found 739 // any reason why we should not either add the PHY to the port 740 // or wait for more phys to become active. 741 if (port->physical_port_index == phy->phy_index) 742 { 743 // The Port either has no active PHYs. 744 // Consider that if the port had any active PHYs we would have 745 // or active PHYs with 746 // a lower PHY Id than this PHY. 747 if (apc_activity != SCIC_SDS_APC_START_TIMER) 748 { 749 apc_activity = SCIC_SDS_APC_ADD_PHY; 750 } 751 752 break; 753 } 754 755 // The current Port has no active PHYs and this PHY could be part 756 // of this Port. Since we dont know as yet setup to start the 757 // timer and see if there is a better configuration. 758 if (port->active_phy_mask == 0) 759 { 760 apc_activity = SCIC_SDS_APC_START_TIMER; 761 } 762 } 763 else if (port->active_phy_mask != 0) 764 { 765 // The Port has an active phy and the current Phy can not 766 // participate in this port so skip the PHY and see if 767 // there is a better configuration. 768 apc_activity = SCIC_SDS_APC_SKIP_PHY; 769 } 770 } 771 } 772 773 // Check to see if the start timer operations should instead map to an 774 // add phy operation. This is caused because we have been waiting to 775 // add a phy to a port but could not becuase the automatic port 776 // configuration engine had a choice of possible ports for the phy. 777 // Since we have gone through a timeout we are going to restrict the 778 // choice to the smallest possible port. 779 if ( 780 (start_timer == FALSE) 781 && (apc_activity == SCIC_SDS_APC_START_TIMER) 782 ) 783 { 784 apc_activity = SCIC_SDS_APC_ADD_PHY; 785 } 786 787 switch (apc_activity) 788 { 789 case SCIC_SDS_APC_ADD_PHY: 790 status = scic_sds_port_add_phy(port, phy); 791 792 if (status == SCI_SUCCESS) 793 { 794 port_agent->phy_configured_mask |= (1 << phy->phy_index); 795 } 796 break; 797 798 case SCIC_SDS_APC_START_TIMER: 799 scic_sds_apc_agent_start_timer( 800 controller, port_agent, phy, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION 801 ); 802 break; 803 804 case SCIC_SDS_APC_SKIP_PHY: 805 default: 806 // do nothing the PHY can not be made part of a port at this time. 807 break; 808 } 809} 810 811/** 812 * This method handles the automatic port configuration for link up notifications. 813 * 814 * @param[in] controller This is the controller object that receives the 815 * link up notification. 816 * @param[in] port This is the port object associated with the phy. If the 817 * is no associated port this is an SCI_INVALID_HANDLE. 818 * @param[in] phy This is the phy object which has gone link up. 819 * 820 * @note Is it possible to get a link down notification from a phy that has 821 * no assocoated port? 822 */ 823static 824void scic_sds_apc_agent_link_up( 825 SCIC_SDS_CONTROLLER_T * controller, 826 SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 827 SCIC_SDS_PORT_T * port, 828 SCIC_SDS_PHY_T * phy 829) 830{ 831 SCIC_LOG_TRACE(( 832 sci_base_object_get_logger(controller), 833 SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 834 "scic_sds_apc_agent_link_up(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 835 controller, port_agent, port, phy 836 )); 837 838 //the phy is not the part of this port, configure the port with this phy 839 if (port == SCI_INVALID_HANDLE) 840 { 841 port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy)); 842 843 scic_sds_apc_agent_start_timer( 844 controller, port_agent, phy, SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION 845 ); 846 } 847 else 848 { 849 //the phy is already the part of the port 850 851 //if the PORT'S state is resetting then the link up is from port hard reset 852 //in this case, we need to tell the port that link up is recieved 853 if ( SCI_BASE_PORT_STATE_RESETTING 854 == port->parent.state_machine.current_state_id 855 ) 856 { 857 //notify the port that port needs to be ready 858 port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy)); 859 scic_sds_port_link_up(port, phy); 860 } 861 else 862 { 863 ASSERT (0); 864 } 865 } 866} 867 868/** 869 * This method handles the automatic port configuration link down notifications. 870 * If this PHY is * not associated with a port there is no action taken. 871 * 872 * @param[in] controller This is the controller object that receives the 873 * link down notification. 874 * @param[in] port This is the port object associated with the phy. If the 875 * is no associated port this is an SCI_INVALID_HANDLE. 876 * @param[in] phy This is the phy object which has gone link down. 877 * 878 * @note Is it possible to get a link down notification from a phy that has 879 * no assocoated port? 880 */ 881static 882void scic_sds_apc_agent_link_down( 883 SCIC_SDS_CONTROLLER_T * controller, 884 SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent, 885 SCIC_SDS_PORT_T * port, 886 SCIC_SDS_PHY_T * phy 887) 888{ 889 SCIC_LOG_TRACE(( 890 sci_base_object_get_logger(controller), 891 SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_PHY, 892 "scic_sds_apc_agent_link_down(0x%08x, 0x%08x, 0x%08x, 0x%08x) enter\n", 893 controller, port_agent, port, phy 894 )); 895 896 port_agent->phy_ready_mask &= ~(1 << scic_sds_phy_get_index(phy)); 897 898 if (port != SCI_INVALID_HANDLE) 899 { 900 if (port_agent->phy_configured_mask & (1 << phy->phy_index)) 901 { 902 SCI_STATUS status; 903 904 status = scic_sds_port_remove_phy(port, phy); 905 906 if (status == SCI_SUCCESS) 907 { 908 port_agent->phy_configured_mask &= ~(1 << phy->phy_index); 909 } 910 } 911 } 912} 913 914/** 915 * This routine will try to configure the phys into ports when the timer fires. 916 * 917 * @param[in] object This is actually the controller that needs to have the 918 * pending phys configured. 919 */ 920static 921void scic_sds_apc_agent_timeout_handler( 922 void * object 923) 924{ 925 U32 index; 926 SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent; 927 SCIC_SDS_CONTROLLER_T * controller = (SCIC_SDS_CONTROLLER_T *)object; 928 U16 configure_phy_mask; 929 930 port_agent = scic_sds_controller_get_port_configuration_agent(controller); 931 932 SCIC_LOG_TRACE(( 933 sci_base_object_get_logger(controller), 934 SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 935 "scic_sds_apc_agent_timeout_handler(0x%08x) enter\n", 936 controller 937 )); 938 939 port_agent->timer_pending = FALSE; 940 941 configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask; 942 943 if (configure_phy_mask != 0x00) 944 { 945 for (index = 0; index < SCI_MAX_PHYS; index++) 946 { 947 if (configure_phy_mask & (1 << index)) 948 { 949 scic_sds_apc_agent_configure_ports( 950 controller, port_agent, &controller->phy_table[index], FALSE 951 ); 952 } 953 } 954 955 //Notify the controller ports are configured. 956 if ( 957 (port_agent->phy_ready_mask == port_agent->phy_configured_mask) && 958 (controller->next_phy_to_start == SCI_MAX_PHYS) && 959 (controller->phy_startup_timer_pending == FALSE) 960 ) 961 { 962 // The controller has successfully finished the start process. 963 // Inform the SCI Core user and transition to the READY state. 964 if (scic_sds_controller_is_start_complete(controller) == TRUE) 965 { 966 scic_sds_controller_port_agent_configured_ports(controller); 967 } 968 } 969 } 970} 971 972//****************************************************************************** 973// Public port configuration agent routines 974//****************************************************************************** 975 976/** 977 * This method will construct the port configuration agent for operation. 978 * This call is universal for both manual port configuration and automatic 979 * port configuration modes. 980 * 981 * @param[in] port_agent This is the port configuration agent for this 982 * controller object. 983 */ 984void scic_sds_port_configuration_agent_construct( 985 SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 986) 987{ 988 U32 index; 989 990 port_agent->phy_configured_mask = 0x00; 991 port_agent->phy_ready_mask = 0x00; 992 993 port_agent->link_up_handler = NULL; 994 port_agent->link_down_handler = NULL; 995 996 port_agent->timer_pending = FALSE; 997 port_agent->timer = NULL; 998 999 for (index = 0; index < SCI_MAX_PORTS; index++) 1000 { 1001 port_agent->phy_valid_port_range[index].min_index = 0; 1002 port_agent->phy_valid_port_range[index].max_index = 0; 1003 } 1004} 1005 1006/** 1007 * This method will construct the port configuration agent for this controller. 1008 * 1009 * @param[in] controller This is the controller object for which the port 1010 * agent is being initialized. 1011 * 1012 * @param[in] port_agent This is the port configuration agent that is being 1013 * initialized. The initialization path is handled differntly 1014 * for the automatic port configuration agent and the manual port 1015 * configuration agent. 1016 * 1017 * @return 1018 */ 1019SCI_STATUS scic_sds_port_configuration_agent_initialize( 1020 SCIC_SDS_CONTROLLER_T * controller, 1021 SCIC_SDS_PORT_CONFIGURATION_AGENT_T * port_agent 1022) 1023{ 1024 SCI_STATUS status = SCI_SUCCESS; 1025 enum SCIC_PORT_CONFIGURATION_MODE mode; 1026 1027 SCIC_LOG_TRACE(( 1028 sci_base_object_get_logger(controller), 1029 SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT, 1030 "scic_sds_port_configuration_agent_initialize(0x%08x, 0x%08x) enter\n", 1031 controller, port_agent 1032 )); 1033 1034 mode = controller->oem_parameters.sds1.controller.mode_type; 1035 1036 if (mode == SCIC_PORT_MANUAL_CONFIGURATION_MODE) 1037 { 1038 status = scic_sds_mpc_agent_validate_phy_configuration(controller, port_agent); 1039 1040 port_agent->link_up_handler = scic_sds_mpc_agent_link_up; 1041 port_agent->link_down_handler = scic_sds_mpc_agent_link_down; 1042 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