scic_sds_phy.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3 *
4 * This file is provided under a dual BSD/GPLv2 license.  When using or
5 * redistributing this file, you may do so under either license.
6 *
7 * GPL LICENSE SUMMARY
8 *
9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23 * The full GNU General Public License is included in this distribution
24 * in the file called LICENSE.GPL.
25 *
26 * BSD LICENSE
27 *
28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 *
35 *   * Redistributions of source code must retain the above copyright
36 *     notice, this list of conditions and the following disclaimer.
37 *   * Redistributions in binary form must reproduce the above copyright
38 *     notice, this list of conditions and the following disclaimer in
39 *     the documentation and/or other materials provided with the
40 *     distribution.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 */
54
55#include <sys/cdefs.h>
56__FBSDID("$FreeBSD: stable/11/sys/dev/isci/scil/scic_sds_phy.c 330897 2018-03-14 03:19:51Z eadler $");
57
58/**
59 * @file
60 *
61 * @brief This file contains the implementation of the SCIC_SDS_PHY public and
62 *        protected methods.
63 */
64
65#include <dev/isci/scil/scic_user_callback.h>
66#include <dev/isci/scil/scic_phy.h>
67#include <dev/isci/scil/scic_sds_phy.h>
68#include <dev/isci/scil/scic_sds_port.h>
69#include <dev/isci/scil/scic_sds_controller_registers.h>
70#include <dev/isci/scil/scic_sds_phy_registers.h>
71#include <dev/isci/scil/scic_sds_logger.h>
72#include <dev/isci/scil/scic_sds_remote_node_context.h>
73#include <dev/isci/scil/sci_util.h>
74#include <dev/isci/scil/scic_sds_controller.h>
75#include <dev/isci/scil/scu_event_codes.h>
76#include <dev/isci/scil/sci_base_state.h>
77#include <dev/isci/scil/intel_ata.h>
78#include <dev/isci/scil/intel_sata.h>
79#include <dev/isci/scil/sci_base_state_machine.h>
80#include <dev/isci/scil/scic_sds_port_registers.h>
81
82#define SCIC_SDS_PHY_MIN_TIMER_COUNT  (SCI_MAX_PHYS)
83#define SCIC_SDS_PHY_MAX_TIMER_COUNT  (SCI_MAX_PHYS)
84
85// Maximum arbitration wait time in micro-seconds
86#define SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME  (700)
87
88#define AFE_REGISTER_WRITE_DELAY 10
89
90//*****************************************************************************
91//* SCIC SDS PHY Internal Methods
92//*****************************************************************************
93
94/**
95 * @brief This method will initialize the phy transport layer registers
96 *
97 * @param[in] this_phy
98 * @param[in] transport_layer_registers
99 *
100 * @return SCI_STATUS
101 */
102static
103SCI_STATUS scic_sds_phy_transport_layer_initialization(
104   SCIC_SDS_PHY_T                  *this_phy,
105   SCU_TRANSPORT_LAYER_REGISTERS_T *transport_layer_registers
106)
107{
108   U32 tl_control;
109
110   SCIC_LOG_TRACE((
111      sci_base_object_get_logger(this_phy),
112      SCIC_LOG_OBJECT_PHY,
113      "scic_sds_phy_link_layer_initialization(this_phy:0x%x, link_layer_registers:0x%x)\n",
114      this_phy, transport_layer_registers
115   ));
116
117   this_phy->transport_layer_registers = transport_layer_registers;
118
119   SCU_STPTLDARNI_WRITE(this_phy, SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX);
120
121   // Hardware team recommends that we enable the STP prefetch for all transports
122   tl_control = SCU_TLCR_READ(this_phy);
123   tl_control |= SCU_TLCR_GEN_BIT(STP_WRITE_DATA_PREFETCH);
124   SCU_TLCR_WRITE(this_phy, tl_control);
125
126   return SCI_SUCCESS;
127}
128
129/**
130 * @brief This method will initialize the phy link layer registers
131 *
132 * @param[in] this_phy
133 * @param[in] link_layer_registers
134 *
135 * @return SCI_STATUS
136 */
137static
138SCI_STATUS scic_sds_phy_link_layer_initialization(
139   SCIC_SDS_PHY_T             *this_phy,
140   SCU_LINK_LAYER_REGISTERS_T *link_layer_registers
141)
142{
143   U32                phy_configuration;
144   SAS_CAPABILITIES_T phy_capabilities;
145   U32                parity_check = 0;
146   U32                parity_count = 0;
147   U32                link_layer_control;
148   U32                phy_timer_timeout_values;
149   U32                clksm_value = 0;
150
151   SCIC_LOG_TRACE((
152      sci_base_object_get_logger(this_phy),
153      SCIC_LOG_OBJECT_PHY,
154      "scic_sds_phy_link_layer_initialization(this_phy:0x%x, link_layer_registers:0x%x)\n",
155      this_phy, link_layer_registers
156   ));
157
158   this_phy->link_layer_registers = link_layer_registers;
159
160   // Set our IDENTIFY frame data
161   #define SCI_END_DEVICE 0x01
162
163   SCU_SAS_TIID_WRITE(
164      this_phy,
165      (   SCU_SAS_TIID_GEN_BIT(SMP_INITIATOR)
166        | SCU_SAS_TIID_GEN_BIT(SSP_INITIATOR)
167        | SCU_SAS_TIID_GEN_BIT(STP_INITIATOR)
168        | SCU_SAS_TIID_GEN_BIT(DA_SATA_HOST)
169        | SCU_SAS_TIID_GEN_VAL(DEVICE_TYPE, SCI_END_DEVICE) )
170      );
171
172   // Write the device SAS Address
173   SCU_SAS_TIDNH_WRITE(this_phy, 0xFEDCBA98);
174   SCU_SAS_TIDNL_WRITE(this_phy, this_phy->phy_index);
175
176   // Write the source SAS Address
177   SCU_SAS_TISSAH_WRITE(
178      this_phy,
179      this_phy->owning_port->owning_controller->oem_parameters.sds1.phys[
180          this_phy->phy_index].sas_address.sci_format.high
181   );
182   SCU_SAS_TISSAL_WRITE(
183      this_phy,
184      this_phy->owning_port->owning_controller->oem_parameters.sds1.phys[
185          this_phy->phy_index].sas_address.sci_format.low
186   );
187
188   // Clear and Set the PHY Identifier
189   SCU_SAS_TIPID_WRITE(this_phy, 0x00000000);
190   SCU_SAS_TIPID_WRITE(this_phy, SCU_SAS_TIPID_GEN_VALUE(ID, this_phy->phy_index));
191
192   // Change the initial state of the phy configuration register
193   phy_configuration = SCU_SAS_PCFG_READ(this_phy);
194
195   // Hold OOB state machine in reset
196   phy_configuration |=  SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
197   SCU_SAS_PCFG_WRITE(this_phy, phy_configuration);
198
199   // Configure the SNW capabilities
200   phy_capabilities.u.all = 0;
201   phy_capabilities.u.bits.start                      = 1;
202   phy_capabilities.u.bits.gen3_without_ssc_supported = 1;
203   phy_capabilities.u.bits.gen2_without_ssc_supported = 1;
204   phy_capabilities.u.bits.gen1_without_ssc_supported = 1;
205
206   /*
207    * Set up SSC settings according to version of OEM Parameters.
208    */
209   {
210       U8 header_version, enable_sata, enable_sas,
211          sata_spread, sas_type, sas_spread;
212       OEM_SSC_PARAMETERS_T ssc;
213
214       header_version = this_phy->owning_port->owning_controller->
215                        oem_parameters_version;
216
217       ssc.bf.ssc_sata_tx_spread_level =
218          this_phy->owning_port->owning_controller->oem_parameters.sds1.controller.ssc_sata_tx_spread_level;
219       ssc.bf.ssc_sas_tx_spread_level =
220          this_phy->owning_port->owning_controller->oem_parameters.sds1.controller.ssc_sas_tx_spread_level;
221       ssc.bf.ssc_sas_tx_type =
222          this_phy->owning_port->owning_controller->oem_parameters.sds1.controller.ssc_sas_tx_type;
223       enable_sata = enable_sas = sata_spread = sas_type = sas_spread = 0;
224
225       if (header_version == SCI_OEM_PARAM_VER_1_0)
226       {
227           /*
228            * Version 1.0 is merely turning SSC on to default values.;
229            */
230           if (ssc.do_enable_ssc != 0)
231           {
232               enable_sas = enable_sata = TRUE;
233               sas_type = 0x0;      // Downspreading
234               sata_spread = 0x2;   // +0 to -1419 PPM
235               sas_spread = 0x2;    // +0 to -1419 PPM
236           }
237       }
238       else // header_version >= SCI_OEM_PARAM_VER_1_1
239       {
240          /*
241           * Version 1.1 can turn on SAS and SATA independently and
242           * specify spread levels. Also can specify spread type for SAS.
243           */
244          if ((sata_spread = ssc.bf.ssc_sata_tx_spread_level) != 0)
245             enable_sata = TRUE;  // Downspreading only
246          if ((sas_spread = ssc.bf.ssc_sas_tx_spread_level) != 0)
247          {
248             enable_sas = TRUE;
249             sas_type = ssc.bf.ssc_sas_tx_type;
250          }
251       }
252
253       if (enable_sas == TRUE)
254       {
255           U32 reg_val = scu_afe_register_read(
256                             this_phy->owning_port->owning_controller,
257                             scu_afe_xcvr[this_phy->phy_index].
258                             afe_xcvr_control0);
259           reg_val |= (0x00100000 | (((U32)sas_type) << 19));
260           scu_afe_register_write(
261               this_phy->owning_port->owning_controller,
262               scu_afe_xcvr[this_phy->phy_index].afe_xcvr_control0,
263               reg_val);
264
265           reg_val = scu_afe_register_read(
266                             this_phy->owning_port->owning_controller,
267                             scu_afe_xcvr[this_phy->phy_index].
268                             afe_tx_ssc_control);
269           reg_val |= (((U32)(sas_spread)) << 8);
270           scu_afe_register_write(
271               this_phy->owning_port->owning_controller,
272               scu_afe_xcvr[this_phy->phy_index].afe_tx_ssc_control,
273               reg_val);
274      phy_capabilities.u.bits.gen3_with_ssc_supported = 1;
275      phy_capabilities.u.bits.gen2_with_ssc_supported = 1;
276      phy_capabilities.u.bits.gen1_with_ssc_supported = 1;
277   }
278
279       if (enable_sata == TRUE)
280       {
281           U32 reg_val = scu_afe_register_read(
282                         this_phy->owning_port->owning_controller,
283                         scu_afe_xcvr[this_phy->phy_index].
284                         afe_tx_ssc_control);
285           reg_val |= (U32)sata_spread;
286           scu_afe_register_write(
287               this_phy->owning_port->owning_controller,
288               scu_afe_xcvr[this_phy->phy_index].afe_tx_ssc_control,
289               reg_val);
290
291           reg_val = scu_link_layer_register_read(
292                         this_phy,
293                         stp_control);
294           reg_val |= (U32)(1 << 12);
295           scu_link_layer_register_write(
296               this_phy,
297               stp_control,
298               reg_val);
299       }
300   }
301
302   // The SAS specification indicates that the phy_capabilities that
303   // are transmitted shall have an even parity.  Calculate the parity.
304   parity_check = phy_capabilities.u.all;
305   while (parity_check != 0)
306   {
307      if (parity_check & 0x1)
308         parity_count++;
309      parity_check >>= 1;
310   }
311
312   // If parity indicates there are an odd number of bits set, then
313   // set the parity bit to 1 in the phy capabilities.
314   if ((parity_count % 2) != 0)
315      phy_capabilities.u.bits.parity = 1;
316
317   SCU_SAS_PHYCAP_WRITE(this_phy, phy_capabilities.u.all);
318
319   // Set the enable spinup period but disable the ability to send notify enable spinup
320   SCU_SAS_ENSPINUP_WRITE(
321     this_phy,
322     SCU_ENSPINUP_GEN_VAL(
323        COUNT,
324        this_phy->owning_port->owning_controller->user_parameters.sds1.
325           phys[this_phy->phy_index].notify_enable_spin_up_insertion_frequency
326     )
327   );
328
329   // Write the ALIGN Insertion Ferequency for connected phy and inpendent of connected state
330   clksm_value = SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL (
331                     CONNECTED,
332                     this_phy->owning_port->owning_controller->user_parameters.sds1.
333                        phys[this_phy->phy_index].in_connection_align_insertion_frequency
334                 );
335
336   clksm_value |= SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL (
337                     GENERAL,
338                     this_phy->owning_port->owning_controller->user_parameters.sds1.
339                        phys[this_phy->phy_index].align_insertion_frequency
340                  );
341
342   SCU_SAS_CLKSM_WRITE ( this_phy, clksm_value);
343
344
345#if defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD) || defined(PBG_HBA_BETA_BUILD)
346   /// @todo Provide a way to write this register correctly
347   scu_link_layer_register_write(this_phy, afe_lookup_table_control, 0x02108421);
348#elif defined(PBG_BUILD)
349   if (
350         (this_phy->owning_port->owning_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
351      || (this_phy->owning_port->owning_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
352      )
353   {
354      scu_link_layer_register_write(this_phy, afe_lookup_table_control, 0x04210400);
355      scu_link_layer_register_write(this_phy, sas_primitive_timeout, 0x20A7C05);
356   }
357   else
358   {
359      scu_link_layer_register_write(this_phy, afe_lookup_table_control, 0x02108421);
360   }
361#else
362   /// @todo Provide a way to write this register correctly
363   scu_link_layer_register_write(this_phy, afe_lookup_table_control, 0x0e739ce7);
364#endif
365
366   link_layer_control = SCU_SAS_LLCTL_GEN_VAL(
367                           NO_OUTBOUND_TASK_TIMEOUT,
368                           (U8) this_phy->owning_port->owning_controller->
369                           user_parameters.sds1.no_outbound_task_timeout
370                        );
371
372#if PHY_MAX_LINK_SPEED_GENERATION == SCIC_SDS_PARM_GEN1_SPEED
373#define COMPILED_MAX_LINK_RATE SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1
374#elif PHY_MAX_LINK_SPEED_GENERATION == SCIC_SDS_PARM_GEN2_SPEED
375#define COMPILED_MAX_LINK_RATE SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2
376#else
377#define COMPILED_MAX_LINK_RATE SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN3
378#endif // PHY_MAX_LINK_SPEED_GENERATION
379
380   if (this_phy->owning_port->owning_controller->user_parameters.sds1.
381       phys[this_phy->phy_index].max_speed_generation == SCIC_SDS_PARM_GEN3_SPEED)
382   {
383      link_layer_control |= SCU_SAS_LLCTL_GEN_VAL(
384                               MAX_LINK_RATE, COMPILED_MAX_LINK_RATE
385                            );
386   }
387   else if (this_phy->owning_port->owning_controller->user_parameters.sds1.
388       phys[this_phy->phy_index].max_speed_generation == SCIC_SDS_PARM_GEN2_SPEED)
389   {
390      link_layer_control |= SCU_SAS_LLCTL_GEN_VAL(
391                               MAX_LINK_RATE,
392                               MIN(
393                                  SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2,
394                                  COMPILED_MAX_LINK_RATE)
395                            );
396   }
397   else
398   {
399      link_layer_control |= SCU_SAS_LLCTL_GEN_VAL(
400                               MAX_LINK_RATE,
401                               MIN(
402                                  SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1,
403                                  COMPILED_MAX_LINK_RATE)
404                            );
405   }
406
407   scu_link_layer_register_write(
408      this_phy, link_layer_control, link_layer_control
409   );
410
411   phy_timer_timeout_values = scu_link_layer_register_read(
412                                 this_phy,
413                                 phy_timer_timeout_values
414                              );
415
416   // Clear the default 0x36 (54us) RATE_CHANGE timeout value.
417   phy_timer_timeout_values &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF);
418
419   // Set RATE_CHANGE timeout value to 0x3B (59us).  This ensures SCU can
420   //  lock with 3Gb drive when SCU max rate is set to 1.5Gb.
421   phy_timer_timeout_values |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B);
422
423   scu_link_layer_register_write(
424      this_phy, phy_timer_timeout_values, phy_timer_timeout_values
425   );
426
427   // Program the max ARB time for the PHY to 700us so we inter-operate with
428   // the PMC expander which shuts down PHYs if the expander PHY generates too
429   // many breaks.  This time value will guarantee that the initiator PHY will
430   // generate the break.
431#if defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD)
432   scu_link_layer_register_write(
433      this_phy,
434      maximum_arbitration_wait_timer_timeout,
435      SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME
436   );
437#endif // defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD)
438
439   // Disable the link layer hang detection timer
440   scu_link_layer_register_write(
441      this_phy, link_layer_hang_detection_timeout, 0x00000000
442   );
443
444   // We can exit the initial state to the stopped state
445   sci_base_state_machine_change_state(
446      scic_sds_phy_get_base_state_machine(this_phy),
447      SCI_BASE_PHY_STATE_STOPPED
448   );
449
450   return SCI_SUCCESS;
451}
452
453/**
454 * This function will handle the sata SIGNATURE FIS timeout condition.  It
455 * will restart the starting substate machine since we dont know what has
456 * actually happening.
457 *
458 * @param[in] cookie This object is cast to the SCIC_SDS_PHY_T object.
459 *
460 * @return none
461 */
462void scic_sds_phy_sata_timeout( SCI_OBJECT_HANDLE_T cookie)
463{
464   SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)cookie;
465
466   SCIC_LOG_INFO((
467      sci_base_object_get_logger(this_phy),
468      SCIC_LOG_OBJECT_PHY,
469      "SCIC SDS Phy 0x%x did not receive signature fis before timeout.\n",
470      this_phy
471   ));
472
473   sci_base_state_machine_stop(
474      scic_sds_phy_get_starting_substate_machine(this_phy));
475
476   sci_base_state_machine_change_state(
477      scic_sds_phy_get_base_state_machine(this_phy),
478      SCI_BASE_PHY_STATE_STARTING
479   );
480}
481
482//*****************************************************************************
483//* SCIC SDS PHY External Methods
484//*****************************************************************************
485
486/**
487 * @brief This method returns the object size for a phy object.
488 *
489 * @return U32
490 */
491U32 scic_sds_phy_get_object_size(void)
492{
493   return sizeof(SCIC_SDS_PHY_T);
494}
495
496/**
497 * @brief This method returns the minimum number of timers required for a
498 *        phy object.
499 *
500 * @return U32
501 */
502U32 scic_sds_phy_get_min_timer_count(void)
503{
504   return SCIC_SDS_PHY_MIN_TIMER_COUNT;
505}
506
507/**
508 * @brief This method returns the maximum number of timers required for a
509 *        phy object.
510 *
511 * @return U32
512 */
513U32 scic_sds_phy_get_max_timer_count(void)
514{
515   return SCIC_SDS_PHY_MAX_TIMER_COUNT;
516}
517
518#ifdef SCI_LOGGING
519static
520void scic_sds_phy_initialize_state_logging(
521   SCIC_SDS_PHY_T *this_phy
522)
523{
524   sci_base_state_machine_logger_initialize(
525      &this_phy->parent.state_machine_logger,
526      &this_phy->parent.state_machine,
527      &this_phy->parent.parent,
528      scic_cb_logger_log_states,
529      "SCIC_SDS_PHY_T", "base state machine",
530      SCIC_LOG_OBJECT_PHY
531   );
532
533   sci_base_state_machine_logger_initialize(
534      &this_phy->starting_substate_machine_logger,
535      &this_phy->starting_substate_machine,
536      &this_phy->parent.parent,
537      scic_cb_logger_log_states,
538      "SCIC_SDS_PHY_T", "starting substate machine",
539      SCIC_LOG_OBJECT_PHY
540   );
541}
542#endif // SCI_LOGGING
543
544#ifdef SCIC_DEBUG_ENABLED
545/**
546 * Debug code to record the state transitions in the phy
547 *
548 * @param our_observer
549 * @param the_state_machine
550 */
551void scic_sds_phy_observe_state_change(
552   SCI_BASE_OBSERVER_T * our_observer,
553   SCI_BASE_SUBJECT_T  * the_subject
554)
555{
556   SCIC_SDS_PHY_T           *this_phy;
557   SCI_BASE_STATE_MACHINE_T *the_state_machine;
558
559   U8  transition_requestor;
560   U32 base_state_id;
561   U32 starting_substate_id;
562
563   the_state_machine = (SCI_BASE_STATE_MACHINE_T *)the_subject;
564   this_phy = (SCIC_SDS_PHY_T *)the_state_machine->state_machine_owner;
565
566   if (the_state_machine == &this_phy->parent.state_machine)
567   {
568      transition_requestor = 0x01;
569   }
570   else if (the_state_machine == &this_phy->starting_substate_machine)
571   {
572      transition_requestor = 0x02;
573   }
574   else
575   {
576      transition_requestor = 0xFF;
577   }
578
579   base_state_id =
580      sci_base_state_machine_get_state(&this_phy->parent.state_machine);
581   starting_substate_id =
582      sci_base_state_machine_get_state(&this_phy->starting_substate_machine);
583
584   this_phy->state_record.state_transition_table[
585      this_phy->state_record.index++] = ( (transition_requestor << 24)
586                                        | ((U8)base_state_id << 8)
587                                        | ((U8)starting_substate_id));
588
589   this_phy->state_record.index =
590      this_phy->state_record.index & (MAX_STATE_TRANSITION_RECORD - 1);
591
592}
593#endif // SCIC_DEBUG_ENABLED
594
595#ifdef SCIC_DEBUG_ENABLED
596/**
597 * This method initializes the state record debug information for the phy
598 * object.
599 *
600 * @pre The state machines for the phy object must be constructed before this
601 *      function is called.
602 *
603 * @param this_phy The phy which is being initialized.
604 */
605void scic_sds_phy_initialize_state_recording(
606   SCIC_SDS_PHY_T *this_phy
607)
608{
609   this_phy->state_record.index = 0;
610
611   sci_base_observer_initialize(
612      &this_phy->state_record.base_state_observer,
613      scic_sds_phy_observe_state_change,
614      &this_phy->parent.state_machine.parent
615   );
616
617   sci_base_observer_initialize(
618      &this_phy->state_record.starting_state_observer,
619      scic_sds_phy_observe_state_change,
620      &this_phy->starting_substate_machine.parent
621   );
622}
623#endif // SCIC_DEBUG_ENABLED
624
625/**
626 * @brief This method will construct the SCIC_SDS_PHY object
627 *
628 * @param[in] this_phy
629 * @param[in] owning_port
630 * @param[in] phy_index
631 *
632 * @return none
633 */
634void scic_sds_phy_construct(
635   SCIC_SDS_PHY_T  *this_phy,
636   SCIC_SDS_PORT_T *owning_port,
637   U8              phy_index
638)
639{
640   // Call the base constructor first
641   // Copy the logger from the port (this could be the dummy port)
642   sci_base_phy_construct(
643      &this_phy->parent,
644      sci_base_object_get_logger(owning_port),
645      scic_sds_phy_state_table
646      );
647
648   // Copy the rest of the input data to our locals
649   this_phy->owning_port = owning_port;
650   this_phy->phy_index = phy_index;
651   this_phy->bcn_received_while_port_unassigned = FALSE;
652   this_phy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN;
653   this_phy->link_layer_registers = NULL;
654   this_phy->max_negotiated_speed = SCI_SAS_NO_LINK_RATE;
655   this_phy->sata_timeout_timer = NULL;
656
657   // Clear out the identification buffer data
658   memset(&this_phy->phy_type, 0, sizeof(this_phy->phy_type));
659
660   // Clear out the error counter data
661   memset(this_phy->error_counter, 0, sizeof(this_phy->error_counter));
662
663   // Initialize the substate machines
664   sci_base_state_machine_construct(
665      &this_phy->starting_substate_machine,
666      &this_phy->parent.parent,
667      scic_sds_phy_starting_substates,
668      SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL
669      );
670
671   #ifdef SCI_LOGGING
672   scic_sds_phy_initialize_state_logging(this_phy);
673   #endif // SCI_LOGGING
674
675   #ifdef SCIC_DEBUG_ENABLED
676   scic_sds_phy_initialize_state_recording(this_phy);
677   #endif // SCIC_DEBUG_ENABLED
678}
679
680/**
681 * @brief This method returns the port currently containing this phy.
682 *        If the phy is currently contained by the dummy port, then
683 *        the phy is considered to not be part of a port.
684 *
685 * @param[in] this_phy This parameter specifies the phy for which to
686 *            retrieve the containing port.
687 *
688 * @return This method returns a handle to a port that contains
689 *         the supplied phy.
690 * @retval SCI_INVALID_HANDLE This value is returned if the phy is not
691 *         part of a real port (i.e. it's contained in the dummy port).
692 * @retval !SCI_INVALID_HANDLE All other values indicate a handle/pointer
693 *         to the port containing the phy.
694 */
695SCI_PORT_HANDLE_T scic_sds_phy_get_port(
696   SCIC_SDS_PHY_T *this_phy
697)
698{
699   SCIC_LOG_TRACE((
700      sci_base_object_get_logger(this_phy),
701      SCIC_LOG_OBJECT_PHY,
702      "scic_phy_get_port(0x%x) enter\n",
703      this_phy
704   ));
705
706   if (scic_sds_port_get_index(this_phy->owning_port) == SCIC_SDS_DUMMY_PORT)
707      return SCI_INVALID_HANDLE;
708
709   return this_phy->owning_port;
710}
711
712/**
713 * @brief This method will assign a port to the phy object.
714 *
715 * @param[in, out] this_phy This parameter specifies the phy for which
716 *    to assign a port object.
717 * @param[in] the_port This parameter is the port to assing to the phy.
718 */
719void scic_sds_phy_set_port(
720   SCIC_SDS_PHY_T * this_phy,
721   SCIC_SDS_PORT_T * the_port
722)
723{
724   this_phy->owning_port = the_port;
725
726   if (this_phy->bcn_received_while_port_unassigned)
727   {
728      this_phy->bcn_received_while_port_unassigned = FALSE;
729      scic_sds_port_broadcast_change_received(this_phy->owning_port, this_phy);
730   }
731}
732
733/**
734 * @brief This method will initialize the constructed phy
735 *
736 * @param[in] this_phy
737 * @param[in] link_layer_registers
738 *
739 * @return SCI_STATUS
740 */
741SCI_STATUS scic_sds_phy_initialize(
742   SCIC_SDS_PHY_T             *this_phy,
743   void                       *transport_layer_registers,
744   SCU_LINK_LAYER_REGISTERS_T *link_layer_registers
745)
746{
747   SCIC_LOG_TRACE((
748      sci_base_object_get_logger(this_phy),
749      SCIC_LOG_OBJECT_PHY,
750      "scic_sds_phy_initialize(this_phy:0x%x, link_layer_registers:0x%x)\n",
751      this_phy, link_layer_registers
752   ));
753
754   // Perform the initialization of the TL hardware
755   scic_sds_phy_transport_layer_initialization(this_phy, transport_layer_registers);
756
757   // Perofrm the initialization of the PE hardware
758   scic_sds_phy_link_layer_initialization(this_phy, link_layer_registers);
759
760   // There is nothing that needs to be done in this state just
761   // transition to the stopped state.
762   sci_base_state_machine_change_state(
763      scic_sds_phy_get_base_state_machine(this_phy),
764      SCI_BASE_PHY_STATE_STOPPED
765   );
766
767   return SCI_SUCCESS;
768}
769
770/**
771 * This method assigns the direct attached device ID for this phy.
772 *
773 * @param[in] this_phy The phy for which the direct attached device id is to
774 *       be assigned.
775 * @param[in] device_id The direct attached device ID to assign to the phy.
776 *       This will either be the RNi for the device or an invalid RNi if there
777 *       is no current device assigned to the phy.
778 */
779void scic_sds_phy_setup_transport(
780   SCIC_SDS_PHY_T * this_phy,
781   U32              device_id
782)
783{
784   U32 tl_control;
785
786   SCU_STPTLDARNI_WRITE(this_phy, device_id);
787
788   // The read should guarntee that the first write gets posted
789   // before the next write
790   tl_control = SCU_TLCR_READ(this_phy);
791   tl_control |= SCU_TLCR_GEN_BIT(CLEAR_TCI_NCQ_MAPPING_TABLE);
792   SCU_TLCR_WRITE(this_phy, tl_control);
793}
794
795/**
796 * This function will perform the register reads/writes to suspend the SCU
797 * hardware protocol engine.
798 *
799 * @param[in,out] this_phy The phy object to be suspended.
800 *
801 * @return none
802 */
803void scic_sds_phy_suspend(
804   SCIC_SDS_PHY_T * this_phy
805)
806{
807   U32 scu_sas_pcfg_value;
808
809   scu_sas_pcfg_value = SCU_SAS_PCFG_READ(this_phy);
810   scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE);
811   SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
812
813   scic_sds_phy_setup_transport(
814      this_phy, SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX
815   );
816}
817
818/**
819 * This function will perform the register reads/writes required to resume the
820 * SCU hardware protocol engine.
821 *
822 * @param[in,out] this_phy The phy object to resume.
823 *
824 * @return none
825 */
826void scic_sds_phy_resume(
827   SCIC_SDS_PHY_T * this_phy
828)
829{
830   U32 scu_sas_pcfg_value;
831
832   scu_sas_pcfg_value = SCU_SAS_PCFG_READ(this_phy);
833
834   scu_sas_pcfg_value &= ~SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE);
835
836   SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
837}
838
839/**
840 * @brief This method returns the local sas address assigned to this phy.
841 *
842 * @param[in] this_phy This parameter specifies the phy for which
843 *            to retrieve the local SAS address.
844 * @param[out] sas_address This parameter specifies the location into
845 *             which to copy the local SAS address.
846 *
847 * @return none
848 */
849void scic_sds_phy_get_sas_address(
850   SCIC_SDS_PHY_T *this_phy,
851   SCI_SAS_ADDRESS_T *sas_address
852)
853{
854   SCIC_LOG_TRACE((
855      sci_base_object_get_logger(this_phy),
856      SCIC_LOG_OBJECT_PHY,
857      "scic_sds_phy_get_sas_address(this_phy:0x%x, sas_address:0x%x)\n",
858      this_phy, sas_address
859   ));
860
861   sas_address->high = SCU_SAS_TISSAH_READ(this_phy);
862   sas_address->low  = SCU_SAS_TISSAL_READ(this_phy);
863}
864
865/**
866 * @brief This method returns the remote end-point (i.e. attached)
867 *        sas address assigned to this phy.
868 *
869 * @param[in] this_phy This parameter specifies the phy for which
870 *            to retrieve the remote end-point SAS address.
871 * @param[out] sas_address This parameter specifies the location into
872 *             which to copy the remote end-point SAS address.
873 *
874 * @return none
875 */
876void scic_sds_phy_get_attached_sas_address(
877   SCIC_SDS_PHY_T    *this_phy,
878   SCI_SAS_ADDRESS_T *sas_address
879)
880{
881   SCIC_LOG_TRACE((
882      sci_base_object_get_logger(this_phy),
883      SCIC_LOG_OBJECT_PHY,
884      "scic_sds_phy_get_attached_sas_address(0x%x, 0x%x) enter\n",
885      this_phy, sas_address
886   ));
887
888   sas_address->high
889      = this_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high;
890   sas_address->low
891      = this_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low;
892}
893
894/**
895 * @brief This method returns the supported protocols assigned to
896 *        this phy
897 *
898 * @param[in] this_phy
899 * @param[out] protocols
900 */
901void scic_sds_phy_get_protocols(
902   SCIC_SDS_PHY_T *this_phy,
903   SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
904)
905{
906   U32 tiid_value = SCU_SAS_TIID_READ(this_phy);
907
908   //Check each bit of this register. please refer to
909   //SAS Transmit Identification Register (SAS_TIID).
910   if (tiid_value & 0x2)
911      protocols->u.bits.smp_target = 1;
912
913   if (tiid_value & 0x4)
914      protocols->u.bits.stp_target = 1;
915
916   if (tiid_value & 0x8)
917      protocols->u.bits.ssp_target = 1;
918
919   if (tiid_value & 0x200)
920      protocols->u.bits.smp_initiator = 1;
921
922   if ((tiid_value & 0x400))
923      protocols->u.bits.stp_initiator = 1;
924
925   if (tiid_value & 0x800)
926      protocols->u.bits.ssp_initiator = 1;
927
928   SCIC_LOG_TRACE((
929      sci_base_object_get_logger(this_phy),
930      SCIC_LOG_OBJECT_PHY,
931      "scic_sds_phy_get_protocols(this_phy:0x%x, protocols:0x%x)\n",
932      this_phy, protocols->u.all
933   ));
934}
935
936/**
937 * This method returns the supported protocols for the attached phy.  If this
938 * is a SAS phy the protocols are returned from the identify address frame.
939 * If this is a SATA phy then protocols are made up and the target phy is an
940 * STP target phy.
941 *
942 * @note The caller will get the entire set of bits for the protocol value.
943 *
944 * @param[in] this_phy The parameter is the phy object for which the attached
945 *       phy protcols are to be returned.
946 * @param[out] protocols The parameter is the returned protocols for the
947 *       attached phy.
948 */
949void scic_sds_phy_get_attached_phy_protocols(
950   SCIC_SDS_PHY_T *this_phy,
951   SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
952)
953{
954   SCIC_LOG_TRACE((
955      sci_base_object_get_logger(this_phy),
956      SCIC_LOG_OBJECT_PHY,
957      "scic_sds_phy_get_attached_phy_protocols(this_phy:0x%x, protocols:0x%x[0x%x])\n",
958      this_phy, protocols, protocols->u.all
959   ));
960
961   protocols->u.all = 0;
962
963   if (this_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS)
964   {
965      protocols->u.all =
966         this_phy->phy_type.sas.identify_address_frame_buffer.protocols.u.all;
967   }
968   else if (this_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA)
969   {
970      protocols->u.bits.stp_target = 1;
971   }
972}
973
974
975/**
976 * @brief This method release resources in for a scic phy.
977 *
978 * @param[in] controller This parameter specifies the core controller, one of
979 *            its phy's resources are to be released.
980 * @param[in] this_phy This parameter specifies the phy whose resource is to
981 *            be released.
982 */
983void scic_sds_phy_release_resource(
984   SCIC_SDS_CONTROLLER_T * controller,
985   SCIC_SDS_PHY_T        * this_phy
986)
987{
988   SCIC_LOG_TRACE((
989      sci_base_object_get_logger(this_phy),
990      SCIC_LOG_OBJECT_PHY,
991      "scic_sds_phy_release_resource(0x%x, 0x%x)\n",
992      controller, this_phy
993   ));
994
995   //Currently, the only resource to be released is a timer.
996   if (this_phy->sata_timeout_timer != NULL)
997   {
998      scic_cb_timer_destroy(controller, this_phy->sata_timeout_timer);
999      this_phy->sata_timeout_timer = NULL;
1000   }
1001}
1002
1003
1004//*****************************************************************************
1005//* SCIC SDS PHY Handler Redirects
1006//*****************************************************************************
1007
1008/**
1009 * @brief This method will attempt to reset the phy.  This
1010 *        request is only valid when the phy is in an ready
1011 *        state
1012 *
1013 * @param[in] this_phy
1014 *
1015 * @return SCI_STATUS
1016 */
1017SCI_STATUS scic_sds_phy_reset(
1018   SCIC_SDS_PHY_T * this_phy
1019)
1020{
1021   SCIC_LOG_TRACE((
1022      sci_base_object_get_logger(this_phy),
1023      SCIC_LOG_OBJECT_PHY,
1024      "scic_sds_phy_reset(this_phy:0x%08x)\n",
1025      this_phy
1026   ));
1027
1028   return this_phy->state_handlers->parent.reset_handler(
1029                                             &this_phy->parent
1030                                           );
1031}
1032
1033/**
1034 * @brief This method will process the event code received.
1035 *
1036 * @param[in] this_phy
1037 * @param[in] event_code
1038 *
1039 * @return SCI_STATUS
1040 */
1041SCI_STATUS scic_sds_phy_event_handler(
1042   SCIC_SDS_PHY_T *this_phy,
1043   U32 event_code
1044)
1045{
1046   SCIC_LOG_TRACE((
1047      sci_base_object_get_logger(this_phy),
1048      SCIC_LOG_OBJECT_PHY,
1049      "scic_sds_phy_event_handler(this_phy:0x%08x, event_code:%x)\n",
1050      this_phy, event_code
1051   ));
1052
1053   return this_phy->state_handlers->event_handler(this_phy, event_code);
1054}
1055
1056/**
1057 * @brief This method will process the frame index received.
1058 *
1059 * @param[in] this_phy
1060 * @param[in] frame_index
1061 *
1062 * @return SCI_STATUS
1063 */
1064SCI_STATUS scic_sds_phy_frame_handler(
1065   SCIC_SDS_PHY_T *this_phy,
1066   U32 frame_index
1067)
1068{
1069   SCIC_LOG_TRACE((
1070      sci_base_object_get_logger(this_phy),
1071      SCIC_LOG_OBJECT_PHY,
1072      "scic_sds_phy_frame_handler(this_phy:0x%08x, frame_index:%d)\n",
1073      this_phy, frame_index
1074   ));
1075
1076   return this_phy->state_handlers->frame_handler(this_phy, frame_index);
1077}
1078
1079/**
1080 * @brief This method will give the phy permission to consume power
1081 *
1082 * @param[in] this_phy
1083 *
1084 * @return SCI_STATUS
1085 */
1086SCI_STATUS scic_sds_phy_consume_power_handler(
1087   SCIC_SDS_PHY_T *this_phy
1088)
1089{
1090   SCIC_LOG_TRACE((
1091      sci_base_object_get_logger(this_phy),
1092      SCIC_LOG_OBJECT_PHY,
1093      "scic_sds_phy_consume_power_handler(this_phy:0x%08x)\n",
1094      this_phy
1095   ));
1096
1097   return this_phy->state_handlers->consume_power_handler(this_phy);
1098}
1099
1100//*****************************************************************************
1101//* SCIC PHY Public Methods
1102//*****************************************************************************
1103
1104SCI_STATUS scic_phy_get_properties(
1105   SCI_PHY_HANDLE_T        phy,
1106   SCIC_PHY_PROPERTIES_T * properties
1107)
1108{
1109   SCIC_SDS_PHY_T *this_phy;
1110   U8 max_speed_generation;
1111
1112   this_phy = (SCIC_SDS_PHY_T *)phy;
1113
1114   SCIC_LOG_TRACE((
1115      sci_base_object_get_logger(this_phy),
1116      SCIC_LOG_OBJECT_PHY,
1117      "scic_phy_get_properties(0x%x, 0x%x) enter\n",
1118      this_phy, properties
1119   ));
1120
1121   if (phy == SCI_INVALID_HANDLE)
1122   {
1123      return SCI_FAILURE_INVALID_PHY;
1124   }
1125
1126   memset(properties, 0, sizeof(SCIC_PHY_PROPERTIES_T));
1127
1128   //get max link rate of this phy set by user.
1129   max_speed_generation =
1130      this_phy->owning_port->owning_controller->user_parameters.sds1.
1131         phys[this_phy->phy_index].max_speed_generation;
1132
1133   properties->negotiated_link_rate     = this_phy->max_negotiated_speed;
1134
1135   if (max_speed_generation == SCIC_SDS_PARM_GEN3_SPEED)
1136      properties->max_link_rate            = SCI_SAS_600_GB;
1137   else if (max_speed_generation == SCIC_SDS_PARM_GEN2_SPEED)
1138      properties->max_link_rate            = SCI_SAS_300_GB;
1139   else
1140      properties->max_link_rate            = SCI_SAS_150_GB;
1141
1142   properties->index                    = this_phy->phy_index;
1143   properties->owning_port              = scic_sds_phy_get_port(this_phy);
1144
1145   scic_sds_phy_get_protocols(this_phy, &properties->transmit_iaf.protocols);
1146
1147   properties->transmit_iaf.sas_address.high =
1148      this_phy->owning_port->owning_controller->oem_parameters.sds1.
1149         phys[this_phy->phy_index].sas_address.sci_format.high;
1150
1151   properties->transmit_iaf.sas_address.low =
1152      this_phy->owning_port->owning_controller->oem_parameters.sds1.
1153         phys[this_phy->phy_index].sas_address.sci_format.low;
1154
1155   return SCI_SUCCESS;
1156}
1157
1158// ---------------------------------------------------------------------------
1159
1160SCI_STATUS scic_sas_phy_get_properties(
1161   SCI_PHY_HANDLE_T            phy,
1162   SCIC_SAS_PHY_PROPERTIES_T * properties
1163)
1164{
1165   SCIC_SDS_PHY_T *this_phy;
1166   this_phy = (SCIC_SDS_PHY_T *)phy;
1167
1168   SCIC_LOG_TRACE((
1169      sci_base_object_get_logger(this_phy),
1170      SCIC_LOG_OBJECT_PHY,
1171      "scic_sas_phy_get_properties(0x%x, 0x%x) enter\n",
1172      this_phy, properties
1173   ));
1174
1175   if (this_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS)
1176   {
1177      memcpy(
1178         &properties->received_iaf,
1179         &this_phy->phy_type.sas.identify_address_frame_buffer,
1180         sizeof(SCI_SAS_IDENTIFY_ADDRESS_FRAME_T)
1181      );
1182
1183      properties->received_capabilities.u.all
1184         = SCU_SAS_RECPHYCAP_READ(this_phy);
1185
1186      return SCI_SUCCESS;
1187   }
1188
1189   return SCI_FAILURE;
1190}
1191
1192// ---------------------------------------------------------------------------
1193
1194SCI_STATUS scic_sata_phy_get_properties(
1195   SCI_PHY_HANDLE_T             phy,
1196   SCIC_SATA_PHY_PROPERTIES_T * properties
1197)
1198{
1199   SCIC_SDS_PHY_T *this_phy;
1200   this_phy = (SCIC_SDS_PHY_T *)phy;
1201
1202   SCIC_LOG_TRACE((
1203      sci_base_object_get_logger(this_phy),
1204      SCIC_LOG_OBJECT_PHY,
1205      "scic_sata_phy_get_properties(0x%x, 0x%x) enter\n",
1206      this_phy, properties
1207   ));
1208
1209   if (this_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA)
1210   {
1211      memcpy(
1212         &properties->signature_fis,
1213         &this_phy->phy_type.sata.signature_fis_buffer,
1214         sizeof(SATA_FIS_REG_D2H_T)
1215      );
1216
1217      /// @todo add support for port selectors.
1218      properties->is_port_selector_present = FALSE;
1219
1220      return SCI_SUCCESS;
1221   }
1222
1223   return SCI_FAILURE;
1224}
1225
1226// ---------------------------------------------------------------------------
1227
1228#if !defined(DISABLE_PORT_SELECTORS)
1229
1230SCI_STATUS scic_sata_phy_send_port_selection_signal(
1231   SCI_PHY_HANDLE_T  phy
1232)
1233{
1234   SCIC_SDS_PHY_T *this_phy;
1235   this_phy = (SCIC_SDS_PHY_T *)phy;
1236
1237   SCIC_LOG_TRACE((
1238      sci_base_object_get_logger(this_phy),
1239      SCIC_LOG_OBJECT_PHY,
1240      "scic_sata_phy_send_port_selection_signals(0x%x) enter\n",
1241      this_phy
1242   ));
1243
1244   /// @todo To be implemented
1245   ASSERT(FALSE);
1246   return SCI_FAILURE;
1247}
1248
1249#endif // !defined(DISABLE_PORT_SELECTORS)
1250
1251// ---------------------------------------------------------------------------
1252
1253#if !defined(DISABLE_PHY_COUNTERS)
1254
1255SCI_STATUS scic_phy_enable_counter(
1256   SCI_PHY_HANDLE_T       phy,
1257   SCIC_PHY_COUNTER_ID_T  counter_id
1258)
1259{
1260   SCIC_SDS_PHY_T *this_phy;
1261   SCI_STATUS status = SCI_SUCCESS;
1262   this_phy = (SCIC_SDS_PHY_T *)phy;
1263
1264   SCIC_LOG_TRACE((
1265      sci_base_object_get_logger(this_phy),
1266      SCIC_LOG_OBJECT_PHY,
1267      "scic_phy_enable_counter(0x%x, 0x%x) enter\n",
1268      this_phy, counter_id
1269   ));
1270
1271   switch(counter_id)
1272   {
1273      case SCIC_PHY_COUNTER_RECEIVED_DONE_ACK_NAK_TIMEOUT:
1274         {
1275            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1276            control |= (1 << SCU_ERR_CNT_RX_DONE_ACK_NAK_TIMEOUT_INDEX);
1277            SCU_SAS_ECENCR_WRITE(this_phy, control);
1278         }
1279         break;
1280      case SCIC_PHY_COUNTER_TRANSMITTED_DONE_ACK_NAK_TIMEOUT:
1281         {
1282            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1283            control |= (1 << SCU_ERR_CNT_TX_DONE_ACK_NAK_TIMEOUT_INDEX);
1284            SCU_SAS_ECENCR_WRITE(this_phy, control);
1285         }
1286         break;
1287      case SCIC_PHY_COUNTER_INACTIVITY_TIMER_EXPIRED:
1288         {
1289            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1290            control |= (1 << SCU_ERR_CNT_INACTIVITY_TIMER_EXPIRED_INDEX);
1291            SCU_SAS_ECENCR_WRITE(this_phy, control);
1292         }
1293         break;
1294      case SCIC_PHY_COUNTER_RECEIVED_DONE_CREDIT_TIMEOUT:
1295         {
1296            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1297            control |= (1 << SCU_ERR_CNT_RX_DONE_CREDIT_TIMEOUT_INDEX);
1298            SCU_SAS_ECENCR_WRITE(this_phy, control);
1299         }
1300         break;
1301      case SCIC_PHY_COUNTER_TRANSMITTED_DONE_CREDIT_TIMEOUT:
1302         {
1303            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1304            control |= (1 << SCU_ERR_CNT_TX_DONE_CREDIT_TIMEOUT_INDEX);
1305            SCU_SAS_ECENCR_WRITE(this_phy, control);
1306         }
1307         break;
1308      case SCIC_PHY_COUNTER_RECEIVED_CREDIT_BLOCKED:
1309         {
1310            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1311            control |= (1 << SCU_ERR_CNT_RX_CREDIT_BLOCKED_RECEIVED_INDEX);
1312            SCU_SAS_ECENCR_WRITE(this_phy, control);
1313         }
1314         break;
1315
1316         // These error counters are enabled by default, and cannot be
1317         //  disabled.  Return SCI_SUCCESS to denote that they are
1318         //  enabled, hiding the fact that enabling the counter is
1319         //  a no-op.
1320      case SCIC_PHY_COUNTER_RECEIVED_FRAME:
1321      case SCIC_PHY_COUNTER_TRANSMITTED_FRAME:
1322      case SCIC_PHY_COUNTER_RECEIVED_FRAME_DWORD:
1323      case SCIC_PHY_COUNTER_TRANSMITTED_FRAME_DWORD:
1324      case SCIC_PHY_COUNTER_LOSS_OF_SYNC_ERROR:
1325      case SCIC_PHY_COUNTER_RECEIVED_DISPARITY_ERROR:
1326      case SCIC_PHY_COUNTER_RECEIVED_FRAME_CRC_ERROR:
1327      case SCIC_PHY_COUNTER_RECEIVED_SHORT_FRAME:
1328      case SCIC_PHY_COUNTER_RECEIVED_FRAME_WITHOUT_CREDIT:
1329      case SCIC_PHY_COUNTER_RECEIVED_FRAME_AFTER_DONE:
1330      case SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR:
1331         break;
1332
1333      default:
1334         status = SCI_FAILURE;
1335         break;
1336   }
1337   return status;
1338}
1339
1340// ---------------------------------------------------------------------------
1341
1342SCI_STATUS scic_phy_disable_counter(
1343   SCI_PHY_HANDLE_T       phy,
1344   SCIC_PHY_COUNTER_ID_T  counter_id
1345)
1346{
1347   SCIC_SDS_PHY_T *this_phy;
1348   SCI_STATUS status = SCI_SUCCESS;
1349
1350   this_phy = (SCIC_SDS_PHY_T *)phy;
1351
1352   SCIC_LOG_TRACE((
1353      sci_base_object_get_logger(this_phy),
1354      SCIC_LOG_OBJECT_PHY,
1355      "scic_phy_disable_counter(0x%x, 0x%x) enter\n",
1356      this_phy, counter_id
1357   ));
1358
1359   switch(counter_id)
1360   {
1361      case SCIC_PHY_COUNTER_RECEIVED_DONE_ACK_NAK_TIMEOUT:
1362         {
1363            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1364            control &= ~(1 << SCU_ERR_CNT_RX_DONE_ACK_NAK_TIMEOUT_INDEX);
1365            SCU_SAS_ECENCR_WRITE(this_phy, control);
1366         }
1367         break;
1368      case SCIC_PHY_COUNTER_TRANSMITTED_DONE_ACK_NAK_TIMEOUT:
1369         {
1370            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1371            control &= ~(1 << SCU_ERR_CNT_TX_DONE_ACK_NAK_TIMEOUT_INDEX);
1372            SCU_SAS_ECENCR_WRITE(this_phy, control);
1373         }
1374         break;
1375      case SCIC_PHY_COUNTER_INACTIVITY_TIMER_EXPIRED:
1376         {
1377            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1378            control &= ~(1 << SCU_ERR_CNT_INACTIVITY_TIMER_EXPIRED_INDEX);
1379            SCU_SAS_ECENCR_WRITE(this_phy, control);
1380         }
1381         break;
1382      case SCIC_PHY_COUNTER_RECEIVED_DONE_CREDIT_TIMEOUT:
1383         {
1384            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1385            control &= ~(1 << SCU_ERR_CNT_RX_DONE_CREDIT_TIMEOUT_INDEX);
1386            SCU_SAS_ECENCR_WRITE(this_phy, control);
1387         }
1388         break;
1389      case SCIC_PHY_COUNTER_TRANSMITTED_DONE_CREDIT_TIMEOUT:
1390         {
1391            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1392            control &= ~(1 << SCU_ERR_CNT_TX_DONE_CREDIT_TIMEOUT_INDEX);
1393            SCU_SAS_ECENCR_WRITE(this_phy, control);
1394         }
1395         break;
1396      case SCIC_PHY_COUNTER_RECEIVED_CREDIT_BLOCKED:
1397         {
1398            U32 control = SCU_SAS_ECENCR_READ(this_phy);
1399            control &= ~(1 << SCU_ERR_CNT_RX_CREDIT_BLOCKED_RECEIVED_INDEX);
1400            SCU_SAS_ECENCR_WRITE(this_phy, control);
1401         }
1402         break;
1403
1404         // These error counters cannot be disabled, so return SCI_FAILURE.
1405      case SCIC_PHY_COUNTER_RECEIVED_FRAME:
1406      case SCIC_PHY_COUNTER_TRANSMITTED_FRAME:
1407      case SCIC_PHY_COUNTER_RECEIVED_FRAME_DWORD:
1408      case SCIC_PHY_COUNTER_TRANSMITTED_FRAME_DWORD:
1409      case SCIC_PHY_COUNTER_LOSS_OF_SYNC_ERROR:
1410      case SCIC_PHY_COUNTER_RECEIVED_DISPARITY_ERROR:
1411      case SCIC_PHY_COUNTER_RECEIVED_FRAME_CRC_ERROR:
1412      case SCIC_PHY_COUNTER_RECEIVED_SHORT_FRAME:
1413      case SCIC_PHY_COUNTER_RECEIVED_FRAME_WITHOUT_CREDIT:
1414      case SCIC_PHY_COUNTER_RECEIVED_FRAME_AFTER_DONE:
1415      case SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR:
1416      default:
1417         status = SCI_FAILURE;
1418         break;
1419   }
1420   return status;
1421}
1422
1423// ---------------------------------------------------------------------------
1424
1425SCI_STATUS scic_phy_get_counter(
1426   SCI_PHY_HANDLE_T        phy,
1427   SCIC_PHY_COUNTER_ID_T   counter_id,
1428   U32                   * data
1429)
1430{
1431   SCIC_SDS_PHY_T *this_phy;
1432   SCI_STATUS status = SCI_SUCCESS;
1433   this_phy = (SCIC_SDS_PHY_T *)phy;
1434
1435   SCIC_LOG_TRACE((
1436      sci_base_object_get_logger(this_phy),
1437      SCIC_LOG_OBJECT_PHY,
1438      "scic_phy_get_counter(0x%x, 0x%x) enter\n",
1439      this_phy, counter_id
1440   ));
1441
1442   switch(counter_id)
1443   {
1444      case SCIC_PHY_COUNTER_RECEIVED_FRAME:
1445         *data = scu_link_layer_register_read(this_phy, received_frame_count);
1446         break;
1447      case SCIC_PHY_COUNTER_TRANSMITTED_FRAME:
1448         *data = scu_link_layer_register_read(this_phy, transmit_frame_count);
1449         break;
1450      case SCIC_PHY_COUNTER_RECEIVED_FRAME_DWORD:
1451         *data = scu_link_layer_register_read(this_phy, received_dword_count);
1452         break;
1453      case SCIC_PHY_COUNTER_TRANSMITTED_FRAME_DWORD:
1454         *data = scu_link_layer_register_read(this_phy, transmit_dword_count);
1455         break;
1456      case SCIC_PHY_COUNTER_LOSS_OF_SYNC_ERROR:
1457         *data = scu_link_layer_register_read(this_phy, loss_of_sync_error_count);
1458         break;
1459      case SCIC_PHY_COUNTER_RECEIVED_DISPARITY_ERROR:
1460         *data = scu_link_layer_register_read(this_phy, running_disparity_error_count);
1461         break;
1462      case SCIC_PHY_COUNTER_RECEIVED_FRAME_CRC_ERROR:
1463         *data = scu_link_layer_register_read(this_phy, received_frame_crc_error_count);
1464         break;
1465      case SCIC_PHY_COUNTER_RECEIVED_DONE_ACK_NAK_TIMEOUT:
1466         *data = this_phy->error_counter[SCU_ERR_CNT_RX_DONE_ACK_NAK_TIMEOUT_INDEX];
1467         break;
1468      case SCIC_PHY_COUNTER_TRANSMITTED_DONE_ACK_NAK_TIMEOUT:
1469         *data = this_phy->error_counter[SCU_ERR_CNT_TX_DONE_ACK_NAK_TIMEOUT_INDEX];
1470         break;
1471      case SCIC_PHY_COUNTER_INACTIVITY_TIMER_EXPIRED:
1472         *data = this_phy->error_counter[SCU_ERR_CNT_INACTIVITY_TIMER_EXPIRED_INDEX];
1473         break;
1474      case SCIC_PHY_COUNTER_RECEIVED_DONE_CREDIT_TIMEOUT:
1475         *data = this_phy->error_counter[SCU_ERR_CNT_RX_DONE_CREDIT_TIMEOUT_INDEX];
1476         break;
1477      case SCIC_PHY_COUNTER_TRANSMITTED_DONE_CREDIT_TIMEOUT:
1478         *data = this_phy->error_counter[SCU_ERR_CNT_TX_DONE_CREDIT_TIMEOUT_INDEX];
1479         break;
1480      case SCIC_PHY_COUNTER_RECEIVED_CREDIT_BLOCKED:
1481         *data = this_phy->error_counter[SCU_ERR_CNT_RX_CREDIT_BLOCKED_RECEIVED_INDEX];
1482         break;
1483      case SCIC_PHY_COUNTER_RECEIVED_SHORT_FRAME:
1484         *data = scu_link_layer_register_read(this_phy, received_short_frame_count);
1485         break;
1486      case SCIC_PHY_COUNTER_RECEIVED_FRAME_WITHOUT_CREDIT:
1487         *data = scu_link_layer_register_read(this_phy, received_frame_without_credit_count);
1488         break;
1489      case SCIC_PHY_COUNTER_RECEIVED_FRAME_AFTER_DONE:
1490         *data = scu_link_layer_register_read(this_phy, received_frame_after_done_count);
1491         break;
1492      case SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR:
1493         *data = scu_link_layer_register_read(this_phy, phy_reset_problem_count);
1494         break;
1495      default:
1496         status = SCI_FAILURE;
1497         break;
1498   }
1499
1500   return status;
1501}
1502
1503// ---------------------------------------------------------------------------
1504
1505SCI_STATUS scic_phy_clear_counter(
1506   SCI_PHY_HANDLE_T       phy,
1507   SCIC_PHY_COUNTER_ID_T  counter_id
1508)
1509{
1510   SCIC_SDS_PHY_T *this_phy;
1511   SCI_STATUS status = SCI_SUCCESS;
1512   this_phy = (SCIC_SDS_PHY_T *)phy;
1513
1514   SCIC_LOG_TRACE((
1515      sci_base_object_get_logger(this_phy),
1516      SCIC_LOG_OBJECT_PHY,
1517      "scic_phy_clear_counter(0x%x, 0x%x) enter\n",
1518      this_phy, counter_id
1519   ));
1520
1521   switch(counter_id)
1522   {
1523      case SCIC_PHY_COUNTER_RECEIVED_FRAME:
1524         scu_link_layer_register_write(this_phy, received_frame_count, 0);
1525         break;
1526      case SCIC_PHY_COUNTER_TRANSMITTED_FRAME:
1527         scu_link_layer_register_write(this_phy, transmit_frame_count, 0);
1528         break;
1529      case SCIC_PHY_COUNTER_RECEIVED_FRAME_DWORD:
1530         scu_link_layer_register_write(this_phy, received_dword_count, 0);
1531         break;
1532      case SCIC_PHY_COUNTER_TRANSMITTED_FRAME_DWORD:
1533         scu_link_layer_register_write(this_phy, transmit_dword_count, 0);
1534         break;
1535      case SCIC_PHY_COUNTER_LOSS_OF_SYNC_ERROR:
1536         scu_link_layer_register_write(this_phy, loss_of_sync_error_count, 0);
1537         break;
1538      case SCIC_PHY_COUNTER_RECEIVED_DISPARITY_ERROR:
1539         scu_link_layer_register_write(this_phy, running_disparity_error_count, 0);
1540         break;
1541      case SCIC_PHY_COUNTER_RECEIVED_FRAME_CRC_ERROR:
1542         scu_link_layer_register_write(this_phy, received_frame_crc_error_count, 0);
1543         break;
1544      case SCIC_PHY_COUNTER_RECEIVED_DONE_ACK_NAK_TIMEOUT:
1545         this_phy->error_counter[SCU_ERR_CNT_RX_DONE_ACK_NAK_TIMEOUT_INDEX] = 0;
1546         break;
1547      case SCIC_PHY_COUNTER_TRANSMITTED_DONE_ACK_NAK_TIMEOUT:
1548         this_phy->error_counter[SCU_ERR_CNT_TX_DONE_ACK_NAK_TIMEOUT_INDEX] = 0;
1549         break;
1550      case SCIC_PHY_COUNTER_INACTIVITY_TIMER_EXPIRED:
1551         this_phy->error_counter[SCU_ERR_CNT_INACTIVITY_TIMER_EXPIRED_INDEX] = 0;
1552         break;
1553      case SCIC_PHY_COUNTER_RECEIVED_DONE_CREDIT_TIMEOUT:
1554         this_phy->error_counter[SCU_ERR_CNT_RX_DONE_CREDIT_TIMEOUT_INDEX] = 0;
1555         break;
1556      case SCIC_PHY_COUNTER_TRANSMITTED_DONE_CREDIT_TIMEOUT:
1557         this_phy->error_counter[SCU_ERR_CNT_TX_DONE_CREDIT_TIMEOUT_INDEX] = 0;
1558         break;
1559      case SCIC_PHY_COUNTER_RECEIVED_CREDIT_BLOCKED:
1560         this_phy->error_counter[SCU_ERR_CNT_RX_CREDIT_BLOCKED_RECEIVED_INDEX] = 0;
1561         break;
1562      case SCIC_PHY_COUNTER_RECEIVED_SHORT_FRAME:
1563         scu_link_layer_register_write(this_phy, received_short_frame_count, 0);
1564         break;
1565      case SCIC_PHY_COUNTER_RECEIVED_FRAME_WITHOUT_CREDIT:
1566         scu_link_layer_register_write(this_phy, received_frame_without_credit_count, 0);
1567         break;
1568      case SCIC_PHY_COUNTER_RECEIVED_FRAME_AFTER_DONE:
1569         scu_link_layer_register_write(this_phy, received_frame_after_done_count, 0);
1570         break;
1571      case SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR:
1572         scu_link_layer_register_write(this_phy, phy_reset_problem_count, 0);
1573         break;
1574      default:
1575         status = SCI_FAILURE;
1576   }
1577
1578   return status;
1579}
1580
1581#endif // !defined(DISABLE_PHY_COUNTERS)
1582
1583SCI_STATUS scic_phy_stop(
1584   SCI_PHY_HANDLE_T       phy
1585)
1586{
1587   SCIC_SDS_PHY_T *this_phy;
1588   this_phy = (SCIC_SDS_PHY_T *)phy;
1589
1590   SCIC_LOG_TRACE((
1591      sci_base_object_get_logger(this_phy),
1592      SCIC_LOG_OBJECT_PHY,
1593      "scic_phy_stop(this_phy:0x%x)\n",
1594      this_phy
1595   ));
1596
1597   return this_phy->state_handlers->parent.stop_handler(&this_phy->parent);
1598}
1599
1600SCI_STATUS scic_phy_start(
1601   SCI_PHY_HANDLE_T       phy
1602)
1603{
1604   SCIC_SDS_PHY_T *this_phy;
1605   this_phy = (SCIC_SDS_PHY_T *)phy;
1606
1607   SCIC_LOG_TRACE((
1608      sci_base_object_get_logger(this_phy),
1609      SCIC_LOG_OBJECT_PHY,
1610      "scic_phy_start(this_phy:0x%x)\n",
1611      this_phy
1612   ));
1613
1614   return this_phy->state_handlers->parent.start_handler(&this_phy->parent);
1615}
1616
1617//******************************************************************************
1618//* PHY STATE MACHINE
1619//******************************************************************************
1620
1621//***************************************************************************
1622//*  DEFAULT HANDLERS
1623//***************************************************************************
1624
1625/**
1626 * This is the default method for phy a start request.  It will report a
1627 * warning and exit.
1628 *
1629 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
1630 *       SCIC_SDS_PHY object.
1631 *
1632 * @return SCI_STATUS
1633 * @retval SCI_FAILURE_INVALID_STATE
1634 */
1635SCI_STATUS scic_sds_phy_default_start_handler(
1636   SCI_BASE_PHY_T *phy
1637)
1638{
1639   SCIC_SDS_PHY_T *this_phy;
1640   this_phy = (SCIC_SDS_PHY_T *)phy;
1641
1642   SCIC_LOG_WARNING((
1643      sci_base_object_get_logger(this_phy),
1644      SCIC_LOG_OBJECT_PHY,
1645      "SCIC Phy 0x%08x requested to start from invalid state %d\n",
1646      this_phy,
1647      sci_base_state_machine_get_state(&this_phy->parent.state_machine)
1648   ));
1649
1650   return SCI_FAILURE_INVALID_STATE;
1651
1652}
1653
1654/**
1655 * This is the default method for phy a stop request.  It will report a
1656 * warning and exit.
1657 *
1658 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
1659 *       SCIC_SDS_PHY object.
1660 *
1661 * @return SCI_STATUS
1662 * @retval SCI_FAILURE_INVALID_STATE
1663 */
1664SCI_STATUS scic_sds_phy_default_stop_handler(
1665   SCI_BASE_PHY_T *phy
1666)
1667{
1668   SCIC_SDS_PHY_T *this_phy;
1669   this_phy = (SCIC_SDS_PHY_T *)phy;
1670
1671   SCIC_LOG_WARNING((
1672      sci_base_object_get_logger(this_phy),
1673      SCIC_LOG_OBJECT_PHY,
1674      "SCIC Phy 0x%08x requested to stop from invalid state %d\n",
1675      this_phy,
1676      sci_base_state_machine_get_state(&this_phy->parent.state_machine)
1677   ));
1678
1679   return SCI_FAILURE_INVALID_STATE;
1680}
1681
1682/**
1683 * This is the default method for phy a reset request.  It will report a
1684 * warning and exit.
1685 *
1686 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
1687 *       SCIC_SDS_PHY object.
1688 *
1689 * @return SCI_STATUS
1690 * @retval SCI_FAILURE_INVALID_STATE
1691 */
1692SCI_STATUS scic_sds_phy_default_reset_handler(
1693   SCI_BASE_PHY_T * phy
1694)
1695{
1696   SCIC_SDS_PHY_T *this_phy;
1697   this_phy = (SCIC_SDS_PHY_T *)phy;
1698
1699   SCIC_LOG_WARNING((
1700      sci_base_object_get_logger(this_phy),
1701      SCIC_LOG_OBJECT_PHY,
1702      "SCIC Phy 0x%08x requested to reset from invalid state %d\n",
1703      this_phy,
1704      sci_base_state_machine_get_state(&this_phy->parent.state_machine)
1705   ));
1706
1707   return SCI_FAILURE_INVALID_STATE;
1708}
1709
1710/**
1711 * This is the default method for phy a destruct request.  It will report a
1712 * warning and exit.
1713 *
1714 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
1715 *       SCIC_SDS_PHY object.
1716 *
1717 * @return SCI_STATUS
1718 * @retval SCI_FAILURE_INVALID_STATE
1719 */
1720SCI_STATUS scic_sds_phy_default_destroy_handler(
1721   SCI_BASE_PHY_T *phy
1722)
1723{
1724   SCIC_SDS_PHY_T *this_phy;
1725   this_phy = (SCIC_SDS_PHY_T *)phy;
1726
1727   /// @todo Implement something for the default
1728   SCIC_LOG_WARNING((
1729      sci_base_object_get_logger(this_phy),
1730      SCIC_LOG_OBJECT_PHY,
1731      "SCIC Phy 0x%08x requested to destroy from invalid state %d\n",
1732      this_phy,
1733      sci_base_state_machine_get_state(&this_phy->parent.state_machine)
1734   ));
1735
1736   return SCI_FAILURE_INVALID_STATE;
1737}
1738
1739/**
1740 * This is the default method for a phy frame handling request.  It will
1741 * report a warning, release the frame and exit.
1742 *
1743 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
1744 *       SCIC_SDS_PHY object.
1745 * @param[in] frame_index This is the frame index that was received from the
1746 *       SCU hardware.
1747 *
1748 * @return SCI_STATUS
1749 * @retval SCI_FAILURE_INVALID_STATE
1750 */
1751SCI_STATUS scic_sds_phy_default_frame_handler(
1752   SCIC_SDS_PHY_T *this_phy,
1753   U32            frame_index
1754)
1755{
1756   SCIC_LOG_WARNING((
1757      sci_base_object_get_logger(this_phy),
1758      SCIC_LOG_OBJECT_PHY,
1759      "SCIC Phy 0x%08x received unexpected frame data %d while in state %d\n",
1760      this_phy, frame_index,
1761      sci_base_state_machine_get_state(&this_phy->parent.state_machine)
1762   ));
1763
1764   scic_sds_controller_release_frame(
1765      scic_sds_phy_get_controller(this_phy), frame_index);
1766
1767   return SCI_FAILURE_INVALID_STATE;
1768}
1769
1770/**
1771 * This is the default method for a phy event handler.  It will report a
1772 * warning and exit.
1773 *
1774 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
1775 *       SCIC_SDS_PHY object.
1776 * @param[in] event_code This is the event code that was received from the SCU
1777 *       hardware.
1778 *
1779 * @return SCI_STATUS
1780 * @retval SCI_FAILURE_INVALID_STATE
1781 */
1782SCI_STATUS scic_sds_phy_default_event_handler(
1783   SCIC_SDS_PHY_T *this_phy,
1784   U32            event_code
1785)
1786{
1787   SCIC_LOG_WARNING((
1788      sci_base_object_get_logger(this_phy),
1789      SCIC_LOG_OBJECT_PHY,
1790      "SCIC Phy 0x%08x received unexpected event status %x while in state %d\n",
1791      this_phy, event_code,
1792      sci_base_state_machine_get_state(&this_phy->parent.state_machine)
1793   ));
1794
1795   return SCI_FAILURE_INVALID_STATE;
1796}
1797
1798/**
1799 * This is the default method for a phy consume power handler.  It will report
1800 * a warning and exit.
1801 *
1802 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
1803 *       SCIC_SDS_PHY object.
1804 *
1805 * @return SCI_STATUS
1806 * @retval SCI_FAILURE_INVALID_STATE
1807 */
1808SCI_STATUS scic_sds_phy_default_consume_power_handler(
1809   SCIC_SDS_PHY_T *this_phy
1810)
1811{
1812   SCIC_LOG_WARNING((
1813      sci_base_object_get_logger(this_phy),
1814      SCIC_LOG_OBJECT_PHY,
1815      "SCIC Phy 0x%08x given unexpected permission to consume power while in state %d\n",
1816      this_phy,
1817      sci_base_state_machine_get_state(&this_phy->parent.state_machine)
1818   ));
1819
1820   return SCI_FAILURE_INVALID_STATE;
1821}
1822
1823//******************************************************************************
1824//* PHY STOPPED STATE HANDLERS
1825//******************************************************************************
1826
1827/**
1828 * This method takes the SCIC_SDS_PHY from a stopped state and attempts to
1829 * start it.
1830 *    - The phy state machine is transitioned to the
1831 *      SCI_BASE_PHY_STATE_STARTING.
1832 *
1833 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
1834 *       SCIC_SDS_PHY object.
1835 *
1836 * @return SCI_STATUS
1837 * @retval SCI_SUCCESS
1838 */
1839static
1840SCI_STATUS scic_sds_phy_stopped_state_start_handler(
1841   SCI_BASE_PHY_T *phy
1842)
1843{
1844   SCIC_SDS_PHY_T *this_phy;
1845   this_phy = (SCIC_SDS_PHY_T *)phy;
1846
1847
1848
1849   // Create the SIGNATURE FIS Timeout timer for this phy
1850   this_phy->sata_timeout_timer = scic_cb_timer_create(
1851      scic_sds_phy_get_controller(this_phy),
1852      scic_sds_phy_sata_timeout,
1853      this_phy
1854   );
1855
1856   if (this_phy->sata_timeout_timer != NULL)
1857   {
1858      sci_base_state_machine_change_state(
1859         scic_sds_phy_get_base_state_machine(this_phy),
1860         SCI_BASE_PHY_STATE_STARTING
1861      );
1862   }
1863
1864   return SCI_SUCCESS;
1865}
1866
1867/**
1868 * This method takes the SCIC_SDS_PHY from a stopped state and destroys it.
1869 *    - This function takes no action.
1870 *
1871 * @todo Shouldn't this function transition the SCI_BASE_PHY::state_machine to
1872 *        the SCI_BASE_PHY_STATE_FINAL?
1873 *
1874 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
1875 *       SCIC_SDS_PHY object.
1876 *
1877 * @return SCI_STATUS
1878 * @retval SCI_SUCCESS
1879 */
1880static
1881SCI_STATUS scic_sds_phy_stopped_state_destroy_handler(
1882   SCI_BASE_PHY_T *phy
1883)
1884{
1885   SCIC_SDS_PHY_T *this_phy;
1886   this_phy = (SCIC_SDS_PHY_T *)phy;
1887
1888   /// @todo what do we actually need to do here?
1889   return SCI_SUCCESS;
1890}
1891
1892//******************************************************************************
1893//* PHY STARTING STATE HANDLERS
1894//******************************************************************************
1895
1896// All of these state handlers are mapped to the starting sub-state machine
1897
1898//******************************************************************************
1899//* PHY READY STATE HANDLERS
1900//******************************************************************************
1901
1902/**
1903 * This method takes the SCIC_SDS_PHY from a ready state and attempts to stop
1904 * it.
1905 *    - The phy state machine is transitioned to the SCI_BASE_PHY_STATE_STOPPED.
1906 *
1907 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
1908 *       SCIC_SDS_PHY object.
1909 *
1910 * @return SCI_STATUS
1911 * @retval SCI_SUCCESS
1912 */
1913static
1914SCI_STATUS scic_sds_phy_ready_state_stop_handler(
1915   SCI_BASE_PHY_T *phy
1916)
1917{
1918   SCIC_SDS_PHY_T *this_phy;
1919   this_phy = (SCIC_SDS_PHY_T *)phy;
1920
1921   sci_base_state_machine_change_state(
1922      scic_sds_phy_get_base_state_machine(this_phy),
1923      SCI_BASE_PHY_STATE_STOPPED
1924   );
1925
1926   scic_sds_controller_link_down(
1927      scic_sds_phy_get_controller(this_phy),
1928      scic_sds_phy_get_port(this_phy),
1929      this_phy
1930   );
1931
1932   return SCI_SUCCESS;
1933}
1934
1935/**
1936 * This method takes the SCIC_SDS_PHY from a ready state and attempts to reset
1937 * it.
1938 *    - The phy state machine is transitioned to the SCI_BASE_PHY_STATE_STARTING.
1939 *
1940 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
1941 *       SCIC_SDS_PHY object.
1942 *
1943 * @return SCI_STATUS
1944 * @retval SCI_SUCCESS
1945 */
1946static
1947SCI_STATUS scic_sds_phy_ready_state_reset_handler(
1948   SCI_BASE_PHY_T * phy
1949)
1950{
1951   SCIC_SDS_PHY_T * this_phy;
1952   this_phy = (SCIC_SDS_PHY_T *)phy;
1953
1954   sci_base_state_machine_change_state(
1955      scic_sds_phy_get_base_state_machine(this_phy),
1956      SCI_BASE_PHY_STATE_RESETTING
1957   );
1958
1959   return SCI_SUCCESS;
1960}
1961
1962/**
1963 * This method request the SCIC_SDS_PHY handle the received event.  The only
1964 * event that we are interested in while in the ready state is the link
1965 * failure event.
1966 *    - decoded event is a link failure
1967 *       - transition the SCIC_SDS_PHY back to the SCI_BASE_PHY_STATE_STARTING
1968 *         state.
1969 *    - any other event received will report a warning message
1970 *
1971 * @param[in] phy This is the SCIC_SDS_PHY object which has received the
1972 *       event.
1973 *
1974 * @return SCI_STATUS
1975 * @retval SCI_SUCCESS if the event received is a link failure
1976 * @retval SCI_FAILURE_INVALID_STATE for any other event received.
1977 */
1978static
1979SCI_STATUS scic_sds_phy_ready_state_event_handler(
1980   SCIC_SDS_PHY_T *this_phy,
1981   U32            event_code
1982)
1983{
1984   SCI_STATUS result = SCI_FAILURE;
1985
1986   switch (scu_get_event_code(event_code))
1987   {
1988   case SCU_EVENT_LINK_FAILURE:
1989      // Link failure change state back to the starting state
1990      sci_base_state_machine_change_state(
1991         scic_sds_phy_get_base_state_machine(this_phy),
1992         SCI_BASE_PHY_STATE_STARTING
1993         );
1994
1995      result = SCI_SUCCESS;
1996      break;
1997
1998   case SCU_EVENT_BROADCAST_CHANGE:
1999      // Broadcast change received. Notify the port.
2000      if (scic_sds_phy_get_port(this_phy) != SCI_INVALID_HANDLE)
2001         scic_sds_port_broadcast_change_received(this_phy->owning_port, this_phy);
2002      else
2003         this_phy->bcn_received_while_port_unassigned = TRUE;
2004      break;
2005
2006   case SCU_EVENT_ERR_CNT(RX_CREDIT_BLOCKED_RECEIVED):
2007   case SCU_EVENT_ERR_CNT(TX_DONE_CREDIT_TIMEOUT):
2008   case SCU_EVENT_ERR_CNT(RX_DONE_CREDIT_TIMEOUT):
2009   case SCU_EVENT_ERR_CNT(INACTIVITY_TIMER_EXPIRED):
2010   case SCU_EVENT_ERR_CNT(TX_DONE_ACK_NAK_TIMEOUT):
2011   case SCU_EVENT_ERR_CNT(RX_DONE_ACK_NAK_TIMEOUT):
2012      {
2013         U32 error_counter_index =
2014                scu_get_event_specifier(event_code) >> SCU_EVENT_SPECIFIC_CODE_SHIFT;
2015
2016         this_phy->error_counter[error_counter_index]++;
2017         result = SCI_SUCCESS;
2018      }
2019      break;
2020
2021   default:
2022      SCIC_LOG_WARNING((
2023         sci_base_object_get_logger(this_phy),
2024         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
2025         "SCIC PHY 0x%x ready state machine received unexpected event_code %x\n",
2026         this_phy, event_code
2027      ));
2028      result = SCI_FAILURE_INVALID_STATE;
2029      break;
2030   }
2031
2032   return result;
2033}
2034
2035// ---------------------------------------------------------------------------
2036
2037/**
2038 * This is the resetting state event handler.
2039 *
2040 * @param[in] this_phy This is the SCIC_SDS_PHY object which is receiving the
2041 *       event.
2042 * @param[in] event_code This is the event code to be processed.
2043 *
2044 * @return SCI_STATUS
2045 * @retval SCI_FAILURE_INVALID_STATE
2046 */
2047static
2048SCI_STATUS scic_sds_phy_resetting_state_event_handler(
2049   SCIC_SDS_PHY_T *this_phy,
2050   U32            event_code
2051)
2052{
2053   SCI_STATUS result = SCI_FAILURE;
2054
2055   switch (scu_get_event_code(event_code))
2056   {
2057   case SCU_EVENT_HARD_RESET_TRANSMITTED:
2058      // Link failure change state back to the starting state
2059      sci_base_state_machine_change_state(
2060         scic_sds_phy_get_base_state_machine(this_phy),
2061         SCI_BASE_PHY_STATE_STARTING
2062         );
2063
2064      result = SCI_SUCCESS;
2065      break;
2066
2067   default:
2068      SCIC_LOG_WARNING((
2069         sci_base_object_get_logger(this_phy),
2070         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
2071         "SCIC PHY 0x%x resetting state machine received unexpected event_code %x\n",
2072         this_phy, event_code
2073      ));
2074
2075      result = SCI_FAILURE_INVALID_STATE;
2076      break;
2077   }
2078
2079   return result;
2080}
2081
2082// ---------------------------------------------------------------------------
2083
2084SCIC_SDS_PHY_STATE_HANDLER_T
2085   scic_sds_phy_state_handler_table[SCI_BASE_PHY_MAX_STATES] =
2086{
2087   // SCI_BASE_PHY_STATE_INITIAL
2088   {
2089      {
2090         scic_sds_phy_default_start_handler,
2091         scic_sds_phy_default_stop_handler,
2092         scic_sds_phy_default_reset_handler,
2093         scic_sds_phy_default_destroy_handler
2094      },
2095      scic_sds_phy_default_frame_handler,
2096      scic_sds_phy_default_event_handler,
2097      scic_sds_phy_default_consume_power_handler
2098   },
2099   // SCI_BASE_PHY_STATE_STOPPED
2100   {
2101      {
2102         scic_sds_phy_stopped_state_start_handler,
2103         scic_sds_phy_default_stop_handler,
2104         scic_sds_phy_default_reset_handler,
2105         scic_sds_phy_stopped_state_destroy_handler
2106      },
2107      scic_sds_phy_default_frame_handler,
2108      scic_sds_phy_default_event_handler,
2109      scic_sds_phy_default_consume_power_handler
2110   },
2111   // SCI_BASE_PHY_STATE_STARTING
2112   {
2113      {
2114         scic_sds_phy_default_start_handler,
2115         scic_sds_phy_default_stop_handler,
2116         scic_sds_phy_default_reset_handler,
2117         scic_sds_phy_default_destroy_handler
2118      },
2119      scic_sds_phy_default_frame_handler,
2120      scic_sds_phy_default_event_handler,
2121      scic_sds_phy_default_consume_power_handler
2122   },
2123   // SCI_BASE_PHY_STATE_READY
2124   {
2125      {
2126         scic_sds_phy_default_start_handler,
2127         scic_sds_phy_ready_state_stop_handler,
2128         scic_sds_phy_ready_state_reset_handler,
2129         scic_sds_phy_default_destroy_handler
2130      },
2131      scic_sds_phy_default_frame_handler,
2132      scic_sds_phy_ready_state_event_handler,
2133      scic_sds_phy_default_consume_power_handler
2134   },
2135   // SCI_BASE_PHY_STATE_RESETTING
2136   {
2137      {
2138         scic_sds_phy_default_start_handler,
2139         scic_sds_phy_default_stop_handler,
2140         scic_sds_phy_default_reset_handler,
2141         scic_sds_phy_default_destroy_handler
2142      },
2143      scic_sds_phy_default_frame_handler,
2144      scic_sds_phy_resetting_state_event_handler,
2145      scic_sds_phy_default_consume_power_handler
2146   },
2147   // SCI_BASE_PHY_STATE_FINAL
2148   {
2149      {
2150         scic_sds_phy_default_start_handler,
2151         scic_sds_phy_default_stop_handler,
2152         scic_sds_phy_default_reset_handler,
2153         scic_sds_phy_default_destroy_handler
2154      },
2155      scic_sds_phy_default_frame_handler,
2156      scic_sds_phy_default_event_handler,
2157      scic_sds_phy_default_consume_power_handler
2158   }
2159};
2160
2161//****************************************************************************
2162//*  PHY STATE PRIVATE METHODS
2163//****************************************************************************
2164
2165/**
2166 * This method will stop the SCIC_SDS_PHY object. This does not reset the
2167 * protocol engine it just suspends it and places it in a state where it will
2168 * not cause the end device to power up.
2169 *
2170 * @param[in] this_phy This is the SCIC_SDS_PHY object to stop.
2171 *
2172 * @return none
2173 */
2174static
2175void scu_link_layer_stop_protocol_engine(
2176   SCIC_SDS_PHY_T *this_phy
2177)
2178{
2179   U32 scu_sas_pcfg_value;
2180   U32 enable_spinup_value;
2181
2182   // Suspend the protocol engine and place it in a sata spinup hold state
2183   scu_sas_pcfg_value  = SCU_SAS_PCFG_READ(this_phy);
2184   scu_sas_pcfg_value |= (
2185                           SCU_SAS_PCFG_GEN_BIT(OOB_RESET)
2186                         | SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE)
2187                         | SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD)
2188                         );
2189   SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
2190
2191   // Disable the notify enable spinup primitives
2192   enable_spinup_value = SCU_SAS_ENSPINUP_READ(this_phy);
2193   enable_spinup_value &= ~SCU_ENSPINUP_GEN_BIT(ENABLE);
2194   SCU_SAS_ENSPINUP_WRITE(this_phy, enable_spinup_value);
2195}
2196
2197/**
2198 * This method will start the OOB/SN state machine for this SCIC_SDS_PHY
2199 * object.
2200 *
2201 * @param[in] this_phy This is the SCIC_SDS_PHY object on which to start the
2202 *       OOB/SN state machine.
2203 */
2204static
2205void scu_link_layer_start_oob(
2206   SCIC_SDS_PHY_T *this_phy
2207)
2208{
2209   U32 scu_sas_pcfg_value;
2210
2211   /* Reset OOB sequence - start */
2212   scu_sas_pcfg_value = SCU_SAS_PCFG_READ(this_phy);
2213   scu_sas_pcfg_value &=
2214      ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | SCU_SAS_PCFG_GEN_BIT(HARD_RESET));
2215   SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
2216   SCU_SAS_PCFG_READ(this_phy);
2217   /* Reset OOB sequence - end */
2218
2219   /* Start OOB sequence - start */
2220   scu_sas_pcfg_value = SCU_SAS_PCFG_READ(this_phy);
2221   scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
2222   SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
2223   SCU_SAS_PCFG_READ(this_phy);
2224   /* Start OOB sequence - end */
2225}
2226
2227/**
2228 * This method will transmit a hard reset request on the specified phy. The
2229 * SCU hardware requires that we reset the OOB state machine and set the hard
2230 * reset bit in the phy configuration register.
2231 * We then must start OOB over with the hard reset bit set.
2232 *
2233 * @param[in] this_phy
2234 */
2235static
2236void scu_link_layer_tx_hard_reset(
2237   SCIC_SDS_PHY_T *this_phy
2238)
2239{
2240   U32 phy_configuration_value;
2241
2242   // SAS Phys must wait for the HARD_RESET_TX event notification to transition
2243   // to the starting state.
2244   phy_configuration_value = SCU_SAS_PCFG_READ(this_phy);
2245   phy_configuration_value |=
2246      (SCU_SAS_PCFG_GEN_BIT(HARD_RESET) | SCU_SAS_PCFG_GEN_BIT(OOB_RESET));
2247   SCU_SAS_PCFG_WRITE(this_phy, phy_configuration_value);
2248
2249   // Now take the OOB state machine out of reset
2250   phy_configuration_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
2251   phy_configuration_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
2252   SCU_SAS_PCFG_WRITE(this_phy, phy_configuration_value);
2253}
2254
2255//****************************************************************************
2256//*  PHY BASE STATE METHODS
2257//****************************************************************************
2258
2259/**
2260 * This method will perform the actions required by the SCIC_SDS_PHY on
2261 * entering the SCI_BASE_PHY_STATE_INITIAL.
2262 *    - This function sets the state handlers for the phy object base state
2263 * machine initial state.
2264 *
2265 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2266 *       SCIC_SDS_PHY object.
2267 *
2268 * @return none
2269 */
2270static
2271void scic_sds_phy_initial_state_enter(
2272   SCI_BASE_OBJECT_T *object
2273)
2274{
2275   SCIC_SDS_PHY_T *this_phy;
2276   this_phy = (SCIC_SDS_PHY_T *)object;
2277
2278   scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_INITIAL);
2279}
2280
2281/**
2282 * This method will perform the actions required by the SCIC_SDS_PHY on
2283 * entering the SCI_BASE_PHY_STATE_INITIAL.
2284 *    - This function sets the state handlers for the phy object base state
2285 * machine initial state.
2286 *    - The SCU hardware is requested to stop the protocol engine.
2287 *
2288 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2289 *       SCIC_SDS_PHY object.
2290 *
2291 * @return none
2292 */
2293static
2294void scic_sds_phy_stopped_state_enter(
2295   SCI_BASE_OBJECT_T *object
2296)
2297{
2298   SCIC_SDS_PHY_T *this_phy;
2299   this_phy = (SCIC_SDS_PHY_T *)object;
2300
2301   /// @todo We need to get to the controller to place this PE in a reset state
2302   scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_STOPPED);
2303
2304   if (this_phy->sata_timeout_timer != NULL)
2305   {
2306      scic_cb_timer_destroy(
2307         scic_sds_phy_get_controller(this_phy),
2308         this_phy->sata_timeout_timer
2309      );
2310
2311      this_phy->sata_timeout_timer = NULL;
2312   }
2313
2314   scu_link_layer_stop_protocol_engine(this_phy);
2315}
2316
2317/**
2318 * This method will perform the actions required by the SCIC_SDS_PHY on
2319 * entering the SCI_BASE_PHY_STATE_STARTING.
2320 *    - This function sets the state handlers for the phy object base state
2321 * machine starting state.
2322 *    - The SCU hardware is requested to start OOB/SN on this protocol engine.
2323 *    - The phy starting substate machine is started.
2324 *    - If the previous state was the ready state then the
2325 *      SCIC_SDS_CONTROLLER is informed that the phy has gone link down.
2326 *
2327 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2328 *       SCIC_SDS_PHY object.
2329 *
2330 * @return none
2331 */
2332static
2333void scic_sds_phy_starting_state_enter(
2334   SCI_BASE_OBJECT_T *object
2335)
2336{
2337   SCIC_SDS_PHY_T *this_phy;
2338   this_phy = (SCIC_SDS_PHY_T *)object;
2339
2340   scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_STARTING);
2341
2342   scu_link_layer_stop_protocol_engine(this_phy);
2343   scu_link_layer_start_oob(this_phy);
2344
2345   // We don't know what kind of phy we are going to be just yet
2346   this_phy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN;
2347   this_phy->bcn_received_while_port_unassigned = FALSE;
2348
2349   // Change over to the starting substate machine to continue
2350   sci_base_state_machine_start(&this_phy->starting_substate_machine);
2351
2352   if (this_phy->parent.state_machine.previous_state_id
2353       == SCI_BASE_PHY_STATE_READY)
2354   {
2355      scic_sds_controller_link_down(
2356         scic_sds_phy_get_controller(this_phy),
2357         scic_sds_phy_get_port(this_phy),
2358         this_phy
2359      );
2360   }
2361}
2362
2363/**
2364 * This method will perform the actions required by the SCIC_SDS_PHY on
2365 * entering the SCI_BASE_PHY_STATE_READY.
2366 *    - This function sets the state handlers for the phy object base state
2367 * machine ready state.
2368 *    - The SCU hardware protocol engine is resumed.
2369 *    - The SCIC_SDS_CONTROLLER is informed that the phy object has gone link
2370 *      up.
2371 *
2372 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2373 *       SCIC_SDS_PHY object.
2374 *
2375 * @return none
2376 */
2377static
2378void scic_sds_phy_ready_state_enter(
2379   SCI_BASE_OBJECT_T *object
2380)
2381{
2382   SCIC_SDS_PHY_T *this_phy;
2383   this_phy = (SCIC_SDS_PHY_T *)object;
2384
2385   scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_READY);
2386
2387   scic_sds_controller_link_up(
2388      scic_sds_phy_get_controller(this_phy),
2389      scic_sds_phy_get_port(this_phy),
2390      this_phy
2391   );
2392}
2393
2394/**
2395 * This method will perform the actions required by the SCIC_SDS_PHY on
2396 * exiting the SCI_BASE_PHY_STATE_INITIAL. This function suspends the SCU
2397 * hardware protocol engine represented by this SCIC_SDS_PHY object.
2398 *
2399 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2400 *       SCIC_SDS_PHY object.
2401 *
2402 * @return none
2403 */
2404static
2405void scic_sds_phy_ready_state_exit(
2406   SCI_BASE_OBJECT_T *object
2407)
2408{
2409   SCIC_SDS_PHY_T *this_phy;
2410   this_phy = (SCIC_SDS_PHY_T *)object;
2411
2412   scic_sds_phy_suspend(this_phy);
2413}
2414
2415/**
2416 * This method will perform the actions required by the SCIC_SDS_PHY on
2417 * entering the SCI_BASE_PHY_STATE_RESETTING.
2418 *    - This function sets the state handlers for the phy object base state
2419 * machine resetting state.
2420 *
2421 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2422 *       SCIC_SDS_PHY object.
2423 *
2424 * @return none
2425 */
2426static
2427void scic_sds_phy_resetting_state_enter(
2428   SCI_BASE_OBJECT_T *object
2429)
2430{
2431   SCIC_SDS_PHY_T * this_phy;
2432   this_phy = (SCIC_SDS_PHY_T *)object;
2433
2434   scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_RESETTING);
2435
2436   // The phy is being reset, therefore deactivate it from the port.
2437   // In the resetting state we don't notify the user regarding
2438   // link up and link down notifications.
2439   scic_sds_port_deactivate_phy(this_phy->owning_port, this_phy, FALSE);
2440
2441   if (this_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS)
2442   {
2443      scu_link_layer_tx_hard_reset(this_phy);
2444   }
2445   else
2446   {
2447      // The SCU does not need to have a descrete reset state so just go back to
2448      // the starting state.
2449      sci_base_state_machine_change_state(
2450         &this_phy->parent.state_machine,
2451         SCI_BASE_PHY_STATE_STARTING
2452      );
2453   }
2454}
2455
2456/**
2457 * This method will perform the actions required by the SCIC_SDS_PHY on
2458 * entering the SCI_BASE_PHY_STATE_FINAL.
2459 *    - This function sets the state handlers for the phy object base state
2460 * machine final state.
2461 *
2462 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2463 *       SCIC_SDS_PHY object.
2464 *
2465 * @return none
2466 */
2467static
2468void scic_sds_phy_final_state_enter(
2469   SCI_BASE_OBJECT_T *object
2470)
2471{
2472   SCIC_SDS_PHY_T *this_phy;
2473   this_phy = (SCIC_SDS_PHY_T *)object;
2474
2475   scic_sds_phy_set_base_state_handlers(this_phy, SCI_BASE_PHY_STATE_FINAL);
2476
2477   // Nothing to do here
2478}
2479
2480// ---------------------------------------------------------------------------
2481
2482SCI_BASE_STATE_T scic_sds_phy_state_table[SCI_BASE_PHY_MAX_STATES] =
2483{
2484   {
2485      SCI_BASE_PHY_STATE_INITIAL,
2486      scic_sds_phy_initial_state_enter,
2487      NULL,
2488   },
2489   {
2490      SCI_BASE_PHY_STATE_STOPPED,
2491      scic_sds_phy_stopped_state_enter,
2492      NULL,
2493   },
2494   {
2495      SCI_BASE_PHY_STATE_STARTING,
2496      scic_sds_phy_starting_state_enter,
2497      NULL,
2498   },
2499   {
2500      SCI_BASE_PHY_STATE_READY,
2501      scic_sds_phy_ready_state_enter,
2502      scic_sds_phy_ready_state_exit,
2503   },
2504   {
2505      SCI_BASE_PHY_STATE_RESETTING,
2506      scic_sds_phy_resetting_state_enter,
2507      NULL,
2508   },
2509   {
2510      SCI_BASE_PHY_STATE_FINAL,
2511      scic_sds_phy_final_state_enter,
2512      NULL,
2513   }
2514};
2515
2516//******************************************************************************
2517//* PHY STARTING SUB-STATE MACHINE
2518//******************************************************************************
2519
2520//*****************************************************************************
2521//* SCIC SDS PHY HELPER FUNCTIONS
2522//*****************************************************************************
2523
2524
2525/**
2526 * This method continues the link training for the phy as if it were a SAS PHY
2527 * instead of a SATA PHY. This is done because the completion queue had a SAS
2528 * PHY DETECTED event when the state machine was expecting a SATA PHY event.
2529 *
2530 * @param[in] this_phy The phy object that received SAS PHY DETECTED.
2531 *
2532 * @return none
2533 */
2534static
2535void scic_sds_phy_start_sas_link_training(
2536   SCIC_SDS_PHY_T * this_phy
2537)
2538{
2539   U32 phy_control;
2540
2541   phy_control = SCU_SAS_PCFG_READ(this_phy);
2542   phy_control |= SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD);
2543   SCU_SAS_PCFG_WRITE(this_phy, phy_control);
2544
2545   sci_base_state_machine_change_state(
2546      &this_phy->starting_substate_machine,
2547      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN
2548   );
2549
2550   this_phy->protocol = SCIC_SDS_PHY_PROTOCOL_SAS;
2551}
2552
2553/**
2554 * This method continues the link training for the phy as if it were a SATA
2555 * PHY instead of a SAS PHY.  This is done because the completion queue had a
2556 * SATA SPINUP HOLD event when the state machine was expecting a SAS PHY
2557 * event.
2558 *
2559 * @param[in] this_phy The phy object that received a SATA SPINUP HOLD event
2560 *
2561 * @return none
2562 */
2563static
2564void scic_sds_phy_start_sata_link_training(
2565   SCIC_SDS_PHY_T * this_phy
2566)
2567{
2568   sci_base_state_machine_change_state(
2569      &this_phy->starting_substate_machine,
2570      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER
2571   );
2572
2573   this_phy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA;
2574}
2575
2576/**
2577 * @brief This method performs processing common to all protocols upon
2578 *        completion of link training.
2579 *
2580 * @param[in,out] this_phy This parameter specifies the phy object for which
2581 *                link training has completed.
2582 * @param[in]     max_link_rate This parameter specifies the maximum link
2583 *                rate to be associated with this phy.
2584 * @param[in]     next_state This parameter specifies the next state for the
2585 *                phy's starting sub-state machine.
2586 *
2587 * @return none
2588 */
2589static
2590void scic_sds_phy_complete_link_training(
2591   SCIC_SDS_PHY_T *   this_phy,
2592   SCI_SAS_LINK_RATE  max_link_rate,
2593   U32                next_state
2594)
2595{
2596   this_phy->max_negotiated_speed = max_link_rate;
2597
2598   sci_base_state_machine_change_state(
2599      scic_sds_phy_get_starting_substate_machine(this_phy), next_state
2600   );
2601}
2602
2603/**
2604 * This method restarts the SCIC_SDS_PHY objects base state machine in the
2605 * starting state from any starting substate.
2606 *
2607 * @param[in] this_phy The SCIC_SDS_PHY object to restart.
2608 *
2609 * @return none
2610 */
2611void scic_sds_phy_restart_starting_state(
2612   SCIC_SDS_PHY_T *this_phy
2613)
2614{
2615   // Stop the current substate machine
2616   sci_base_state_machine_stop(
2617      scic_sds_phy_get_starting_substate_machine(this_phy)
2618   );
2619
2620   // Re-enter the base state machine starting state
2621   sci_base_state_machine_change_state(
2622      scic_sds_phy_get_base_state_machine(this_phy),
2623      SCI_BASE_PHY_STATE_STARTING
2624      );
2625}
2626
2627
2628//*****************************************************************************
2629//* SCIC SDS PHY general handlers
2630//*****************************************************************************
2631
2632static
2633SCI_STATUS scic_sds_phy_starting_substate_general_stop_handler(
2634   SCI_BASE_PHY_T *phy
2635)
2636{
2637   SCIC_SDS_PHY_T *this_phy;
2638   this_phy = (SCIC_SDS_PHY_T *)phy;
2639
2640   sci_base_state_machine_stop(
2641      &this_phy->starting_substate_machine
2642   );
2643
2644   sci_base_state_machine_change_state(
2645      &phy->state_machine,
2646      SCI_BASE_PHY_STATE_STOPPED
2647   );
2648
2649   return SCI_SUCCESS;
2650}
2651
2652//*****************************************************************************
2653//* SCIC SDS PHY EVENT_HANDLERS
2654//*****************************************************************************
2655
2656/**
2657 * This method is called when an event notification is received for the phy
2658 * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SPEED_EN.
2659 *    - decode the event
2660 *       - sas phy detected causes a state transition to the wait for speed
2661 *         event notification.
2662 *       - any other events log a warning message and set a failure status
2663 *
2664 * @param[in] phy This SCIC_SDS_PHY object which has received an event.
2665 * @param[in] event_code This is the event code which the phy object is to
2666 *       decode.
2667 *
2668 * @return SCI_STATUS
2669 * @retval SCI_SUCCESS on any valid event notification
2670 * @retval SCI_FAILURE on any unexpected event notifation
2671 */
2672static
2673SCI_STATUS scic_sds_phy_starting_substate_await_ossp_event_handler(
2674   SCIC_SDS_PHY_T *this_phy,
2675   U32 event_code
2676)
2677{
2678   U32 result = SCI_SUCCESS;
2679
2680   switch (scu_get_event_code(event_code))
2681   {
2682   case SCU_EVENT_SAS_PHY_DETECTED:
2683      scic_sds_phy_start_sas_link_training(this_phy);
2684      this_phy->is_in_link_training = TRUE;
2685   break;
2686
2687   case SCU_EVENT_SATA_SPINUP_HOLD:
2688      scic_sds_phy_start_sata_link_training(this_phy);
2689      this_phy->is_in_link_training = TRUE;
2690   break;
2691
2692   default:
2693      SCIC_LOG_WARNING((
2694         sci_base_object_get_logger(this_phy),
2695         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
2696         "PHY starting substate machine received unexpected event_code %x\n",
2697         event_code
2698      ));
2699
2700      result = SCI_FAILURE;
2701   break;
2702   }
2703
2704   return result;
2705}
2706
2707/**
2708 * This method is called when an event notification is received for the phy
2709 * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SPEED_EN.
2710 *    - decode the event
2711 *       - sas phy detected returns us back to this state.
2712 *       - speed event detected causes a state transition to the wait for iaf.
2713 *       - identify timeout is an un-expected event and the state machine is
2714 *         restarted.
2715 *       - link failure events restart the starting state machine
2716 *       - any other events log a warning message and set a failure status
2717 *
2718 * @param[in] phy This SCIC_SDS_PHY object which has received an event.
2719 * @param[in] event_code This is the event code which the phy object is to
2720 *       decode.
2721 *
2722 * @return SCI_STATUS
2723 * @retval SCI_SUCCESS on any valid event notification
2724 * @retval SCI_FAILURE on any unexpected event notifation
2725 */
2726static
2727SCI_STATUS scic_sds_phy_starting_substate_await_sas_phy_speed_event_handler(
2728   SCIC_SDS_PHY_T *this_phy,
2729   U32 event_code
2730)
2731{
2732   U32 result = SCI_SUCCESS;
2733
2734   switch (scu_get_event_code(event_code))
2735   {
2736   case SCU_EVENT_SAS_PHY_DETECTED:
2737      // Why is this being reported again by the controller?
2738      // We would re-enter this state so just stay here
2739   break;
2740
2741   case SCU_EVENT_SAS_15:
2742   case SCU_EVENT_SAS_15_SSC:
2743      scic_sds_phy_complete_link_training(
2744         this_phy, SCI_SAS_150_GB, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF
2745      );
2746   break;
2747
2748   case SCU_EVENT_SAS_30:
2749   case SCU_EVENT_SAS_30_SSC:
2750      scic_sds_phy_complete_link_training(
2751         this_phy, SCI_SAS_300_GB, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF
2752      );
2753   break;
2754
2755   case SCU_EVENT_SAS_60:
2756   case SCU_EVENT_SAS_60_SSC:
2757      scic_sds_phy_complete_link_training(
2758         this_phy, SCI_SAS_600_GB, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF
2759      );
2760   break;
2761
2762   case SCU_EVENT_SATA_SPINUP_HOLD:
2763      // We were doing SAS PHY link training and received a SATA PHY event
2764      // continue OOB/SN as if this were a SATA PHY
2765      scic_sds_phy_start_sata_link_training(this_phy);
2766   break;
2767
2768   case SCU_EVENT_LINK_FAILURE:
2769      // Link failure change state back to the starting state
2770      scic_sds_phy_restart_starting_state(this_phy);
2771   break;
2772
2773   default:
2774      SCIC_LOG_WARNING((
2775         sci_base_object_get_logger(this_phy),
2776         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
2777         "PHY starting substate machine received unexpected event_code %x\n",
2778         event_code
2779      ));
2780
2781      result = SCI_FAILURE;
2782   break;
2783   }
2784
2785   return result;
2786}
2787
2788/**
2789 * This method is called when an event notification is received for the phy
2790 * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF.
2791 *    - decode the event
2792 *       - sas phy detected event backs up the state machine to the await
2793 *         speed notification.
2794 *       - identify timeout is an un-expected event and the state machine is
2795 *         restarted.
2796 *       - link failure events restart the starting state machine
2797 *       - any other events log a warning message and set a failure status
2798 *
2799 * @param[in] phy This SCIC_SDS_PHY object which has received an event.
2800 * @param[in] event_code This is the event code which the phy object is to
2801 *       decode.
2802 *
2803 * @return SCI_STATUS
2804 * @retval SCI_SUCCESS on any valid event notification
2805 * @retval SCI_FAILURE on any unexpected event notifation
2806 */
2807static
2808SCI_STATUS scic_sds_phy_starting_substate_await_iaf_uf_event_handler(
2809   SCIC_SDS_PHY_T *this_phy,
2810   U32 event_code
2811)
2812{
2813   U32 result = SCI_SUCCESS;
2814
2815   switch (scu_get_event_code(event_code))
2816   {
2817   case SCU_EVENT_SAS_PHY_DETECTED:
2818      // Backup the state machine
2819      scic_sds_phy_start_sas_link_training(this_phy);
2820      break;
2821
2822   case SCU_EVENT_SATA_SPINUP_HOLD:
2823      // We were doing SAS PHY link training and received a SATA PHY event
2824      // continue OOB/SN as if this were a SATA PHY
2825      scic_sds_phy_start_sata_link_training(this_phy);
2826   break;
2827
2828   case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT:
2829   case SCU_EVENT_LINK_FAILURE:
2830   case SCU_EVENT_HARD_RESET_RECEIVED:
2831      // Start the oob/sn state machine over again
2832      scic_sds_phy_restart_starting_state(this_phy);
2833      break;
2834
2835   default:
2836      SCIC_LOG_WARNING((
2837         sci_base_object_get_logger(this_phy),
2838         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
2839         "PHY starting substate machine received unexpected event_code %x\n",
2840         event_code
2841      ));
2842
2843      result = SCI_FAILURE;
2844      break;
2845   }
2846
2847   return result;
2848}
2849
2850/**
2851 * This method is called when an event notification is received for the phy
2852 * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_POWER.
2853 *    - decode the event
2854 *       - link failure events restart the starting state machine
2855 *       - any other events log a warning message and set a failure status
2856 *
2857 * @param[in] phy This SCIC_SDS_PHY object which has received an event.
2858 * @param[in] event_code This is the event code which the phy object is to
2859 *       decode.
2860 *
2861 * @return SCI_STATUS
2862 * @retval SCI_SUCCESS on a link failure event
2863 * @retval SCI_FAILURE on any unexpected event notifation
2864 */
2865static
2866SCI_STATUS scic_sds_phy_starting_substate_await_sas_power_event_handler(
2867   SCIC_SDS_PHY_T *this_phy,
2868   U32 event_code
2869)
2870{
2871   U32 result = SCI_SUCCESS;
2872
2873   switch (scu_get_event_code(event_code))
2874   {
2875   case SCU_EVENT_LINK_FAILURE:
2876      // Link failure change state back to the starting state
2877      scic_sds_phy_restart_starting_state(this_phy);
2878      break;
2879
2880   default:
2881      SCIC_LOG_WARNING((
2882         sci_base_object_get_logger(this_phy),
2883         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
2884         "PHY starting substate machine received unexpected event_code %x\n",
2885         event_code
2886      ));
2887
2888      result = SCI_FAILURE;
2889      break;
2890   }
2891
2892   return result;
2893}
2894
2895/**
2896 * This method is called when an event notification is received for the phy
2897 * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER.
2898 *    - decode the event
2899 *       - link failure events restart the starting state machine
2900 *       - sata spinup hold events are ignored since they are expected
2901 *       - any other events log a warning message and set a failure status
2902 *
2903 * @param[in] phy This SCIC_SDS_PHY object which has received an event.
2904 * @param[in] event_code This is the event code which the phy object is to
2905 *       decode.
2906 *
2907 * @return SCI_STATUS
2908 * @retval SCI_SUCCESS on a link failure event
2909 * @retval SCI_FAILURE on any unexpected event notifation
2910 */
2911static
2912SCI_STATUS scic_sds_phy_starting_substate_await_sata_power_event_handler(
2913   SCIC_SDS_PHY_T *this_phy,
2914   U32 event_code
2915)
2916{
2917   U32 result = SCI_SUCCESS;
2918
2919   switch (scu_get_event_code(event_code))
2920   {
2921   case SCU_EVENT_LINK_FAILURE:
2922      // Link failure change state back to the starting state
2923      scic_sds_phy_restart_starting_state(this_phy);
2924      break;
2925
2926   case SCU_EVENT_SATA_SPINUP_HOLD:
2927      // These events are received every 10ms and are expected while in this state
2928      break;
2929
2930   case SCU_EVENT_SAS_PHY_DETECTED:
2931      // There has been a change in the phy type before OOB/SN for the
2932      // SATA finished start down the SAS link traning path.
2933      scic_sds_phy_start_sas_link_training(this_phy);
2934   break;
2935
2936   default:
2937      SCIC_LOG_WARNING((
2938         sci_base_object_get_logger(this_phy),
2939         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
2940         "PHY starting substate machine received unexpected event_code %x\n",
2941         event_code
2942      ));
2943
2944      result = SCI_FAILURE;
2945      break;
2946   }
2947
2948   return result;
2949}
2950
2951/**
2952 * This method is called when an event notification is received for the phy
2953 * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN.
2954 *    - decode the event
2955 *       - link failure events restart the starting state machine
2956 *       - sata spinup hold events are ignored since they are expected
2957 *       - sata phy detected event change to the wait speed event
2958 *       - any other events log a warning message and set a failure status
2959 *
2960 * @param[in] phy This SCIC_SDS_PHY object which has received an event.
2961 * @param[in] event_code This is the event code which the phy object is to
2962 *       decode.
2963 *
2964 * @return SCI_STATUS
2965 * @retval SCI_SUCCESS on a link failure event
2966 * @retval SCI_FAILURE on any unexpected event notifation
2967 */
2968static
2969SCI_STATUS scic_sds_phy_starting_substate_await_sata_phy_event_handler(
2970   SCIC_SDS_PHY_T *this_phy,
2971   U32 event_code
2972)
2973{
2974   U32 result = SCI_SUCCESS;
2975
2976   switch (scu_get_event_code(event_code))
2977   {
2978   case SCU_EVENT_LINK_FAILURE:
2979      // Link failure change state back to the starting state
2980      scic_sds_phy_restart_starting_state(this_phy);
2981      break;
2982
2983   case SCU_EVENT_SATA_SPINUP_HOLD:
2984      // These events might be received since we dont know how many may be in
2985      // the completion queue while waiting for power
2986      break;
2987
2988   case SCU_EVENT_SATA_PHY_DETECTED:
2989      this_phy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA;
2990
2991      // We have received the SATA PHY notification change state
2992      sci_base_state_machine_change_state(
2993         scic_sds_phy_get_starting_substate_machine(this_phy),
2994         SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN
2995         );
2996      break;
2997
2998   case SCU_EVENT_SAS_PHY_DETECTED:
2999      // There has been a change in the phy type before OOB/SN for the
3000      // SATA finished start down the SAS link traning path.
3001      scic_sds_phy_start_sas_link_training(this_phy);
3002   break;
3003
3004   default:
3005      SCIC_LOG_WARNING((
3006         sci_base_object_get_logger(this_phy),
3007         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
3008         "PHY starting substate machine received unexpected event_code %x\n",
3009         event_code
3010      ));
3011
3012      result = SCI_FAILURE;
3013      break;
3014   }
3015
3016   return result;
3017}
3018
3019/**
3020 * This method is called when an event notification is received for the phy
3021 * object when in the state
3022 * SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN.
3023 *    - decode the event
3024 *       - sata phy detected returns us back to this state.
3025 *       - speed event detected causes a state transition to the wait for
3026 *         signature.
3027 *       - link failure events restart the starting state machine
3028 *       - any other events log a warning message and set a failure status
3029 *
3030 * @param[in] phy This SCIC_SDS_PHY object which has received an event.
3031 * @param[in] event_code This is the event code which the phy object is to
3032 *       decode.
3033 *
3034 * @return SCI_STATUS
3035 * @retval SCI_SUCCESS on any valid event notification
3036 * @retval SCI_FAILURE on any unexpected event notifation
3037 */
3038static
3039SCI_STATUS scic_sds_phy_starting_substate_await_sata_speed_event_handler(
3040   SCIC_SDS_PHY_T *this_phy,
3041   U32 event_code
3042)
3043{
3044   U32 result = SCI_SUCCESS;
3045
3046   switch (scu_get_event_code(event_code))
3047   {
3048   case SCU_EVENT_SATA_PHY_DETECTED:
3049      // The hardware reports multiple SATA PHY detected events
3050      // ignore the extras
3051   break;
3052
3053   case SCU_EVENT_SATA_15:
3054   case SCU_EVENT_SATA_15_SSC:
3055      scic_sds_phy_complete_link_training(
3056         this_phy,
3057         SCI_SAS_150_GB,
3058         SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF
3059      );
3060   break;
3061
3062   case SCU_EVENT_SATA_30:
3063   case SCU_EVENT_SATA_30_SSC:
3064      scic_sds_phy_complete_link_training(
3065         this_phy,
3066         SCI_SAS_300_GB,
3067         SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF
3068      );
3069   break;
3070
3071   case SCU_EVENT_SATA_60:
3072   case SCU_EVENT_SATA_60_SSC:
3073      scic_sds_phy_complete_link_training(
3074         this_phy,
3075         SCI_SAS_600_GB,
3076         SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF
3077      );
3078   break;
3079
3080   case SCU_EVENT_LINK_FAILURE:
3081      // Link failure change state back to the starting state
3082      scic_sds_phy_restart_starting_state(this_phy);
3083   break;
3084
3085   case SCU_EVENT_SAS_PHY_DETECTED:
3086      // There has been a change in the phy type before OOB/SN for the
3087      // SATA finished start down the SAS link traning path.
3088      scic_sds_phy_start_sas_link_training(this_phy);
3089   break;
3090
3091   default:
3092      SCIC_LOG_WARNING((
3093         sci_base_object_get_logger(this_phy),
3094         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
3095         "PHY starting substate machine received unexpected event_code %x\n",
3096         event_code
3097      ));
3098
3099      result = SCI_FAILURE;
3100   break;
3101   }
3102
3103   return result;
3104}
3105
3106/**
3107 * This method is called when an event notification is received for the phy
3108 * object when in the state SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF.
3109 *    - decode the event
3110 *       - sas phy detected event backs up the state machine to the await
3111 *         speed notification.
3112 *       - identify timeout is an un-expected event and the state machine is
3113 *         restarted.
3114 *       - link failure events restart the starting state machine
3115 *       - any other events log a warning message and set a failure status
3116 *
3117 * @param[in] phy This SCIC_SDS_PHY object which has received an event.
3118 * @param[in] event_code This is the event code which the phy object is to
3119 *       decode.
3120 *
3121 * @return SCI_STATUS
3122 * @retval SCI_SUCCESS on any valid event notification
3123 * @retval SCI_FAILURE on any unexpected event notifation
3124 */
3125static
3126SCI_STATUS scic_sds_phy_starting_substate_await_sig_fis_event_handler(
3127   SCIC_SDS_PHY_T *this_phy,
3128   U32 event_code
3129)
3130{
3131   U32 result = SCI_SUCCESS;
3132
3133   switch (scu_get_event_code(event_code))
3134   {
3135   case SCU_EVENT_SATA_PHY_DETECTED:
3136      // Backup the state machine
3137      sci_base_state_machine_change_state(
3138         scic_sds_phy_get_starting_substate_machine(this_phy),
3139         SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN
3140         );
3141      break;
3142
3143   case SCU_EVENT_LINK_FAILURE:
3144      // Link failure change state back to the starting state
3145      scic_sds_phy_restart_starting_state(this_phy);
3146      break;
3147
3148   default:
3149      SCIC_LOG_WARNING((
3150         sci_base_object_get_logger(this_phy),
3151         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_RECEIVED_EVENTS,
3152         "PHY starting substate machine received unexpected event_code %x\n",
3153         event_code
3154      ));
3155
3156      result = SCI_FAILURE;
3157      break;
3158   }
3159
3160   return result;
3161}
3162
3163
3164//*****************************************************************************
3165//*  SCIC SDS PHY FRAME_HANDLERS
3166//*****************************************************************************
3167
3168/**
3169 * This method decodes the unsolicited frame when the SCIC_SDS_PHY is in the
3170 * SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF.
3171 *    - Get the UF Header
3172 *    - If the UF is an IAF
3173 *       - Copy IAF data to local phy object IAF data buffer.
3174 *       - Change starting substate to wait power.
3175 *    - else
3176 *       - log warning message of unexpected unsolicted frame
3177 *    - release frame buffer
3178 *
3179 * @param[in] phy This is SCIC_SDS_PHY object which is being requested to
3180 *       decode the frame data.
3181 * @param[in] frame_index This is the index of the unsolicited frame which was
3182 *       received for this phy.
3183 *
3184 * @return SCI_STATUS
3185 * @retval SCI_SUCCESS
3186 */
3187static
3188SCI_STATUS scic_sds_phy_starting_substate_await_iaf_uf_frame_handler(
3189   SCIC_SDS_PHY_T *this_phy,
3190   U32            frame_index
3191)
3192{
3193   SCI_STATUS                        result;
3194   U32                              *frame_words;
3195   SCI_SAS_IDENTIFY_ADDRESS_FRAME_T *identify_frame;
3196
3197   result = scic_sds_unsolicited_frame_control_get_header(
3198               &(scic_sds_phy_get_controller(this_phy)->uf_control),
3199               frame_index,
3200               (void **)&frame_words);
3201
3202   if (result != SCI_SUCCESS)
3203   {
3204      return result;
3205   }
3206
3207   frame_words[0] = SCIC_SWAP_DWORD(frame_words[0]);
3208   identify_frame = (SCI_SAS_IDENTIFY_ADDRESS_FRAME_T *)frame_words;
3209
3210   if (identify_frame->address_frame_type == 0)
3211   {
3212      // Byte swap the rest of the frame so we can make
3213      // a copy of the buffer
3214      frame_words[1] = SCIC_SWAP_DWORD(frame_words[1]);
3215      frame_words[2] = SCIC_SWAP_DWORD(frame_words[2]);
3216      frame_words[3] = SCIC_SWAP_DWORD(frame_words[3]);
3217      frame_words[4] = SCIC_SWAP_DWORD(frame_words[4]);
3218      frame_words[5] = SCIC_SWAP_DWORD(frame_words[5]);
3219
3220      memcpy(
3221         &this_phy->phy_type.sas.identify_address_frame_buffer,
3222         identify_frame,
3223         sizeof(SCI_SAS_IDENTIFY_ADDRESS_FRAME_T)
3224      );
3225
3226      if (identify_frame->protocols.u.bits.smp_target)
3227      {
3228         // We got the IAF for an expander PHY go to the final state since
3229         // there are no power requirements for expander phys.
3230         sci_base_state_machine_change_state(
3231            scic_sds_phy_get_starting_substate_machine(this_phy),
3232            SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL
3233         );
3234      }
3235      else
3236      {
3237         // We got the IAF we can now go to the await spinup semaphore state
3238         sci_base_state_machine_change_state(
3239            scic_sds_phy_get_starting_substate_machine(this_phy),
3240            SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER
3241         );
3242      }
3243
3244      result = SCI_SUCCESS;
3245   }
3246   else
3247   {
3248      SCIC_LOG_WARNING((
3249         sci_base_object_get_logger(this_phy),
3250         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_UNSOLICITED_FRAMES,
3251         "PHY starting substate machine received unexpected frame id %x\n",
3252         frame_index
3253      ));
3254   }
3255
3256   // Regardless of the result release this frame since we are done with it
3257   scic_sds_controller_release_frame(
3258      scic_sds_phy_get_controller(this_phy), frame_index
3259      );
3260
3261   return result;
3262}
3263
3264/**
3265 * This method decodes the unsolicited frame when the SCIC_SDS_PHY is in the
3266 * SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF.
3267 *    - Get the UF Header
3268 *    - If the UF is an SIGNATURE FIS
3269 *       - Copy IAF data to local phy object SIGNATURE FIS data buffer.
3270 *    - else
3271 *       - log warning message of unexpected unsolicted frame
3272 *    - release frame buffer
3273 *
3274 * @param[in] phy This is SCIC_SDS_PHY object which is being requested to
3275 *       decode the frame data.
3276 * @param[in] frame_index This is the index of the unsolicited frame which was
3277 *       received for this phy.
3278 *
3279 * @return SCI_STATUS
3280 * @retval SCI_SUCCESS
3281 *
3282 * @todo Must decode the SIGNATURE FIS data
3283 */
3284static
3285SCI_STATUS scic_sds_phy_starting_substate_await_sig_fis_frame_handler(
3286   SCIC_SDS_PHY_T *this_phy,
3287   U32            frame_index
3288)
3289{
3290   SCI_STATUS          result;
3291   U32               * frame_words;
3292   SATA_FIS_HEADER_T * fis_frame_header;
3293   U32               * fis_frame_data;
3294
3295   result = scic_sds_unsolicited_frame_control_get_header(
3296               &(scic_sds_phy_get_controller(this_phy)->uf_control),
3297               frame_index,
3298               (void **)&frame_words);
3299
3300   if (result != SCI_SUCCESS)
3301   {
3302      return result;
3303   }
3304
3305   fis_frame_header = (SATA_FIS_HEADER_T *)frame_words;
3306
3307   if (
3308         (fis_frame_header->fis_type == SATA_FIS_TYPE_REGD2H)
3309      && !(fis_frame_header->status & ATA_STATUS_REG_BSY_BIT)
3310      )
3311   {
3312      scic_sds_unsolicited_frame_control_get_buffer(
3313         &(scic_sds_phy_get_controller(this_phy)->uf_control),
3314         frame_index,
3315         (void **)&fis_frame_data
3316      );
3317
3318      scic_sds_controller_copy_sata_response(
3319         &this_phy->phy_type.sata.signature_fis_buffer,
3320         frame_words,
3321         fis_frame_data
3322      );
3323
3324      // We got the IAF we can now go to the await spinup semaphore state
3325      sci_base_state_machine_change_state(
3326         scic_sds_phy_get_starting_substate_machine(this_phy),
3327         SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL
3328         );
3329
3330      result = SCI_SUCCESS;
3331   }
3332   else
3333   {
3334      SCIC_LOG_WARNING((
3335         sci_base_object_get_logger(this_phy),
3336         SCIC_LOG_OBJECT_PHY | SCIC_LOG_OBJECT_UNSOLICITED_FRAMES,
3337         "PHY starting substate machine received unexpected frame id %x\n",
3338         frame_index
3339      ));
3340   }
3341
3342   // Regardless of the result release this frame since we are done with it
3343   scic_sds_controller_release_frame(
3344      scic_sds_phy_get_controller(this_phy), frame_index
3345      );
3346
3347   return result;
3348}
3349
3350//*****************************************************************************
3351//* SCIC SDS PHY POWER_HANDLERS
3352//*****************************************************************************
3353
3354/**
3355 * This method is called by the SCIC_SDS_CONTROLLER when the phy object is
3356 * granted power.
3357 *    - The notify enable spinups are turned on for this phy object
3358 *    - The phy state machine is transitioned to the
3359 *    SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL.
3360 *
3361 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
3362 *       SCIC_SDS_PHY object.
3363 *
3364 * @return SCI_STATUS
3365 * @retval SCI_SUCCESS
3366 */
3367static
3368SCI_STATUS scic_sds_phy_starting_substate_await_sas_power_consume_power_handler(
3369   SCIC_SDS_PHY_T *this_phy
3370)
3371{
3372   U32 enable_spinup;
3373
3374   enable_spinup = SCU_SAS_ENSPINUP_READ(this_phy);
3375   enable_spinup |= SCU_ENSPINUP_GEN_BIT(ENABLE);
3376   SCU_SAS_ENSPINUP_WRITE(this_phy, enable_spinup);
3377
3378   // Change state to the final state this substate machine has run to completion
3379   sci_base_state_machine_change_state(
3380      scic_sds_phy_get_starting_substate_machine(this_phy),
3381      SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL
3382      );
3383
3384   return SCI_SUCCESS;
3385}
3386
3387/**
3388 * This method is called by the SCIC_SDS_CONTROLLER when the phy object is
3389 * granted power.
3390 *    - The phy state machine is transitioned to the
3391 *    SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN.
3392 *
3393 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
3394 *       SCIC_SDS_PHY object.
3395 *
3396 * @return SCI_STATUS
3397 * @retval SCI_SUCCESS
3398 */
3399static
3400SCI_STATUS scic_sds_phy_starting_substate_await_sata_power_consume_power_handler(
3401   SCIC_SDS_PHY_T *this_phy
3402)
3403{
3404   U32 scu_sas_pcfg_value;
3405
3406   // Release the spinup hold state and reset the OOB state machine
3407   scu_sas_pcfg_value = SCU_SAS_PCFG_READ(this_phy);
3408   scu_sas_pcfg_value &=
3409      ~(SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD) | SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE));
3410   scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
3411   SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
3412
3413   // Now restart the OOB operation
3414   scu_sas_pcfg_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET);
3415   scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE);
3416   SCU_SAS_PCFG_WRITE(this_phy, scu_sas_pcfg_value);
3417
3418   // Change state to the final state this substate machine has run to completion
3419   sci_base_state_machine_change_state(
3420      scic_sds_phy_get_starting_substate_machine(this_phy),
3421      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN
3422   );
3423
3424   return SCI_SUCCESS;
3425}
3426
3427// ---------------------------------------------------------------------------
3428
3429SCIC_SDS_PHY_STATE_HANDLER_T
3430   scic_sds_phy_starting_substate_handler_table[SCIC_SDS_PHY_STARTING_MAX_SUBSTATES] =
3431{
3432   // SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL
3433   {
3434      {
3435         scic_sds_phy_default_start_handler,
3436         scic_sds_phy_starting_substate_general_stop_handler,
3437         scic_sds_phy_default_reset_handler,
3438         scic_sds_phy_default_destroy_handler
3439      },
3440      scic_sds_phy_default_frame_handler,
3441      scic_sds_phy_default_event_handler,
3442      scic_sds_phy_default_consume_power_handler
3443   },
3444   // SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN
3445   {
3446      {
3447         scic_sds_phy_default_start_handler,
3448         scic_sds_phy_starting_substate_general_stop_handler,
3449         scic_sds_phy_default_reset_handler,
3450         scic_sds_phy_default_destroy_handler
3451      },
3452      scic_sds_phy_default_frame_handler,
3453      scic_sds_phy_starting_substate_await_ossp_event_handler,
3454      scic_sds_phy_default_consume_power_handler
3455   },
3456   // SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN
3457   {
3458      {
3459         scic_sds_phy_default_start_handler,
3460         scic_sds_phy_starting_substate_general_stop_handler,
3461         scic_sds_phy_default_reset_handler,
3462         scic_sds_phy_default_destroy_handler
3463      },
3464      scic_sds_phy_default_frame_handler,
3465      scic_sds_phy_starting_substate_await_sas_phy_speed_event_handler,
3466      scic_sds_phy_default_consume_power_handler
3467   },
3468   // SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF
3469   {
3470      {
3471         scic_sds_phy_default_start_handler,
3472         scic_sds_phy_default_stop_handler,
3473         scic_sds_phy_default_reset_handler,
3474         scic_sds_phy_default_destroy_handler
3475      },
3476      scic_sds_phy_starting_substate_await_iaf_uf_frame_handler,
3477      scic_sds_phy_starting_substate_await_iaf_uf_event_handler,
3478      scic_sds_phy_default_consume_power_handler
3479   },
3480   // SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER
3481   {
3482      {
3483         scic_sds_phy_default_start_handler,
3484         scic_sds_phy_starting_substate_general_stop_handler,
3485         scic_sds_phy_default_reset_handler,
3486         scic_sds_phy_default_destroy_handler
3487      },
3488      scic_sds_phy_default_frame_handler,
3489      scic_sds_phy_starting_substate_await_sas_power_event_handler,
3490      scic_sds_phy_starting_substate_await_sas_power_consume_power_handler
3491   },
3492   // SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER,
3493   {
3494      {
3495         scic_sds_phy_default_start_handler,
3496         scic_sds_phy_starting_substate_general_stop_handler,
3497         scic_sds_phy_default_reset_handler,
3498         scic_sds_phy_default_destroy_handler
3499      },
3500      scic_sds_phy_default_frame_handler,
3501      scic_sds_phy_starting_substate_await_sata_power_event_handler,
3502      scic_sds_phy_starting_substate_await_sata_power_consume_power_handler
3503   },
3504   // SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN,
3505   {
3506      {
3507         scic_sds_phy_default_start_handler,
3508         scic_sds_phy_starting_substate_general_stop_handler,
3509         scic_sds_phy_default_reset_handler,
3510         scic_sds_phy_default_destroy_handler
3511      },
3512      scic_sds_phy_default_frame_handler,
3513      scic_sds_phy_starting_substate_await_sata_phy_event_handler,
3514      scic_sds_phy_default_consume_power_handler
3515   },
3516   // SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN,
3517   {
3518      {
3519         scic_sds_phy_default_start_handler,
3520         scic_sds_phy_starting_substate_general_stop_handler,
3521         scic_sds_phy_default_reset_handler,
3522         scic_sds_phy_default_destroy_handler
3523      },
3524      scic_sds_phy_default_frame_handler,
3525      scic_sds_phy_starting_substate_await_sata_speed_event_handler,
3526      scic_sds_phy_default_consume_power_handler
3527   },
3528   // SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF,
3529   {
3530      {
3531         scic_sds_phy_default_start_handler,
3532         scic_sds_phy_starting_substate_general_stop_handler,
3533         scic_sds_phy_default_reset_handler,
3534         scic_sds_phy_default_destroy_handler
3535      },
3536      scic_sds_phy_starting_substate_await_sig_fis_frame_handler,
3537      scic_sds_phy_starting_substate_await_sig_fis_event_handler,
3538      scic_sds_phy_default_consume_power_handler
3539   },
3540   // SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL
3541   {
3542      {
3543         scic_sds_phy_default_start_handler,
3544         scic_sds_phy_starting_substate_general_stop_handler,
3545         scic_sds_phy_default_reset_handler,
3546         scic_sds_phy_default_destroy_handler
3547      },
3548      scic_sds_phy_default_frame_handler,
3549      scic_sds_phy_default_event_handler,
3550      scic_sds_phy_default_consume_power_handler
3551   }
3552};
3553
3554/**
3555 * This macro sets the starting substate handlers by state_id
3556 */
3557#define scic_sds_phy_set_starting_substate_handlers(phy, state_id) \
3558   scic_sds_phy_set_state_handlers( \
3559      (phy), \
3560      &scic_sds_phy_starting_substate_handler_table[(state_id)] \
3561   )
3562
3563//****************************************************************************
3564//*  PHY STARTING SUBSTATE METHODS
3565//****************************************************************************
3566
3567/**
3568 * This method will perform the actions required by the SCIC_SDS_PHY on
3569 * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL.
3570 *    - The initial state handlers are put in place for the SCIC_SDS_PHY
3571 *      object.
3572 *    - The state is changed to the wait phy type event notification.
3573 *
3574 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3575 *       SCIC_SDS_PHY object.
3576 *
3577 * @return none
3578 */
3579static
3580void scic_sds_phy_starting_initial_substate_enter(
3581   SCI_BASE_OBJECT_T *object
3582)
3583{
3584   SCIC_SDS_PHY_T *this_phy;
3585   this_phy = (SCIC_SDS_PHY_T *)object;
3586
3587   scic_sds_phy_set_starting_substate_handlers(
3588      this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL);
3589
3590   // This is just an temporary state go off to the starting state
3591   sci_base_state_machine_change_state(
3592      scic_sds_phy_get_starting_substate_machine(this_phy),
3593      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN
3594   );
3595}
3596
3597/**
3598 * This method will perform the actions required by the SCIC_SDS_PHY on
3599 * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_PHY_TYPE_EN.
3600 *    - Set the SCIC_SDS_PHY object state handlers for this state.
3601 *
3602 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3603 *       SCIC_SDS_PHY object.
3604 *
3605 * @return none
3606 */
3607static
3608void scic_sds_phy_starting_await_ossp_en_substate_enter(
3609   SCI_BASE_OBJECT_T *object
3610)
3611{
3612   SCIC_SDS_PHY_T *this_phy;
3613   this_phy = (SCIC_SDS_PHY_T *)object;
3614
3615   scic_sds_phy_set_starting_substate_handlers(
3616      this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN
3617      );
3618}
3619
3620/**
3621 * This method will perform the actions required by the SCIC_SDS_PHY on
3622 * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SPEED_EN.
3623 *    - Set the SCIC_SDS_PHY object state handlers for this state.
3624 *
3625 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3626 *       SCIC_SDS_PHY object.
3627 *
3628 * @return none
3629 */
3630static
3631void scic_sds_phy_starting_await_sas_speed_en_substate_enter(
3632   SCI_BASE_OBJECT_T *object
3633)
3634{
3635   SCIC_SDS_PHY_T *this_phy;
3636   this_phy = (SCIC_SDS_PHY_T *)object;
3637
3638   scic_sds_phy_set_starting_substate_handlers(
3639      this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN
3640      );
3641}
3642
3643/**
3644 * This method will perform the actions required by the SCIC_SDS_PHY on
3645 * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF.
3646 *    - Set the SCIC_SDS_PHY object state handlers for this state.
3647 *
3648 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3649 *       SCIC_SDS_PHY object.
3650 *
3651 * @return none
3652 */
3653static
3654void scic_sds_phy_starting_await_iaf_uf_substate_enter(
3655   SCI_BASE_OBJECT_T *object
3656)
3657{
3658   SCIC_SDS_PHY_T *this_phy;
3659   this_phy = (SCIC_SDS_PHY_T *)object;
3660
3661   scic_sds_phy_set_starting_substate_handlers(
3662      this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF
3663      );
3664}
3665
3666/**
3667 * This method will perform the actions required by the SCIC_SDS_PHY on
3668 * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER.
3669 *    - Set the SCIC_SDS_PHY object state handlers for this state.
3670 *    - Add this phy object to the power control queue
3671 *
3672 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3673 *       SCIC_SDS_PHY object.
3674 *
3675 * @return none
3676 */
3677static
3678void scic_sds_phy_starting_await_sas_power_substate_enter(
3679   SCI_BASE_OBJECT_T *object
3680)
3681{
3682   SCIC_SDS_PHY_T *this_phy;
3683   this_phy = (SCIC_SDS_PHY_T *)object;
3684
3685   scic_sds_phy_set_starting_substate_handlers(
3686      this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER
3687      );
3688
3689   scic_sds_controller_power_control_queue_insert(
3690      scic_sds_phy_get_controller(this_phy),
3691      this_phy
3692      );
3693}
3694
3695/**
3696 * This method will perform the actions required by the SCIC_SDS_PHY on
3697 * exiting the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER.
3698 *    - Remove the SCIC_SDS_PHY object from the power control queue.
3699 *
3700 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3701 *       SCIC_SDS_PHY object.
3702 *
3703 * @return none
3704 */
3705static
3706void scic_sds_phy_starting_await_sas_power_substate_exit(
3707   SCI_BASE_OBJECT_T *object
3708)
3709{
3710   SCIC_SDS_PHY_T *this_phy;
3711   this_phy = (SCIC_SDS_PHY_T *)object;
3712
3713   scic_sds_controller_power_control_queue_remove(
3714      scic_sds_phy_get_controller(this_phy), this_phy
3715   );
3716}
3717
3718/**
3719 * This method will perform the actions required by the SCIC_SDS_PHY on
3720 * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER.
3721 *    - Set the SCIC_SDS_PHY object state handlers for this state.
3722 *    - Add this phy object to the power control queue
3723 *
3724 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3725 *       SCIC_SDS_PHY object.
3726 *
3727 * @return none
3728 */
3729static
3730void scic_sds_phy_starting_await_sata_power_substate_enter(
3731   SCI_BASE_OBJECT_T *object
3732)
3733{
3734   SCIC_SDS_PHY_T *this_phy;
3735   this_phy = (SCIC_SDS_PHY_T *)object;
3736
3737   scic_sds_phy_set_starting_substate_handlers(
3738      this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER
3739      );
3740
3741   scic_sds_controller_power_control_queue_insert(
3742      scic_sds_phy_get_controller(this_phy),
3743      this_phy
3744      );
3745}
3746
3747/**
3748 * This method will perform the actions required by the SCIC_SDS_PHY on
3749 * exiting the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER.
3750 *    - Remove the SCIC_SDS_PHY object from the power control queue.
3751 *
3752 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3753 *       SCIC_SDS_PHY object.
3754 *
3755 * @return none
3756 */
3757static
3758void scic_sds_phy_starting_await_sata_power_substate_exit(
3759   SCI_BASE_OBJECT_T *object
3760)
3761{
3762   SCIC_SDS_PHY_T *this_phy;
3763   this_phy = (SCIC_SDS_PHY_T *)object;
3764
3765   scic_sds_controller_power_control_queue_remove(
3766      scic_sds_phy_get_controller(this_phy),
3767      this_phy
3768      );
3769}
3770
3771/**
3772 * This method will perform the actions required by the SCIC_SDS_PHY on
3773 * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN.
3774 *    - Set the SCIC_SDS_PHY object state handlers for this state.
3775 *
3776 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3777 *       SCIC_SDS_PHY object.
3778 *
3779 * @return none
3780 */
3781static
3782void scic_sds_phy_starting_await_sata_phy_substate_enter(
3783   SCI_BASE_OBJECT_T *object
3784)
3785{
3786   SCIC_SDS_PHY_T *this_phy;
3787   this_phy = (SCIC_SDS_PHY_T *)object;
3788
3789   scic_sds_phy_set_starting_substate_handlers(
3790      this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN
3791      );
3792
3793   scic_cb_timer_start(
3794      scic_sds_phy_get_controller(this_phy),
3795      this_phy->sata_timeout_timer,
3796      SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT
3797   );
3798}
3799
3800/**
3801 * This method will perform the actions required by the SCIC_SDS_PHY on
3802 * exiting the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN.
3803 *    - stop the timer that was started on entry to await sata phy
3804 *      event notification
3805 *
3806 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3807 *       SCIC_SDS_PHY object.
3808 *
3809 * @return none
3810 */
3811static
3812void scic_sds_phy_starting_await_sata_phy_substate_exit(
3813   SCI_BASE_OBJECT_T *object
3814)
3815{
3816   SCIC_SDS_PHY_T *this_phy;
3817   this_phy = (SCIC_SDS_PHY_T *)object;
3818
3819   scic_cb_timer_stop(
3820      scic_sds_phy_get_controller(this_phy),
3821      this_phy->sata_timeout_timer
3822   );
3823}
3824
3825/**
3826 * This method will perform the actions required by the SCIC_SDS_PHY on
3827 * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN.
3828 *    - Set the SCIC_SDS_PHY object state handlers for this state.
3829 *
3830 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3831 *       SCIC_SDS_PHY object.
3832 *
3833 * @return none
3834 */
3835static
3836void scic_sds_phy_starting_await_sata_speed_substate_enter(
3837   SCI_BASE_OBJECT_T *object
3838)
3839{
3840   SCIC_SDS_PHY_T *this_phy;
3841   this_phy = (SCIC_SDS_PHY_T *)object;
3842
3843   scic_sds_phy_set_starting_substate_handlers(
3844      this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN
3845      );
3846
3847   scic_cb_timer_start(
3848      scic_sds_phy_get_controller(this_phy),
3849      this_phy->sata_timeout_timer,
3850      SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT
3851   );
3852}
3853
3854/**
3855 * This method will perform the actions required by the SCIC_SDS_PHY on
3856 * exiting the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN.
3857 *    - stop the timer that was started on entry to await sata phy
3858 *      event notification
3859 *
3860 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3861 *       SCIC_SDS_PHY object.
3862 *
3863 * @return none
3864 */
3865static
3866void scic_sds_phy_starting_await_sata_speed_substate_exit(
3867   SCI_BASE_OBJECT_T *object
3868)
3869{
3870   SCIC_SDS_PHY_T *this_phy;
3871   this_phy = (SCIC_SDS_PHY_T *)object;
3872
3873   scic_cb_timer_stop(
3874      scic_sds_phy_get_controller(this_phy),
3875      this_phy->sata_timeout_timer
3876   );
3877}
3878
3879/**
3880 * This method will perform the actions required by the SCIC_SDS_PHY on
3881 * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF.
3882 *    - Set the SCIC_SDS_PHY object state handlers for this state.
3883 *    - Start the SIGNATURE FIS timeout timer
3884 *
3885 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3886 *       SCIC_SDS_PHY object.
3887 *
3888 * @return none
3889 */
3890static
3891void scic_sds_phy_starting_await_sig_fis_uf_substate_enter(
3892   SCI_BASE_OBJECT_T *object
3893)
3894{
3895   BOOL             continue_to_ready_state;
3896   SCIC_SDS_PHY_T * this_phy;
3897
3898   this_phy = (SCIC_SDS_PHY_T *)object;
3899
3900   scic_sds_phy_set_starting_substate_handlers(
3901      this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF
3902   );
3903
3904   continue_to_ready_state = scic_sds_port_link_detected(
3905                                 this_phy->owning_port,
3906                                 this_phy
3907                             );
3908
3909   if (continue_to_ready_state)
3910   {
3911      // Clear the PE suspend condition so we can actually receive SIG FIS
3912      // The hardware will not respond to the XRDY until the PE suspend
3913      // condition is cleared.
3914      scic_sds_phy_resume(this_phy);
3915
3916      scic_cb_timer_start(
3917         scic_sds_phy_get_controller(this_phy),
3918         this_phy->sata_timeout_timer,
3919         SCIC_SDS_SIGNATURE_FIS_TIMEOUT
3920      );
3921   }
3922   else
3923   {
3924      this_phy->is_in_link_training = FALSE;
3925   }
3926}
3927
3928/**
3929 * This method will perform the actions required by the SCIC_SDS_PHY on
3930 * exiting the SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF.
3931 *    - Stop the SIGNATURE FIS timeout timer.
3932 *
3933 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3934 *       SCIC_SDS_PHY object.
3935 *
3936 * @return none
3937 */
3938static
3939void scic_sds_phy_starting_await_sig_fis_uf_substate_exit(
3940   SCI_BASE_OBJECT_T *object
3941)
3942{
3943   SCIC_SDS_PHY_T *this_phy;
3944   this_phy = (SCIC_SDS_PHY_T *)object;
3945
3946   scic_cb_timer_stop(
3947      scic_sds_phy_get_controller(this_phy),
3948      this_phy->sata_timeout_timer
3949   );
3950}
3951
3952/**
3953 * This method will perform the actions required by the SCIC_SDS_PHY on
3954 * entering the SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL.
3955 *    - Set the SCIC_SDS_PHY object state handlers for this state.
3956 *    - Change base state machine to the ready state.
3957 *
3958 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3959 *       SCIC_SDS_PHY object.
3960 *
3961 * @return none
3962 */
3963static
3964void scic_sds_phy_starting_final_substate_enter(
3965   SCI_BASE_OBJECT_T *object
3966)
3967{
3968   SCIC_SDS_PHY_T *this_phy;
3969   this_phy = (SCIC_SDS_PHY_T *)object;
3970
3971   scic_sds_phy_set_starting_substate_handlers(
3972      this_phy, SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL
3973      );
3974
3975   // State machine has run to completion so exit out and change
3976   // the base state machine to the ready state
3977   sci_base_state_machine_change_state(
3978      scic_sds_phy_get_base_state_machine(this_phy),
3979      SCI_BASE_PHY_STATE_READY);
3980}
3981
3982// ---------------------------------------------------------------------------
3983
3984SCI_BASE_STATE_T
3985   scic_sds_phy_starting_substates[SCIC_SDS_PHY_STARTING_MAX_SUBSTATES] =
3986{
3987   {
3988      SCIC_SDS_PHY_STARTING_SUBSTATE_INITIAL,
3989      scic_sds_phy_starting_initial_substate_enter,
3990      NULL,
3991   },
3992   {
3993      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_OSSP_EN,
3994      scic_sds_phy_starting_await_ossp_en_substate_enter,
3995      NULL,
3996   },
3997   {
3998      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_SPEED_EN,
3999      scic_sds_phy_starting_await_sas_speed_en_substate_enter,
4000      NULL,
4001   },
4002   {
4003      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_IAF_UF,
4004      scic_sds_phy_starting_await_iaf_uf_substate_enter,
4005      NULL,
4006   },
4007   {
4008      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SAS_POWER,
4009      scic_sds_phy_starting_await_sas_power_substate_enter,
4010      scic_sds_phy_starting_await_sas_power_substate_exit,
4011   },
4012   {
4013      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_POWER,
4014      scic_sds_phy_starting_await_sata_power_substate_enter,
4015      scic_sds_phy_starting_await_sata_power_substate_exit
4016   },
4017   {
4018      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_PHY_EN,
4019      scic_sds_phy_starting_await_sata_phy_substate_enter,
4020      scic_sds_phy_starting_await_sata_phy_substate_exit
4021   },
4022   {
4023      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SATA_SPEED_EN,
4024      scic_sds_phy_starting_await_sata_speed_substate_enter,
4025      scic_sds_phy_starting_await_sata_speed_substate_exit
4026   },
4027   {
4028      SCIC_SDS_PHY_STARTING_SUBSTATE_AWAIT_SIG_FIS_UF,
4029      scic_sds_phy_starting_await_sig_fis_uf_substate_enter,
4030      scic_sds_phy_starting_await_sig_fis_uf_substate_exit
4031   },
4032   {
4033      SCIC_SDS_PHY_STARTING_SUBSTATE_FINAL,
4034      scic_sds_phy_starting_final_substate_enter,
4035      NULL,
4036   }
4037};
4038
4039