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