xref: /freebsd/sys/dev/isci/scil/scic_sds_phy.c (revision b077aed33b7b6aefca7b17ddb250cf521f938613)
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$");
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  */
102 static
103 SCI_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  */
137 static
138 SCI_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  */
462 void 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  */
491 U32 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  */
502 U32 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  */
513 U32 scic_sds_phy_get_max_timer_count(void)
514 {
515    return SCIC_SDS_PHY_MAX_TIMER_COUNT;
516 }
517 
518 #ifdef SCI_LOGGING
519 static
520 void 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  */
551 void 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  */
605 void 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  */
634 void 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  */
695 SCI_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  */
719 void 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  */
741 SCI_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  */
779 void 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  */
803 void 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  */
826 void 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  */
849 void 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  */
876 void 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  */
901 void 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  */
949 void 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  */
983 void 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  */
1017 SCI_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  */
1041 SCI_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  */
1064 SCI_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  */
1086 SCI_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 
1104 SCI_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 
1160 SCI_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 
1194 SCI_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 
1230 SCI_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 
1255 SCI_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 
1342 SCI_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 
1425 SCI_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 
1505 SCI_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 
1583 SCI_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 
1600 SCI_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  */
1635 SCI_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  */
1664 SCI_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  */
1692 SCI_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  */
1720 SCI_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  */
1751 SCI_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  */
1782 SCI_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  */
1808 SCI_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  */
1839 static
1840 SCI_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  */
1880 static
1881 SCI_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  */
1913 static
1914 SCI_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  */
1946 static
1947 SCI_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  */
1978 static
1979 SCI_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  */
2047 static
2048 SCI_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 
2084 SCIC_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  */
2174 static
2175 void 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  */
2204 static
2205 void 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  */
2235 static
2236 void 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  */
2270 static
2271 void 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  */
2293 static
2294 void 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  */
2332 static
2333 void 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  */
2377 static
2378 void 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  */
2404 static
2405 void 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  */
2426 static
2427 void 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  */
2467 static
2468 void 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 
2482 SCI_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  */
2534 static
2535 void 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  */
2563 static
2564 void 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  */
2589 static
2590 void 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  */
2611 void 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 
2632 static
2633 SCI_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  */
2672 static
2673 SCI_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  */
2726 static
2727 SCI_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  */
2807 static
2808 SCI_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  */
2865 static
2866 SCI_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  */
2911 static
2912 SCI_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  */
2968 static
2969 SCI_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  */
3038 static
3039 SCI_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  */
3125 static
3126 SCI_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  */
3187 static
3188 SCI_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  */
3284 static
3285 SCI_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  */
3367 static
3368 SCI_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  */
3399 static
3400 SCI_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 
3429 SCIC_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  */
3579 static
3580 void 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  */
3607 static
3608 void 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  */
3630 static
3631 void 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  */
3653 static
3654 void 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  */
3677 static
3678 void 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  */
3705 static
3706 void 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  */
3729 static
3730 void 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  */
3757 static
3758 void 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  */
3781 static
3782 void 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  */
3811 static
3812 void 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  */
3835 static
3836 void 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  */
3865 static
3866 void 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  */
3890 static
3891 void 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  */
3938 static
3939 void 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  */
3963 static
3964 void 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 
3984 SCI_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