scic_sds_controller.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3 *
4 * This file is provided under a dual BSD/GPLv2 license.  When using or
5 * redistributing this file, you may do so under either license.
6 *
7 * GPL LICENSE SUMMARY
8 *
9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23 * The full GNU General Public License is included in this distribution
24 * in the file called LICENSE.GPL.
25 *
26 * BSD LICENSE
27 *
28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 *
35 *   * Redistributions of source code must retain the above copyright
36 *     notice, this list of conditions and the following disclaimer.
37 *   * Redistributions in binary form must reproduce the above copyright
38 *     notice, this list of conditions and the following disclaimer in
39 *     the documentation and/or other materials provided with the
40 *     distribution.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 */
54
55#include <sys/cdefs.h>
56__FBSDID("$FreeBSD: stable/11/sys/dev/isci/scil/scic_sds_controller.c 330897 2018-03-14 03:19:51Z eadler $");
57
58/**
59 * @file
60 *
61 * @brief This file contains the implementation of the SCIC_SDS_CONTROLLER
62 *        public, protected, and private methods.
63 */
64
65#include <dev/isci/types.h>
66#include <dev/isci/scil/sci_util.h>
67#include <dev/isci/scil/scic_controller.h>
68#include <dev/isci/scil/scic_port.h>
69#include <dev/isci/scil/scic_phy.h>
70#include <dev/isci/scil/scic_remote_device.h>
71#include <dev/isci/scil/scic_user_callback.h>
72#include <dev/isci/scil/scic_sds_pci.h>
73#include <dev/isci/scil/scic_sds_library.h>
74#include <dev/isci/scil/scic_sds_controller.h>
75#include <dev/isci/scil/scic_sds_controller_registers.h>
76#include <dev/isci/scil/scic_sds_port.h>
77#include <dev/isci/scil/scic_sds_phy.h>
78#include <dev/isci/scil/scic_sds_remote_device.h>
79#include <dev/isci/scil/scic_sds_request.h>
80#include <dev/isci/scil/scic_sds_logger.h>
81#include <dev/isci/scil/scic_sds_port_configuration_agent.h>
82#include <dev/isci/scil/scu_constants.h>
83#include <dev/isci/scil/scu_event_codes.h>
84#include <dev/isci/scil/scu_completion_codes.h>
85#include <dev/isci/scil/scu_task_context.h>
86#include <dev/isci/scil/scu_remote_node_context.h>
87#include <dev/isci/scil/scu_unsolicited_frame.h>
88#include <dev/isci/scil/intel_pci.h>
89#include <dev/isci/scil/scic_sgpio.h>
90#include <dev/isci/scil/scic_sds_phy_registers.h>
91
92#define SCU_CONTEXT_RAM_INIT_STALL_TIME      200
93#define SCIC_SDS_CONTROLLER_MIN_TIMER_COUNT  3
94#define SCIC_SDS_CONTROLLER_MAX_TIMER_COUNT  3
95
96#define SCU_MAX_ZPT_DWORD_INDEX              131
97
98/**
99 * The number of milliseconds to wait for a phy to start.
100 */
101#define SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT      100
102
103/**
104 * The number of milliseconds to wait while a given phy is consuming
105 * power before allowing another set of phys to consume power.
106 * Ultimately, this will be specified by OEM parameter.
107 */
108#define SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL 500
109
110/**
111 * This macro will return the cycle bit of the completion queue entry
112 */
113#define COMPLETION_QUEUE_CYCLE_BIT(x) ((x) & 0x80000000)
114
115/**
116 * This macro will normalize the completion queue get pointer so its value
117 * can be used as an index into an array
118 */
119#define NORMALIZE_GET_POINTER(x) \
120   ((x) & SMU_COMPLETION_QUEUE_GET_POINTER_MASK)
121
122/**
123 *  This macro will normalize the completion queue put pointer so its value
124 *  can be used as an array inde
125 */
126#define NORMALIZE_PUT_POINTER(x) \
127   ((x) & SMU_COMPLETION_QUEUE_PUT_POINTER_MASK)
128
129
130/**
131 * This macro will normalize the completion queue cycle pointer so it
132 * matches the completion queue cycle bit
133 */
134#define NORMALIZE_GET_POINTER_CYCLE_BIT(x) \
135   (((U32)(SMU_CQGR_CYCLE_BIT & (x))) << (31 - SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT))
136
137/**
138 * This macro will normalize the completion queue event entry so its value
139 * can be used as an index.
140 */
141#define NORMALIZE_EVENT_POINTER(x) \
142   ( \
143        ((U32)((x) & SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_MASK)) \
144     >> SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_SHIFT \
145   )
146
147/**
148 * This macro will increment the controllers completion queue index value
149 * and possibly toggle the cycle bit if the completion queue index wraps
150 * back to 0.
151 */
152#define INCREMENT_COMPLETION_QUEUE_GET(controller, index, cycle) \
153   INCREMENT_QUEUE_GET( \
154      (index), \
155      (cycle), \
156      (controller)->completion_queue_entries, \
157      SMU_CQGR_CYCLE_BIT \
158   )
159
160/**
161 * This macro will increment the controllers event queue index value and
162 * possibly toggle the event cycle bit if the event queue index wraps back
163 * to 0.
164 */
165#define INCREMENT_EVENT_QUEUE_GET(controller, index, cycle) \
166   INCREMENT_QUEUE_GET( \
167      (index), \
168      (cycle), \
169      (controller)->completion_event_entries, \
170      SMU_CQGR_EVENT_CYCLE_BIT \
171   )
172
173//****************************************************************************-
174//* SCIC SDS Controller Initialization Methods
175//****************************************************************************-
176
177/**
178 * @brief This timer is used to start another phy after we have given up on
179 *        the previous phy to transition to the ready state.
180 *
181 * @param[in] controller
182 */
183static
184void scic_sds_controller_phy_startup_timeout_handler(
185   void *controller
186)
187{
188   SCI_STATUS status;
189   SCIC_SDS_CONTROLLER_T *this_controller;
190   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
191
192   this_controller->phy_startup_timer_pending = FALSE;
193
194   status = SCI_FAILURE;
195
196   while (status != SCI_SUCCESS)
197   {
198      status = scic_sds_controller_start_next_phy(this_controller);
199   }
200}
201
202/**
203 * This method initializes the phy startup operations for controller start.
204 *
205 * @param this_controller
206 */
207static
208SCI_STATUS scic_sds_controller_initialize_phy_startup(
209   SCIC_SDS_CONTROLLER_T *this_controller
210)
211{
212   this_controller->phy_startup_timer = scic_cb_timer_create(
213      this_controller,
214      scic_sds_controller_phy_startup_timeout_handler,
215      this_controller
216   );
217
218   if (this_controller->phy_startup_timer == NULL)
219   {
220      return SCI_FAILURE_INSUFFICIENT_RESOURCES;
221   }
222   else
223   {
224      this_controller->next_phy_to_start = 0;
225      this_controller->phy_startup_timer_pending = FALSE;
226   }
227
228   return SCI_SUCCESS;
229}
230
231/**
232 * This method initializes the power control operations for the controller
233 * object.
234 *
235 * @param this_controller
236 */
237void scic_sds_controller_initialize_power_control(
238   SCIC_SDS_CONTROLLER_T *this_controller
239)
240{
241   this_controller->power_control.timer = scic_cb_timer_create(
242      this_controller,
243      scic_sds_controller_power_control_timer_handler,
244      this_controller
245   );
246
247   memset(
248      this_controller->power_control.requesters,
249      0,
250      sizeof(this_controller->power_control.requesters)
251   );
252
253   this_controller->power_control.phys_waiting = 0;
254   this_controller->power_control.remote_devices_granted_power = 0;
255}
256
257// ---------------------------------------------------------------------------
258
259#define SCU_REMOTE_NODE_CONTEXT_ALIGNMENT       (32)
260#define SCU_TASK_CONTEXT_ALIGNMENT              (256)
261#define SCU_UNSOLICITED_FRAME_ADDRESS_ALIGNMENT (64)
262#define SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT  (1024)
263#define SCU_UNSOLICITED_FRAME_HEADER_ALIGNMENT  (64)
264
265// ---------------------------------------------------------------------------
266
267/**
268 * @brief This method builds the memory descriptor table for this
269 *        controller.
270 *
271 * @param[in] this_controller This parameter specifies the controller
272 *            object for which to build the memory table.
273 *
274 * @return none
275 */
276void scic_sds_controller_build_memory_descriptor_table(
277   SCIC_SDS_CONTROLLER_T *this_controller
278)
279{
280   sci_base_mde_construct(
281      &this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE],
282      SCU_COMPLETION_RAM_ALIGNMENT,
283      (sizeof(U32) * this_controller->completion_queue_entries),
284      (SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS)
285   );
286
287   sci_base_mde_construct(
288      &this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT],
289      SCU_REMOTE_NODE_CONTEXT_ALIGNMENT,
290      this_controller->remote_node_entries * sizeof(SCU_REMOTE_NODE_CONTEXT_T),
291      SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
292   );
293
294   sci_base_mde_construct(
295      &this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT],
296      SCU_TASK_CONTEXT_ALIGNMENT,
297      this_controller->task_context_entries * sizeof(SCU_TASK_CONTEXT_T),
298      SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
299   );
300
301   // The UF buffer address table size must be programmed to a power
302   // of 2.  Find the first power of 2 that is equal to or greater then
303   // the number of unsolicited frame buffers to be utilized.
304   scic_sds_unsolicited_frame_control_set_address_table_count(
305      &this_controller->uf_control
306   );
307
308   sci_base_mde_construct(
309      &this_controller->memory_descriptors[SCU_MDE_UF_BUFFER],
310      SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT,
311      scic_sds_unsolicited_frame_control_get_mde_size(this_controller->uf_control),
312      SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
313   );
314}
315
316/**
317 * @brief This method validates the driver supplied memory descriptor
318 *        table.
319 *
320 * @param[in] this_controller
321 *
322 * @return SCI_STATUS
323 */
324SCI_STATUS scic_sds_controller_validate_memory_descriptor_table(
325   SCIC_SDS_CONTROLLER_T *this_controller
326)
327{
328   BOOL mde_list_valid;
329
330   mde_list_valid = sci_base_mde_is_valid(
331      &this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE],
332      SCU_COMPLETION_RAM_ALIGNMENT,
333      (sizeof(U32) * this_controller->completion_queue_entries),
334      (SCI_MDE_ATTRIBUTE_CACHEABLE | SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS)
335   );
336
337   if (mde_list_valid == FALSE)
338      return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
339
340   mde_list_valid = sci_base_mde_is_valid(
341      &this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT],
342      SCU_REMOTE_NODE_CONTEXT_ALIGNMENT,
343      this_controller->remote_node_entries * sizeof(SCU_REMOTE_NODE_CONTEXT_T),
344      SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
345   );
346
347   if (mde_list_valid == FALSE)
348      return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
349
350   mde_list_valid = sci_base_mde_is_valid(
351      &this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT],
352      SCU_TASK_CONTEXT_ALIGNMENT,
353      this_controller->task_context_entries * sizeof(SCU_TASK_CONTEXT_T),
354      SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
355   );
356
357   if (mde_list_valid == FALSE)
358      return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
359
360   mde_list_valid = sci_base_mde_is_valid(
361      &this_controller->memory_descriptors[SCU_MDE_UF_BUFFER],
362      SCU_UNSOLICITED_FRAME_BUFFER_ALIGNMENT,
363      scic_sds_unsolicited_frame_control_get_mde_size(this_controller->uf_control),
364      SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
365   );
366
367   if (mde_list_valid == FALSE)
368      return SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD;
369
370   return SCI_SUCCESS;
371}
372
373/**
374 * @brief This method initializes the controller with the physical memory
375 *        addresses that are used to communicate with the driver.
376 *
377 * @param[in] this_controller
378 *
379 * @return none
380 */
381void scic_sds_controller_ram_initialization(
382   SCIC_SDS_CONTROLLER_T *this_controller
383)
384{
385   SCI_PHYSICAL_MEMORY_DESCRIPTOR_T *mde;
386
387   // The completion queue is actually placed in cacheable memory
388   // Therefore it no longer comes out of memory in the MDL.
389   mde = &this_controller->memory_descriptors[SCU_MDE_COMPLETION_QUEUE];
390   this_controller->completion_queue = (U32*) mde->virtual_address;
391   SMU_CQBAR_WRITE(this_controller, mde->physical_address);
392
393   // Program the location of the Remote Node Context table
394   // into the SCU.
395   mde = &this_controller->memory_descriptors[SCU_MDE_REMOTE_NODE_CONTEXT];
396   this_controller->remote_node_context_table = (SCU_REMOTE_NODE_CONTEXT_T *)
397                                                mde->virtual_address;
398   SMU_RNCBAR_WRITE(this_controller, mde->physical_address);
399
400   // Program the location of the Task Context table into the SCU.
401   mde = &this_controller->memory_descriptors[SCU_MDE_TASK_CONTEXT];
402   this_controller->task_context_table = (SCU_TASK_CONTEXT_T *)
403                                         mde->virtual_address;
404   SMU_HTTBAR_WRITE(this_controller, mde->physical_address);
405
406   mde = &this_controller->memory_descriptors[SCU_MDE_UF_BUFFER];
407   scic_sds_unsolicited_frame_control_construct(
408      &this_controller->uf_control, mde, this_controller
409   );
410
411   // Inform the silicon as to the location of the UF headers and
412   // address table.
413   SCU_UFHBAR_WRITE(
414      this_controller,
415      this_controller->uf_control.headers.physical_address);
416   SCU_PUFATHAR_WRITE(
417      this_controller,
418      this_controller->uf_control.address_table.physical_address);
419
420   //enable the ECC correction and detection.
421   SCU_SECR0_WRITE(
422      this_controller,
423      (SIGNLE_BIT_ERROR_CORRECTION_ENABLE
424       | MULTI_BIT_ERROR_REPORTING_ENABLE
425       | SINGLE_BIT_ERROR_REPORTING_ENABLE) );
426   SCU_SECR1_WRITE(
427      this_controller,
428      (SIGNLE_BIT_ERROR_CORRECTION_ENABLE
429       | MULTI_BIT_ERROR_REPORTING_ENABLE
430       | SINGLE_BIT_ERROR_REPORTING_ENABLE) );
431}
432
433/**
434 * @brief This method initializes the task context data for the controller.
435 *
436 * @param[in] this_controller
437 *
438 * @return none
439 */
440void scic_sds_controller_assign_task_entries(
441   SCIC_SDS_CONTROLLER_T *this_controller
442)
443{
444   U32 task_assignment;
445
446   // Assign all the TCs to function 0
447   // TODO: Do we actually need to read this register to write it back?
448   task_assignment = SMU_TCA_READ(this_controller, 0);
449
450   task_assignment =
451      (
452          task_assignment
453        | (SMU_TCA_GEN_VAL(STARTING, 0))
454        | (SMU_TCA_GEN_VAL(ENDING,  this_controller->task_context_entries - 1))
455        | (SMU_TCA_GEN_BIT(RANGE_CHECK_ENABLE))
456      );
457
458   SMU_TCA_WRITE(this_controller, 0, task_assignment);
459}
460
461/**
462 * @brief This method initializes the hardware completion queue.
463 *
464 * @param[in] this_controller
465 */
466void scic_sds_controller_initialize_completion_queue(
467   SCIC_SDS_CONTROLLER_T *this_controller
468)
469{
470   U32 index;
471   U32 completion_queue_control_value;
472   U32 completion_queue_get_value;
473   U32 completion_queue_put_value;
474
475   this_controller->completion_queue_get = 0;
476
477   completion_queue_control_value = (
478        SMU_CQC_QUEUE_LIMIT_SET(this_controller->completion_queue_entries - 1)
479      | SMU_CQC_EVENT_LIMIT_SET(this_controller->completion_event_entries - 1)
480   );
481
482   SMU_CQC_WRITE(this_controller, completion_queue_control_value);
483
484   // Set the completion queue get pointer and enable the queue
485   completion_queue_get_value = (
486        (SMU_CQGR_GEN_VAL(POINTER, 0))
487      | (SMU_CQGR_GEN_VAL(EVENT_POINTER, 0))
488      | (SMU_CQGR_GEN_BIT(ENABLE))
489      | (SMU_CQGR_GEN_BIT(EVENT_ENABLE))
490   );
491
492   SMU_CQGR_WRITE(this_controller, completion_queue_get_value);
493
494   this_controller->completion_queue_get = completion_queue_get_value;
495
496   // Set the completion queue put pointer
497   completion_queue_put_value = (
498        (SMU_CQPR_GEN_VAL(POINTER, 0))
499      | (SMU_CQPR_GEN_VAL(EVENT_POINTER, 0))
500   );
501
502   SMU_CQPR_WRITE(this_controller, completion_queue_put_value);
503
504   // Initialize the cycle bit of the completion queue entries
505   for (index = 0; index < this_controller->completion_queue_entries; index++)
506   {
507      // If get.cycle_bit != completion_queue.cycle_bit
508      // its not a valid completion queue entry
509      // so at system start all entries are invalid
510      this_controller->completion_queue[index] = 0x80000000;
511   }
512}
513
514/**
515 * @brief This method initializes the hardware unsolicited frame queue.
516 *
517 * @param[in] this_controller
518 */
519void scic_sds_controller_initialize_unsolicited_frame_queue(
520   SCIC_SDS_CONTROLLER_T *this_controller
521)
522{
523   U32 frame_queue_control_value;
524   U32 frame_queue_get_value;
525   U32 frame_queue_put_value;
526
527   // Write the queue size
528   frame_queue_control_value =
529      SCU_UFQC_GEN_VAL(QUEUE_SIZE, this_controller->uf_control.address_table.count);
530
531   SCU_UFQC_WRITE(this_controller, frame_queue_control_value);
532
533   // Setup the get pointer for the unsolicited frame queue
534   frame_queue_get_value = (
535         SCU_UFQGP_GEN_VAL(POINTER, 0)
536      |  SCU_UFQGP_GEN_BIT(ENABLE_BIT)
537      );
538
539   SCU_UFQGP_WRITE(this_controller, frame_queue_get_value);
540
541   // Setup the put pointer for the unsolicited frame queue
542   frame_queue_put_value = SCU_UFQPP_GEN_VAL(POINTER, 0);
543
544   SCU_UFQPP_WRITE(this_controller, frame_queue_put_value);
545}
546
547/**
548 * @brief This method enables the hardware port task scheduler.
549 *
550 * @param[in] this_controller
551 */
552void scic_sds_controller_enable_port_task_scheduler(
553   SCIC_SDS_CONTROLLER_T *this_controller
554)
555{
556   U32 port_task_scheduler_value;
557
558   port_task_scheduler_value = SCU_PTSGCR_READ(this_controller);
559
560   port_task_scheduler_value |=
561      (SCU_PTSGCR_GEN_BIT(ETM_ENABLE) | SCU_PTSGCR_GEN_BIT(PTSG_ENABLE));
562
563   SCU_PTSGCR_WRITE(this_controller, port_task_scheduler_value);
564}
565
566// ---------------------------------------------------------------------------
567
568#ifdef ARLINGTON_BUILD
569/**
570 * This method will read from the lexington status register.  This is required
571 * as a read fence to the lexington register writes.
572 *
573 * @param this_controller
574 */
575void scic_sds_controller_lex_status_read_fence(
576   SCIC_SDS_CONTROLLER_T *this_controller
577)
578{
579   U32 lex_status;
580
581   // Read Fence
582   lex_status = lex_register_read(
583                  this_controller, this_controller->lex_registers + 0xC4);
584
585   SCIC_LOG_TRACE((
586      sci_base_object_get_logger(this_controller),
587      SCIC_LOG_OBJECT_CONTROLLER,
588      "Controller 0x%x lex_status = 0x%08x\n",
589      this_controller, lex_status
590   ));
591}
592
593/**
594 * This method will initialize the arlington through the LEX_BAR.
595 *
596 * @param this_controller
597 */
598void scic_sds_controller_lex_atux_initialization(
599   SCIC_SDS_CONTROLLER_T *this_controller
600)
601{
602   // 1. Reset all SCU PHY
603   lex_register_write(
604      this_controller, this_controller->lex_registers + 0x28, 0x0020FFFF) ;
605
606   // 2. Write to LEX_CTRL
607   lex_register_write(
608      this_controller, this_controller->lex_registers + 0xC0, 0x00000700);
609
610   scic_sds_controller_lex_status_read_fence(this_controller);
611
612   // 3. Enable PCI Master
613   lex_register_write(
614      this_controller, this_controller->lex_registers + 0x70, 0x00000002);
615
616   // 4. Enable SCU Register Clock Domain
617   lex_register_write(
618      this_controller, this_controller->lex_registers + 0xC0, 0x00000300);
619
620   scic_sds_controller_lex_status_read_fence(this_controller);
621
622   // 5.1 Release PHY-A Reg Reset
623   lex_register_write(
624      this_controller, this_controller->lex_registers + 0x28, 0x0000FFFF);
625
626   // 5.2 Initialize the AFE for PHY-A
627   scic_sds_controller_afe_initialization(this_controller);
628
629   scic_sds_controller_lex_status_read_fence(this_controller);
630
631#if 0
632   // 5.3 Release PHY Reg Reset
633   lex_register_write(
634      this_controller, this_controller->lex_registers + 0x28, 0x0000FFFF);
635#endif
636
637   // 6.1 Release PHY-B Reg Reset
638   lex_register_write(
639      this_controller, this_controller->lex_registers + 0x28, 0x0040FFFF) ;
640
641   // 6.2 Initialize the AFE for PHY-B
642   scic_sds_controller_afe_initialization(this_controller);
643
644   scic_sds_controller_lex_status_read_fence(this_controller);
645
646#if 0
647   // 6.3 Release PHY-B Reg Reset
648   lex_register_write(
649      this_controller, this_controller->lex_registers + 0x28, 0x0040FFFF) ;
650#endif
651
652   // 7. Enable SCU clock domaion
653   lex_register_write(
654      this_controller, this_controller->lex_registers + 0xC0, 0x00000100);
655
656   scic_sds_controller_lex_status_read_fence(this_controller);
657
658   // 8. Release LEX SCU Reset
659   lex_register_write(
660      this_controller, this_controller->lex_registers + 0xC0, 0x00000000);
661
662   scic_sds_controller_lex_status_read_fence(this_controller);
663
664#if !defined(DISABLE_INTERRUPTS)
665   // 8a. Set legacy interrupts (SCU INTx to PCI-x INTA)
666   lex_register_write(
667      this_controller, this_controller->lex_registers + 0xC0, 0x00000800);
668
669   scic_sds_controller_lex_status_read_fence(this_controller);
670#endif
671
672#if 0
673   // 9. Override TXOLVL
674   //write to lex_ctrl
675   lex_register_write(
676      this_controller, this_controller->lex_registers + 0xC0, 0x27800000);
677#endif
678
679   // 10. Release PHY-A & PHY-B Resets
680   lex_register_write(
681      this_controller, this_controller->lex_registers + 0x28, 0x0000FF77);
682
683   lex_register_write(
684      this_controller, this_controller->lex_registers + 0x28, 0x0000FF55);
685
686   lex_register_write(
687      this_controller, this_controller->lex_registers + 0x28, 0x0000FF11);
688
689   lex_register_write(
690      this_controller, this_controller->lex_registers + 0x28, 0x0000FF00);
691
692   lex_register_write(
693      this_controller, this_controller->lex_registers + 0x28, 0x0003FF00);
694}
695#endif // ARLINGTON_BUILD
696
697// ---------------------------------------------------------------------------
698
699#ifdef ARLINGTON_BUILD
700/**
701 * This method enables chipwatch on the arlington board
702 *
703 * @param[in] this_controller
704 */
705void scic_sds_controller_enable_chipwatch(
706   SCIC_SDS_CONTROLLER_T *this_controller
707)
708{
709   lex_register_write(
710      this_controller, this_controller->lex_registers + 0x88, 0x09090909);
711
712   lex_register_write(
713      this_controller, this_controller->lex_registers + 0x8C, 0xcac9c862);
714}
715#endif
716
717/**
718 * This macro is used to delay between writes to the AFE registers
719 * during AFE initialization.
720 */
721#define AFE_REGISTER_WRITE_DELAY 10
722
723/**
724 * Initialize the AFE for this phy index.
725 *
726 * @todo We need to read the AFE setup from the OEM parameters
727 *
728 * @param[in] this_controller
729 *
730 * @return none
731 */
732#if defined(ARLINGTON_BUILD)
733void scic_sds_controller_afe_initialization(
734   SCIC_SDS_CONTROLLER_T *this_controller
735)
736{
737   // 1. Establish Power
738   //       Hold Bias, PLL, and RX TX in reset and powerdown
739   //       pe_afe0_rst_n = 0
740   //       pe_afe0_txpdn0,1,2,3 = 1
741   //       pe_afe0_rxpdn0,1,2,3 = 1
742   //       pe_afe0_txrst0,1,2,3_n = 0
743   //       pe_afe0_rxrst0,1,2,3_n = 0
744   //       wait 1us
745   //       pe_afe0_rst_n = 1
746   //       wait 1us
747   scu_afe_register_write(
748      this_controller, afe_pll_control, 0x00247506);
749
750   // 2. Write 0x00000000 to AFE XCVR Ctrl2
751   scu_afe_register_write(
752      this_controller, afe_dfx_transceiver_status_clear, 0x00000000);
753
754   // 3. afe0_override_en = 0
755   //    afe0_pll_dis_override = 0
756   //    afe0_tx_rst_override = 0
757   //    afe0_pll_dis = 1
758   //    pe_afe0_txrate = 01
759   //    pe_afe0_rxrate = 01
760   //    pe_afe0_txdis = 11
761   //    pe_afe0_txoob = 1
762   //    pe_afe0_txovlv = 9'b001110000
763   scu_afe_register_write(
764      this_controller, afe_transceiver_control0[0], 0x0700141e);
765
766   // 4. Configure PLL Unit
767   //    Write 0x00200506 to AFE PLL Ctrl Register 0
768   scu_afe_register_write(this_controller, afe_pll_control,     0x00200506);
769   scu_afe_register_write(this_controller, afe_pll_dfx_control, 0x10000080);
770
771   // 5. Configure Bias Unit
772   scu_afe_register_write(this_controller, afe_bias_control[0], 0x00124814);
773   scu_afe_register_write(this_controller, afe_bias_control[1], 0x24900000);
774
775   // 6. Configure Transceiver Units
776   scu_afe_register_write(
777      this_controller, afe_transceiver_control0[0], 0x0702941e);
778
779   scu_afe_register_write(
780      this_controller, afe_transceiver_control1[0], 0x0000000a);
781
782   // 7. Configure RX Units
783   scu_afe_register_write(
784      this_controller, afe_transceiver_equalization_control[0], 0x00ba2223);
785
786   scu_afe_register_write(
787      this_controller, reserved_0028_003c[2], 0x00000000);
788
789   // 8. Configure TX Units
790   scu_afe_register_write(
791      this_controller, afe_dfx_transmit_control_register[0], 0x03815428);
792
793   // 9. Transfer control to PE signals
794   scu_afe_register_write(
795      this_controller, afe_dfx_transceiver_status_clear, 0x00000010);
796
797   // 10. Release PLL Powerdown
798   scu_afe_register_write(this_controller, afe_pll_control, 0x00200504);
799
800   // 11. Release PLL Reset
801   scu_afe_register_write(this_controller, afe_pll_control, 0x00200505);
802
803   // 12. Wait for PLL to Lock
804   // (afe0_comm_sta [1:0] should go to 1'b11, and
805   //                [5:2] is 0x5, 0x6, 0x7, 0x8, or 0x9
806   scu_afe_register_write(this_controller, afe_pll_control, 0x00200501);
807
808   while ((scu_afe_register_read(this_controller, afe_common_status) & 0x03) != 0x03)
809   {
810      // Give time for the PLLs to lock
811      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
812   }
813
814   // 13. pe_afe0_rxpdn0 = 0
815   //     pe_afe0_rxrst0 = 1
816   //     pe_afe0_txrst0_n = 1
817   //     pe_afe_txoob0_n = 0
818   scu_afe_register_write(
819      this_controller, afe_transceiver_control0[0], 0x07028c11);
820}
821
822#elif defined(PLEASANT_RIDGE_BUILD)
823
824void scic_sds_controller_afe_initialization(
825   SCIC_SDS_CONTROLLER_T *this_controller
826)
827{
828   U32 afe_status;
829   U32 phy_id;
830
831#if defined(SPREADSHEET_AFE_SETTINGS)
832   // Clear DFX Status registers
833   scu_afe_register_write(
834      this_controller, afe_dfx_master_control0, 0x0000000f);
835   // Configure bias currents to normal
836   scu_afe_register_write(
837      this_controller, afe_bias_control, 0x0000aa00);
838   // Enable PLL
839   scu_afe_register_write(
840      this_controller, afe_pll_control0, 0x80000908);
841
842   // Wait for the PLL to lock
843   do
844   {
845      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
846      afe_status = scu_afe_register_read(
847                     this_controller, afe_common_block_status);
848   }
849   while((afe_status & 0x00001000) == 0);
850
851   for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++)
852   {
853      // Initialize transceiver channels
854      scu_afe_register_write(
855         this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000157);
856      // Configure transceiver modes
857      scu_afe_register_write(
858         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016d1a);
859      // Configure receiver parameters
860      scu_afe_register_write(
861         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01501014);
862      // Configure transmitter parameters
863      scu_afe_register_write(
864         this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00000000);
865      // Configure transmitter equalization
866      scu_afe_register_write(
867         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0, 0x000bdd08);
868      scu_afe_register_write(
869         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1, 0x000ffc00);
870      scu_afe_register_write(
871         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2, 0x000b7c09);
872      scu_afe_register_write(
873         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3, 0x000afc6e);
874      // Configure transmitter SSC parameters
875      scu_afe_register_write(
876         this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00000000);
877      // Configure receiver parameters
878      scu_afe_register_write(
879         this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x3208903f);
880
881      // Start power on sequence
882      // Enable bias currents to transceivers and wait 200ns
883      scu_afe_register_write(
884         this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000154);
885      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
886      // Take receiver out of power down and wait 200ns
887      scu_afe_register_write(
888         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x3801611a);
889      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
890      // Take receiver out of reset and wait 200ns
891      scu_afe_register_write(
892         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x3801631a);
893      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
894      // Take transmitter out of power down and wait 200ns
895      scu_afe_register_write(
896         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016318);
897      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
898      // Take transmitter out of reset and wait 200ns
899      scu_afe_register_write(
900         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016319);
901      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
902      // Take transmitter out of DC idle
903      scu_afe_register_write(
904         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x38016319);
905      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
906   }
907
908   // Transfer control to the PEs
909   scu_afe_register_write(
910      this_controller, afe_dfx_master_control0, 0x00010f00);
911#else // !defined(SPREADSHEET_AFE_SETTINGS)
912   // These are the AFEE settings used by the SV group
913   // Clear DFX Status registers
914   scu_afe_register_write(
915      this_controller, afe_dfx_master_control0, 0x0081000f);
916   // Configure bias currents to normal
917   scu_afe_register_write(
918      this_controller, afe_bias_control, 0x0000aa00);
919   // Enable PLL
920   scu_afe_register_write(
921      this_controller, afe_pll_control0, 0x80000908);
922
923   // Wait for the PLL to lock
924   // Note: this is done later in the SV shell script however this looks
925   //       like the location to do this since we have enabled the PLL.
926   do
927   {
928      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
929      afe_status = scu_afe_register_read(
930                     this_controller, afe_common_block_status);
931   }
932   while((afe_status & 0x00001000) == 0);
933
934   // Make sure BIST is disabled
935   scu_afe_register_write(
936      this_controller, afe_dfx_master_control1, 0x00000000);
937   // Shorten SAS SNW lock time
938   scu_afe_register_write(
939      this_controller, afe_pmsn_master_control0, 0x7bd316ad);
940
941   for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++)
942   {
943      // Initialize transceiver channels
944      scu_afe_register_write(
945         this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000174);
946      // Configure SSC control
947      scu_afe_register_write(
948         this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00030000);
949      // Configure transceiver modes
950      scu_afe_register_write(
951         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0000651a);
952      // Power up TX RX and RX OOB
953      scu_afe_register_write(
954         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006518);
955      // Enable RX OOB Detect
956      scu_afe_register_write(
957         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006518);
958      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
959      #if 0
960      // Configure transmitter parameters
961      scu_afe_register_write(
962         this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00000000);
963      // Configure transmitter equalization
964      scu_afe_register_write(
965         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0, 0x000bdd08);
966      scu_afe_register_write(
967         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1, 0x000ffc00);
968      scu_afe_register_write(
969         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2, 0x000b7c09);
970      scu_afe_register_write(
971         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3, 0x000afc6e);
972      // Configure transmitter SSC parameters
973      // Power up TX RX
974
975      scu_afe_register_write(
976         this_controller, scu_afe_xcvr[phy_id].afe_channel_control, 0x00000154);
977      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
978
979      // FFE = Max
980      scu_afe_register_write(
981         this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x00000080);
982      // DFE1-5 = small
983      scu_afe_register_write(
984         this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x01041042);
985      // Enable DFE/FFE and freeze
986      scu_afe_register_write(
987         this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x320891bf);
988      #endif
989      // Take receiver out of power down and wait 200ns
990      scu_afe_register_write(
991         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006118);
992      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
993      // TX Electrical Idle
994      scu_afe_register_write(
995         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006108);
996      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
997
998      // Leave DFE/FFE on
999      scu_afe_register_write(
1000         this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x0317108f);
1001
1002      // Configure receiver parameters
1003      scu_afe_register_write(
1004         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01e00021);
1005
1006      // Bring RX out of reset
1007      scu_afe_register_write(
1008         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006109);
1009      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1010
1011      scu_afe_register_write(
1012         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006009);
1013      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1014
1015      scu_afe_register_write(
1016         this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00006209);
1017      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1018   }
1019
1020   // Transfer control to the PEs
1021   scu_afe_register_write(
1022      this_controller, afe_dfx_master_control0, 0x00010f00);
1023#endif
1024}
1025
1026#elif defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD) || defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD)
1027
1028void scic_sds_controller_afe_initialization(
1029   SCIC_SDS_CONTROLLER_T *this_controller
1030)
1031{
1032   U32  afe_status;
1033   U32  phy_id;
1034   U8   cable_selection_mask;
1035
1036   if (
1037         (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_A0)
1038      && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_A2)
1039      && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_B0)
1040      && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_C0)
1041      && (this_controller->pci_revision != SCIC_SDS_PCI_REVISION_C1)
1042      )
1043   {
1044      // A programming bug has occurred if we are attempting to
1045      // support a PCI revision other than those listed.  Default
1046      // to B0, and attempt to limp along if it isn't B0.
1047      ASSERT(FALSE);
1048      this_controller->pci_revision = SCIC_SDS_PCI_REVISION_C1;
1049   }
1050
1051   cable_selection_mask =
1052      this_controller->oem_parameters.sds1.controller.cable_selection_mask;
1053
1054   // These are the AFEE settings used by the SV group
1055   // Clear DFX Status registers
1056   scu_afe_register_write(
1057      this_controller, afe_dfx_master_control0, 0x0081000f);
1058   scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1059
1060   if (
1061         (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
1062      || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
1063      || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
1064      )
1065   {
1066      // PM Rx Equalization Save, PM SPhy Rx Acknowledgement Timer, PM Stagger Timer
1067      scu_afe_register_write(
1068         this_controller, afe_pmsn_master_control2, 0x0007FFFF);
1069      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1070   }
1071
1072   // Configure bias currents to normal
1073   if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
1074      scu_afe_register_write(this_controller, afe_bias_control, 0x00005500);
1075   else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
1076      scu_afe_register_write(this_controller, afe_bias_control, 0x00005A00);
1077   else if (  (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
1078           || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) )
1079      scu_afe_register_write(this_controller, afe_bias_control, 0x00005F00);
1080   else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
1081      scu_afe_register_write(this_controller, afe_bias_control, 0x00005500);
1082   // For C0 the AFE BIAS Control is unchanged
1083
1084   scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1085
1086      // Enable PLL
1087   if (  (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
1088      || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
1089   {
1090      scu_afe_register_write(this_controller, afe_pll_control0, 0x80040908);
1091   }
1092   else if (  (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
1093           || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0) )
1094   {
1095      scu_afe_register_write(this_controller, afe_pll_control0, 0x80040A08);
1096   }
1097   else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
1098   {
1099      scu_afe_register_write(this_controller, afe_pll_control0, 0x80000b08);
1100      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1101      scu_afe_register_write(this_controller, afe_pll_control0, 0x00000b08);
1102      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1103      scu_afe_register_write(this_controller, afe_pll_control0, 0x80000b08);
1104   }
1105
1106   scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1107
1108   // Wait for the PLL to lock
1109   // Note: this is done later in the SV shell script however this looks
1110   //       like the location to do this since we have enabled the PLL.
1111   do
1112   {
1113      afe_status = scu_afe_register_read(
1114                      this_controller, afe_common_block_status);
1115      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1116   }
1117   while((afe_status & 0x00001000) == 0);
1118
1119   if (  (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
1120      || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
1121   {
1122      // Shorten SAS SNW lock time (RxLock timer value from 76 us to 50 us)
1123      scu_afe_register_write(
1124         this_controller, afe_pmsn_master_control0, 0x7bcc96ad);
1125      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1126   }
1127
1128   for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++)
1129   {
1130      U8 cable_length_long   = (cable_selection_mask >> phy_id) & 1;
1131      U8 cable_length_medium = (cable_selection_mask >> (phy_id + 4)) & 1;
1132
1133      if (  (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
1134         || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
1135      {
1136         // All defaults, except the Receive Word Alignament/Comma Detect
1137         // Enable....(0xe800)
1138         scu_afe_register_write(
1139            this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00004512
1140         );
1141         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1142
1143         scu_afe_register_write(
1144            this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x0050100F
1145         );
1146         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1147      }
1148      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
1149      {
1150         // Configure transmitter SSC parameters
1151         scu_afe_register_write(
1152            this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00030000
1153         );
1154         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1155      }
1156      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
1157      {
1158         // Configure transmitter SSC parameters
1159         scu_afe_register_write(
1160            this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00010202
1161         );
1162         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1163
1164         // All defaults, except the Receive Word Alignament/Comma Detect
1165         // Enable....(0xe800)
1166         scu_afe_register_write(
1167            this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00014500
1168         );
1169         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1170      }
1171      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
1172      {
1173         // Configure transmitter SSC parameters
1174         scu_afe_register_write(
1175            this_controller, scu_afe_xcvr[phy_id].afe_tx_ssc_control, 0x00010202
1176         );
1177         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1178
1179         // All defaults, except the Receive Word Alignament/Comma Detect
1180         // Enable....(0xe800)
1181         scu_afe_register_write(
1182            this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0001C500
1183         );
1184         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1185      }
1186      // Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
1187      // & increase TX int & ext bias 20%....(0xe85c)
1188      if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
1189      {
1190         scu_afe_register_write(
1191            this_controller,
1192            scu_afe_xcvr[phy_id].afe_channel_control,
1193            0x000003D4
1194         );
1195      }
1196      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
1197      {
1198         scu_afe_register_write(
1199            this_controller,
1200            scu_afe_xcvr[phy_id].afe_channel_control,
1201            0x000003F0
1202         );
1203      }
1204      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
1205      {
1206         // Power down TX and RX (PWRDNTX and PWRDNRX)
1207         scu_afe_register_write(
1208            this_controller,
1209            scu_afe_xcvr[phy_id].afe_channel_control,
1210            0x000003d7
1211         );
1212
1213         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1214
1215         // Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
1216         // & increase TX int & ext bias 20%....(0xe85c)
1217         scu_afe_register_write(
1218            this_controller,
1219            scu_afe_xcvr[phy_id].afe_channel_control,
1220            0x000003d4
1221         );
1222      }
1223      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
1224      {
1225         scu_afe_register_write(
1226            this_controller,
1227            scu_afe_xcvr[phy_id].afe_channel_control,
1228            0x000001e7
1229         );
1230
1231         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1232
1233         // Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
1234         // & increase TX int & ext bias 20%....(0xe85c)
1235         scu_afe_register_write(
1236            this_controller,
1237            scu_afe_xcvr[phy_id].afe_channel_control,
1238            0x000001e4
1239         );
1240      }
1241      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
1242      {
1243         scu_afe_register_write(
1244            this_controller,
1245            scu_afe_xcvr[phy_id].afe_channel_control,
1246            cable_length_long   ? 0x000002F7 :
1247            cable_length_medium ? 0x000001F7 : 0x000001F7
1248         );
1249
1250         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1251
1252         // Power up TX and RX out from power down (PWRDNTX and PWRDNRX)
1253         // & increase TX int & ext bias 20%....(0xe85c)
1254         scu_afe_register_write(
1255            this_controller,
1256            scu_afe_xcvr[phy_id].afe_channel_control,
1257            cable_length_long   ? 0x000002F4 :
1258            cable_length_medium ? 0x000001F4 : 0x000001F4
1259         );
1260      }
1261
1262      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1263
1264      if (  (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
1265         || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2) )
1266      {
1267         // Enable TX equalization (0xe824)
1268         scu_afe_register_write(
1269            this_controller,
1270            scu_afe_xcvr[phy_id].afe_tx_control,
1271            0x00040000
1272         );
1273         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1274      }
1275
1276      if (  (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
1277         || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
1278         || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) )
1279      {
1280         // RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, TPD=0x0(TX Power On),
1281         // RDD=0x0(RX Detect Enabled) ....(0xe800)
1282         scu_afe_register_write(
1283            this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00004100);
1284         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1285      }
1286      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
1287      {
1288         scu_afe_register_write(
1289            this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x00014100);
1290         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1291      }
1292      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
1293      {
1294         scu_afe_register_write(
1295            this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control0, 0x0001c100);
1296         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1297      }
1298
1299      // Leave DFE/FFE on
1300      if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
1301      {
1302         scu_afe_register_write(
1303            this_controller,
1304            scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
1305            0x3F09983F
1306         );
1307      }
1308      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
1309      {
1310         scu_afe_register_write(
1311            this_controller,
1312            scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
1313            0x3F11103F
1314         );
1315      }
1316      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0)
1317      {
1318         scu_afe_register_write(
1319            this_controller,
1320            scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
1321            0x3F11103F
1322         );
1323         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1324
1325         // Enable TX equalization (0xe824)
1326         scu_afe_register_write(
1327            this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000);
1328      }
1329      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C0)
1330      {
1331         scu_afe_register_write(
1332            this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1, 0x01400c0f);
1333         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1334
1335         scu_afe_register_write(
1336            this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0, 0x3f6f103f);
1337         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1338
1339         // Enable TX equalization (0xe824)
1340         scu_afe_register_write(
1341            this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000);
1342      }
1343      else if (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_C1)
1344      {
1345         scu_afe_register_write(
1346            this_controller, scu_afe_xcvr[phy_id].afe_xcvr_control1,
1347            cable_length_long   ? 0x01500C0C :
1348            cable_length_medium ? 0x01400C0D : 0x02400C0D
1349         );
1350         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1351
1352         scu_afe_register_write(
1353            this_controller, scu_afe_xcvr[phy_id].afe_dfx_rx_control1, 0x000003e0);
1354         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1355
1356         scu_afe_register_write(
1357            this_controller, scu_afe_xcvr[phy_id].afe_rx_ssc_control0,
1358            cable_length_long   ? 0x33091C1F :
1359            cable_length_medium ? 0x3315181F : 0x2B17161F
1360         );
1361         scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1362
1363         // Enable TX equalization (0xe824)
1364         scu_afe_register_write(
1365            this_controller, scu_afe_xcvr[phy_id].afe_tx_control, 0x00040000);
1366      }
1367
1368      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1369
1370      scu_afe_register_write(
1371         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control0,
1372         this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control0
1373      );
1374      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1375
1376      scu_afe_register_write(
1377         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control1,
1378         this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control1
1379      );
1380      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1381
1382      scu_afe_register_write(
1383         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control2,
1384         this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control2
1385      );
1386      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1387
1388      scu_afe_register_write(
1389         this_controller, scu_afe_xcvr[phy_id].afe_tx_amp_control3,
1390         this_controller->oem_parameters.sds1.phys[phy_id].afe_tx_amp_control3
1391      );
1392      scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1393   }
1394
1395   // Transfer control to the PEs
1396   scu_afe_register_write(
1397      this_controller, afe_dfx_master_control0, 0x00010f00);
1398   scic_cb_stall_execution(AFE_REGISTER_WRITE_DELAY);
1399}
1400#else
1401   #error "Unsupported board type"
1402#endif
1403
1404//****************************************************************************-
1405//* SCIC SDS Controller Internal Start/Stop Routines
1406//****************************************************************************-
1407
1408
1409/**
1410 * @brief This method will attempt to transition into the ready state
1411 *        for the controller and indicate that the controller start
1412 *        operation has completed if all criteria are met.
1413 *
1414 * @param[in,out] this_controller This parameter indicates the controller
1415 *                object for which to transition to ready.
1416 * @param[in]     status This parameter indicates the status value to be
1417 *                pass into the call to scic_cb_controller_start_complete().
1418 *
1419 * @return none.
1420 */
1421static
1422void scic_sds_controller_transition_to_ready(
1423   SCIC_SDS_CONTROLLER_T *this_controller,
1424   SCI_STATUS             status
1425)
1426{
1427   SCIC_LOG_TRACE((
1428      sci_base_object_get_logger(this_controller),
1429      SCIC_LOG_OBJECT_CONTROLLER,
1430      "scic_sds_controller_transition_to_ready(0x%x, 0x%x) enter\n",
1431      this_controller, status
1432   ));
1433
1434   if (this_controller->parent.state_machine.current_state_id
1435       == SCI_BASE_CONTROLLER_STATE_STARTING)
1436   {
1437      // We move into the ready state, because some of the phys/ports
1438      // may be up and operational.
1439      sci_base_state_machine_change_state(
1440         scic_sds_controller_get_base_state_machine(this_controller),
1441         SCI_BASE_CONTROLLER_STATE_READY
1442      );
1443
1444      scic_cb_controller_start_complete(this_controller, status);
1445   }
1446}
1447
1448/**
1449 * @brief This method is the general timeout handler for the controller.
1450 *        It will take the correct timetout action based on the current
1451 *        controller state
1452 *
1453 * @param[in] controller This parameter indicates the controller on which
1454 *            a timeout occurred.
1455 *
1456 * @return none
1457 */
1458void scic_sds_controller_timeout_handler(
1459   SCI_CONTROLLER_HANDLE_T controller
1460)
1461{
1462   SCI_BASE_CONTROLLER_STATES current_state;
1463   SCIC_SDS_CONTROLLER_T *this_controller;
1464   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
1465
1466   current_state = sci_base_state_machine_get_state(
1467                      scic_sds_controller_get_base_state_machine(this_controller)
1468                   );
1469
1470   if (current_state == SCI_BASE_CONTROLLER_STATE_STARTING)
1471   {
1472      scic_sds_controller_transition_to_ready(
1473         this_controller, SCI_FAILURE_TIMEOUT
1474      );
1475   }
1476   else if (current_state == SCI_BASE_CONTROLLER_STATE_STOPPING)
1477   {
1478      sci_base_state_machine_change_state(
1479         scic_sds_controller_get_base_state_machine(this_controller),
1480         SCI_BASE_CONTROLLER_STATE_FAILED
1481      );
1482
1483      scic_cb_controller_stop_complete(controller, SCI_FAILURE_TIMEOUT);
1484   }
1485   else
1486   {
1487      /// @todo Now what do we want to do in this case?
1488      SCIC_LOG_ERROR((
1489         sci_base_object_get_logger(this_controller),
1490         SCIC_LOG_OBJECT_CONTROLLER,
1491         "Controller timer fired when controller was not in a state being timed.\n"
1492      ));
1493   }
1494}
1495
1496/**
1497 * @brief
1498 *
1499 * @param[in] this_controller
1500 *
1501 * @return SCI_STATUS
1502 */
1503SCI_STATUS scic_sds_controller_stop_ports(
1504   SCIC_SDS_CONTROLLER_T *this_controller
1505)
1506{
1507   U32        index;
1508   SCI_STATUS status;
1509   SCI_STATUS port_status;
1510
1511   status = SCI_SUCCESS;
1512
1513   for (index = 0; index < this_controller->logical_port_entries; index++)
1514   {
1515      port_status = this_controller->port_table[index].
1516         state_handlers->parent.stop_handler(&this_controller->port_table[index].parent);
1517      if (
1518            (port_status != SCI_SUCCESS)
1519         && (port_status != SCI_FAILURE_INVALID_STATE)
1520         )
1521      {
1522         status = SCI_FAILURE;
1523
1524         SCIC_LOG_WARNING((
1525            sci_base_object_get_logger(this_controller),
1526            SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PORT,
1527            "Controller stop operation failed to stop port %d because of status %d.\n",
1528            this_controller->port_table[index].logical_port_index, port_status
1529         ));
1530      }
1531   }
1532
1533   return status;
1534}
1535
1536/**
1537 * @brief
1538 *
1539 * @param[in] this_controller
1540 */
1541static
1542void scic_sds_controller_phy_timer_start(
1543   SCIC_SDS_CONTROLLER_T *this_controller
1544)
1545{
1546   scic_cb_timer_start(
1547      this_controller,
1548      this_controller->phy_startup_timer,
1549      SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT
1550   );
1551
1552   this_controller->phy_startup_timer_pending = TRUE;
1553}
1554
1555/**
1556 * @brief
1557 *
1558 * @param[in] this_controller
1559 */
1560void scic_sds_controller_phy_timer_stop(
1561   SCIC_SDS_CONTROLLER_T *this_controller
1562)
1563{
1564   scic_cb_timer_stop(
1565      this_controller,
1566      this_controller->phy_startup_timer
1567   );
1568
1569   this_controller->phy_startup_timer_pending = FALSE;
1570}
1571
1572/**
1573 * @brief This method is called internally to determine whether the
1574 *        controller start process is complete.  This is only true when:
1575 *          - all links have been given an opportunity to start
1576 *          - have no indication of a connected device
1577 *          - have an indication of a connected device and it has
1578 *             finished the link training process.
1579 *
1580 * @param[in] this_controller This parameter specifies the controller
1581 *            object for which to start the next phy.
1582 *
1583 * @return BOOL
1584 */
1585BOOL scic_sds_controller_is_start_complete(
1586   SCIC_SDS_CONTROLLER_T *this_controller
1587)
1588{
1589   U8 index;
1590
1591   for (index = 0; index < SCI_MAX_PHYS; index++)
1592   {
1593      SCIC_SDS_PHY_T *the_phy = & this_controller->phy_table[index];
1594
1595      if (
1596            (
1597                  this_controller->oem_parameters.sds1.controller.mode_type
1598               == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE
1599            )
1600         || (
1601               (
1602                  this_controller->oem_parameters.sds1.controller.mode_type
1603               == SCIC_PORT_MANUAL_CONFIGURATION_MODE
1604               )
1605            && (scic_sds_phy_get_port(the_phy) != SCI_INVALID_HANDLE)
1606            )
1607         )
1608      {
1609         /**
1610          * The controller start operation is complete if and only
1611          * if:
1612          * - all links have been given an opportunity to start
1613          * - have no indication of a connected device
1614          * - have an indication of a connected device and it has
1615          *   finished the link training process.
1616          */
1617        if (
1618               (
1619                  (the_phy->is_in_link_training == FALSE)
1620               && (the_phy->parent.state_machine.current_state_id
1621                   == SCI_BASE_PHY_STATE_INITIAL)
1622               )
1623            || (
1624                  (the_phy->is_in_link_training == FALSE)
1625               && (the_phy->parent.state_machine.current_state_id
1626                   == SCI_BASE_PHY_STATE_STOPPED)
1627               )
1628            || (
1629                  (the_phy->is_in_link_training == TRUE)
1630               && (the_phy->parent.state_machine.current_state_id
1631                   == SCI_BASE_PHY_STATE_STARTING)
1632               )
1633            || (
1634                  this_controller->port_agent.phy_ready_mask
1635                  != this_controller->port_agent.phy_configured_mask
1636               )
1637            )
1638         {
1639            return FALSE;
1640         }
1641      }
1642   }
1643
1644   return TRUE;
1645}
1646
1647/**
1648 * @brief This method is called internally by the controller object to
1649 *        start the next phy on the controller.  If all the phys have
1650 *        been starte, then this method will attempt to transition the
1651 *        controller to the READY state and inform the user
1652 *        (scic_cb_controller_start_complete()).
1653 *
1654 * @param[in] this_controller This parameter specifies the controller
1655 *            object for which to start the next phy.
1656 *
1657 * @return SCI_STATUS
1658 */
1659SCI_STATUS scic_sds_controller_start_next_phy(
1660   SCIC_SDS_CONTROLLER_T *this_controller
1661)
1662{
1663   SCI_STATUS status;
1664
1665   status = SCI_SUCCESS;
1666
1667   if (this_controller->phy_startup_timer_pending == FALSE)
1668   {
1669      if (this_controller->next_phy_to_start == SCI_MAX_PHYS)
1670      {
1671         // The controller has successfully finished the start process.
1672         // Inform the SCI Core user and transition to the READY state.
1673         if (scic_sds_controller_is_start_complete(this_controller) == TRUE)
1674         {
1675            scic_sds_controller_transition_to_ready(
1676               this_controller, SCI_SUCCESS
1677            );
1678         }
1679      }
1680      else
1681      {
1682         SCIC_SDS_PHY_T * the_phy;
1683
1684         the_phy = &this_controller->phy_table[this_controller->next_phy_to_start];
1685
1686         if (
1687               this_controller->oem_parameters.sds1.controller.mode_type
1688            == SCIC_PORT_MANUAL_CONFIGURATION_MODE
1689            )
1690         {
1691            if (scic_sds_phy_get_port(the_phy) == SCI_INVALID_HANDLE)
1692            {
1693               this_controller->next_phy_to_start++;
1694
1695               // Caution recursion ahead be forwarned
1696               //
1697               // The PHY was never added to a PORT in MPC mode so start the next phy in sequence
1698               // This phy will never go link up and will not draw power the OEM parameters either
1699               // configured the phy incorrectly for the PORT or it was never assigned to a PORT
1700               return scic_sds_controller_start_next_phy(this_controller);
1701            }
1702         }
1703
1704         status = scic_phy_start(the_phy);
1705
1706         if (status == SCI_SUCCESS)
1707         {
1708            scic_sds_controller_phy_timer_start(this_controller);
1709         }
1710         else
1711         {
1712            SCIC_LOG_WARNING((
1713               sci_base_object_get_logger(this_controller),
1714               SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PHY,
1715               "Controller stop operation failed to stop phy %d because of status %d.\n",
1716               this_controller->phy_table[this_controller->next_phy_to_start].phy_index,
1717               status
1718            ));
1719         }
1720
1721         this_controller->next_phy_to_start++;
1722      }
1723   }
1724
1725   return status;
1726}
1727
1728/**
1729 * @brief
1730 *
1731 * @param[in] this_controller
1732 *
1733 * @return SCI_STATUS
1734 */
1735SCI_STATUS scic_sds_controller_stop_phys(
1736   SCIC_SDS_CONTROLLER_T *this_controller
1737)
1738{
1739   U32        index;
1740   SCI_STATUS status;
1741   SCI_STATUS phy_status;
1742
1743   status = SCI_SUCCESS;
1744
1745   for (index = 0; index < SCI_MAX_PHYS; index++)
1746   {
1747      phy_status = scic_phy_stop(&this_controller->phy_table[index]);
1748
1749      if (
1750              (phy_status != SCI_SUCCESS)
1751           && (phy_status != SCI_FAILURE_INVALID_STATE)
1752         )
1753      {
1754         status = SCI_FAILURE;
1755
1756         SCIC_LOG_WARNING((
1757            sci_base_object_get_logger(this_controller),
1758            SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_PHY,
1759            "Controller stop operation failed to stop phy %d because of status %d.\n",
1760            this_controller->phy_table[index].phy_index, phy_status
1761         ));
1762      }
1763   }
1764
1765   return status;
1766}
1767
1768/**
1769 * @brief
1770 *
1771 * @param[in] this_controller
1772 *
1773 * @return SCI_STATUS
1774 */
1775SCI_STATUS scic_sds_controller_stop_devices(
1776   SCIC_SDS_CONTROLLER_T *this_controller
1777)
1778{
1779   U32        index;
1780   SCI_STATUS status;
1781   SCI_STATUS device_status;
1782
1783   status = SCI_SUCCESS;
1784
1785   for (index = 0; index < this_controller->remote_node_entries; index++)
1786   {
1787      if (this_controller->device_table[index] != SCI_INVALID_HANDLE)
1788      {
1789         /// @todo What timeout value do we want to provide to this request?
1790         device_status = scic_remote_device_stop(this_controller->device_table[index], 0);
1791
1792         if (
1793                 (device_status != SCI_SUCCESS)
1794              && (device_status != SCI_FAILURE_INVALID_STATE)
1795            )
1796         {
1797            SCIC_LOG_WARNING((
1798               sci_base_object_get_logger(this_controller),
1799               SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_SSP_REMOTE_TARGET,
1800               "Controller stop operation failed to stop device 0x%x because of status %d.\n",
1801               this_controller->device_table[index], device_status
1802            ));
1803         }
1804      }
1805   }
1806
1807   return status;
1808}
1809
1810//****************************************************************************-
1811//* SCIC SDS Controller Power Control (Staggered Spinup)
1812//****************************************************************************-
1813
1814/**
1815 * This method starts the power control timer for this controller object.
1816 *
1817 * @param this_controller
1818 */
1819static
1820void scic_sds_controller_power_control_timer_start(
1821   SCIC_SDS_CONTROLLER_T *this_controller
1822)
1823{
1824   scic_cb_timer_start(
1825      this_controller, this_controller->power_control.timer,
1826      SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL
1827   );
1828
1829   this_controller->power_control.timer_started = TRUE;
1830}
1831
1832/**
1833 * This method stops the power control timer for this controller object.
1834 *
1835 * @param this_controller
1836 */
1837static
1838void scic_sds_controller_power_control_timer_stop(
1839   SCIC_SDS_CONTROLLER_T *this_controller
1840)
1841{
1842   if (this_controller->power_control.timer_started)
1843   {
1844      scic_cb_timer_stop(
1845         this_controller, this_controller->power_control.timer
1846      );
1847
1848      this_controller->power_control.timer_started = FALSE;
1849   }
1850}
1851
1852/**
1853 * This method stops and starts the power control timer for this controller object.
1854 *
1855 * @param this_controller
1856 */
1857static
1858void scic_sds_controller_power_control_timer_restart(
1859   SCIC_SDS_CONTROLLER_T *this_controller
1860)
1861{
1862   scic_sds_controller_power_control_timer_stop(this_controller);
1863   scic_sds_controller_power_control_timer_start(this_controller);
1864}
1865
1866
1867/**
1868 * @brief
1869 *
1870 * @param[in] controller
1871 */
1872void scic_sds_controller_power_control_timer_handler(
1873   void *controller
1874)
1875{
1876   SCIC_SDS_CONTROLLER_T *this_controller;
1877   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
1878
1879   this_controller->power_control.remote_devices_granted_power = 0;
1880
1881   if (this_controller->power_control.phys_waiting == 0)
1882   {
1883      this_controller->power_control.timer_started = FALSE;
1884   }
1885   else
1886   {
1887      SCIC_SDS_PHY_T *the_phy = NULL;
1888      U8 i;
1889
1890      for (i=0;
1891              (i < SCI_MAX_PHYS)
1892           && (this_controller->power_control.phys_waiting != 0);
1893           i++)
1894      {
1895         if (this_controller->power_control.requesters[i] != NULL)
1896         {
1897            if ( this_controller->power_control.remote_devices_granted_power <
1898                 this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up
1899               )
1900            {
1901               the_phy = this_controller->power_control.requesters[i];
1902               this_controller->power_control.requesters[i] = NULL;
1903               this_controller->power_control.phys_waiting--;
1904               this_controller->power_control.remote_devices_granted_power ++;
1905               scic_sds_phy_consume_power_handler(the_phy);
1906
1907               if (the_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS)
1908               {
1909                  U8 j;
1910                  SCIC_SDS_PHY_T * current_requester_phy;
1911
1912                  for (j = 0; j < SCI_MAX_PHYS; j++)
1913                  {
1914                     current_requester_phy = this_controller->power_control.requesters[j];
1915
1916                     //Search the power_control queue to see if there are other phys attached to
1917                     //the same remote device. If found, take all of them out of await_sas_power state.
1918                     if (current_requester_phy != NULL &&
1919                         current_requester_phy != the_phy &&
1920                         current_requester_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high
1921                            == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high &&
1922                         current_requester_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low
1923                            == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low)
1924                     {
1925                        this_controller->power_control.requesters[j] = NULL;
1926                        this_controller->power_control.phys_waiting--;
1927                        scic_sds_phy_consume_power_handler(current_requester_phy);
1928                     }
1929                  }
1930               }
1931            }
1932            else
1933            {
1934               break;
1935            }
1936         }
1937      }
1938
1939      // It doesn't matter if the power list is empty, we need to start the
1940      // timer in case another phy becomes ready.
1941      scic_sds_controller_power_control_timer_start(this_controller);
1942   }
1943}
1944
1945/**
1946 * @brief This method inserts the phy in the stagger spinup control queue.
1947 *
1948 * @param[in] this_controller
1949 * @param[in] the_phy
1950 */
1951void scic_sds_controller_power_control_queue_insert(
1952   SCIC_SDS_CONTROLLER_T *this_controller,
1953   SCIC_SDS_PHY_T        *the_phy
1954)
1955{
1956   ASSERT (the_phy != NULL);
1957
1958   if( this_controller->power_control.remote_devices_granted_power <
1959       this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up
1960     )
1961   {
1962      this_controller->power_control.remote_devices_granted_power ++;
1963      scic_sds_phy_consume_power_handler(the_phy);
1964
1965      //stop and start the power_control timer. When the timer fires, the
1966      //no_of_devices_granted_power will be set to 0
1967      scic_sds_controller_power_control_timer_restart (this_controller);
1968   }
1969   else
1970   {
1971      //there are phys, attached to the same sas address as this phy, are already
1972      //in READY state, this phy don't need wait.
1973      U8 i;
1974      SCIC_SDS_PHY_T * current_phy;
1975      for(i = 0; i < SCI_MAX_PHYS; i++)
1976      {
1977         current_phy = &this_controller->phy_table[i];
1978
1979         if (current_phy->parent.state_machine.current_state_id == SCI_BASE_PHY_STATE_READY &&
1980             current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS &&
1981             current_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high
1982                == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.high &&
1983             current_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low
1984                == the_phy->phy_type.sas.identify_address_frame_buffer.sas_address.low)
1985         {
1986            scic_sds_phy_consume_power_handler(the_phy);
1987            break;
1988         }
1989      }
1990
1991      if (i == SCI_MAX_PHYS)
1992      {
1993         //Add the phy in the waiting list
1994         this_controller->power_control.requesters[the_phy->phy_index] = the_phy;
1995         this_controller->power_control.phys_waiting++;
1996      }
1997   }
1998}
1999
2000/**
2001 * @brief This method removes the phy from the stagger spinup control
2002 *        queue.
2003 *
2004 * @param[in] this_controller
2005 * @param[in] the_phy
2006 */
2007void scic_sds_controller_power_control_queue_remove(
2008   SCIC_SDS_CONTROLLER_T *this_controller,
2009   SCIC_SDS_PHY_T        *the_phy
2010)
2011{
2012   ASSERT (the_phy != NULL);
2013
2014   if (this_controller->power_control.requesters[the_phy->phy_index] != NULL)
2015   {
2016      this_controller->power_control.phys_waiting--;
2017   }
2018
2019   this_controller->power_control.requesters[the_phy->phy_index] = NULL;
2020}
2021
2022//****************************************************************************-
2023//* SCIC SDS Controller Completion Routines
2024//****************************************************************************-
2025
2026/**
2027 * @brief This method returns a TRUE value if the completion queue has
2028 *        entries that can be processed
2029 *
2030 * @param[in] this_controller
2031 *
2032 * @return BOOL
2033 * @retval TRUE if the completion queue has entries to process
2034 *         FALSE if the completion queue has no entries to process
2035 */
2036static
2037BOOL scic_sds_controller_completion_queue_has_entries(
2038   SCIC_SDS_CONTROLLER_T *this_controller
2039)
2040{
2041   U32 get_value = this_controller->completion_queue_get;
2042   U32 get_index = get_value & SMU_COMPLETION_QUEUE_GET_POINTER_MASK;
2043   if (
2044           NORMALIZE_GET_POINTER_CYCLE_BIT(get_value)
2045        == COMPLETION_QUEUE_CYCLE_BIT(this_controller->completion_queue[get_index])
2046      )
2047   {
2048      return TRUE;
2049   }
2050
2051   return FALSE;
2052}
2053
2054// ---------------------------------------------------------------------------
2055
2056/**
2057 * @brief This method processes a task completion notification.  This is
2058 *        called from within the controller completion handler.
2059 *
2060 * @param[in] this_controller
2061 * @param[in] completion_entry
2062 *
2063 * @return none
2064 */
2065static
2066void scic_sds_controller_task_completion(
2067   SCIC_SDS_CONTROLLER_T *this_controller,
2068   U32                   completion_entry
2069)
2070{
2071   U32 index;
2072   SCIC_SDS_REQUEST_T *io_request;
2073
2074   index = SCU_GET_COMPLETION_INDEX(completion_entry);
2075   io_request = this_controller->io_request_table[index];
2076
2077   // Make sure that we really want to process this IO request
2078   if (
2079           (io_request != SCI_INVALID_HANDLE)
2080        && (io_request->io_tag != SCI_CONTROLLER_INVALID_IO_TAG)
2081        && (
2082                scic_sds_io_tag_get_sequence(io_request->io_tag)
2083             == this_controller->io_request_sequence[index]
2084           )
2085      )
2086   {
2087      // Yep this is a valid io request pass it along to the io request handler
2088      scic_sds_io_request_tc_completion(io_request, completion_entry);
2089   }
2090}
2091
2092/**
2093 * @brief This method processes an SDMA completion event.  This is called
2094 *        from within the controller completion handler.
2095 *
2096 * @param[in] this_controller
2097 * @param[in] completion_entry
2098 *
2099 * @return none
2100 */
2101static
2102void scic_sds_controller_sdma_completion(
2103   SCIC_SDS_CONTROLLER_T *this_controller,
2104   U32                   completion_entry
2105)
2106{
2107   U32 index;
2108   SCIC_SDS_REQUEST_T       *io_request;
2109   SCIC_SDS_REMOTE_DEVICE_T *device;
2110
2111   index = SCU_GET_COMPLETION_INDEX(completion_entry);
2112
2113   switch (scu_get_command_request_type(completion_entry))
2114   {
2115   case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC:
2116   case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_TC:
2117      io_request = this_controller->io_request_table[index];
2118      SCIC_LOG_ERROR((
2119         sci_base_object_get_logger(this_controller),
2120           SCIC_LOG_OBJECT_CONTROLLER
2121         | SCIC_LOG_OBJECT_SMP_IO_REQUEST
2122         | SCIC_LOG_OBJECT_SSP_IO_REQUEST
2123         | SCIC_LOG_OBJECT_STP_IO_REQUEST,
2124         "SCIC SDS Completion type SDMA %x for io request %x\n",
2125         completion_entry,
2126         io_request
2127      ));
2128      /// @todo For a post TC operation we need to fail the IO request
2129      break;
2130
2131   case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC:
2132   case SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC:
2133   case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC:
2134      device = this_controller->device_table[index];
2135      SCIC_LOG_ERROR((
2136         sci_base_object_get_logger(this_controller),
2137           SCIC_LOG_OBJECT_CONTROLLER
2138         | SCIC_LOG_OBJECT_SSP_REMOTE_TARGET
2139         | SCIC_LOG_OBJECT_SMP_REMOTE_TARGET
2140         | SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
2141         "SCIC SDS Completion type SDMA %x for remote device %x\n",
2142         completion_entry,
2143         device
2144      ));
2145      /// @todo For a port RNC operation we need to fail the device
2146      break;
2147
2148   default:
2149      SCIC_LOG_ERROR((
2150         sci_base_object_get_logger(this_controller),
2151         SCIC_LOG_OBJECT_CONTROLLER,
2152         "SCIC SDS Completion unknown SDMA completion type %x\n",
2153         completion_entry
2154      ));
2155      break;
2156   }
2157
2158   /// This is an unexpected completion type and is un-recoverable
2159   /// Transition to the failed state and wait for a controller reset
2160   sci_base_state_machine_change_state(
2161      scic_sds_controller_get_base_state_machine(this_controller),
2162      SCI_BASE_CONTROLLER_STATE_FAILED
2163   );
2164}
2165
2166/**
2167 * This method processes an unsolicited frame message.  This is called from
2168 * within the controller completion handler.
2169 *
2170 * @param[in] this_controller
2171 * @param[in] completion_entry
2172 *
2173 * @return none
2174 */
2175static
2176void scic_sds_controller_unsolicited_frame(
2177   SCIC_SDS_CONTROLLER_T *this_controller,
2178   U32                   completion_entry
2179)
2180{
2181   U32 index;
2182   U32 frame_index;
2183
2184   SCU_UNSOLICITED_FRAME_HEADER_T * frame_header;
2185   SCIC_SDS_PHY_T                 * phy;
2186   SCIC_SDS_REMOTE_DEVICE_T       * device;
2187
2188   SCI_STATUS result = SCI_FAILURE;
2189
2190   frame_index = SCU_GET_FRAME_INDEX(completion_entry);
2191
2192   frame_header
2193      = this_controller->uf_control.buffers.array[frame_index].header;
2194   this_controller->uf_control.buffers.array[frame_index].state
2195      = UNSOLICITED_FRAME_IN_USE;
2196
2197   if (SCU_GET_FRAME_ERROR(completion_entry))
2198   {
2199      /// @todo If the IAF frame or SIGNATURE FIS frame has an error will
2200      ///       this cause a problem? We expect the phy initialization will
2201      ///       fail if there is an error in the frame.
2202      scic_sds_controller_release_frame(this_controller, frame_index);
2203      return;
2204   }
2205
2206   if (frame_header->is_address_frame)
2207   {
2208      index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry);
2209      phy = &this_controller->phy_table[index];
2210      if (phy != NULL)
2211      {
2212         result = scic_sds_phy_frame_handler(phy, frame_index);
2213      }
2214   }
2215   else
2216   {
2217
2218      index = SCU_GET_COMPLETION_INDEX(completion_entry);
2219
2220      if (index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
2221      {
2222         // This is a signature fis or a frame from a direct attached SATA
2223         // device that has not yet been created.  In either case forwared
2224         // the frame to the PE and let it take care of the frame data.
2225         index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry);
2226         phy = &this_controller->phy_table[index];
2227         result = scic_sds_phy_frame_handler(phy, frame_index);
2228      }
2229      else
2230      {
2231         if (index < this_controller->remote_node_entries)
2232            device = this_controller->device_table[index];
2233         else
2234            device = NULL;
2235
2236         if (device != NULL)
2237            result = scic_sds_remote_device_frame_handler(device, frame_index);
2238         else
2239            scic_sds_controller_release_frame(this_controller, frame_index);
2240      }
2241   }
2242
2243   if (result != SCI_SUCCESS)
2244   {
2245      /// @todo Is there any reason to report some additional error message
2246      ///       when we get this failure notifiction?
2247   }
2248}
2249
2250/**
2251 * @brief This method processes an event completion entry.  This is called
2252 *        from within the controller completion handler.
2253 *
2254 * @param[in] this_controller
2255 * @param[in] completion_entry
2256 *
2257 * @return none
2258 */
2259static
2260void scic_sds_controller_event_completion(
2261   SCIC_SDS_CONTROLLER_T *this_controller,
2262   U32                   completion_entry
2263)
2264{
2265   U32 index;
2266   SCIC_SDS_REQUEST_T       *io_request;
2267   SCIC_SDS_REMOTE_DEVICE_T *device;
2268   SCIC_SDS_PHY_T           *phy;
2269
2270   index = SCU_GET_COMPLETION_INDEX(completion_entry);
2271
2272   switch (scu_get_event_type(completion_entry))
2273   {
2274   case SCU_EVENT_TYPE_SMU_COMMAND_ERROR:
2275      /// @todo The driver did something wrong and we need to fix the condtion.
2276      SCIC_LOG_ERROR((
2277         sci_base_object_get_logger(this_controller),
2278         SCIC_LOG_OBJECT_CONTROLLER,
2279         "SCIC Controller 0x%x received SMU command error 0x%x\n",
2280         this_controller, completion_entry
2281      ));
2282      break;
2283
2284   case SCU_EVENT_TYPE_FATAL_MEMORY_ERROR:
2285       // report fatal memory error
2286       this_controller->parent.error = SCI_CONTROLLER_FATAL_MEMORY_ERROR;
2287
2288       sci_base_state_machine_change_state(
2289          scic_sds_controller_get_base_state_machine(this_controller),
2290          SCI_BASE_CONTROLLER_STATE_FAILED
2291       );
2292
2293       //continue as in following events
2294   case SCU_EVENT_TYPE_SMU_PCQ_ERROR:
2295   case SCU_EVENT_TYPE_SMU_ERROR:
2296      SCIC_LOG_ERROR((
2297         sci_base_object_get_logger(this_controller),
2298         SCIC_LOG_OBJECT_CONTROLLER,
2299         "SCIC Controller 0x%x received fatal controller event 0x%x\n",
2300         this_controller, completion_entry
2301      ));
2302      break;
2303
2304   case SCU_EVENT_TYPE_TRANSPORT_ERROR:
2305      io_request = this_controller->io_request_table[index];
2306      scic_sds_io_request_event_handler(io_request, completion_entry);
2307      break;
2308
2309   case SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT:
2310      switch (scu_get_event_specifier(completion_entry))
2311      {
2312      case SCU_EVENT_SPECIFIC_SMP_RESPONSE_NO_PE:
2313      case SCU_EVENT_SPECIFIC_TASK_TIMEOUT:
2314         io_request = this_controller->io_request_table[index];
2315         if (io_request != SCI_INVALID_HANDLE)
2316         {
2317            scic_sds_io_request_event_handler(io_request, completion_entry);
2318         }
2319         else
2320         {
2321            SCIC_LOG_WARNING((
2322               sci_base_object_get_logger(this_controller),
2323               SCIC_LOG_OBJECT_CONTROLLER |
2324               SCIC_LOG_OBJECT_SMP_IO_REQUEST |
2325               SCIC_LOG_OBJECT_SSP_IO_REQUEST |
2326               SCIC_LOG_OBJECT_STP_IO_REQUEST,
2327               "SCIC Controller 0x%x received event 0x%x for io request object that doesnt exist.\n",
2328               this_controller, completion_entry
2329            ));
2330         }
2331         break;
2332
2333      case SCU_EVENT_SPECIFIC_IT_NEXUS_TIMEOUT:
2334         device = this_controller->device_table[index];
2335         if (device != SCI_INVALID_HANDLE)
2336         {
2337            scic_sds_remote_device_event_handler(device, completion_entry);
2338         }
2339         else
2340         {
2341            SCIC_LOG_WARNING((
2342               sci_base_object_get_logger(this_controller),
2343               SCIC_LOG_OBJECT_CONTROLLER |
2344               SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
2345               SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
2346               SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
2347               "SCIC Controller 0x%x received event 0x%x for remote device object that doesnt exist.\n",
2348               this_controller, completion_entry
2349            ));
2350         }
2351         break;
2352      }
2353      break;
2354
2355   case SCU_EVENT_TYPE_BROADCAST_CHANGE:
2356      // direct the broadcast change event to the phy first and then let
2357      // the phy redirect the broadcast change to the port object
2358   case SCU_EVENT_TYPE_ERR_CNT_EVENT:
2359      // direct error counter event to the phy object since that is where
2360      // we get the event notification.  This is a type 4 event.
2361   case SCU_EVENT_TYPE_OSSP_EVENT:
2362      index = SCU_GET_PROTOCOL_ENGINE_INDEX(completion_entry);
2363      phy = &this_controller->phy_table[index];
2364      scic_sds_phy_event_handler(phy, completion_entry);
2365      break;
2366
2367   case SCU_EVENT_TYPE_RNC_SUSPEND_TX:
2368   case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX:
2369   case SCU_EVENT_TYPE_RNC_OPS_MISC:
2370      if (index < this_controller->remote_node_entries)
2371      {
2372         device = this_controller->device_table[index];
2373
2374         if (device != NULL)
2375         {
2376            scic_sds_remote_device_event_handler(device, completion_entry);
2377         }
2378      }
2379      else
2380      {
2381         SCIC_LOG_ERROR((
2382            sci_base_object_get_logger(this_controller),
2383            SCIC_LOG_OBJECT_CONTROLLER |
2384            SCIC_LOG_OBJECT_SMP_REMOTE_TARGET |
2385            SCIC_LOG_OBJECT_SSP_REMOTE_TARGET |
2386            SCIC_LOG_OBJECT_STP_REMOTE_TARGET,
2387            "SCIC Controller 0x%x received event 0x%x for remote device object 0x%0x that doesnt exist.\n",
2388            this_controller, completion_entry, index
2389         ));
2390      }
2391      break;
2392
2393   default:
2394      SCIC_LOG_WARNING((
2395         sci_base_object_get_logger(this_controller),
2396         SCIC_LOG_OBJECT_CONTROLLER,
2397         "SCIC Controller received unknown event code %x\n",
2398         completion_entry
2399      ));
2400      break;
2401   }
2402}
2403
2404/**
2405 * @brief This method is a private routine for processing the completion
2406 *        queue entries.
2407 *
2408 * @param[in] this_controller
2409 *
2410 * @return none
2411 */
2412static
2413void scic_sds_controller_process_completions(
2414   SCIC_SDS_CONTROLLER_T *this_controller
2415)
2416{
2417   U32 completion_count = 0;
2418   U32 completion_entry;
2419   U32 get_index;
2420   U32 get_cycle;
2421   U32 event_index;
2422   U32 event_cycle;
2423
2424   SCIC_LOG_TRACE((
2425      sci_base_object_get_logger(this_controller),
2426      SCIC_LOG_OBJECT_CONTROLLER,
2427      "scic_sds_controller_process_completions(0x%x) enter\n",
2428      this_controller
2429   ));
2430
2431   SCIC_LOG_TRACE((
2432      sci_base_object_get_logger(this_controller),
2433      SCIC_LOG_OBJECT_COMPLETION_QUEUE,
2434      "completion queue beginning get : 0x%08x\n",
2435      this_controller->completion_queue_get
2436   ));
2437
2438   // Get the component parts of the completion queue
2439   get_index = NORMALIZE_GET_POINTER(this_controller->completion_queue_get);
2440   get_cycle = SMU_CQGR_CYCLE_BIT & this_controller->completion_queue_get;
2441
2442   event_index = NORMALIZE_EVENT_POINTER(this_controller->completion_queue_get);
2443   event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & this_controller->completion_queue_get;
2444
2445   while (
2446               NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle)
2447            == COMPLETION_QUEUE_CYCLE_BIT(this_controller->completion_queue[get_index])
2448         )
2449   {
2450      completion_count++;
2451
2452      completion_entry = this_controller->completion_queue[get_index];
2453      INCREMENT_COMPLETION_QUEUE_GET(this_controller, get_index, get_cycle);
2454
2455      SCIC_LOG_TRACE((
2456         sci_base_object_get_logger(this_controller),
2457         SCIC_LOG_OBJECT_COMPLETION_QUEUE,
2458         "completion queue entry : 0x%08x\n",
2459         completion_entry
2460      ));
2461
2462      switch (SCU_GET_COMPLETION_TYPE(completion_entry))
2463      {
2464      case SCU_COMPLETION_TYPE_TASK:
2465         scic_sds_controller_task_completion(this_controller, completion_entry);
2466         break;
2467
2468      case SCU_COMPLETION_TYPE_SDMA:
2469         scic_sds_controller_sdma_completion(this_controller, completion_entry);
2470         break;
2471
2472      case SCU_COMPLETION_TYPE_UFI:
2473         scic_sds_controller_unsolicited_frame(this_controller, completion_entry);
2474         break;
2475
2476      case SCU_COMPLETION_TYPE_EVENT:
2477         scic_sds_controller_event_completion(this_controller, completion_entry);
2478         break;
2479
2480      case SCU_COMPLETION_TYPE_NOTIFY:
2481         // Presently we do the same thing with a notify event that we do with the
2482         // other event codes.
2483         INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
2484         scic_sds_controller_event_completion(this_controller, completion_entry);
2485         break;
2486
2487      default:
2488         SCIC_LOG_WARNING((
2489            sci_base_object_get_logger(this_controller),
2490            SCIC_LOG_OBJECT_CONTROLLER,
2491            "SCIC Controller received unknown completion type %x\n",
2492            completion_entry
2493         ));
2494         break;
2495      }
2496   }
2497
2498   // Update the get register if we completed one or more entries
2499   if (completion_count > 0)
2500   {
2501      this_controller->completion_queue_get =
2502           SMU_CQGR_GEN_BIT(ENABLE)
2503         | SMU_CQGR_GEN_BIT(EVENT_ENABLE)
2504         | event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index)
2505         | get_cycle   | SMU_CQGR_GEN_VAL(POINTER, get_index)  ;
2506
2507      SMU_CQGR_WRITE(this_controller, this_controller->completion_queue_get);
2508   }
2509
2510   SCIC_LOG_TRACE((
2511      sci_base_object_get_logger(this_controller),
2512      SCIC_LOG_OBJECT_COMPLETION_QUEUE,
2513      "completion queue ending get : 0x%08x\n",
2514      this_controller->completion_queue_get
2515   ));
2516
2517}
2518
2519/**
2520 * @brief This method is a private routine for processing the completion
2521 *        queue entries.
2522 *
2523 * @param[in] this_controller
2524 *
2525 * @return none
2526 */
2527static
2528void scic_sds_controller_transitioned_process_completions(
2529   SCIC_SDS_CONTROLLER_T * this_controller
2530)
2531{
2532   U32 completion_count = 0;
2533   U32 completion_entry;
2534   U32 get_index;
2535   U32 get_cycle;
2536   U32 event_index;
2537   U32 event_cycle;
2538
2539   SCIC_LOG_TRACE((
2540      sci_base_object_get_logger(this_controller),
2541      SCIC_LOG_OBJECT_CONTROLLER,
2542      "scic_sds_controller_transitioned_process_completions(0x%x) enter\n",
2543      this_controller
2544   ));
2545
2546   SCIC_LOG_TRACE((
2547      sci_base_object_get_logger(this_controller),
2548      SCIC_LOG_OBJECT_COMPLETION_QUEUE,
2549      "completion queue beginning get : 0x%08x\n",
2550      this_controller->completion_queue_get
2551   ));
2552
2553   // Get the component parts of the completion queue
2554   get_index = NORMALIZE_GET_POINTER(this_controller->completion_queue_get);
2555   get_cycle = SMU_CQGR_CYCLE_BIT & this_controller->completion_queue_get;
2556
2557   event_index = NORMALIZE_EVENT_POINTER(this_controller->completion_queue_get);
2558   event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & this_controller->completion_queue_get;
2559
2560   while (
2561               NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle)
2562            == COMPLETION_QUEUE_CYCLE_BIT(
2563                  this_controller->completion_queue[get_index])
2564         )
2565   {
2566      completion_count++;
2567
2568      completion_entry = this_controller->completion_queue[get_index];
2569      INCREMENT_COMPLETION_QUEUE_GET(this_controller, get_index, get_cycle);
2570
2571      SCIC_LOG_TRACE((
2572         sci_base_object_get_logger(this_controller),
2573         SCIC_LOG_OBJECT_COMPLETION_QUEUE,
2574         "completion queue entry : 0x%08x\n",
2575         completion_entry
2576      ));
2577
2578      switch (SCU_GET_COMPLETION_TYPE(completion_entry))
2579      {
2580      case SCU_COMPLETION_TYPE_TASK:
2581         scic_sds_controller_task_completion(this_controller, completion_entry);
2582      break;
2583
2584      case SCU_COMPLETION_TYPE_NOTIFY:
2585         INCREMENT_EVENT_QUEUE_GET(this_controller, event_index, event_cycle);
2586         // Fall-through
2587
2588      case SCU_COMPLETION_TYPE_EVENT:
2589      case SCU_COMPLETION_TYPE_SDMA:
2590      case SCU_COMPLETION_TYPE_UFI:
2591      default:
2592         SCIC_LOG_WARNING((
2593            sci_base_object_get_logger(this_controller),
2594            SCIC_LOG_OBJECT_CONTROLLER,
2595            "SCIC Controller ignoring completion type %x\n",
2596            completion_entry
2597         ));
2598      break;
2599      }
2600   }
2601
2602   // Update the get register if we completed one or more entries
2603   if (completion_count > 0)
2604   {
2605      this_controller->completion_queue_get =
2606           SMU_CQGR_GEN_BIT(ENABLE)
2607         | SMU_CQGR_GEN_BIT(EVENT_ENABLE)
2608         | event_cycle | SMU_CQGR_GEN_VAL(EVENT_POINTER, event_index)
2609         | get_cycle   | SMU_CQGR_GEN_VAL(POINTER, get_index)  ;
2610
2611      SMU_CQGR_WRITE(this_controller, this_controller->completion_queue_get);
2612   }
2613
2614   SCIC_LOG_TRACE((
2615      sci_base_object_get_logger(this_controller),
2616      SCIC_LOG_OBJECT_COMPLETION_QUEUE,
2617      "completion queue ending get : 0x%08x\n",
2618      this_controller->completion_queue_get
2619   ));
2620}
2621
2622//****************************************************************************-
2623//* SCIC SDS Controller Interrupt and Completion functions
2624//****************************************************************************-
2625
2626/**
2627 * @brief This method provides standard (common) processing of interrupts
2628 *        for polling and legacy based interrupts.
2629 *
2630 * @param[in] controller
2631 * @param[in] interrupt_status
2632 *
2633 * @return This method returns a boolean (BOOL) indication as to
2634 *         whether an completions are pending to be processed.
2635 * @retval TRUE if an interrupt is to be processed
2636 * @retval FALSE if no interrupt was pending
2637 */
2638static
2639BOOL scic_sds_controller_standard_interrupt_handler(
2640   SCIC_SDS_CONTROLLER_T *this_controller,
2641   U32                    interrupt_status
2642)
2643{
2644   BOOL  is_completion_needed = FALSE;
2645
2646   SCIC_LOG_TRACE((
2647      sci_base_object_get_logger(this_controller),
2648      SCIC_LOG_OBJECT_CONTROLLER,
2649      "scic_sds_controller_standard_interrupt_handler(0x%d,0x%d) enter\n",
2650      this_controller, interrupt_status
2651   ));
2652
2653   if (
2654         (interrupt_status & SMU_ISR_QUEUE_ERROR)
2655      || (
2656            (interrupt_status & SMU_ISR_QUEUE_SUSPEND)
2657         && (!scic_sds_controller_completion_queue_has_entries(this_controller))
2658         )
2659      )
2660   {
2661      // We have a fatal error on the read of the completion queue bar
2662      // OR
2663      // We have a fatal error there is nothing in the completion queue
2664      // but we have a report from the hardware that the queue is full
2665      /// @todo how do we request the a controller reset
2666      is_completion_needed = TRUE;
2667      this_controller->encountered_fatal_error = TRUE;
2668   }
2669
2670   if (scic_sds_controller_completion_queue_has_entries(this_controller))
2671   {
2672      is_completion_needed = TRUE;
2673   }
2674
2675   return is_completion_needed;
2676}
2677
2678/**
2679 * @brief This is the method provided to handle polling for interrupts
2680 *        for the controller object.
2681 *
2682 * @param[in] controller
2683 *
2684 * @return BOOL
2685 * @retval TRUE if an interrupt is to be processed
2686 * @retval FALSE if no interrupt was pending
2687 */
2688static
2689BOOL scic_sds_controller_polling_interrupt_handler(
2690   SCI_CONTROLLER_HANDLE_T controller
2691)
2692{
2693   U32                    interrupt_status;
2694   SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
2695
2696   SCIC_LOG_TRACE((
2697      sci_base_object_get_logger(controller),
2698      SCIC_LOG_OBJECT_CONTROLLER,
2699      "scic_sds_controller_polling_interrupt_handler(0x%d) enter\n",
2700      controller
2701   ));
2702
2703   /*
2704    * In INTERRUPT_POLLING_MODE we exit the interrupt handler if the hardware
2705    * indicates nothing is pending. Since we are not being called from a real
2706    * interrupt, we don't want to confuse the hardware by servicing the
2707    * completion queue before the hardware indicates it is ready. We'll
2708    * simply wait for another polling interval and check again.
2709    */
2710   interrupt_status = SMU_ISR_READ(this_controller);
2711   if ((interrupt_status &
2712         (SMU_ISR_COMPLETION |
2713          SMU_ISR_QUEUE_ERROR |
2714          SMU_ISR_QUEUE_SUSPEND)) == 0)
2715   {
2716      return FALSE;
2717   }
2718
2719   return scic_sds_controller_standard_interrupt_handler(
2720             controller, interrupt_status
2721          );
2722}
2723
2724/**
2725 * @brief This is the method provided to handle completions when interrupt
2726 *        polling is in use.
2727 *
2728 * @param[in] controller
2729 *
2730 * @return none
2731 */
2732static
2733void scic_sds_controller_polling_completion_handler(
2734   SCI_CONTROLLER_HANDLE_T controller
2735)
2736{
2737   SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
2738
2739   SCIC_LOG_TRACE((
2740      sci_base_object_get_logger(controller),
2741      SCIC_LOG_OBJECT_CONTROLLER,
2742      "scic_sds_controller_polling_completion_handler(0x%d) enter\n",
2743      controller
2744   ));
2745
2746   if (this_controller->encountered_fatal_error == TRUE)
2747   {
2748      SCIC_LOG_ERROR((
2749         sci_base_object_get_logger(this_controller),
2750         SCIC_LOG_OBJECT_CONTROLLER,
2751         "SCIC Controller has encountered a fatal error.\n"
2752      ));
2753
2754      sci_base_state_machine_change_state(
2755         scic_sds_controller_get_base_state_machine(this_controller),
2756         SCI_BASE_CONTROLLER_STATE_FAILED
2757      );
2758   }
2759   else if (scic_sds_controller_completion_queue_has_entries(this_controller))
2760   {
2761      if (this_controller->restrict_completions == FALSE)
2762         scic_sds_controller_process_completions(this_controller);
2763      else
2764         scic_sds_controller_transitioned_process_completions(this_controller);
2765   }
2766
2767   /*
2768    * The interrupt handler does not adjust the CQ's
2769    * get pointer.  So, SCU's INTx pin stays asserted during the
2770    * interrupt handler even though it tries to clear the interrupt
2771    * source.  Therefore, the completion handler must ensure that the
2772    * interrupt source is cleared.  Otherwise, we get a spurious
2773    * interrupt for which the interrupt handler will not issue a
2774    * corresponding completion event. Also, we unmask interrupts.
2775    */
2776   SMU_ISR_WRITE(
2777      this_controller,
2778      (U32)(SMU_ISR_COMPLETION | SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)
2779   );
2780}
2781
2782#if !defined(DISABLE_INTERRUPTS)
2783/**
2784 * @brief This is the method provided to handle legacy interrupts for the
2785 *        controller object.
2786 *
2787 * @param[in] controller
2788 *
2789 * @return BOOL
2790 * @retval TRUE if an interrupt is processed
2791 *         FALSE if no interrupt was processed
2792 */
2793static
2794BOOL scic_sds_controller_legacy_interrupt_handler(
2795   SCI_CONTROLLER_HANDLE_T controller
2796)
2797{
2798   U32                    interrupt_status;
2799   BOOL                   is_completion_needed;
2800   SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
2801
2802   interrupt_status     = SMU_ISR_READ(this_controller);
2803   is_completion_needed = scic_sds_controller_standard_interrupt_handler(
2804                             this_controller, interrupt_status
2805                          );
2806
2807   return is_completion_needed;
2808}
2809
2810
2811/**
2812 * @brief This is the method provided to handle legacy completions it is
2813 *        expected that the SCI User will call this completion handler
2814 *        anytime the interrupt handler reports that it has handled an
2815 *        interrupt.
2816 *
2817 * @param[in] controller
2818 *
2819 * @return none
2820 */
2821static
2822void scic_sds_controller_legacy_completion_handler(
2823   SCI_CONTROLLER_HANDLE_T controller
2824)
2825{
2826   SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
2827
2828   SCIC_LOG_TRACE((
2829      sci_base_object_get_logger(controller),
2830      SCIC_LOG_OBJECT_CONTROLLER,
2831      "scic_sds_controller_legacy_completion_handler(0x%d) enter\n",
2832      controller
2833   ));
2834
2835   scic_sds_controller_polling_completion_handler(controller);
2836
2837   SMU_IMR_WRITE(this_controller, 0x00000000);
2838
2839#ifdef IMR_READ_FENCE
2840   {
2841      volatile U32 int_mask_value = 0;
2842      ULONG count = 0;
2843
2844      /*
2845       * Temporary code since we have seen with legacy interrupts
2846       * that interrupts are still masked after clearing the mask
2847       * above. This may be an Arlington problem or it may be an
2848       * old driver problem.  Presently this code is turned off
2849       * since we have not seen this problem recently.
2850       */
2851      do
2852      {
2853         int_mask_value = SMU_IMR_READ(this_controler);
2854
2855         if (count++ > 10)
2856         {
2857            #ifdef ALLOW_ENTER_DEBUGGER
2858            __debugbreak();
2859            #endif
2860            break;
2861         }
2862      } while (int_mask_value != 0);
2863   }
2864#endif
2865}
2866
2867/**
2868 * @brief This is the method provided to handle an MSIX interrupt message
2869 *        when there is just a single MSIX message being provided by the
2870 *        hardware.  This mode of operation is single vector mode.
2871 *
2872 * @param[in] controller
2873 *
2874 * @return BOOL
2875 * @retval TRUE if an interrupt is processed
2876 *         FALSE if no interrupt was processed
2877 */
2878static
2879BOOL scic_sds_controller_single_vector_interrupt_handler(
2880   SCI_CONTROLLER_HANDLE_T controller
2881)
2882{
2883   U32 interrupt_status;
2884   SCIC_SDS_CONTROLLER_T *this_controller;
2885   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
2886
2887   // Mask the interrupts
2888   // There is a race in the hardware that could cause us not to be notified
2889   // of an interrupt completion if we do not take this step.  We will unmask
2890   // the interrupts in the completion routine.
2891   SMU_IMR_WRITE(this_controller, 0xFFFFFFFF);
2892
2893   interrupt_status = SMU_ISR_READ(this_controller);
2894   interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
2895
2896   if (
2897           (interrupt_status == 0)
2898        && scic_sds_controller_completion_queue_has_entries(this_controller)
2899      )
2900   {
2901      // There is at least one completion queue entry to process so we can
2902      // return a success and ignore for now the case of an error interrupt
2903      SMU_ISR_WRITE(this_controller, SMU_ISR_COMPLETION);
2904
2905      return TRUE;
2906   }
2907
2908
2909   if (interrupt_status != 0)
2910   {
2911      // There is an error interrupt pending so let it through and handle
2912      // in the callback
2913      return TRUE;
2914   }
2915
2916   // Clear any offending interrupts since we could not find any to handle
2917   // and unmask them all
2918   SMU_ISR_WRITE(this_controller, 0x00000000);
2919   SMU_IMR_WRITE(this_controller, 0x00000000);
2920
2921   return FALSE;
2922}
2923
2924/**
2925 * @brief This is the method provided to handle completions for a single
2926 *        MSIX message.
2927 *
2928 * @param[in] controller
2929 */
2930static
2931void scic_sds_controller_single_vector_completion_handler(
2932   SCI_CONTROLLER_HANDLE_T controller
2933)
2934{
2935   U32 interrupt_status;
2936   SCIC_SDS_CONTROLLER_T *this_controller;
2937   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
2938
2939   SCIC_LOG_TRACE((
2940      sci_base_object_get_logger(controller),
2941      SCIC_LOG_OBJECT_CONTROLLER,
2942      "scic_sds_controller_single_vector_completion_handler(0x%d) enter\n",
2943      controller
2944   ));
2945
2946   interrupt_status = SMU_ISR_READ(this_controller);
2947   interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
2948
2949   if (interrupt_status & SMU_ISR_QUEUE_ERROR)
2950   {
2951      SCIC_LOG_ERROR((
2952         sci_base_object_get_logger(this_controller),
2953         SCIC_LOG_OBJECT_CONTROLLER,
2954         "SCIC Controller has encountered a fatal error.\n"
2955      ));
2956
2957      // We have a fatal condition and must reset the controller
2958      // Leave the interrupt mask in place and get the controller reset
2959      sci_base_state_machine_change_state(
2960         scic_sds_controller_get_base_state_machine(this_controller),
2961         SCI_BASE_CONTROLLER_STATE_FAILED
2962      );
2963      return;
2964   }
2965
2966   if (
2967           (interrupt_status & SMU_ISR_QUEUE_SUSPEND)
2968        && !scic_sds_controller_completion_queue_has_entries(this_controller)
2969      )
2970   {
2971      SCIC_LOG_ERROR((
2972         sci_base_object_get_logger(this_controller),
2973         SCIC_LOG_OBJECT_CONTROLLER,
2974         "SCIC Controller has encountered a fatal error.\n"
2975      ));
2976
2977      // We have a fatal condtion and must reset the controller
2978      // Leave the interrupt mask in place and get the controller reset
2979      sci_base_state_machine_change_state(
2980         scic_sds_controller_get_base_state_machine(this_controller),
2981         SCI_BASE_CONTROLLER_STATE_FAILED
2982      );
2983      return;
2984   }
2985
2986   if (scic_sds_controller_completion_queue_has_entries(this_controller))
2987   {
2988      scic_sds_controller_process_completions(this_controller);
2989
2990      // We dont care which interrupt got us to processing the completion queu
2991      // so clear them both.
2992      SMU_ISR_WRITE(
2993         this_controller,
2994         (SMU_ISR_COMPLETION | SMU_ISR_QUEUE_SUSPEND)
2995      );
2996   }
2997
2998   SMU_IMR_WRITE(this_controller, 0x00000000);
2999}
3000
3001/**
3002 * @brief This is the method provided to handle a MSIX message for a normal
3003 *        completion.
3004 *
3005 * @param[in] controller
3006 *
3007 * @return BOOL
3008 * @retval TRUE if an interrupt is processed
3009 *         FALSE if no interrupt was processed
3010 */
3011static
3012BOOL scic_sds_controller_normal_vector_interrupt_handler(
3013   SCI_CONTROLLER_HANDLE_T controller
3014)
3015{
3016   SCIC_SDS_CONTROLLER_T *this_controller;
3017   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
3018
3019   if (scic_sds_controller_completion_queue_has_entries(this_controller))
3020   {
3021      return TRUE;
3022   }
3023   else
3024   {
3025      // we have a spurious interrupt it could be that we have already
3026      // emptied the completion queue from a previous interrupt
3027      SMU_ISR_WRITE(this_controller, SMU_ISR_COMPLETION);
3028
3029      // There is a race in the hardware that could cause us not to be notified
3030      // of an interrupt completion if we do not take this step.  We will mask
3031      // then unmask the interrupts so if there is another interrupt pending
3032      // the clearing of the interrupt source we get the next interrupt message.
3033      SMU_IMR_WRITE(this_controller, 0xFF000000);
3034      SMU_IMR_WRITE(this_controller, 0x00000000);
3035   }
3036
3037   return FALSE;
3038}
3039
3040/**
3041 * @brief This is the method provided to handle the completions for a
3042 *        normal MSIX message.
3043 *
3044 * @param[in] controller
3045 */
3046static
3047void scic_sds_controller_normal_vector_completion_handler(
3048   SCI_CONTROLLER_HANDLE_T controller
3049)
3050{
3051   SCIC_SDS_CONTROLLER_T *this_controller;
3052   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
3053
3054   SCIC_LOG_TRACE((
3055      sci_base_object_get_logger(controller),
3056      SCIC_LOG_OBJECT_CONTROLLER,
3057      "scic_sds_controller_normal_vector_completion_handler(0x%d) enter\n",
3058      controller
3059   ));
3060
3061   // Empty out the completion queue
3062   if (scic_sds_controller_completion_queue_has_entries(this_controller))
3063   {
3064      scic_sds_controller_process_completions(this_controller);
3065   }
3066
3067   // Clear the interrupt and enable all interrupts again
3068   SMU_ISR_WRITE(this_controller, SMU_ISR_COMPLETION);
3069   // Could we write the value of SMU_ISR_COMPLETION?
3070   SMU_IMR_WRITE(this_controller, 0xFF000000);
3071   SMU_IMR_WRITE(this_controller, 0x00000000);
3072}
3073
3074/**
3075 * @brief This is the method provided to handle the error MSIX message
3076 *        interrupt.  This is the normal operating mode for the hardware if
3077 *        MSIX is enabled.
3078 *
3079 * @param[in] controller
3080 *
3081 * @return BOOL
3082 * @retval TRUE if an interrupt is processed
3083 *         FALSE if no interrupt was processed
3084 */
3085static
3086BOOL scic_sds_controller_error_vector_interrupt_handler(
3087   SCI_CONTROLLER_HANDLE_T controller
3088)
3089{
3090   U32 interrupt_status;
3091   SCIC_SDS_CONTROLLER_T *this_controller;
3092   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
3093
3094
3095   interrupt_status = SMU_ISR_READ(this_controller);
3096   interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
3097
3098   if (interrupt_status != 0)
3099   {
3100      // There is an error interrupt pending so let it through and handle
3101      // in the callback
3102      return TRUE;
3103   }
3104
3105   // There is a race in the hardware that could cause us not to be notified
3106   // of an interrupt completion if we do not take this step.  We will mask
3107   // then unmask the error interrupts so if there was another interrupt
3108   // pending we will be notified.
3109   // Could we write the value of (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)?
3110   SMU_IMR_WRITE(this_controller, 0x000000FF);
3111   SMU_IMR_WRITE(this_controller, 0x00000000);
3112
3113   return FALSE;
3114}
3115
3116/**
3117 * @brief This is the method provided to handle the error completions when
3118 *        the hardware is using two MSIX messages.
3119 *
3120 * @param[in] controller
3121 */
3122static
3123void scic_sds_controller_error_vector_completion_handler(
3124   SCI_CONTROLLER_HANDLE_T controller
3125)
3126{
3127   U32 interrupt_status;
3128   SCIC_SDS_CONTROLLER_T *this_controller;
3129   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
3130
3131   SCIC_LOG_TRACE((
3132      sci_base_object_get_logger(controller),
3133      SCIC_LOG_OBJECT_CONTROLLER,
3134      "scic_sds_controller_error_vector_completion_handler(0x%d) enter\n",
3135      controller
3136   ));
3137
3138   interrupt_status = SMU_ISR_READ(this_controller);
3139
3140   if (
3141            (interrupt_status & SMU_ISR_QUEUE_SUSPEND)
3142         && scic_sds_controller_completion_queue_has_entries(this_controller)
3143      )
3144   {
3145      scic_sds_controller_process_completions(this_controller);
3146
3147      SMU_ISR_WRITE(this_controller, SMU_ISR_QUEUE_SUSPEND);
3148   }
3149   else
3150   {
3151      SCIC_LOG_ERROR((
3152         sci_base_object_get_logger(this_controller),
3153         SCIC_LOG_OBJECT_CONTROLLER,
3154         "SCIC Controller reports CRC error on completion ISR %x\n",
3155         interrupt_status
3156      ));
3157
3158      sci_base_state_machine_change_state(
3159         scic_sds_controller_get_base_state_machine(this_controller),
3160         SCI_BASE_CONTROLLER_STATE_FAILED
3161      );
3162
3163      return;
3164   }
3165
3166   // If we dont process any completions I am not sure that we want to do this.
3167   // We are in the middle of a hardware fault and should probably be reset.
3168   SMU_IMR_WRITE(this_controller, 0x00000000);
3169}
3170
3171#endif // !defined(DISABLE_INTERRUPTS)
3172
3173//****************************************************************************-
3174//* SCIC SDS Controller External Methods
3175//****************************************************************************-
3176
3177/**
3178 * @brief This method returns the sizeof the SCIC SDS Controller Object
3179 *
3180 * @return U32
3181 */
3182U32 scic_sds_controller_get_object_size(void)
3183{
3184   return sizeof(SCIC_SDS_CONTROLLER_T);
3185}
3186
3187/**
3188 * This method returns the minimum number of timers that are required by the
3189 * controller object.  This will include required timers for phys and ports.
3190 *
3191 * @return U32
3192 * @retval The minimum number of timers that are required to make this
3193 *         controller operational.
3194 */
3195U32 scic_sds_controller_get_min_timer_count(void)
3196{
3197   return   SCIC_SDS_CONTROLLER_MIN_TIMER_COUNT
3198          + scic_sds_port_get_min_timer_count()
3199          + scic_sds_phy_get_min_timer_count();
3200}
3201
3202/**
3203 * This method returns the maximum number of timers that are required by the
3204 * controller object.  This will include required timers for phys and ports.
3205 *
3206 * @return U32
3207 * @retval The maximum number of timers that will be used by the controller
3208 *         object
3209 */
3210U32 scic_sds_controller_get_max_timer_count(void)
3211{
3212   return   SCIC_SDS_CONTROLLER_MAX_TIMER_COUNT
3213          + scic_sds_port_get_max_timer_count()
3214          + scic_sds_phy_get_max_timer_count();
3215}
3216
3217/**
3218 * @brief
3219 *
3220 * @param[in] this_controller
3221 * @param[in] the_port
3222 * @param[in] the_phy
3223 *
3224 * @return none
3225 */
3226void scic_sds_controller_link_up(
3227   SCIC_SDS_CONTROLLER_T *this_controller,
3228   SCIC_SDS_PORT_T       *the_port,
3229   SCIC_SDS_PHY_T        *the_phy
3230)
3231{
3232   if (this_controller->state_handlers->link_up_handler != NULL)
3233   {
3234      this_controller->state_handlers->link_up_handler(
3235         this_controller, the_port, the_phy);
3236   }
3237   else
3238   {
3239      SCIC_LOG_INFO((
3240         sci_base_object_get_logger(this_controller),
3241         SCIC_LOG_OBJECT_CONTROLLER,
3242         "SCIC Controller linkup event from phy %d in unexpected state %d\n",
3243         the_phy->phy_index,
3244         sci_base_state_machine_get_state(
3245            scic_sds_controller_get_base_state_machine(this_controller))
3246      ));
3247   }
3248}
3249
3250/**
3251 * @brief
3252 *
3253 * @param[in] this_controller
3254 * @param[in] the_port
3255 * @param[in] the_phy
3256 */
3257void scic_sds_controller_link_down(
3258   SCIC_SDS_CONTROLLER_T *this_controller,
3259   SCIC_SDS_PORT_T       *the_port,
3260   SCIC_SDS_PHY_T        *the_phy
3261)
3262{
3263   if (this_controller->state_handlers->link_down_handler != NULL)
3264   {
3265      this_controller->state_handlers->link_down_handler(
3266         this_controller, the_port, the_phy);
3267   }
3268   else
3269   {
3270      SCIC_LOG_INFO((
3271         sci_base_object_get_logger(this_controller),
3272         SCIC_LOG_OBJECT_CONTROLLER,
3273         "SCIC Controller linkdown event from phy %d in unexpected state %d\n",
3274         the_phy->phy_index,
3275         sci_base_state_machine_get_state(
3276            scic_sds_controller_get_base_state_machine(this_controller))
3277      ));
3278   }
3279}
3280
3281/**
3282 * @brief This method is called by the remote device to inform the controller
3283 *        that this remote device has started.
3284 *
3285 * @param[in] this_controller
3286 * @param[in] the_device
3287 */
3288void scic_sds_controller_remote_device_started(
3289   SCIC_SDS_CONTROLLER_T    * this_controller,
3290   SCIC_SDS_REMOTE_DEVICE_T * the_device
3291)
3292{
3293   if (this_controller->state_handlers->remote_device_started_handler != NULL)
3294   {
3295      this_controller->state_handlers->remote_device_started_handler(
3296         this_controller, the_device
3297      );
3298   }
3299   else
3300   {
3301      SCIC_LOG_INFO((
3302         sci_base_object_get_logger(this_controller),
3303         SCIC_LOG_OBJECT_CONTROLLER,
3304         "SCIC Controller 0x%x remote device started event from device 0x%x in unexpected state %d\n",
3305         this_controller,
3306         the_device,
3307         sci_base_state_machine_get_state(
3308            scic_sds_controller_get_base_state_machine(this_controller))
3309      ));
3310   }
3311}
3312
3313/**
3314 * @brief This is a helper method to determine if any remote devices on this
3315 *        controller are still in the stopping state.
3316 *
3317 * @param[in] this_controller
3318 */
3319BOOL scic_sds_controller_has_remote_devices_stopping(
3320   SCIC_SDS_CONTROLLER_T * this_controller
3321)
3322{
3323   U32 index;
3324
3325   for (index = 0; index < this_controller->remote_node_entries; index++)
3326   {
3327      if (
3328            (this_controller->device_table[index] != NULL)
3329         && (
3330               this_controller->device_table[index]->parent.state_machine.current_state_id
3331            == SCI_BASE_REMOTE_DEVICE_STATE_STOPPING
3332            )
3333         )
3334      {
3335         return TRUE;
3336      }
3337   }
3338
3339   return FALSE;
3340}
3341
3342/**
3343 * @brief This method is called by the remote device to inform the controller
3344 *        object that the remote device has stopped.
3345 *
3346 * @param[in] this_controller
3347 * @param[in] the_device
3348 */
3349void scic_sds_controller_remote_device_stopped(
3350   SCIC_SDS_CONTROLLER_T    * this_controller,
3351   SCIC_SDS_REMOTE_DEVICE_T * the_device
3352)
3353{
3354   if (this_controller->state_handlers->remote_device_stopped_handler != NULL)
3355   {
3356      this_controller->state_handlers->remote_device_stopped_handler(
3357         this_controller, the_device
3358      );
3359   }
3360   else
3361   {
3362      SCIC_LOG_INFO((
3363         sci_base_object_get_logger(this_controller),
3364         SCIC_LOG_OBJECT_CONTROLLER,
3365         "SCIC Controller 0x%x remote device stopped event from device 0x%x in unexpected state %d\n",
3366         this_controller,
3367         the_device,
3368         sci_base_state_machine_get_state(
3369            scic_sds_controller_get_base_state_machine(this_controller))
3370      ));
3371   }
3372}
3373
3374/**
3375 * @brief This method will write to the SCU PCP register the request value.
3376 *        The method is used to suspend/resume ports, devices, and phys.
3377 *
3378 * @param[in] this_controller
3379 * @param[in] request
3380 */
3381void scic_sds_controller_post_request(
3382   SCIC_SDS_CONTROLLER_T *this_controller,
3383   U32                    request
3384)
3385{
3386   SCIC_LOG_INFO((
3387      sci_base_object_get_logger(this_controller),
3388      SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_COMPLETION_QUEUE,
3389      "SCIC Controller 0x%08x post request 0x%08x\n",
3390      this_controller, request
3391   ));
3392
3393   SMU_PCP_WRITE(this_controller, request);
3394}
3395
3396/**
3397 * @brief This method will copy the soft copy of the task context into
3398 *        the physical memory accessible by the controller.
3399 *
3400 * @note After this call is made the SCIC_SDS_IO_REQUEST object will
3401 *       always point to the physical memory version of the task context.
3402 *       Thus, all subsequent updates to the task context are performed in
3403 *       the TC table (i.e. DMAable memory).
3404 *
3405 * @param[in]  this_controller This parameter specifies the controller for
3406 *             which to copy the task context.
3407 * @param[in]  this_request This parameter specifies the request for which
3408 *             the task context is being copied.
3409 *
3410 * @return none
3411 */
3412void scic_sds_controller_copy_task_context(
3413   SCIC_SDS_CONTROLLER_T *this_controller,
3414   SCIC_SDS_REQUEST_T    *this_request
3415)
3416{
3417   SCU_TASK_CONTEXT_T *task_context_buffer;
3418
3419   task_context_buffer = scic_sds_controller_get_task_context_buffer(
3420                            this_controller, this_request->io_tag
3421                         );
3422
3423   memcpy(
3424      task_context_buffer,
3425      this_request->task_context_buffer,
3426      SCI_FIELD_OFFSET(SCU_TASK_CONTEXT_T, sgl_snapshot_ac)
3427   );
3428
3429   // Now that the soft copy of the TC has been copied into the TC
3430   // table accessible by the silicon.  Thus, any further changes to
3431   // the TC (e.g. TC termination) occur in the appropriate location.
3432   this_request->task_context_buffer = task_context_buffer;
3433}
3434
3435/**
3436 * @brief This method returns the task context buffer for the given io tag.
3437 *
3438 * @param[in] this_controller
3439 * @param[in] io_tag
3440 *
3441 * @return struct SCU_TASK_CONTEXT*
3442 */
3443SCU_TASK_CONTEXT_T * scic_sds_controller_get_task_context_buffer(
3444   SCIC_SDS_CONTROLLER_T * this_controller,
3445   U16                     io_tag
3446)
3447{
3448   U16 task_index = scic_sds_io_tag_get_index(io_tag);
3449
3450   if (task_index < this_controller->task_context_entries)
3451   {
3452      return &this_controller->task_context_table[task_index];
3453   }
3454
3455   return NULL;
3456}
3457
3458/**
3459 * @brief This method returnst the sequence value from the io tag value
3460 *
3461 * @param[in] this_controller
3462 * @param[in] io_tag
3463 *
3464 * @return U16
3465 */
3466U16 scic_sds_controller_get_io_sequence_from_tag(
3467   SCIC_SDS_CONTROLLER_T *this_controller,
3468   U16                    io_tag
3469)
3470{
3471   return scic_sds_io_tag_get_sequence(io_tag);
3472}
3473
3474/**
3475 * @brief This method returns the IO request associated with the tag value
3476 *
3477 * @param[in] this_controller
3478 * @param[in] io_tag
3479 *
3480 * @return SCIC_SDS_IO_REQUEST_T*
3481 * @retval NULL if there is no valid IO request at the tag value
3482 */
3483SCIC_SDS_REQUEST_T *scic_sds_controller_get_io_request_from_tag(
3484   SCIC_SDS_CONTROLLER_T *this_controller,
3485   U16                    io_tag
3486)
3487{
3488   U16 task_index;
3489   U16 task_sequence;
3490
3491   task_index = scic_sds_io_tag_get_index(io_tag);
3492
3493   if (task_index  < this_controller->task_context_entries)
3494   {
3495      if (this_controller->io_request_table[task_index] != SCI_INVALID_HANDLE)
3496      {
3497         task_sequence = scic_sds_io_tag_get_sequence(io_tag);
3498
3499         if (task_sequence == this_controller->io_request_sequence[task_index])
3500         {
3501            return this_controller->io_request_table[task_index];
3502         }
3503      }
3504   }
3505
3506   return SCI_INVALID_HANDLE;
3507}
3508
3509/**
3510 * @brief This method allocates remote node index and the reserves the
3511 *        remote node context space for use. This method can fail if there
3512 *        are no more remote node index available.
3513 *
3514 * @param[in] this_controller This is the controller object which contains
3515 *            the set of free remote node ids
3516 * @param[in] the_devce This is the device object which is requesting the a
3517 *            remote node id
3518 * @param[out] node_id This is the remote node id that is assinged to the
3519 *             device if one is available
3520 *
3521 * @return SCI_STATUS
3522 * @retval SCI_FAILURE_OUT_OF_RESOURCES if there are no available remote
3523 *         node index available.
3524 */
3525SCI_STATUS scic_sds_controller_allocate_remote_node_context(
3526   SCIC_SDS_CONTROLLER_T    * this_controller,
3527   SCIC_SDS_REMOTE_DEVICE_T * the_device,
3528   U16                      * node_id
3529)
3530{
3531   U16 node_index;
3532   U32 remote_node_count = scic_sds_remote_device_node_count(the_device);
3533
3534   node_index = scic_sds_remote_node_table_allocate_remote_node(
3535                  &this_controller->available_remote_nodes, remote_node_count
3536              );
3537
3538   if (node_index != SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX)
3539   {
3540      this_controller->device_table[node_index] = the_device;
3541
3542      *node_id = node_index;
3543
3544      return SCI_SUCCESS;
3545   }
3546
3547   return SCI_FAILURE_INSUFFICIENT_RESOURCES;
3548}
3549
3550/**
3551 * @brief This method frees the remote node index back to the available
3552 *        pool.  Once this is done the remote node context buffer is no
3553 *        longer valid and can not be used.
3554 *
3555 * @param[in] this_controller
3556 * @param[in] the_device
3557 * @param[in] node_id
3558 *
3559 * @return none
3560 */
3561void scic_sds_controller_free_remote_node_context(
3562   SCIC_SDS_CONTROLLER_T    * this_controller,
3563   SCIC_SDS_REMOTE_DEVICE_T * the_device,
3564   U16                        node_id
3565)
3566{
3567   U32 remote_node_count = scic_sds_remote_device_node_count(the_device);
3568
3569   if (this_controller->device_table[node_id] == the_device)
3570   {
3571      this_controller->device_table[node_id] = SCI_INVALID_HANDLE;
3572
3573      scic_sds_remote_node_table_release_remote_node_index(
3574         &this_controller->available_remote_nodes, remote_node_count, node_id
3575      );
3576   }
3577}
3578
3579/**
3580 * @brief This method returns the SCU_REMOTE_NODE_CONTEXT for the specified
3581 *        remote node id.
3582 *
3583 * @param[in] this_controller
3584 * @param[in] node_id
3585 *
3586 * @return SCU_REMOTE_NODE_CONTEXT_T*
3587 */
3588SCU_REMOTE_NODE_CONTEXT_T *scic_sds_controller_get_remote_node_context_buffer(
3589   SCIC_SDS_CONTROLLER_T *this_controller,
3590   U16                    node_id
3591)
3592{
3593   if (
3594           (node_id < this_controller->remote_node_entries)
3595        && (this_controller->device_table[node_id] != SCI_INVALID_HANDLE)
3596      )
3597   {
3598      return &this_controller->remote_node_context_table[node_id];
3599   }
3600
3601   return NULL;
3602}
3603
3604/**
3605 * This method will combind the frame header and frame buffer to create
3606 * a SATA D2H register FIS
3607 *
3608 * @param[out] resposne_buffer This is the buffer into which the D2H register
3609 *             FIS will be constructed.
3610 * @param[in]  frame_header This is the frame header returned by the hardware.
3611 * @param[in]  frame_buffer This is the frame buffer returned by the hardware.
3612 *
3613 * @erturn none
3614 */
3615void scic_sds_controller_copy_sata_response(
3616   void * response_buffer,
3617   void * frame_header,
3618   void * frame_buffer
3619)
3620{
3621   memcpy(
3622      response_buffer,
3623      frame_header,
3624      sizeof(U32)
3625   );
3626
3627   memcpy(
3628      (char *)((char *)response_buffer + sizeof(U32)),
3629      frame_buffer,
3630      sizeof(SATA_FIS_REG_D2H_T) - sizeof(U32)
3631   );
3632}
3633
3634/**
3635 * @brief This method releases the frame once this is done the frame is
3636 *        available for re-use by the hardware.  The data contained in the
3637 *        frame header and frame buffer is no longer valid.
3638 *        The UF queue get pointer is only updated if UF control indicates
3639 *        this is appropriate.
3640 *
3641 * @param[in] this_controller
3642 * @param[in] frame_index
3643 *
3644 * @return none
3645 */
3646void scic_sds_controller_release_frame(
3647   SCIC_SDS_CONTROLLER_T *this_controller,
3648   U32                    frame_index
3649)
3650{
3651   if (scic_sds_unsolicited_frame_control_release_frame(
3652          &this_controller->uf_control, frame_index) == TRUE)
3653      SCU_UFQGP_WRITE(this_controller, this_controller->uf_control.get);
3654}
3655
3656#ifdef SCI_LOGGING
3657void scic_sds_controller_initialize_state_logging(
3658   SCIC_SDS_CONTROLLER_T *this_controller
3659)
3660{
3661   sci_base_state_machine_logger_initialize(
3662      &this_controller->parent.state_machine_logger,
3663      &this_controller->parent.state_machine,
3664      &this_controller->parent.parent,
3665      scic_cb_logger_log_states,
3666      "SCIC_SDS_CONTROLLER_T", "base state machine",
3667      SCIC_LOG_OBJECT_CONTROLLER
3668   );
3669}
3670
3671void scic_sds_controller_deinitialize_state_logging(
3672   SCIC_SDS_CONTROLLER_T *this_controller
3673)
3674{
3675   sci_base_state_machine_logger_deinitialize(
3676      &this_controller->parent.state_machine_logger,
3677      &this_controller->parent.state_machine
3678   );
3679}
3680#endif
3681
3682/**
3683 * @brief This method sets user parameters and OEM parameters to
3684 *        default values.  Users can override these values utilizing
3685 *        the scic_user_parameters_set() and scic_oem_parameters_set()
3686 *        methods.
3687 *
3688 * @param[in] controller This parameter specifies the controller for
3689 *            which to set the configuration parameters to their
3690 *            default values.
3691 *
3692 * @return none
3693 */
3694static
3695void scic_sds_controller_set_default_config_parameters(
3696   SCIC_SDS_CONTROLLER_T *this_controller
3697)
3698{
3699   U16 index;
3700
3701   // Default to APC mode.
3702   this_controller->oem_parameters.sds1.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE;
3703
3704   // Default to 1
3705   this_controller->oem_parameters.sds1.controller.max_number_concurrent_device_spin_up = 1;
3706
3707   // Default to no SSC operation.
3708   this_controller->oem_parameters.sds1.controller.ssc_sata_tx_spread_level = 0;
3709   this_controller->oem_parameters.sds1.controller.ssc_sas_tx_spread_level  = 0;
3710   this_controller->oem_parameters.sds1.controller.ssc_sas_tx_type          = 0;
3711
3712   // Default to all phys to using short cables
3713   this_controller->oem_parameters.sds1.controller.cable_selection_mask = 0;
3714
3715   // Initialize all of the port parameter information to narrow ports.
3716   for (index = 0; index < SCI_MAX_PORTS; index++)
3717   {
3718      this_controller->oem_parameters.sds1.ports[index].phy_mask = 0;
3719   }
3720
3721   // Initialize all of the phy parameter information.
3722   for (index = 0; index < SCI_MAX_PHYS; index++)
3723   {
3724      // Default to 6G (i.e. Gen 3) for now.  User can override if
3725      // they choose.
3726      this_controller->user_parameters.sds1.phys[index].max_speed_generation = 2;
3727
3728      //the frequencies cannot be 0
3729      this_controller->user_parameters.sds1.phys[index].align_insertion_frequency = 0x7f;
3730      this_controller->user_parameters.sds1.phys[index].in_connection_align_insertion_frequency = 0xff;
3731      this_controller->user_parameters.sds1.phys[index].notify_enable_spin_up_insertion_frequency = 0x33;
3732
3733      // Previous Vitesse based expanders had a arbitration issue that
3734      // is worked around by having the upper 32-bits of SAS address
3735      // with a value greater then the Vitesse company identifier.
3736      // Hence, usage of 0x5FCFFFFF.
3737      this_controller->oem_parameters.sds1.phys[index].sas_address.sci_format.high
3738         = 0x5FCFFFFF;
3739
3740      // Add in controller index to ensure each controller will have unique SAS addresses by default.
3741      this_controller->oem_parameters.sds1.phys[index].sas_address.sci_format.low
3742         = 0x00000001 + this_controller->controller_index;
3743
3744      if (  (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A0)
3745         || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_A2)
3746         || (this_controller->pci_revision == SCIC_SDS_PCI_REVISION_B0) )
3747      {
3748         this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control0 = 0x000E7C03;
3749         this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control1 = 0x000E7C03;
3750         this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control2 = 0x000E7C03;
3751         this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control3 = 0x000E7C03;
3752      }
3753      else // This must be SCIC_SDS_PCI_REVISION_C0
3754      {
3755         this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control0 = 0x000BDD08;
3756         this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control1 = 0x000B7069;
3757         this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control2 = 0x000B7C09;
3758         this_controller->oem_parameters.sds1.phys[index].afe_tx_amp_control3 = 0x000AFC6E;
3759      }
3760   }
3761
3762   this_controller->user_parameters.sds1.stp_inactivity_timeout = 5;
3763   this_controller->user_parameters.sds1.ssp_inactivity_timeout = 5;
3764   this_controller->user_parameters.sds1.stp_max_occupancy_timeout = 5;
3765   this_controller->user_parameters.sds1.ssp_max_occupancy_timeout = 20;
3766   this_controller->user_parameters.sds1.no_outbound_task_timeout = 20;
3767
3768}
3769
3770
3771/**
3772 * @brief This method release resources in SCI controller.
3773 *
3774 * @param[in] this_controller This parameter specifies the core
3775 *            controller and associated objects whose resources are to be
3776 *            released.
3777 *
3778 * @return This method returns a value indicating if the operation succeeded.
3779 * @retval SCI_SUCCESS This value indicates that all the timers are destroyed.
3780 * @retval SCI_FAILURE This value indicates certain failure during the process
3781 *            of cleaning timer resource.
3782 */
3783static
3784SCI_STATUS scic_sds_controller_release_resource(
3785   SCIC_SDS_CONTROLLER_T * this_controller
3786)
3787{
3788   SCIC_SDS_PORT_T * port;
3789   SCIC_SDS_PHY_T * phy;
3790   U8 index;
3791
3792   SCIC_LOG_TRACE((
3793      sci_base_object_get_logger(this_controller),
3794      SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
3795      "scic_sds_controller_release_resource(0x%x) enter\n",
3796      this_controller
3797   ));
3798
3799   if(this_controller->phy_startup_timer != NULL)
3800   {
3801      scic_cb_timer_destroy(this_controller, this_controller->phy_startup_timer);
3802      this_controller->phy_startup_timer = NULL;
3803   }
3804
3805   if(this_controller->power_control.timer != NULL)
3806   {
3807      scic_cb_timer_destroy(this_controller, this_controller->power_control.timer);
3808      this_controller->power_control.timer = NULL;
3809   }
3810
3811   if(this_controller->timeout_timer != NULL)
3812   {
3813      scic_cb_timer_destroy(this_controller, this_controller->timeout_timer);
3814      this_controller->timeout_timer = NULL;
3815   }
3816
3817   scic_sds_port_configuration_agent_release_resource(
3818      this_controller,
3819      &this_controller->port_agent);
3820
3821   for(index = 0; index < SCI_MAX_PORTS+1; index++)
3822   {
3823      port = &this_controller->port_table[index];
3824      scic_sds_port_release_resource(this_controller, port);
3825   }
3826
3827   for(index = 0; index < SCI_MAX_PHYS; index++)
3828   {
3829      phy = &this_controller->phy_table[index];
3830      scic_sds_phy_release_resource(this_controller, phy);
3831   }
3832
3833   return SCI_SUCCESS;
3834}
3835
3836
3837/**
3838 * @brief This method process the ports configured message from port configuration
3839 *           agent.
3840 *
3841 * @param[in] this_controller This parameter specifies the core
3842 *            controller that its ports are configured.
3843 *
3844 * @return None.
3845 */
3846void scic_sds_controller_port_agent_configured_ports(
3847   SCIC_SDS_CONTROLLER_T * this_controller
3848)
3849{
3850   //simply transit to ready. The function below checks the controller state
3851   scic_sds_controller_transition_to_ready(
3852      this_controller, SCI_SUCCESS
3853   );
3854}
3855
3856
3857//****************************************************************************-
3858//* SCIC Controller Public Methods
3859//****************************************************************************-
3860
3861SCI_STATUS scic_controller_construct(
3862   SCI_LIBRARY_HANDLE_T    library,
3863   SCI_CONTROLLER_HANDLE_T controller,
3864   void *                  user_object
3865)
3866{
3867   SCIC_SDS_LIBRARY_T    *my_library;
3868   SCIC_SDS_CONTROLLER_T *this_controller;
3869
3870   my_library = (SCIC_SDS_LIBRARY_T *)library;
3871   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
3872
3873   SCIC_LOG_TRACE((
3874      sci_base_object_get_logger(library),
3875      SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
3876      "scic_controller_construct(0x%x, 0x%x) enter\n",
3877      library, controller
3878   ));
3879
3880   // Just clear out the memory of the structure to be safe.
3881   memset(this_controller, 0, sizeof(SCIC_SDS_CONTROLLER_T));
3882
3883   // Make sure that the static data is assigned before moving onto the
3884   // base constroller construct as this will cause the controller to
3885   // enter its initial state and the controller_index and pci_revision
3886   // will be required to complete those operations correctly
3887   this_controller->controller_index =
3888      scic_sds_library_get_controller_index(my_library, this_controller);
3889
3890   this_controller->pci_revision = my_library->pci_revision;
3891
3892   sci_base_controller_construct(
3893      &this_controller->parent,
3894      sci_base_object_get_logger(my_library),
3895      scic_sds_controller_state_table,
3896      this_controller->memory_descriptors,
3897      ARRAY_SIZE(this_controller->memory_descriptors),
3898      NULL
3899   );
3900
3901   sci_object_set_association(controller, user_object);
3902
3903   scic_sds_controller_initialize_state_logging(this_controller);
3904
3905   scic_sds_pci_bar_initialization(this_controller);
3906
3907   return SCI_SUCCESS;
3908}
3909
3910// ---------------------------------------------------------------------------
3911
3912SCI_STATUS scic_controller_initialize(
3913   SCI_CONTROLLER_HANDLE_T   controller
3914)
3915{
3916   SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
3917   SCIC_SDS_CONTROLLER_T *this_controller;
3918   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
3919
3920   SCIC_LOG_TRACE((
3921      sci_base_object_get_logger(controller),
3922      SCIC_LOG_OBJECT_CONTROLLER,
3923      "scic_controller_initialize(0x%x, 0x%d) enter\n",
3924      controller
3925   ));
3926
3927   if (this_controller->state_handlers->parent.initialize_handler != NULL)
3928   {
3929      status = this_controller->state_handlers->parent.initialize_handler(
3930                  (SCI_BASE_CONTROLLER_T *)controller
3931               );
3932   }
3933   else
3934   {
3935      SCIC_LOG_WARNING((
3936         sci_base_object_get_logger(this_controller),
3937         SCIC_LOG_OBJECT_CONTROLLER,
3938         "SCIC Controller initialize operation requested in invalid state %d\n",
3939         sci_base_state_machine_get_state(
3940            scic_sds_controller_get_base_state_machine(this_controller))
3941      ));
3942   }
3943
3944   return status;
3945}
3946
3947// ---------------------------------------------------------------------------
3948
3949U32 scic_controller_get_suggested_start_timeout(
3950   SCI_CONTROLLER_HANDLE_T  controller
3951)
3952{
3953   // Validate the user supplied parameters.
3954   if (controller == SCI_INVALID_HANDLE)
3955      return 0;
3956
3957   // The suggested minimum timeout value for a controller start operation:
3958   //
3959   //     Signature FIS Timeout
3960   //   + Phy Start Timeout
3961   //   + Number of Phy Spin Up Intervals
3962   //   ---------------------------------
3963   //   Number of milliseconds for the controller start operation.
3964   //
3965   // NOTE: The number of phy spin up intervals will be equivalent
3966   //       to the number of phys divided by the number phys allowed
3967   //       per interval - 1 (once OEM parameters are supported).
3968   //       Currently we assume only 1 phy per interval.
3969
3970   return (SCIC_SDS_SIGNATURE_FIS_TIMEOUT
3971           + SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT
3972           + ((SCI_MAX_PHYS-1) * SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL));
3973}
3974
3975// ---------------------------------------------------------------------------
3976
3977SCI_STATUS scic_controller_start(
3978   SCI_CONTROLLER_HANDLE_T controller,
3979   U32 timeout
3980)
3981{
3982   SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
3983   SCIC_SDS_CONTROLLER_T *this_controller;
3984   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
3985
3986   SCIC_LOG_TRACE((
3987      sci_base_object_get_logger(controller),
3988      SCIC_LOG_OBJECT_CONTROLLER,
3989      "scic_controller_start(0x%x, 0x%d) enter\n",
3990      controller, timeout
3991   ));
3992
3993   if (this_controller->state_handlers->parent.start_handler != NULL)
3994   {
3995      status = this_controller->state_handlers->parent.start_handler(
3996                  (SCI_BASE_CONTROLLER_T *)controller, timeout
3997               );
3998   }
3999   else
4000   {
4001      SCIC_LOG_WARNING((
4002         sci_base_object_get_logger(this_controller),
4003         SCIC_LOG_OBJECT_CONTROLLER,
4004         "SCIC Controller start operation requested in invalid state %d\n",
4005         sci_base_state_machine_get_state(
4006            scic_sds_controller_get_base_state_machine(this_controller))
4007      ));
4008   }
4009
4010   return status;
4011}
4012
4013// ---------------------------------------------------------------------------
4014
4015SCI_STATUS scic_controller_stop(
4016   SCI_CONTROLLER_HANDLE_T controller,
4017   U32 timeout
4018)
4019{
4020   SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
4021   SCIC_SDS_CONTROLLER_T *this_controller;
4022   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4023
4024   SCIC_LOG_TRACE((
4025      sci_base_object_get_logger(controller),
4026      SCIC_LOG_OBJECT_CONTROLLER,
4027      "scic_controller_stop(0x%x, 0x%d) enter\n",
4028      controller, timeout
4029   ));
4030
4031   if (this_controller->state_handlers->parent.stop_handler != NULL)
4032   {
4033      status = this_controller->state_handlers->parent.stop_handler(
4034                  (SCI_BASE_CONTROLLER_T *)controller, timeout
4035               );
4036   }
4037   else
4038   {
4039      SCIC_LOG_WARNING((
4040         sci_base_object_get_logger(this_controller),
4041         SCIC_LOG_OBJECT_CONTROLLER,
4042         "SCIC Controller stop operation requested in invalid state %d\n",
4043         sci_base_state_machine_get_state(
4044            scic_sds_controller_get_base_state_machine(this_controller))
4045      ));
4046   }
4047
4048   return status;
4049}
4050
4051// ---------------------------------------------------------------------------
4052
4053SCI_STATUS scic_controller_reset(
4054   SCI_CONTROLLER_HANDLE_T controller
4055)
4056{
4057   SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
4058   SCIC_SDS_CONTROLLER_T *this_controller;
4059   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4060
4061   SCIC_LOG_TRACE((
4062      sci_base_object_get_logger(controller),
4063      SCIC_LOG_OBJECT_CONTROLLER,
4064      "scic_controller_reset(0x%x) enter\n",
4065      controller
4066   ));
4067
4068   if (this_controller->state_handlers->parent.reset_handler != NULL)
4069   {
4070      status = this_controller->state_handlers->parent.reset_handler(
4071                  (SCI_BASE_CONTROLLER_T *)controller
4072               );
4073   }
4074   else
4075   {
4076      SCIC_LOG_WARNING((
4077         sci_base_object_get_logger(this_controller),
4078         SCIC_LOG_OBJECT_CONTROLLER,
4079         "SCIC Controller reset operation requested in invalid state %d\n",
4080         sci_base_state_machine_get_state(
4081            scic_sds_controller_get_base_state_machine(this_controller))
4082      ));
4083   }
4084
4085   return status;
4086}
4087
4088// ---------------------------------------------------------------------------
4089
4090SCI_STATUS scic_controller_get_handler_methods(
4091   SCIC_INTERRUPT_TYPE                interrupt_type,
4092   U16                                message_count,
4093   SCIC_CONTROLLER_HANDLER_METHODS_T *handler_methods
4094)
4095{
4096   SCI_STATUS status = SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT;
4097
4098   switch (interrupt_type)
4099   {
4100#if !defined(DISABLE_INTERRUPTS)
4101   case SCIC_LEGACY_LINE_INTERRUPT_TYPE:
4102      if (message_count == 0)
4103      {
4104         handler_methods[0].interrupt_handler
4105            = scic_sds_controller_legacy_interrupt_handler;
4106         handler_methods[0].completion_handler
4107            = scic_sds_controller_legacy_completion_handler;
4108
4109         status = SCI_SUCCESS;
4110      }
4111      break;
4112
4113   case SCIC_MSIX_INTERRUPT_TYPE:
4114      if (message_count == 1)
4115      {
4116         handler_methods[0].interrupt_handler
4117            = scic_sds_controller_single_vector_interrupt_handler;
4118         handler_methods[0].completion_handler
4119            = scic_sds_controller_single_vector_completion_handler;
4120
4121         status = SCI_SUCCESS;
4122      }
4123      else if (message_count == 2)
4124      {
4125         handler_methods[0].interrupt_handler
4126            = scic_sds_controller_normal_vector_interrupt_handler;
4127         handler_methods[0].completion_handler
4128            = scic_sds_controller_normal_vector_completion_handler;
4129
4130         handler_methods[1].interrupt_handler
4131            = scic_sds_controller_error_vector_interrupt_handler;
4132         handler_methods[1].completion_handler
4133            = scic_sds_controller_error_vector_completion_handler;
4134
4135         status = SCI_SUCCESS;
4136      }
4137      break;
4138#endif // !defined(DISABLE_INTERRUPTS)
4139
4140   case SCIC_NO_INTERRUPTS:
4141      if (message_count == 0)
4142      {
4143
4144         handler_methods[0].interrupt_handler
4145            = scic_sds_controller_polling_interrupt_handler;
4146         handler_methods[0].completion_handler
4147            = scic_sds_controller_polling_completion_handler;
4148
4149         status = SCI_SUCCESS;
4150      }
4151      break;
4152
4153   default:
4154      status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
4155      break;
4156   }
4157
4158   return status;
4159}
4160
4161// ---------------------------------------------------------------------------
4162
4163SCI_IO_STATUS scic_controller_start_io(
4164   SCI_CONTROLLER_HANDLE_T    controller,
4165   SCI_REMOTE_DEVICE_HANDLE_T remote_device,
4166   SCI_IO_REQUEST_HANDLE_T    io_request,
4167   U16                        io_tag
4168)
4169{
4170   SCI_STATUS          status;
4171   SCIC_SDS_CONTROLLER_T *this_controller;
4172   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4173
4174   SCIC_LOG_TRACE((
4175      sci_base_object_get_logger(controller),
4176      SCIC_LOG_OBJECT_CONTROLLER,
4177      "scic_controller_start_io(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
4178      controller, remote_device, io_request, io_tag
4179   ));
4180
4181   status = this_controller->state_handlers->parent.start_io_handler(
4182               &this_controller->parent,
4183               (SCI_BASE_REMOTE_DEVICE_T *)remote_device,
4184               (SCI_BASE_REQUEST_T *)io_request,
4185               io_tag
4186            );
4187
4188   return (SCI_IO_STATUS)status;
4189}
4190
4191// ---------------------------------------------------------------------------
4192
4193SCI_STATUS scic_controller_terminate_request(
4194   SCI_CONTROLLER_HANDLE_T    controller,
4195   SCI_REMOTE_DEVICE_HANDLE_T remote_device,
4196   SCI_IO_REQUEST_HANDLE_T    request
4197)
4198{
4199   SCI_STATUS status;
4200   SCIC_SDS_CONTROLLER_T *this_controller;
4201   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4202
4203   SCIC_LOG_TRACE((
4204      sci_base_object_get_logger(controller),
4205      SCIC_LOG_OBJECT_CONTROLLER,
4206      "scic_controller_terminate_request(0x%x, 0x%x, 0x%x) enter\n",
4207      controller, remote_device, request
4208   ));
4209
4210   status = this_controller->state_handlers->terminate_request_handler(
4211      &this_controller->parent,
4212      (SCI_BASE_REMOTE_DEVICE_T *)remote_device,
4213      (SCI_BASE_REQUEST_T *)request
4214   );
4215
4216   return status;
4217}
4218
4219// ---------------------------------------------------------------------------
4220
4221SCI_STATUS scic_controller_complete_io(
4222   SCI_CONTROLLER_HANDLE_T controller,
4223   SCI_REMOTE_DEVICE_HANDLE_T remote_device,
4224   SCI_IO_REQUEST_HANDLE_T io_request
4225)
4226{
4227   SCI_STATUS status;
4228   SCIC_SDS_CONTROLLER_T *this_controller;
4229   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4230
4231   SCIC_LOG_TRACE((
4232      sci_base_object_get_logger(controller),
4233      SCIC_LOG_OBJECT_CONTROLLER,
4234      "scic_controller_complete_io(0x%x, 0x%x, 0x%x) enter\n",
4235      controller, remote_device, io_request
4236   ));
4237
4238   status = this_controller->state_handlers->parent.complete_io_handler(
4239      &this_controller->parent,
4240      (SCI_BASE_REMOTE_DEVICE_T *)remote_device,
4241      (SCI_BASE_REQUEST_T *)io_request
4242   );
4243
4244   return status;
4245}
4246
4247// ---------------------------------------------------------------------------
4248
4249#if !defined(DISABLE_TASK_MANAGEMENT)
4250
4251SCI_TASK_STATUS scic_controller_start_task(
4252   SCI_CONTROLLER_HANDLE_T    controller,
4253   SCI_REMOTE_DEVICE_HANDLE_T remote_device,
4254   SCI_TASK_REQUEST_HANDLE_T  task_request,
4255   U16                        task_tag
4256)
4257{
4258   SCI_STATUS             status = SCI_FAILURE_INVALID_STATE;
4259   SCIC_SDS_CONTROLLER_T *this_controller;
4260   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4261
4262   SCIC_LOG_TRACE((
4263      sci_base_object_get_logger(controller),
4264      SCIC_LOG_OBJECT_CONTROLLER,
4265      "scic_controller_start_task(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
4266      controller, remote_device, task_request, task_tag
4267   ));
4268
4269   if (this_controller->state_handlers->parent.start_task_handler != NULL)
4270   {
4271      status = this_controller->state_handlers->parent.start_task_handler(
4272                  &this_controller->parent,
4273                  (SCI_BASE_REMOTE_DEVICE_T *)remote_device,
4274                  (SCI_BASE_REQUEST_T *)task_request,
4275                  task_tag
4276               );
4277   }
4278   else
4279   {
4280      SCIC_LOG_INFO((
4281         sci_base_object_get_logger(controller),
4282         SCIC_LOG_OBJECT_CONTROLLER,
4283         "SCIC Controller starting task from invalid state\n"
4284      ));
4285   }
4286
4287   return (SCI_TASK_STATUS)status;
4288}
4289
4290// ---------------------------------------------------------------------------
4291
4292SCI_STATUS scic_controller_complete_task(
4293   SCI_CONTROLLER_HANDLE_T    controller,
4294   SCI_REMOTE_DEVICE_HANDLE_T remote_device,
4295   SCI_TASK_REQUEST_HANDLE_T  task_request
4296)
4297{
4298   SCI_STATUS status = SCI_FAILURE_INVALID_STATE;
4299   SCIC_SDS_CONTROLLER_T *this_controller;
4300   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4301
4302   SCIC_LOG_TRACE((
4303      sci_base_object_get_logger(controller),
4304      SCIC_LOG_OBJECT_CONTROLLER,
4305      "scic_controller_complete_task(0x%x, 0x%x, 0x%x) enter\n",
4306      controller, remote_device, task_request
4307   ));
4308
4309   if (this_controller->state_handlers->parent.complete_task_handler != NULL)
4310   {
4311      status = this_controller->state_handlers->parent.complete_task_handler(
4312                  &this_controller->parent,
4313                  (SCI_BASE_REMOTE_DEVICE_T *)remote_device,
4314                  (SCI_BASE_REQUEST_T *)task_request
4315               );
4316   }
4317   else
4318   {
4319      SCIC_LOG_INFO((
4320         sci_base_object_get_logger(controller),
4321         SCIC_LOG_OBJECT_CONTROLLER,
4322         "SCIC Controller completing task from invalid state\n"
4323      ));
4324   }
4325
4326   return status;
4327}
4328
4329#endif // !defined(DISABLE_TASK_MANAGEMENT)
4330
4331// ---------------------------------------------------------------------------
4332
4333SCI_STATUS scic_controller_get_port_handle(
4334   SCI_CONTROLLER_HANDLE_T controller,
4335   U8                      port_index,
4336   SCI_PORT_HANDLE_T *     port_handle
4337)
4338{
4339   SCIC_SDS_CONTROLLER_T *this_controller;
4340   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4341
4342   SCIC_LOG_TRACE((
4343      sci_base_object_get_logger(controller),
4344      SCIC_LOG_OBJECT_CONTROLLER,
4345      "scic_controller_get_port_handle(0x%x, 0x%x, 0x%x) enter\n",
4346      controller, port_index, port_handle
4347   ));
4348
4349   if (port_index < this_controller->logical_port_entries)
4350   {
4351      *port_handle = &this_controller->port_table[port_index];
4352
4353      return SCI_SUCCESS;
4354   }
4355
4356   return SCI_FAILURE_INVALID_PORT;
4357}
4358
4359// ---------------------------------------------------------------------------
4360
4361SCI_STATUS scic_controller_get_phy_handle(
4362   SCI_CONTROLLER_HANDLE_T controller,
4363   U8                      phy_index,
4364   SCI_PHY_HANDLE_T *      phy_handle
4365)
4366{
4367   SCIC_SDS_CONTROLLER_T *this_controller;
4368   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4369
4370   SCIC_LOG_TRACE((
4371      sci_base_object_get_logger(controller),
4372      SCIC_LOG_OBJECT_CONTROLLER,
4373      "scic_controller_get_phy_handle(0x%x, 0x%x, 0x%x) enter\n",
4374      controller, phy_index, phy_handle
4375   ));
4376
4377   if (phy_index < ARRAY_SIZE(this_controller->phy_table))
4378   {
4379      *phy_handle = &this_controller->phy_table[phy_index];
4380
4381      return SCI_SUCCESS;
4382   }
4383
4384   SCIC_LOG_ERROR((
4385      sci_base_object_get_logger(this_controller),
4386      SCIC_LOG_OBJECT_PORT | SCIC_LOG_OBJECT_CONTROLLER,
4387      "Controller:0x%x PhyId:0x%x invalid phy index\n",
4388      this_controller, phy_index
4389   ));
4390
4391   return SCI_FAILURE_INVALID_PHY;
4392}
4393
4394// ---------------------------------------------------------------------------
4395
4396U16 scic_controller_allocate_io_tag(
4397   SCI_CONTROLLER_HANDLE_T controller
4398)
4399{
4400   U16 task_context;
4401   U16 sequence_count;
4402   SCIC_SDS_CONTROLLER_T *this_controller;
4403   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4404
4405   SCIC_LOG_TRACE((
4406      sci_base_object_get_logger(controller),
4407      SCIC_LOG_OBJECT_CONTROLLER,
4408      "scic_controller_allocate_io_tag(0x%x) enter\n",
4409      controller
4410   ));
4411
4412   if (!sci_pool_empty(this_controller->tci_pool))
4413   {
4414      sci_pool_get(this_controller->tci_pool, task_context);
4415
4416      sequence_count = this_controller->io_request_sequence[task_context];
4417
4418      return scic_sds_io_tag_construct(sequence_count, task_context);
4419   }
4420
4421   return SCI_CONTROLLER_INVALID_IO_TAG;
4422}
4423
4424// ---------------------------------------------------------------------------
4425
4426SCI_STATUS scic_controller_free_io_tag(
4427   SCI_CONTROLLER_HANDLE_T controller,
4428   U16                     io_tag
4429)
4430{
4431   U16 sequence;
4432   U16 index;
4433
4434   SCIC_SDS_CONTROLLER_T *this_controller;
4435   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4436
4437   ASSERT(io_tag != SCI_CONTROLLER_INVALID_IO_TAG);
4438
4439   SCIC_LOG_TRACE((
4440      sci_base_object_get_logger(controller),
4441      SCIC_LOG_OBJECT_CONTROLLER,
4442      "scic_controller_free_io_tag(0x%x, 0x%x) enter\n",
4443      controller, io_tag
4444   ));
4445
4446   sequence = scic_sds_io_tag_get_sequence(io_tag);
4447   index    = scic_sds_io_tag_get_index(io_tag);
4448
4449   if (!sci_pool_full(this_controller->tci_pool))
4450   {
4451      if (sequence == this_controller->io_request_sequence[index])
4452      {
4453         scic_sds_io_sequence_increment(
4454            this_controller->io_request_sequence[index]);
4455
4456         sci_pool_put(this_controller->tci_pool, index);
4457
4458         return SCI_SUCCESS;
4459      }
4460   }
4461
4462   return SCI_FAILURE_INVALID_IO_TAG;
4463}
4464
4465// ---------------------------------------------------------------------------
4466
4467void scic_controller_enable_interrupts(
4468   SCI_CONTROLLER_HANDLE_T controller
4469)
4470{
4471   SCIC_SDS_CONTROLLER_T *this_controller;
4472   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4473
4474   ASSERT(this_controller->smu_registers != NULL);
4475
4476   SMU_IMR_WRITE(this_controller, 0x00000000);
4477}
4478
4479// ---------------------------------------------------------------------------
4480
4481void scic_controller_disable_interrupts(
4482   SCI_CONTROLLER_HANDLE_T controller
4483)
4484{
4485   SCIC_SDS_CONTROLLER_T *this_controller;
4486   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4487
4488   ASSERT(this_controller->smu_registers != NULL);
4489
4490   SMU_IMR_WRITE(this_controller, 0xffffffff);
4491}
4492
4493// ---------------------------------------------------------------------------
4494
4495SCI_STATUS scic_controller_set_mode(
4496   SCI_CONTROLLER_HANDLE_T   controller,
4497   SCI_CONTROLLER_MODE       operating_mode
4498)
4499{
4500   SCIC_SDS_CONTROLLER_T *this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
4501   SCI_STATUS             status          = SCI_SUCCESS;
4502
4503   SCIC_LOG_TRACE((
4504      sci_base_object_get_logger(controller),
4505      SCIC_LOG_OBJECT_CONTROLLER,
4506      "scic_controller_set_mode(0x%x, 0x%x) enter\n",
4507      controller, operating_mode
4508   ));
4509
4510   if (
4511         (this_controller->parent.state_machine.current_state_id
4512          == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
4513      || (this_controller->parent.state_machine.current_state_id
4514          == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
4515      )
4516   {
4517      switch (operating_mode)
4518      {
4519      case SCI_MODE_SPEED:
4520         this_controller->remote_node_entries =
4521            MIN(this_controller->remote_node_entries, SCI_MAX_REMOTE_DEVICES);
4522         this_controller->task_context_entries =
4523            MIN(this_controller->task_context_entries, SCU_IO_REQUEST_COUNT);
4524         this_controller->uf_control.buffers.count =
4525            MIN(this_controller->uf_control.buffers.count, SCU_UNSOLICITED_FRAME_COUNT);
4526         this_controller->completion_event_entries =
4527            MIN(this_controller->completion_event_entries, SCU_EVENT_COUNT);
4528         this_controller->completion_queue_entries =
4529            MIN(this_controller->completion_queue_entries, SCU_COMPLETION_QUEUE_COUNT);
4530
4531         scic_sds_controller_build_memory_descriptor_table(this_controller);
4532      break;
4533
4534      case SCI_MODE_SIZE:
4535         this_controller->remote_node_entries =
4536            MIN(this_controller->remote_node_entries, SCI_MIN_REMOTE_DEVICES);
4537         this_controller->task_context_entries =
4538            MIN(this_controller->task_context_entries, SCI_MIN_IO_REQUESTS);
4539         this_controller->uf_control.buffers.count =
4540            MIN(this_controller->uf_control.buffers.count, SCU_MIN_UNSOLICITED_FRAMES);
4541         this_controller->completion_event_entries =
4542            MIN(this_controller->completion_event_entries, SCU_MIN_EVENTS);
4543         this_controller->completion_queue_entries =
4544            MIN(this_controller->completion_queue_entries, SCU_MIN_COMPLETION_QUEUE_ENTRIES);
4545
4546         scic_sds_controller_build_memory_descriptor_table(this_controller);
4547      break;
4548
4549      default:
4550         status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
4551      break;
4552      }
4553   }
4554   else
4555      status = SCI_FAILURE_INVALID_STATE;
4556
4557   return status;
4558}
4559
4560/**
4561 * This method will reset the controller hardware.
4562 *
4563 * @param[in] this_controller The controller that is to be reset.
4564 */
4565void scic_sds_controller_reset_hardware(
4566   SCIC_SDS_CONTROLLER_T * this_controller
4567)
4568{
4569   // Disable interrupts so we dont take any spurious interrupts
4570   scic_controller_disable_interrupts(this_controller);
4571
4572   // Reset the SCU
4573   SMU_SMUSRCR_WRITE(this_controller, 0xFFFFFFFF);
4574
4575   // Delay for 1ms to before clearing the CQP and UFQPR.
4576   scic_cb_stall_execution(1000);
4577
4578   // The write to the CQGR clears the CQP
4579   SMU_CQGR_WRITE(this_controller, 0x00000000);
4580
4581   // The write to the UFQGP clears the UFQPR
4582   SCU_UFQGP_WRITE(this_controller, 0x00000000);
4583}
4584
4585// ---------------------------------------------------------------------------
4586
4587SCI_STATUS scic_user_parameters_set(
4588   SCI_CONTROLLER_HANDLE_T   controller,
4589   SCIC_USER_PARAMETERS_T  * scic_parms
4590)
4591{
4592   SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
4593
4594   if (
4595         (this_controller->parent.state_machine.current_state_id
4596          == SCI_BASE_CONTROLLER_STATE_RESET)
4597      || (this_controller->parent.state_machine.current_state_id
4598          == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
4599      || (this_controller->parent.state_machine.current_state_id
4600          == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
4601      )
4602   {
4603      U16  index;
4604
4605      // Validate the user parameters.  If they are not legal, then
4606      // return a failure.
4607      for (index = 0; index < SCI_MAX_PHYS; index++)
4608      {
4609         if (!
4610               (  scic_parms->sds1.phys[index].max_speed_generation
4611                  <= SCIC_SDS_PARM_MAX_SPEED
4612               && scic_parms->sds1.phys[index].max_speed_generation
4613                  > SCIC_SDS_PARM_NO_SPEED
4614               )
4615            )
4616            return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4617
4618         if (
4619               (scic_parms->sds1.phys[index].in_connection_align_insertion_frequency < 3) ||
4620               (scic_parms->sds1.phys[index].align_insertion_frequency == 0) ||
4621               (scic_parms->sds1.phys[index].notify_enable_spin_up_insertion_frequency == 0)
4622            )
4623         {
4624            return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4625         }
4626      }
4627
4628      if (
4629            (scic_parms->sds1.stp_inactivity_timeout == 0) ||
4630            (scic_parms->sds1.ssp_inactivity_timeout == 0) ||
4631            (scic_parms->sds1.stp_max_occupancy_timeout == 0) ||
4632            (scic_parms->sds1.ssp_max_occupancy_timeout == 0) ||
4633            (scic_parms->sds1.no_outbound_task_timeout == 0)
4634         )
4635      {
4636         return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4637      }
4638
4639      memcpy(
4640         (&this_controller->user_parameters), scic_parms, sizeof(*scic_parms));
4641
4642      return SCI_SUCCESS;
4643   }
4644
4645   return SCI_FAILURE_INVALID_STATE;
4646}
4647
4648// ---------------------------------------------------------------------------
4649
4650void scic_user_parameters_get(
4651   SCI_CONTROLLER_HANDLE_T   controller,
4652   SCIC_USER_PARAMETERS_T   * scic_parms
4653)
4654{
4655   SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
4656
4657   memcpy(scic_parms, (&this_controller->user_parameters), sizeof(*scic_parms));
4658}
4659
4660// ---------------------------------------------------------------------------
4661SCI_STATUS scic_oem_parameters_set(
4662   SCI_CONTROLLER_HANDLE_T   controller,
4663   SCIC_OEM_PARAMETERS_T   * scic_parms,
4664   U8 scic_parms_version
4665)
4666{
4667   SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
4668   SCI_BIOS_OEM_PARAM_ELEMENT_T *old_oem_params =
4669                (SCI_BIOS_OEM_PARAM_ELEMENT_T *)(&(scic_parms->sds1));
4670
4671
4672   if (
4673         (this_controller->parent.state_machine.current_state_id
4674          == SCI_BASE_CONTROLLER_STATE_RESET)
4675      || (this_controller->parent.state_machine.current_state_id
4676          == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
4677      || (this_controller->parent.state_machine.current_state_id
4678          == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
4679      )
4680   {
4681      U16  index;
4682      U8   combined_phy_mask = 0;
4683
4684      /*
4685       * Set the OEM parameter version for the controller. This comes
4686       * from the OEM parameter block header or the registry depending
4687       * on what WCDL is set to retrieve.
4688       */
4689      this_controller->oem_parameters_version = scic_parms_version;
4690
4691      // Validate the oem parameters.  If they are not legal, then
4692      // return a failure.
4693      for(index=0; index<SCI_MAX_PORTS; index++)
4694      {
4695         if (scic_parms->sds1.ports[index].phy_mask > SCIC_SDS_PARM_PHY_MASK_MAX)
4696         {
4697            return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4698         }
4699      }
4700
4701      for(index=0; index<SCI_MAX_PHYS; index++)
4702      {
4703         if (
4704             scic_parms->sds1.phys[index].sas_address.sci_format.high == 0
4705                 && scic_parms->sds1.phys[index].sas_address.sci_format.low  == 0
4706        )
4707        {
4708            return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4709        }
4710
4711#if defined(PBG_HBA_A0_BUILD) || defined(PBG_HBA_A2_BUILD) || defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD)
4712        if (
4713              (scic_parms->sds1.phys[index].afe_tx_amp_control0 == 0) ||
4714              (scic_parms->sds1.phys[index].afe_tx_amp_control1 == 0) ||
4715              (scic_parms->sds1.phys[index].afe_tx_amp_control2 == 0) ||
4716              (scic_parms->sds1.phys[index].afe_tx_amp_control3 == 0)
4717              )
4718        {
4719           return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4720        }
4721#endif
4722      }
4723
4724      if (scic_parms->sds1.controller.mode_type == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE)
4725      {
4726         for(index=0; index<SCI_MAX_PHYS; index++)
4727         {
4728            if (scic_parms->sds1.ports[index].phy_mask != 0)
4729            {
4730               return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4731            }
4732         }
4733      }
4734      else if (scic_parms->sds1.controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE)
4735      {
4736         for(index=0; index<SCI_MAX_PHYS; index++)
4737         {
4738            combined_phy_mask |= scic_parms->sds1.ports[index].phy_mask;
4739         }
4740
4741         if (combined_phy_mask == 0)
4742         {
4743            return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4744         }
4745      }
4746      else
4747      {
4748         return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4749      }
4750
4751      if (scic_parms->sds1.controller.max_number_concurrent_device_spin_up > MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT)
4752      {
4753         return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4754      }
4755
4756      if (old_oem_params->controller.do_enable_ssc != 0)
4757      {
4758         if (  (scic_parms_version == SCI_OEM_PARAM_VER_1_0)
4759            && (old_oem_params->controller.do_enable_ssc != 0x01))
4760             return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4761
4762         if (scic_parms_version >= SCI_OEM_PARAM_VER_1_1)
4763         {
4764            SCI_BIOS_OEM_PARAM_ELEMENT_v_1_1_T *oem_params =
4765                (SCI_BIOS_OEM_PARAM_ELEMENT_v_1_1_T*)(&(scic_parms->sds1));
4766
4767            U8 test = oem_params->controller.ssc_sata_tx_spread_level;
4768            if ( !((test == 0x0) || (test == 0x2) || (test == 0x3) ||
4769                 (test == 0x6) || (test == 0x7)) )
4770                return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4771
4772            test = oem_params->controller.ssc_sas_tx_spread_level;
4773            if (oem_params->controller.ssc_sas_tx_type == 0)
4774            {
4775                if ( !((test == 0x0) || (test == 0x2) || (test == 0x3)) )
4776                    return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4777            }
4778            else
4779            if (oem_params->controller.ssc_sas_tx_type == 1)
4780            {
4781                if ( !((test == 0x0) || (test == 0x3) || (test == 0x6)) )
4782                    return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4783            }
4784         }
4785      }
4786
4787      memcpy(
4788         (&this_controller->oem_parameters), scic_parms, sizeof(*scic_parms));
4789      return SCI_SUCCESS;
4790   }
4791
4792   return SCI_FAILURE_INVALID_STATE;
4793}
4794
4795// ---------------------------------------------------------------------------
4796
4797void scic_oem_parameters_get(
4798   SCI_CONTROLLER_HANDLE_T   controller,
4799   SCIC_OEM_PARAMETERS_T   * scic_parms
4800)
4801{
4802   SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
4803
4804   memcpy(scic_parms, (&this_controller->oem_parameters), sizeof(*scic_parms));
4805}
4806
4807// ---------------------------------------------------------------------------
4808
4809#if !defined(DISABLE_INTERRUPTS)
4810
4811#define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS 853
4812#define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS 1280
4813#define INTERRUPT_COALESCE_TIMEOUT_MAX_US                    2700000
4814#define INTERRUPT_COALESCE_NUMBER_MAX                        256
4815#define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN                7
4816#define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX                28
4817
4818SCI_STATUS scic_controller_set_interrupt_coalescence(
4819   SCI_CONTROLLER_HANDLE_T controller,
4820   U32                     coalesce_number,
4821   U32                     coalesce_timeout
4822)
4823{
4824   SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4825   U8 timeout_encode = 0;
4826   U32 min = 0;
4827   U32 max = 0;
4828
4829   //Check if the input parameters fall in the range.
4830   if (coalesce_number > INTERRUPT_COALESCE_NUMBER_MAX)
4831      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4832
4833   //  Defined encoding for interrupt coalescing timeout:
4834   //              Value   Min      Max     Units
4835   //              -----   ---      ---     -----
4836   //              0       -        -       Disabled
4837   //              1       13.3     20.0    ns
4838   //              2       26.7     40.0
4839   //              3       53.3     80.0
4840   //              4       106.7    160.0
4841   //              5       213.3    320.0
4842   //              6       426.7    640.0
4843   //              7       853.3    1280.0
4844   //              8       1.7      2.6     us
4845   //              9       3.4      5.1
4846   //              10      6.8      10.2
4847   //              11      13.7     20.5
4848   //              12      27.3     41.0
4849   //              13      54.6     81.9
4850   //              14      109.2    163.8
4851   //              15      218.5    327.7
4852   //              16      436.9    655.4
4853   //              17      873.8    1310.7
4854   //              18      1.7      2.6     ms
4855   //              19      3.5      5.2
4856   //              20      7.0      10.5
4857   //              21      14.0     21.0
4858   //              22      28.0     41.9
4859   //              23      55.9     83.9
4860   //              24      111.8    167.8
4861   //              25      223.7    335.5
4862   //              26      447.4    671.1
4863   //              27      894.8    1342.2
4864   //              28      1.8      2.7     s
4865   //              Others Undefined
4866
4867   //Use the table above to decide the encode of interrupt coalescing timeout
4868   //value for register writing.
4869   if (coalesce_timeout == 0)
4870      timeout_encode = 0;
4871   else
4872   {
4873      //make the timeout value in unit of (10 ns).
4874      coalesce_timeout = coalesce_timeout * 100;
4875      min = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS / 10;
4876      max = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS / 10;
4877
4878      //get the encode of timeout for register writing.
4879      for ( timeout_encode = INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN;
4880            timeout_encode <= INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX;
4881            timeout_encode++ )
4882      {
4883         if (min <= coalesce_timeout &&  max > coalesce_timeout)
4884            break;
4885         else if (coalesce_timeout >= max && coalesce_timeout < min*2
4886            && coalesce_timeout <= INTERRUPT_COALESCE_TIMEOUT_MAX_US*100)
4887         {
4888            if ( (coalesce_timeout-max) < (2*min - coalesce_timeout) )
4889               break;
4890            else
4891            {
4892               timeout_encode++;
4893               break;
4894            }
4895         }
4896         else
4897         {
4898            max = max*2;
4899            min = min*2;
4900         }
4901      }
4902
4903      if ( timeout_encode == INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX+1 )
4904         //the value is out of range.
4905         return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4906   }
4907
4908   SMU_ICC_WRITE(
4909      scic_controller,
4910      (SMU_ICC_GEN_VAL(NUMBER, coalesce_number)|
4911       SMU_ICC_GEN_VAL(TIMER, timeout_encode))
4912   );
4913
4914   scic_controller->interrupt_coalesce_number = (U16)coalesce_number;
4915   scic_controller->interrupt_coalesce_timeout = coalesce_timeout/100;
4916
4917   return SCI_SUCCESS;
4918}
4919
4920// ---------------------------------------------------------------------------
4921
4922void scic_controller_get_interrupt_coalescence(
4923   SCI_CONTROLLER_HANDLE_T   controller,
4924   U32                     * coalesce_number,
4925   U32                     * coalesce_timeout
4926)
4927{
4928   SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4929   *coalesce_number = scic_controller->interrupt_coalesce_number;
4930   *coalesce_timeout = scic_controller->interrupt_coalesce_timeout;
4931}
4932
4933#endif // !defined(DISABLE_INTERRUPTS)
4934
4935// ---------------------------------------------------------------------------
4936
4937U32 scic_controller_get_scratch_ram_size(
4938   SCI_CONTROLLER_HANDLE_T   controller
4939)
4940{
4941   return SCU_SCRATCH_RAM_SIZE_IN_DWORDS;
4942}
4943
4944// ---------------------------------------------------------------------------
4945
4946SCI_STATUS scic_controller_read_scratch_ram_dword(
4947   SCI_CONTROLLER_HANDLE_T   controller,
4948   U32                       offset,
4949   U32                     * value
4950)
4951{
4952   U32 zpt_index;
4953   SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
4954   U32 status = SMU_SMUCSR_READ(scic_controller);
4955
4956   //Check if the SCU Scratch RAM been initialized, if not return zeros
4957   if ((status & SCU_RAM_INIT_COMPLETED) != SCU_RAM_INIT_COMPLETED)
4958   {
4959      *value = 0x00000000;
4960      return SCI_SUCCESS;
4961   }
4962
4963   if (offset < scic_controller_get_scratch_ram_size(controller))
4964   {
4965      if(offset <= SCU_MAX_ZPT_DWORD_INDEX)
4966      {
4967         zpt_index = offset + (offset - (offset % 4)) + 4;
4968
4969         *value = scu_controller_scratch_ram_register_read(scic_controller,zpt_index);
4970      }
4971      else //offset > SCU_MAX_ZPT_DWORD_INDEX
4972      {
4973         offset = offset - 132;
4974
4975         zpt_index = offset + (offset - (offset % 4)) + 4;
4976
4977         *value = scu_controller_scratch_ram_register_read_ext(scic_controller,zpt_index);
4978      }
4979
4980      return SCI_SUCCESS;
4981   }
4982   else
4983   {
4984      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
4985   }
4986}
4987
4988// ---------------------------------------------------------------------------
4989
4990SCI_STATUS scic_controller_write_scratch_ram_dword(
4991   SCI_CONTROLLER_HANDLE_T   controller,
4992   U32                       offset,
4993   U32                       value
4994)
4995{
4996   U32 zpt_index;
4997
4998   if (offset < scic_controller_get_scratch_ram_size(controller))
4999   {
5000      SCIC_SDS_CONTROLLER_T * scic_controller = (SCIC_SDS_CONTROLLER_T *)controller;
5001
5002      if(offset <= SCU_MAX_ZPT_DWORD_INDEX)
5003      {
5004         zpt_index = offset + (offset - (offset % 4)) + 4;
5005
5006         scu_controller_scratch_ram_register_write(scic_controller,zpt_index,value);
5007      }
5008      else //offset > SCU_MAX_ZPT_DWORD_INDEX
5009      {
5010         offset = offset - 132;
5011
5012         zpt_index = offset + (offset - (offset % 4)) + 4;
5013
5014         scu_controller_scratch_ram_register_write_ext(scic_controller,zpt_index,value);
5015
5016      }
5017
5018      return SCI_SUCCESS;
5019   }
5020   else
5021   {
5022      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
5023   }
5024}
5025
5026// ---------------------------------------------------------------------------
5027
5028SCI_STATUS scic_controller_suspend(
5029   SCI_CONTROLLER_HANDLE_T   controller
5030)
5031{
5032   SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
5033   U8 index;
5034
5035   // As a precaution, disable interrupts.  The user is required
5036   // to re-enable interrupts if so desired after the call.
5037   scic_controller_disable_interrupts(controller);
5038
5039   // Stop all the timers
5040   // Maybe change the states of the objects to avoid processing stuff.
5041
5042
5043   // Suspend the Ports in order to ensure no unexpected
5044   // frame reception occurs on the links from the target
5045   for (index = 0; index < SCI_MAX_PORTS; index++)
5046      scic_sds_port_suspend_port_task_scheduler(
5047         &(this_controller->port_table[index]));
5048
5049   // Disable/Reset the completion queue and unsolicited frame
5050   // queue.
5051   SMU_CQGR_WRITE(this_controller, 0x00000000);
5052   SCU_UFQGP_WRITE(this_controller, 0x00000000);
5053
5054   // Clear any interrupts that may be pending or may have been generated
5055   // by setting CQGR and CQPR back to 0
5056   SMU_ISR_WRITE(this_controller, 0xFFFFFFFF);
5057
5058   //reset the software get pointer to completion queue.
5059   this_controller->completion_queue_get = 0;
5060
5061   return SCI_SUCCESS;
5062}
5063
5064// ---------------------------------------------------------------------------
5065
5066SCI_STATUS scic_controller_resume(
5067   SCI_CONTROLLER_HANDLE_T   controller
5068)
5069{
5070   SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
5071   U8 index;
5072
5073   // Initialize the completion queue and unsolicited frame queue.
5074   scic_sds_controller_initialize_completion_queue(this_controller);
5075   scic_sds_controller_initialize_unsolicited_frame_queue(this_controller);
5076
5077   this_controller->restrict_completions = FALSE;
5078
5079   // Release the port suspensions to allow for further successful
5080   // operation.
5081   for (index = 0; index < SCI_MAX_PORTS; index++)
5082      scic_sds_port_resume_port_task_scheduler(
5083         &(this_controller->port_table[index]));
5084
5085   //check the link layer status register DWORD sync acquired bit to detect
5086   //link down event. If there is any link down event happened during controller
5087   //suspension, restart phy state machine.
5088   for (index = 0; index < SCI_MAX_PHYS; index ++)
5089   {
5090      SCIC_SDS_PHY_T * curr_phy = &this_controller->phy_table[index];
5091      U32 link_layer_status = SCU_SAS_LLSTA_READ(curr_phy);
5092
5093      if ((link_layer_status & SCU_SAS_LLSTA_DWORD_SYNCA_BIT) == 0)
5094      {
5095         //Need to put the phy back to start OOB. Then an appropriate link event
5096         //message will be send to scic user.
5097         scic_sds_phy_restart_starting_state(curr_phy);
5098      }
5099   }
5100
5101   return SCI_SUCCESS;
5102}
5103
5104// ---------------------------------------------------------------------------
5105
5106SCI_STATUS scic_controller_transition(
5107   SCI_CONTROLLER_HANDLE_T   controller,
5108   BOOL                      restrict_completions
5109)
5110{
5111   SCI_STATUS              result = SCI_FAILURE_INVALID_STATE;
5112   SCIC_SDS_CONTROLLER_T * this_controller = (SCIC_SDS_CONTROLLER_T*)controller;
5113   U8                      index;
5114
5115   SCIC_LOG_TRACE((
5116      sci_base_object_get_logger(controller),
5117      SCIC_LOG_OBJECT_CONTROLLER,
5118      "scic_controller_transition(0x%x) enter\n",
5119      controller
5120   ));
5121
5122   if (this_controller->parent.state_machine.current_state_id
5123       == SCI_BASE_CONTROLLER_STATE_READY)
5124   {
5125      // Ensure that there are no outstanding IO operations at this
5126      // time.
5127      for (index = 0; index < SCI_MAX_PORTS; index++)
5128      {
5129         if (this_controller->port_table[index].started_request_count != 0)
5130            return result;
5131      }
5132
5133      scic_controller_suspend(controller);
5134
5135      // Loop through the memory descriptor list and reprogram
5136      // the silicon memory registers accordingly.
5137      result = scic_sds_controller_validate_memory_descriptor_table(
5138                  this_controller);
5139      if (result == SCI_SUCCESS)
5140      {
5141         scic_sds_controller_ram_initialization(this_controller);
5142         this_controller->restrict_completions = restrict_completions;
5143      }
5144
5145      scic_controller_resume(controller);
5146   }
5147
5148   return result;
5149}
5150
5151// ---------------------------------------------------------------------------
5152
5153SCI_STATUS scic_controller_get_max_ports(
5154   SCI_CONTROLLER_HANDLE_T   controller,
5155   U8                      * count
5156)
5157{
5158   *count = SCI_MAX_PORTS;
5159   return SCI_SUCCESS;
5160}
5161
5162// ---------------------------------------------------------------------------
5163
5164SCI_STATUS scic_controller_get_max_phys(
5165   SCI_CONTROLLER_HANDLE_T   controller,
5166   U8                      * count
5167)
5168{
5169   *count = SCI_MAX_PHYS;
5170   return SCI_SUCCESS;
5171}
5172
5173
5174//******************************************************************************
5175//* CONTROLLER STATE MACHINE
5176//******************************************************************************
5177
5178/**
5179 * This macro returns the maximum number of logical ports supported by the
5180 * hardware. The caller passes in the value read from the device context
5181 * capacity register and this macro will mash and shift the value
5182 * appropriately.
5183 */
5184#define smu_dcc_get_max_ports(dcc_value) \
5185   ( \
5186     (    ((U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK)) \
5187       >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT ) + 1\
5188   )
5189
5190/**
5191 * This macro returns the maximum number of task contexts supported by the
5192 * hardware. The caller passes in the value read from the device context
5193 * capacity register and this macro will mash and shift the value
5194 * appropriately.
5195 */
5196#define smu_dcc_get_max_task_context(dcc_value) \
5197   ( \
5198     (   ((U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK)) \
5199       >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT ) + 1\
5200   )
5201
5202/**
5203 * This macro returns the maximum number of remote node contexts supported
5204 * by the hardware. The caller passes in the value read from the device
5205 * context capacity register and this macro will mash and shift the value
5206 * appropriately.
5207 */
5208#define smu_dcc_get_max_remote_node_context(dcc_value) \
5209   ( \
5210     (  ( (U32)((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK) )\
5211       >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT ) + 1\
5212   )
5213
5214//*****************************************************************************
5215//* DEFAULT STATE HANDLERS
5216//*****************************************************************************
5217
5218/**
5219 * This method is called when the SCIC_SDS_CONTROLLER default start
5220 * io/task handler is in place.
5221 *    - Issue a warning message
5222 *
5223 * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
5224 *       into a SCIC_SDS_CONTROLLER object.
5225 * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which, if it was
5226 *       used, would be cast to a SCIC_SDS_REMOTE_DEVICE.
5227 * @param[in] io_request This is the SCI_BASE_REQUEST which, if it was used,
5228 *       would be cast to a SCIC_SDS_IO_REQUEST.
5229 * @param[in] io_tag This is the IO tag to be assigned to the IO request or
5230 *       SCI_CONTROLLER_INVALID_IO_TAG.
5231 *
5232 * @return SCI_STATUS
5233 * @retval SCI_FAILURE_INVALID_STATE
5234 */
5235static
5236SCI_STATUS scic_sds_controller_default_start_operation_handler(
5237   SCI_BASE_CONTROLLER_T    *controller,
5238   SCI_BASE_REMOTE_DEVICE_T *remote_device,
5239   SCI_BASE_REQUEST_T       *io_request,
5240   U16                       io_tag
5241)
5242{
5243   SCIC_SDS_CONTROLLER_T *this_controller;
5244   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
5245
5246   SCIC_LOG_WARNING((
5247      sci_base_object_get_logger(this_controller),
5248      SCIC_LOG_OBJECT_CONTROLLER,
5249      "SCIC Controller requested to start an io/task from invalid state %d\n",
5250      sci_base_state_machine_get_state(
5251         scic_sds_controller_get_base_state_machine(this_controller))
5252   ));
5253
5254   return SCI_FAILURE_INVALID_STATE;
5255}
5256
5257/**
5258 * This method is called when the SCIC_SDS_CONTROLLER default
5259 * request handler is in place.
5260 *    - Issue a warning message
5261 *
5262 * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
5263 *       into a SCIC_SDS_CONTROLLER object.
5264 * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which, if it was
5265 *       used, would be cast to a SCIC_SDS_REMOTE_DEVICE.
5266 * @param[in] io_request This is the SCI_BASE_REQUEST which, if it was used,
5267 *       would be cast to a SCIC_SDS_IO_REQUEST.
5268 *
5269 * @return SCI_STATUS
5270 * @retval SCI_FAILURE_INVALID_STATE
5271 */
5272static
5273SCI_STATUS scic_sds_controller_default_request_handler(
5274   SCI_BASE_CONTROLLER_T    *controller,
5275   SCI_BASE_REMOTE_DEVICE_T *remote_device,
5276   SCI_BASE_REQUEST_T       *io_request
5277)
5278{
5279   SCIC_SDS_CONTROLLER_T *this_controller;
5280   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
5281
5282   SCIC_LOG_WARNING((
5283      sci_base_object_get_logger(this_controller),
5284      SCIC_LOG_OBJECT_CONTROLLER,
5285      "SCIC Controller request operation from invalid state %d\n",
5286      sci_base_state_machine_get_state(
5287         scic_sds_controller_get_base_state_machine(this_controller))
5288   ));
5289
5290   return SCI_FAILURE_INVALID_STATE;
5291}
5292
5293//*****************************************************************************
5294//* GENERAL (COMMON) STATE HANDLERS
5295//*****************************************************************************
5296
5297/**
5298 * This method is called when the SCIC_SDS_CONTROLLER is in the ready state
5299 * reset handler is in place.
5300 *    - Transition to SCI_BASE_CONTROLLER_STATE_RESETTING
5301 *
5302 * @param[in] controller The SCI_BASE_CONTROLLER object which is cast into a
5303 *       SCIC_SDS_CONTROLLER object.
5304 *
5305 * @return SCI_STATUS
5306 * @retval SCI_SUCCESS
5307 */
5308static
5309SCI_STATUS scic_sds_controller_general_reset_handler(
5310   SCI_BASE_CONTROLLER_T *controller
5311)
5312{
5313   SCIC_SDS_CONTROLLER_T *this_controller;
5314   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
5315
5316   SCIC_LOG_TRACE((
5317      sci_base_object_get_logger(controller),
5318      SCIC_LOG_OBJECT_CONTROLLER,
5319      "scic_sds_controller_resetting_state_enter(0x%x) enter\n",
5320      controller
5321   ));
5322
5323   //Release resource. So far only resource to be released are timers.
5324   scic_sds_controller_release_resource(this_controller);
5325
5326   // The reset operation is not a graceful cleanup just perform the state
5327   // transition.
5328   sci_base_state_machine_change_state(
5329      scic_sds_controller_get_base_state_machine(this_controller),
5330      SCI_BASE_CONTROLLER_STATE_RESETTING
5331   );
5332
5333   return SCI_SUCCESS;
5334}
5335
5336//*****************************************************************************
5337//* RESET STATE HANDLERS
5338//*****************************************************************************
5339
5340/**
5341 * This method is the SCIC_SDS_CONTROLLER initialize handler for the reset
5342 * state.
5343 *    - Currently this function does nothing
5344 *
5345 * @param[in] controller This is the SCI_BASE_CONTROLLER object which is cast
5346 *       into a SCIC_SDS_CONTROLLER object.
5347 *
5348 * @return SCI_STATUS
5349 * @retval SCI_FAILURE
5350 *
5351 * @todo This function is not yet implemented and is a valid request from the
5352 *       reset state.
5353 */
5354static
5355SCI_STATUS scic_sds_controller_reset_state_initialize_handler(
5356   SCI_BASE_CONTROLLER_T *controller
5357)
5358{
5359   U32 index;
5360   SCI_STATUS result = SCI_SUCCESS;
5361   SCIC_SDS_CONTROLLER_T *this_controller;
5362
5363   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
5364
5365   SCIC_LOG_TRACE((
5366      sci_base_object_get_logger(controller),
5367      SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
5368      "scic_sds_controller_reset_state_initialize_handler(0x%x) enter\n",
5369      controller
5370   ));
5371
5372   sci_base_state_machine_change_state(
5373      scic_sds_controller_get_base_state_machine(this_controller),
5374      SCI_BASE_CONTROLLER_STATE_INITIALIZING
5375   );
5376
5377   this_controller->timeout_timer = scic_cb_timer_create(
5378      controller,
5379      scic_sds_controller_timeout_handler,
5380      controller
5381   );
5382
5383   scic_sds_controller_initialize_power_control(this_controller);
5384
5385   /// todo: This should really be done in the reset state enter but
5386   ///       the controller has not yet been initialized before getting
5387   ///       to the reset enter state so the PCI BAR is not yet assigned
5388   scic_sds_controller_reset_hardware(this_controller);
5389
5390#if defined(ARLINGTON_BUILD)
5391   scic_sds_controller_lex_atux_initialization(this_controller);
5392#elif    defined(PLEASANT_RIDGE_BUILD) \
5393      || defined(PBG_HBA_A0_BUILD) \
5394      || defined(PBG_HBA_A2_BUILD)
5395   scic_sds_controller_afe_initialization(this_controller);
5396#elif defined(PBG_HBA_BETA_BUILD) || defined(PBG_BUILD)
5397   // There is nothing to do here for B0 since we do not have to
5398   // program the AFE registers.
5399   /// @todo The AFE settings are supposed to be correct for the B0 but
5400   ///       presently they seem to be wrong.
5401   scic_sds_controller_afe_initialization(this_controller);
5402#else  // !defined(ARLINGTON_BUILD) && !defined(PLEASANT_RIDGE_BUILD)
5403   // What other systems do we want to add here?
5404#endif // !defined(ARLINGTON_BUILD) && !defined(PLEASANT_RIDGE_BUILD)
5405
5406   if (SCI_SUCCESS == result)
5407   {
5408      U32 status;
5409      U32 terminate_loop;
5410
5411      // Take the hardware out of reset
5412      SMU_SMUSRCR_WRITE(this_controller, 0x00000000);
5413
5414      /// @todo Provide meaningfull error code for hardware failure
5415      //result = SCI_FAILURE_CONTROLLER_HARDWARE;
5416      result = SCI_FAILURE;
5417      terminate_loop = 100;
5418
5419      while (terminate_loop-- && (result != SCI_SUCCESS))
5420      {
5421         // Loop until the hardware reports success
5422         scic_cb_stall_execution(SCU_CONTEXT_RAM_INIT_STALL_TIME);
5423         status = SMU_SMUCSR_READ(this_controller);
5424
5425         if ((status & SCU_RAM_INIT_COMPLETED) == SCU_RAM_INIT_COMPLETED)
5426         {
5427            result = SCI_SUCCESS;
5428         }
5429      }
5430   }
5431
5432#ifdef ARLINGTON_BUILD
5433   scic_sds_controller_enable_chipwatch(this_controller);
5434#endif
5435
5436   if (result == SCI_SUCCESS)
5437   {
5438      U32 max_supported_ports;
5439      U32 max_supported_devices;
5440      U32 max_supported_io_requests;
5441      U32 device_context_capacity;
5442
5443      // Determine what are the actaul device capacities that the
5444      // hardware will support
5445      device_context_capacity = SMU_DCC_READ(this_controller);
5446
5447      max_supported_ports =
5448         smu_dcc_get_max_ports(device_context_capacity);
5449      max_supported_devices =
5450         smu_dcc_get_max_remote_node_context(device_context_capacity);
5451      max_supported_io_requests =
5452         smu_dcc_get_max_task_context(device_context_capacity);
5453
5454      // Make all PEs that are unassigned match up with the logical ports
5455      for (index = 0; index < max_supported_ports; index++)
5456      {
5457         scu_register_write(
5458            this_controller,
5459            this_controller->scu_registers->peg0.ptsg.protocol_engine[index],
5460            index
5461         );
5462      }
5463
5464      // Now that we have the correct hardware reported minimum values
5465      // build the MDL for the controller.  Default to a performance
5466      // configuration.
5467      scic_controller_set_mode(this_controller, SCI_MODE_SPEED);
5468
5469      // Record the smaller of the two capacity values
5470      this_controller->logical_port_entries =
5471         MIN(max_supported_ports, this_controller->logical_port_entries);
5472
5473      this_controller->task_context_entries =
5474         MIN(max_supported_io_requests, this_controller->task_context_entries);
5475
5476      this_controller->remote_node_entries =
5477         MIN(max_supported_devices, this_controller->remote_node_entries);
5478   }
5479
5480   // Initialize hardware PCI Relaxed ordering in DMA engines
5481   if (result == SCI_SUCCESS)
5482   {
5483      U32 dma_configuration;
5484
5485      // Configure the payload DMA
5486      dma_configuration = SCU_PDMACR_READ(this_controller);
5487      dma_configuration |= SCU_PDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
5488      SCU_PDMACR_WRITE(this_controller, dma_configuration);
5489
5490      // Configure the control DMA
5491      dma_configuration = SCU_CDMACR_READ(this_controller);
5492      dma_configuration |= SCU_CDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE);
5493      SCU_CDMACR_WRITE(this_controller, dma_configuration);
5494   }
5495
5496   // Initialize the PHYs before the PORTs because the PHY registers
5497   // are accessed during the port initialization.
5498   if (result == SCI_SUCCESS)
5499   {
5500      // Initialize the phys
5501      for (index = 0;
5502           (result == SCI_SUCCESS) && (index < SCI_MAX_PHYS);
5503           index++)
5504      {
5505         result = scic_sds_phy_initialize(
5506            &this_controller->phy_table[index],
5507            &this_controller->scu_registers->peg0.pe[index].tl,
5508            &this_controller->scu_registers->peg0.pe[index].ll
5509         );
5510      }
5511   }
5512
5513   //Initialize the SGPIO Unit for HARDWARE controlled SGPIO
5514   if(result == SCI_SUCCESS)
5515   {
5516      scic_sgpio_hardware_initialize(this_controller);
5517   }
5518
5519   if (result == SCI_SUCCESS)
5520   {
5521      // Initialize the logical ports
5522      for (index = 0;
5523              (index < this_controller->logical_port_entries)
5524           && (result == SCI_SUCCESS);
5525           index++)
5526      {
5527         result = scic_sds_port_initialize(
5528            &this_controller->port_table[index],
5529            &this_controller->scu_registers->peg0.ptsg.port[index],
5530            &this_controller->scu_registers->peg0.ptsg.protocol_engine,
5531            &this_controller->scu_registers->peg0.viit[index]
5532         );
5533      }
5534   }
5535
5536   if (SCI_SUCCESS == result)
5537   {
5538      result = scic_sds_port_configuration_agent_initialize(
5539                  this_controller,
5540                  &this_controller->port_agent
5541               );
5542   }
5543
5544   // Advance the controller state machine
5545   if (result == SCI_SUCCESS)
5546   {
5547      sci_base_state_machine_change_state(
5548         scic_sds_controller_get_base_state_machine(this_controller),
5549         SCI_BASE_CONTROLLER_STATE_INITIALIZED
5550      );
5551   }
5552   else
5553   {
5554      //stay in the same state and release the resource
5555      scic_sds_controller_release_resource(this_controller);
5556
5557      SCIC_LOG_TRACE((
5558         sci_base_object_get_logger(controller),
5559         SCIC_LOG_OBJECT_CONTROLLER | SCIC_LOG_OBJECT_INITIALIZATION,
5560         "Invalid Port Configuration from scic_sds_controller_reset_state_initialize_handler(0x%x) \n",
5561         controller
5562      ));
5563
5564   }
5565
5566   return result;
5567}
5568
5569//*****************************************************************************
5570//* INITIALIZED STATE HANDLERS
5571//*****************************************************************************
5572
5573/**
5574 * This method is the SCIC_SDS_CONTROLLER start handler for the initialized
5575 * state.
5576 *    - Validate we have a good memory descriptor table
5577 *    - Initialze the physical memory before programming the hardware
5578 *    - Program the SCU hardware with the physical memory addresses passed in
5579 *      the memory descriptor table.
5580 *    - Initialzie the TCi pool
5581 *    - Initialize the RNi pool
5582 *    - Initialize the completion queue
5583 *    - Initialize the unsolicited frame data
5584 *    - Take the SCU port task scheduler out of reset
5585 *    - Start the first phy object.
5586 *    - Transition to SCI_BASE_CONTROLLER_STATE_STARTING.
5587 *
5588 * @param[in] controller This is the SCI_BASE_CONTROLLER object which is cast
5589 *       into a SCIC_SDS_CONTROLLER object.
5590 * @param[in] timeout This is the allowed time for the controller object to
5591 *       reach the started state.
5592 *
5593 * @return SCI_STATUS
5594 * @retval SCI_SUCCESS if all of the controller start operations complete
5595 * @retval SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD if one or more of the
5596 *         memory descriptor fields is invalid.
5597 */
5598static
5599SCI_STATUS scic_sds_controller_initialized_state_start_handler(
5600   SCI_BASE_CONTROLLER_T * controller,
5601   U32                     timeout
5602)
5603{
5604   U16                     index;
5605   SCI_STATUS              result;
5606   SCIC_SDS_CONTROLLER_T * this_controller;
5607
5608   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
5609
5610   // Make sure that the SCI User filled in the memory descriptor table correctly
5611   result = scic_sds_controller_validate_memory_descriptor_table(this_controller);
5612
5613   if (result == SCI_SUCCESS)
5614   {
5615      // The memory descriptor list looks good so program the hardware
5616      scic_sds_controller_ram_initialization(this_controller);
5617   }
5618
5619   if (SCI_SUCCESS == result)
5620   {
5621      // Build the TCi free pool
5622      sci_pool_initialize(this_controller->tci_pool);
5623      for (index = 0; index < this_controller->task_context_entries; index++)
5624      {
5625         sci_pool_put(this_controller->tci_pool, index);
5626      }
5627
5628      // Build the RNi free pool
5629      scic_sds_remote_node_table_initialize(
5630         &this_controller->available_remote_nodes,
5631         this_controller->remote_node_entries
5632      );
5633   }
5634
5635   if (SCI_SUCCESS == result)
5636   {
5637      // Before anything else lets make sure we will not be interrupted
5638      // by the hardware.
5639      scic_controller_disable_interrupts(controller);
5640
5641      // Enable the port task scheduler
5642      scic_sds_controller_enable_port_task_scheduler(this_controller);
5643
5644      // Assign all the task entries to this controller physical function
5645      scic_sds_controller_assign_task_entries(this_controller);
5646
5647      // Now initialze the completion queue
5648      scic_sds_controller_initialize_completion_queue(this_controller);
5649
5650      // Initialize the unsolicited frame queue for use
5651      scic_sds_controller_initialize_unsolicited_frame_queue(this_controller);
5652
5653      // Setup the phy start timer
5654      result = scic_sds_controller_initialize_phy_startup(this_controller);
5655   }
5656
5657   // Start all of the ports on this controller
5658   for (
5659          index = 0;
5660          (index < this_controller->logical_port_entries) && (result == SCI_SUCCESS);
5661          index++
5662       )
5663   {
5664      result = this_controller->port_table[index].
5665         state_handlers->parent.start_handler(&this_controller->port_table[index].parent);
5666   }
5667
5668   if (SCI_SUCCESS == result)
5669   {
5670      scic_sds_controller_start_next_phy(this_controller);
5671
5672      // See if the user requested to timeout this operation.
5673      if (timeout != 0)
5674         scic_cb_timer_start(controller, this_controller->timeout_timer, timeout);
5675
5676      sci_base_state_machine_change_state(
5677         scic_sds_controller_get_base_state_machine(this_controller),
5678         SCI_BASE_CONTROLLER_STATE_STARTING
5679      );
5680   }
5681
5682   return result;
5683}
5684
5685//*****************************************************************************
5686//* STARTING STATE HANDLERS
5687//*****************************************************************************
5688
5689/**
5690 * This method is called when the SCIC_SDS_CONTROLLER is in the starting state
5691 * link up handler is called.  This method will perform the following:
5692 *    - Stop the phy timer
5693 *    - Start the next phy
5694 *    - Report the link up condition to the port object
5695 *
5696 * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the link up
5697 *       notification.
5698 * @param[in] port This is SCIC_SDS_PORT with which the phy is associated.
5699 * @param[in] phy This is the SCIC_SDS_PHY which has gone link up.
5700 *
5701 * @return none
5702 */
5703static
5704void scic_sds_controller_starting_state_link_up_handler(
5705   SCIC_SDS_CONTROLLER_T *this_controller,
5706   SCIC_SDS_PORT_T       *port,
5707   SCIC_SDS_PHY_T        *phy
5708)
5709{
5710   scic_sds_controller_phy_timer_stop(this_controller);
5711
5712   this_controller->port_agent.link_up_handler(
5713      this_controller, &this_controller->port_agent, port, phy
5714   );
5715   //scic_sds_port_link_up(port, phy);
5716
5717   scic_sds_controller_start_next_phy(this_controller);
5718}
5719
5720/**
5721 * This method is called when the SCIC_SDS_CONTROLLER is in the starting state
5722 * link down handler is called.
5723 *    - Report the link down condition to the port object
5724 *
5725 * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the
5726 *       link down notification.
5727 * @param[in] port This is SCIC_SDS_PORT with which the phy is associated.
5728 * @param[in] phy This is the SCIC_SDS_PHY which has gone link down.
5729 *
5730 * @return none
5731 */
5732static
5733void scic_sds_controller_starting_state_link_down_handler(
5734   SCIC_SDS_CONTROLLER_T *this_controller,
5735   SCIC_SDS_PORT_T       *port,
5736   SCIC_SDS_PHY_T        *phy
5737)
5738{
5739   this_controller->port_agent.link_down_handler(
5740      this_controller, &this_controller->port_agent, port, phy
5741   );
5742   //scic_sds_port_link_down(port, phy);
5743}
5744
5745//*****************************************************************************
5746//* READY STATE HANDLERS
5747//*****************************************************************************
5748
5749/**
5750 * This method is called when the SCIC_SDS_CONTROLLER is in the ready state
5751 * stop handler is called.
5752 *    - Start the timeout timer
5753 *    - Transition to SCI_BASE_CONTROLLER_STATE_STOPPING.
5754 *
5755 * @param[in] controller The SCI_BASE_CONTROLLER object which is cast into a
5756 *       SCIC_SDS_CONTROLLER object.
5757 * @param[in] timeout The timeout for when the stop operation should report a
5758 *       failure.
5759 *
5760 * @return SCI_STATUS
5761 * @retval SCI_SUCCESS
5762 */
5763static
5764SCI_STATUS scic_sds_controller_ready_state_stop_handler(
5765   SCI_BASE_CONTROLLER_T *controller,
5766   U32                   timeout
5767)
5768{
5769   SCIC_SDS_CONTROLLER_T *this_controller;
5770   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
5771
5772   // See if the user requested to timeout this operation
5773   if (timeout != 0)
5774      scic_cb_timer_start(controller, this_controller->timeout_timer, timeout);
5775
5776   sci_base_state_machine_change_state(
5777      scic_sds_controller_get_base_state_machine(this_controller),
5778      SCI_BASE_CONTROLLER_STATE_STOPPING
5779   );
5780
5781   return SCI_SUCCESS;
5782}
5783
5784/**
5785 * This method is called when the SCIC_SDS_CONTROLLER is in the ready state
5786 * and the start io handler is called.
5787 *    - Start the io request on the remote device
5788 *    - if successful
5789 *       - assign the io_request to the io_request_table
5790 *       - post the request to the hardware
5791 *
5792 * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
5793 *       into a SCIC_SDS_CONTROLLER object.
5794 * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
5795 *       SCIC_SDS_REMOTE_DEVICE object.
5796 * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
5797 *       SCIC_SDS_IO_REQUEST object.
5798 * @param[in] io_tag This is the IO tag to be assigned to the IO request or
5799 *       SCI_CONTROLLER_INVALID_IO_TAG.
5800 *
5801 * @return SCI_STATUS
5802 * @retval SCI_SUCCESS if the start io operation succeeds
5803 * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES if the IO tag could not be
5804 *         allocated for the io request.
5805 * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid
5806 *         state to accept io requests.
5807 *
5808 * @todo How does the io_tag parameter get assigned to the io request?
5809 */
5810static
5811SCI_STATUS scic_sds_controller_ready_state_start_io_handler(
5812   SCI_BASE_CONTROLLER_T    *controller,
5813   SCI_BASE_REMOTE_DEVICE_T *remote_device,
5814   SCI_BASE_REQUEST_T       *io_request,
5815   U16                       io_tag
5816)
5817{
5818   SCI_STATUS status;
5819
5820   SCIC_SDS_CONTROLLER_T    *this_controller;
5821   SCIC_SDS_REQUEST_T       *the_request;
5822   SCIC_SDS_REMOTE_DEVICE_T *the_device;
5823
5824   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
5825   the_request = (SCIC_SDS_REQUEST_T *)io_request;
5826   the_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
5827
5828   status = scic_sds_remote_device_start_io(this_controller, the_device, the_request);
5829
5830   if (status == SCI_SUCCESS)
5831   {
5832      this_controller->io_request_table[
5833            scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
5834
5835      scic_sds_controller_post_request(
5836         this_controller,
5837         scic_sds_request_get_post_context(the_request)
5838      );
5839   }
5840
5841   return status;
5842}
5843
5844/**
5845 * This method is called when the SCIC_SDS_CONTROLLER is in the ready state
5846 * and the complete io handler is called.
5847 *    - Complete the io request on the remote device
5848 *    - if successful
5849 *       - remove the io_request to the io_request_table
5850 *
5851 * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
5852 *       into a SCIC_SDS_CONTROLLER object.
5853 * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
5854 *       SCIC_SDS_REMOTE_DEVICE object.
5855 * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
5856 *       SCIC_SDS_IO_REQUEST object.
5857 *
5858 * @return SCI_STATUS
5859 * @retval SCI_SUCCESS if the start io operation succeeds
5860 * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid
5861 *         state to accept io requests.
5862 */
5863static
5864SCI_STATUS scic_sds_controller_ready_state_complete_io_handler(
5865   SCI_BASE_CONTROLLER_T    *controller,
5866   SCI_BASE_REMOTE_DEVICE_T *remote_device,
5867   SCI_BASE_REQUEST_T       *io_request
5868)
5869{
5870   U16        index;
5871   SCI_STATUS status;
5872   SCIC_SDS_CONTROLLER_T    *this_controller;
5873   SCIC_SDS_REQUEST_T       *the_request;
5874   SCIC_SDS_REMOTE_DEVICE_T *the_device;
5875
5876   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
5877   the_request = (SCIC_SDS_REQUEST_T *)io_request;
5878   the_device = (SCIC_SDS_REMOTE_DEVICE_T *)remote_device;
5879
5880   status = scic_sds_remote_device_complete_io(
5881                  this_controller, the_device, the_request);
5882
5883   if (status == SCI_SUCCESS)
5884   {
5885      index = scic_sds_io_tag_get_index(the_request->io_tag);
5886      this_controller->io_request_table[index] = SCI_INVALID_HANDLE;
5887   }
5888
5889   return status;
5890}
5891
5892/**
5893 * This method is called when the SCIC_SDS_CONTROLLER is in the ready state
5894 * and the continue io handler is called.
5895 *
5896 * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
5897 *       into a SCIC_SDS_CONTROLLER object.
5898 * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
5899 *       SCIC_SDS_REMOTE_DEVICE object.
5900 * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
5901 *       SCIC_SDS_IO_REQUEST object.
5902 *
5903 * @return SCI_STATUS
5904 */
5905static
5906SCI_STATUS scic_sds_controller_ready_state_continue_io_handler(
5907   SCI_BASE_CONTROLLER_T    *controller,
5908   SCI_BASE_REMOTE_DEVICE_T *remote_device,
5909   SCI_BASE_REQUEST_T       *io_request
5910)
5911{
5912   SCIC_SDS_CONTROLLER_T *this_controller;
5913   SCIC_SDS_REQUEST_T    *the_request;
5914
5915   the_request     = (SCIC_SDS_REQUEST_T *)io_request;
5916   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
5917
5918   this_controller->io_request_table[
5919      scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
5920
5921   scic_sds_controller_post_request(
5922      this_controller,
5923      scic_sds_request_get_post_context(the_request)
5924   );
5925
5926   return SCI_SUCCESS;
5927}
5928
5929/**
5930 * This method is called when the SCIC_SDS_CONTROLLER is in the ready state
5931 * and the start task handler is called.
5932 *    - The remote device is requested to start the task request
5933 *    - if successful
5934 *       - assign the task to the io_request_table
5935 *       - post the request to the SCU hardware
5936 *
5937 * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
5938 *       into a SCIC_SDS_CONTROLLER object.
5939 * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
5940 *       SCIC_SDS_REMOTE_DEVICE object.
5941 * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
5942 *       SCIC_SDS_IO_REQUEST object.
5943 * @param[in] task_tag This is the task tag to be assigned to the task request
5944 *       or SCI_CONTROLLER_INVALID_IO_TAG.
5945 *
5946 * @return SCI_STATUS
5947 * @retval SCI_SUCCESS if the start io operation succeeds
5948 * @retval SCI_FAILURE_INSUFFICIENT_RESOURCES if the IO tag could not be
5949 *         allocated for the io request.
5950 * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid
5951 *         state to accept io requests.
5952 *
5953 * @todo How does the io tag get assigned in this code path?
5954 */
5955static
5956SCI_STATUS scic_sds_controller_ready_state_start_task_handler(
5957   SCI_BASE_CONTROLLER_T    *controller,
5958   SCI_BASE_REMOTE_DEVICE_T *remote_device,
5959   SCI_BASE_REQUEST_T       *io_request,
5960   U16                       task_tag
5961)
5962{
5963   SCIC_SDS_CONTROLLER_T    *this_controller = (SCIC_SDS_CONTROLLER_T *)
5964                                               controller;
5965   SCIC_SDS_REQUEST_T       *the_request     = (SCIC_SDS_REQUEST_T *)
5966                                               io_request;
5967   SCIC_SDS_REMOTE_DEVICE_T *the_device      = (SCIC_SDS_REMOTE_DEVICE_T *)
5968                                               remote_device;
5969   SCI_STATUS                status;
5970
5971   status = scic_sds_remote_device_start_task(
5972               this_controller, the_device, the_request
5973            );
5974
5975   if (status == SCI_SUCCESS)
5976   {
5977      this_controller->io_request_table[
5978         scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
5979
5980      scic_sds_controller_post_request(
5981         this_controller,
5982         scic_sds_request_get_post_context(the_request)
5983      );
5984   }
5985   else if (status == SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS)
5986   {
5987      this_controller->io_request_table[
5988         scic_sds_io_tag_get_index(the_request->io_tag)] = the_request;
5989
5990      //We will let framework know this task request started successfully,
5991      //although core is still woring on starting the request (to post tc when
5992      //RNC is resumed.)
5993      status = SCI_SUCCESS;
5994   }
5995   return status;
5996}
5997
5998/**
5999 * This method is called when the SCIC_SDS_CONTROLLER is in the ready state
6000 * and the terminate request handler is called.
6001 *    - call the io request terminate function
6002 *    - if successful
6003 *       - post the terminate request to the SCU hardware
6004 *
6005 * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
6006 *       into a SCIC_SDS_CONTROLLER object.
6007 * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
6008 *       SCIC_SDS_REMOTE_DEVICE object.
6009 * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
6010 *       SCIC_SDS_IO_REQUEST object.
6011 *
6012 * @return SCI_STATUS
6013 * @retval SCI_SUCCESS if the start io operation succeeds
6014 * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid
6015 *         state to accept io requests.
6016 */
6017static
6018SCI_STATUS scic_sds_controller_ready_state_terminate_request_handler(
6019   SCI_BASE_CONTROLLER_T    *controller,
6020   SCI_BASE_REMOTE_DEVICE_T *remote_device,
6021   SCI_BASE_REQUEST_T       *io_request
6022)
6023{
6024   SCIC_SDS_CONTROLLER_T    *this_controller = (SCIC_SDS_CONTROLLER_T *)
6025                                               controller;
6026   SCIC_SDS_REQUEST_T       *the_request     = (SCIC_SDS_REQUEST_T *)
6027                                               io_request;
6028   SCI_STATUS                status;
6029
6030   status = scic_sds_io_request_terminate(the_request);
6031   if (status == SCI_SUCCESS)
6032   {
6033      // Utilize the original post context command and or in the POST_TC_ABORT
6034      // request sub-type.
6035      scic_sds_controller_post_request(
6036         this_controller,
6037         scic_sds_request_get_post_context(the_request)
6038         | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT
6039      );
6040   }
6041
6042   return status;
6043}
6044
6045/**
6046 * This method is called when the SCIC_SDS_CONTROLLER is in the starting state
6047 * link up handler is called.  This method will perform the following:
6048 *    - Stop the phy timer
6049 *    - Start the next phy
6050 *    - Report the link up condition to the port object
6051 *
6052 * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the link up
6053 *       notification.
6054 * @param[in] port This is SCIC_SDS_PORT with which the phy is associated.
6055 * @param[in] phy This is the SCIC_SDS_PHY which has gone link up.
6056 *
6057 * @return none
6058 */
6059static
6060void scic_sds_controller_ready_state_link_up_handler(
6061   SCIC_SDS_CONTROLLER_T *this_controller,
6062   SCIC_SDS_PORT_T       *port,
6063   SCIC_SDS_PHY_T        *phy
6064)
6065{
6066   this_controller->port_agent.link_up_handler(
6067      this_controller, &this_controller->port_agent, port, phy
6068   );
6069}
6070
6071/**
6072 * This method is called when the SCIC_SDS_CONTROLLER is in the starting state
6073 * link down handler is called.
6074 *    - Report the link down condition to the port object
6075 *
6076 * @param[in] controller This is SCIC_SDS_CONTROLLER which receives the
6077 *       link down notification.
6078 * @param[in] port This is SCIC_SDS_PORT with which the phy is associated.
6079 * @param[in] phy This is the SCIC_SDS_PHY which has gone link down.
6080 *
6081 * @return none
6082 */
6083static
6084void scic_sds_controller_ready_state_link_down_handler(
6085   SCIC_SDS_CONTROLLER_T *this_controller,
6086   SCIC_SDS_PORT_T       *port,
6087   SCIC_SDS_PHY_T        *phy
6088)
6089{
6090   this_controller->port_agent.link_down_handler(
6091      this_controller, &this_controller->port_agent, port, phy
6092   );
6093}
6094
6095//*****************************************************************************
6096//* STOPPING STATE HANDLERS
6097//*****************************************************************************
6098
6099/**
6100 * This method is called when the SCIC_SDS_CONTROLLER is in a stopping state
6101 * and the complete io handler is called.
6102 *    - This function is not yet implemented
6103 *
6104 * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
6105 *       into a SCIC_SDS_CONTROLLER object.
6106 * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
6107 *       SCIC_SDS_REMOTE_DEVICE object.
6108 * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
6109 *       SCIC_SDS_IO_REQUEST object.
6110 *
6111 * @return SCI_STATUS
6112 * @retval SCI_FAILURE
6113 */
6114static
6115SCI_STATUS scic_sds_controller_stopping_state_complete_io_handler(
6116   SCI_BASE_CONTROLLER_T    *controller,
6117   SCI_BASE_REMOTE_DEVICE_T *remote_device,
6118   SCI_BASE_REQUEST_T       *io_request
6119)
6120{
6121   SCIC_SDS_CONTROLLER_T *this_controller;
6122   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
6123
6124   /// @todo Implement this function
6125   return SCI_FAILURE;
6126}
6127
6128/**
6129 * This method is called when the SCIC_SDS_CONTROLLER is in a stopping state
6130 * and the a remote device has stopped.
6131 *
6132 * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
6133 *       into a SCIC_SDS_CONTROLLER object.
6134 * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
6135 *       SCIC_SDS_REMOTE_DEVICE object.
6136 *
6137 * @return none
6138 */
6139static
6140void scic_sds_controller_stopping_state_device_stopped_handler(
6141   SCIC_SDS_CONTROLLER_T    * controller,
6142   SCIC_SDS_REMOTE_DEVICE_T * remote_device
6143)
6144{
6145   if (!scic_sds_controller_has_remote_devices_stopping(controller))
6146   {
6147      sci_base_state_machine_change_state(
6148         &controller->parent.state_machine,
6149         SCI_BASE_CONTROLLER_STATE_STOPPED
6150      );
6151   }
6152}
6153
6154//*****************************************************************************
6155//* STOPPED STATE HANDLERS
6156//*****************************************************************************
6157
6158//*****************************************************************************
6159//* FAILED STATE HANDLERS
6160//*****************************************************************************
6161
6162/**
6163 * This method is called when the SCIC_SDS_CONTROLLER failed state start
6164 * io/task handler is in place.
6165 *    - Issue a warning message
6166 *
6167 * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
6168 *       into a SCIC_SDS_CONTROLLER object.
6169 * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which, if it was
6170 *       used, would be cast to a SCIC_SDS_REMOTE_DEVICE.
6171 * @param[in] io_request This is the SCI_BASE_REQUEST which, if it was used,
6172 *       would be cast to a SCIC_SDS_IO_REQUEST.
6173 * @param[in] io_tag This is the IO tag to be assigned to the IO request or
6174 *       SCI_CONTROLLER_INVALID_IO_TAG.
6175 *
6176 * @return SCI_FAILURE
6177 * @retval SCI_FAILURE
6178 */
6179static
6180SCI_STATUS scic_sds_controller_failed_state_start_operation_handler(
6181   SCI_BASE_CONTROLLER_T    *controller,
6182   SCI_BASE_REMOTE_DEVICE_T *remote_device,
6183   SCI_BASE_REQUEST_T       *io_request,
6184   U16                       io_tag
6185)
6186{
6187   SCIC_SDS_CONTROLLER_T *this_controller;
6188   this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
6189
6190   SCIC_LOG_WARNING((
6191      sci_base_object_get_logger(this_controller),
6192      SCIC_LOG_OBJECT_CONTROLLER,
6193      "SCIC Controller requested to start an io/task from failed state %d\n",
6194      sci_base_state_machine_get_state(
6195         scic_sds_controller_get_base_state_machine(this_controller))
6196   ));
6197
6198   return SCI_FAILURE;
6199}
6200
6201/**
6202 * This method is called when the SCIC_SDS_CONTROLLER is in the failed state
6203 * reset handler is in place.
6204 *    - Transition to SCI_BASE_CONTROLLER_STATE_RESETTING
6205 *
6206 * @param[in] controller The SCI_BASE_CONTROLLER object which is cast into a
6207 *       SCIC_SDS_CONTROLLER object.
6208 *
6209 * @return SCI_STATUS
6210 * @retval SCI_FAILURE if fatal memory error occurred
6211 */
6212static
6213SCI_STATUS scic_sds_controller_failed_state_reset_handler(
6214   SCI_BASE_CONTROLLER_T *controller
6215)
6216{
6217    SCIC_SDS_CONTROLLER_T *this_controller;
6218    this_controller = (SCIC_SDS_CONTROLLER_T *)controller;
6219
6220    if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR) {
6221        SCIC_LOG_TRACE((
6222           sci_base_object_get_logger(controller),
6223           SCIC_LOG_OBJECT_CONTROLLER,
6224           "scic_sds_controller_resetting_state_enter(0x%x) enter\n not allowed with fatal memory error",
6225           controller
6226        ));
6227
6228        return SCI_FAILURE;
6229    } else {
6230        return scic_sds_controller_general_reset_handler(controller);
6231    }
6232}
6233
6234/**
6235 * This method is called when the SCIC_SDS_CONTROLLER is in the failed state
6236 * and the terminate request handler is called.
6237 *    - call the io request terminate function
6238 *    - if successful
6239 *       - post the terminate request to the SCU hardware
6240 *
6241 * @param[in] controller This is SCI_BASE_CONTROLLER object which is cast
6242 *       into a SCIC_SDS_CONTROLLER object.
6243 * @param[in] remote_device This is SCI_BASE_REMOTE_DEVICE which is cast to a
6244 *       SCIC_SDS_REMOTE_DEVICE object.
6245 * @param[in] io_request This is the SCI_BASE_REQUEST which is cast to a
6246 *       SCIC_SDS_IO_REQUEST object.
6247 *
6248 * @return SCI_STATUS
6249 * @retval SCI_SUCCESS if the start io operation succeeds
6250 * @retval SCI_FAILURE_INVALID_STATE if one or more objects are not in a valid
6251 *         state to accept io requests.
6252 */
6253static
6254SCI_STATUS scic_sds_controller_failed_state_terminate_request_handler(
6255   SCI_BASE_CONTROLLER_T    *controller,
6256   SCI_BASE_REMOTE_DEVICE_T *remote_device,
6257   SCI_BASE_REQUEST_T       *io_request
6258)
6259{
6260   SCIC_SDS_REQUEST_T       *the_request     = (SCIC_SDS_REQUEST_T *)
6261                                               io_request;
6262
6263   return scic_sds_io_request_terminate(the_request);
6264}
6265
6266SCIC_SDS_CONTROLLER_STATE_HANDLER_T
6267   scic_sds_controller_state_handler_table[SCI_BASE_CONTROLLER_MAX_STATES] =
6268{
6269   // SCI_BASE_CONTROLLER_STATE_INITIAL
6270   {
6271      {
6272         NULL,
6273         NULL,
6274         NULL,
6275         NULL,
6276         scic_sds_controller_default_start_operation_handler,
6277         scic_sds_controller_default_start_operation_handler,
6278         scic_sds_controller_default_request_handler,
6279         scic_sds_controller_default_request_handler,
6280         scic_sds_controller_default_request_handler,
6281         NULL,
6282         NULL
6283      },
6284      scic_sds_controller_default_request_handler,
6285      NULL,
6286      NULL,
6287      NULL,
6288      NULL
6289   },
6290   // SCI_BASE_CONTROLLER_STATE_RESET
6291   {
6292      {
6293         NULL,
6294         NULL,
6295         NULL,
6296         scic_sds_controller_reset_state_initialize_handler,
6297         scic_sds_controller_default_start_operation_handler,
6298         scic_sds_controller_default_start_operation_handler,
6299         scic_sds_controller_default_request_handler,
6300         scic_sds_controller_default_request_handler,
6301         scic_sds_controller_default_request_handler,
6302         NULL,
6303         NULL
6304      },
6305      scic_sds_controller_default_request_handler,
6306      NULL,
6307      NULL,
6308      NULL,
6309      NULL
6310   },
6311   // SCI_BASE_CONTROLLER_STATE_INITIALIZING
6312   {
6313      {
6314         NULL,
6315         NULL,
6316         NULL,
6317         NULL,
6318         scic_sds_controller_default_start_operation_handler,
6319         scic_sds_controller_default_start_operation_handler,
6320         scic_sds_controller_default_request_handler,
6321         scic_sds_controller_default_request_handler,
6322         scic_sds_controller_default_request_handler,
6323         NULL,
6324         NULL
6325      },
6326      scic_sds_controller_default_request_handler,
6327      NULL,
6328      NULL,
6329      NULL,
6330      NULL
6331   },
6332   // SCI_BASE_CONTROLLER_STATE_INITIALIZED
6333   {
6334      {
6335         scic_sds_controller_initialized_state_start_handler,
6336         NULL,
6337         NULL,
6338         NULL,
6339         scic_sds_controller_default_start_operation_handler,
6340         scic_sds_controller_default_start_operation_handler,
6341         scic_sds_controller_default_request_handler,
6342         scic_sds_controller_default_request_handler,
6343         scic_sds_controller_default_request_handler,
6344         NULL,
6345         NULL
6346      },
6347      scic_sds_controller_default_request_handler,
6348      NULL,
6349      NULL,
6350      NULL,
6351      NULL
6352   },
6353   // SCI_BASE_CONTROLLER_STATE_STARTING
6354   {
6355      {
6356         NULL,
6357         NULL,
6358         NULL,
6359         NULL,
6360         scic_sds_controller_default_start_operation_handler,
6361         scic_sds_controller_default_start_operation_handler,
6362         scic_sds_controller_default_request_handler,
6363         scic_sds_controller_default_request_handler,
6364         scic_sds_controller_default_request_handler,
6365         NULL,
6366         NULL
6367      },
6368      scic_sds_controller_default_request_handler,
6369      scic_sds_controller_starting_state_link_up_handler,
6370      scic_sds_controller_starting_state_link_down_handler,
6371      NULL,
6372      NULL
6373   },
6374   // SCI_BASE_CONTROLLER_STATE_READY
6375   {
6376      {
6377         NULL,
6378         scic_sds_controller_ready_state_stop_handler,
6379         scic_sds_controller_general_reset_handler,
6380         NULL,
6381         scic_sds_controller_ready_state_start_io_handler,
6382         scic_sds_controller_default_start_operation_handler,
6383         scic_sds_controller_ready_state_complete_io_handler,
6384         scic_sds_controller_default_request_handler,
6385         scic_sds_controller_ready_state_continue_io_handler,
6386         scic_sds_controller_ready_state_start_task_handler,
6387         scic_sds_controller_ready_state_complete_io_handler
6388      },
6389      scic_sds_controller_ready_state_terminate_request_handler,
6390      scic_sds_controller_ready_state_link_up_handler,
6391      scic_sds_controller_ready_state_link_down_handler,
6392      NULL,
6393      NULL
6394   },
6395   // SCI_BASE_CONTROLLER_STATE_RESETTING
6396   {
6397      {
6398         NULL,
6399         NULL,
6400         NULL,
6401         NULL,
6402         scic_sds_controller_default_start_operation_handler,
6403         scic_sds_controller_default_start_operation_handler,
6404         scic_sds_controller_default_request_handler,
6405         scic_sds_controller_default_request_handler,
6406         scic_sds_controller_default_request_handler,
6407         NULL,
6408         NULL
6409      },
6410      scic_sds_controller_default_request_handler,
6411      NULL,
6412      NULL,
6413      NULL,
6414      NULL
6415   },
6416   // SCI_BASE_CONTROLLER_STATE_STOPPING
6417   {
6418      {
6419         NULL,
6420         NULL,
6421         NULL,
6422         NULL,
6423         scic_sds_controller_default_start_operation_handler,
6424         scic_sds_controller_default_start_operation_handler,
6425         scic_sds_controller_stopping_state_complete_io_handler,
6426         scic_sds_controller_default_request_handler,
6427         scic_sds_controller_default_request_handler,
6428         NULL,
6429         NULL
6430      },
6431      scic_sds_controller_default_request_handler,
6432      NULL,
6433      NULL,
6434      NULL,
6435      scic_sds_controller_stopping_state_device_stopped_handler
6436   },
6437   // SCI_BASE_CONTROLLER_STATE_STOPPED
6438   {
6439      {
6440         NULL,
6441         NULL,
6442         scic_sds_controller_failed_state_reset_handler,
6443         NULL,
6444         scic_sds_controller_default_start_operation_handler,
6445         scic_sds_controller_default_start_operation_handler,
6446         scic_sds_controller_default_request_handler,
6447         scic_sds_controller_default_request_handler,
6448         scic_sds_controller_default_request_handler,
6449         NULL,
6450         NULL
6451      },
6452      scic_sds_controller_default_request_handler,
6453      NULL,
6454      NULL,
6455      NULL,
6456      NULL
6457   },
6458   // SCI_BASE_CONTROLLER_STATE_FAILED
6459   {
6460      {
6461         NULL,
6462         NULL,
6463         scic_sds_controller_general_reset_handler,
6464         NULL,
6465         scic_sds_controller_failed_state_start_operation_handler,
6466         scic_sds_controller_failed_state_start_operation_handler,
6467         scic_sds_controller_default_request_handler,
6468         scic_sds_controller_default_request_handler,
6469         scic_sds_controller_default_request_handler,
6470         NULL,
6471         NULL
6472      },
6473      scic_sds_controller_failed_state_terminate_request_handler,
6474      NULL,
6475      NULL,
6476      NULL
6477   }
6478};
6479
6480/**
6481 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
6482 * entry to the SCI_BASE_CONTROLLER_STATE_INITIAL.
6483 *    - Set the state handlers to the controllers initial state.
6484 *
6485 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6486 *       SCIC_SDS_CONTROLLER object.
6487 *
6488 * @return none
6489 *
6490 * @todo This function should initialze the controller object.
6491 */
6492static
6493void scic_sds_controller_initial_state_enter(
6494   SCI_BASE_OBJECT_T *object
6495)
6496{
6497   SCIC_SDS_CONTROLLER_T *this_controller;
6498   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6499
6500   scic_sds_controller_set_base_state_handlers(
6501      this_controller, SCI_BASE_CONTROLLER_STATE_INITIAL);
6502
6503   sci_base_state_machine_change_state(
6504      &this_controller->parent.state_machine, SCI_BASE_CONTROLLER_STATE_RESET);
6505}
6506
6507/**
6508 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
6509 * entry to the SCI_BASE_CONTROLLER_STATE_RESET.
6510 *    - Set the state handlers to the controllers reset state.
6511 *
6512 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6513 *       SCIC_SDS_CONTROLLER object.
6514 *
6515 * @return none
6516 */
6517static
6518void scic_sds_controller_reset_state_enter(
6519   SCI_BASE_OBJECT_T *object
6520)
6521{
6522   U8 index;
6523   SCIC_SDS_CONTROLLER_T *this_controller;
6524   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6525
6526   scic_sds_controller_set_base_state_handlers(
6527      this_controller, SCI_BASE_CONTROLLER_STATE_RESET);
6528
6529   scic_sds_port_configuration_agent_construct(&this_controller->port_agent);
6530
6531   // Construct the ports for this controller
6532   for (index = 0; index < (SCI_MAX_PORTS + 1); index++)
6533   {
6534      scic_sds_port_construct(
6535         &this_controller->port_table[index],
6536         (index == SCI_MAX_PORTS) ? SCIC_SDS_DUMMY_PORT : index,
6537         this_controller
6538      );
6539   }
6540
6541   // Construct the phys for this controller
6542   for (index = 0; index < SCI_MAX_PHYS; index++)
6543   {
6544      // Add all the PHYs to the dummy port
6545      scic_sds_phy_construct(
6546         &this_controller->phy_table[index],
6547         &this_controller->port_table[SCI_MAX_PORTS],
6548         index
6549      );
6550   }
6551
6552   this_controller->invalid_phy_mask = 0;
6553
6554   // Set the default maximum values
6555   this_controller->completion_event_entries      = SCU_EVENT_COUNT;
6556   this_controller->completion_queue_entries      = SCU_COMPLETION_QUEUE_COUNT;
6557   this_controller->remote_node_entries           = SCI_MAX_REMOTE_DEVICES;
6558   this_controller->logical_port_entries          = SCI_MAX_PORTS;
6559   this_controller->task_context_entries          = SCU_IO_REQUEST_COUNT;
6560   this_controller->uf_control.buffers.count      = SCU_UNSOLICITED_FRAME_COUNT;
6561   this_controller->uf_control.address_table.count= SCU_UNSOLICITED_FRAME_COUNT;
6562
6563   // Initialize the User and OEM parameters to default values.
6564   scic_sds_controller_set_default_config_parameters(this_controller);
6565}
6566
6567/**
6568 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
6569 * entry to the SCI_BASE_CONTROLLER_STATE_INITIALIZING.
6570 *    - Set the state handlers to the controllers initializing state.
6571 *
6572 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6573 *       SCIC_SDS_CONTROLLER object.
6574 *
6575 * @return none
6576 */
6577static
6578void scic_sds_controller_initializing_state_enter(
6579   SCI_BASE_OBJECT_T *object
6580)
6581{
6582   SCIC_SDS_CONTROLLER_T *this_controller;
6583   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6584
6585   scic_sds_controller_set_base_state_handlers(
6586      this_controller, SCI_BASE_CONTROLLER_STATE_INITIALIZING);
6587}
6588
6589/**
6590 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
6591 * entry to the SCI_BASE_CONTROLLER_STATE_INITIALIZED.
6592 *    - Set the state handlers to the controllers initialized state.
6593 *
6594 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6595 *       SCIC_SDS_CONTROLLER object.
6596 *
6597 * @return none
6598 */
6599static
6600void scic_sds_controller_initialized_state_enter(
6601   SCI_BASE_OBJECT_T *object
6602)
6603{
6604   SCIC_SDS_CONTROLLER_T *this_controller;
6605   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6606
6607   scic_sds_controller_set_base_state_handlers(
6608      this_controller, SCI_BASE_CONTROLLER_STATE_INITIALIZED);
6609}
6610
6611/**
6612 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
6613 * entry to the SCI_BASE_CONTROLLER_STATE_STARTING.
6614 *    - Set the state handlers to the controllers starting state.
6615 *
6616 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6617 *       SCIC_SDS_CONTROLLER object.
6618 *
6619 * @return none
6620 */
6621static
6622void scic_sds_controller_starting_state_enter(
6623   SCI_BASE_OBJECT_T *object
6624)
6625{
6626   SCIC_SDS_CONTROLLER_T *this_controller;
6627   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6628
6629   scic_sds_controller_set_base_state_handlers(
6630      this_controller, SCI_BASE_CONTROLLER_STATE_STARTING);
6631
6632}
6633
6634/**
6635 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on exit
6636 * from the SCI_BASE_CONTROLLER_STATE_STARTING.
6637 *    - This function stops the controller starting timeout timer.
6638 *
6639 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6640 *       SCIC_SDS_CONTROLLER object.
6641 *
6642 * @return none
6643 */
6644static
6645void scic_sds_controller_starting_state_exit(
6646   SCI_BASE_OBJECT_T *object
6647)
6648{
6649   SCIC_SDS_CONTROLLER_T *this_controller;
6650   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6651
6652   scic_cb_timer_stop(object, this_controller->timeout_timer);
6653
6654   // We are done with this timer since we are exiting the starting
6655   // state so remove it
6656   scic_cb_timer_destroy(
6657      this_controller,
6658      this_controller->phy_startup_timer
6659   );
6660
6661   this_controller->phy_startup_timer = NULL;
6662}
6663
6664/**
6665 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
6666 * entry to the SCI_BASE_CONTROLLER_STATE_READY.
6667 *    - Set the state handlers to the controllers ready state.
6668 *
6669 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6670 *       SCIC_SDS_CONTROLLER object.
6671 *
6672 * @return none
6673 */
6674static
6675void scic_sds_controller_ready_state_enter(
6676   SCI_BASE_OBJECT_T *object
6677)
6678{
6679   U32 clock_gating_unit_value;
6680   SCIC_SDS_CONTROLLER_T *this_controller;
6681   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6682
6683   scic_sds_controller_set_base_state_handlers(
6684      this_controller, SCI_BASE_CONTROLLER_STATE_READY);
6685
6686   /**
6687    * enable clock gating for power control of the scu unit
6688    */
6689   clock_gating_unit_value = SMU_CGUCR_READ(this_controller);
6690
6691   clock_gating_unit_value &= ~( SMU_CGUCR_GEN_BIT(REGCLK_ENABLE)
6692                               | SMU_CGUCR_GEN_BIT(TXCLK_ENABLE)
6693                               | SMU_CGUCR_GEN_BIT(XCLK_ENABLE) );
6694   clock_gating_unit_value |= SMU_CGUCR_GEN_BIT(IDLE_ENABLE);
6695
6696   SMU_CGUCR_WRITE(this_controller, clock_gating_unit_value);
6697
6698   //set the default interrupt coalescence number and timeout value.
6699   scic_controller_set_interrupt_coalescence(
6700      this_controller, 0x10, 250);
6701}
6702
6703/**
6704 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on exit
6705 * from the SCI_BASE_CONTROLLER_STATE_READY.
6706 *    - This function does nothing.
6707 *
6708 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6709 *       SCIC_SDS_CONTROLLER object.
6710 *
6711 * @return none
6712 */
6713static
6714void scic_sds_controller_ready_state_exit(
6715   SCI_BASE_OBJECT_T *object
6716)
6717{
6718   U32 clock_gating_unit_value;
6719   SCIC_SDS_CONTROLLER_T *this_controller;
6720   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6721
6722   /**
6723    * restore clock gating for power control of the scu unit
6724    */
6725   clock_gating_unit_value = SMU_CGUCR_READ(this_controller);
6726
6727   clock_gating_unit_value &= ~SMU_CGUCR_GEN_BIT(IDLE_ENABLE);
6728   clock_gating_unit_value |= ( SMU_CGUCR_GEN_BIT(REGCLK_ENABLE)
6729                              | SMU_CGUCR_GEN_BIT(TXCLK_ENABLE)
6730                              | SMU_CGUCR_GEN_BIT(XCLK_ENABLE) );
6731
6732   SMU_CGUCR_WRITE(this_controller, clock_gating_unit_value);
6733
6734   //disable interrupt coalescence.
6735   scic_controller_set_interrupt_coalescence(this_controller, 0, 0);
6736}
6737
6738/**
6739 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
6740 * entry to the SCI_BASE_CONTROLLER_STATE_READY.
6741 *    - Set the state handlers to the controllers ready state.
6742 *    - Stop all of the remote devices on this controller
6743 *    - Stop the ports on this controller
6744 *    - Stop the phys on this controller
6745 *
6746 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6747 *       SCIC_SDS_CONTROLLER object.
6748 *
6749 * @return none
6750 */
6751static
6752void scic_sds_controller_stopping_state_enter(
6753   SCI_BASE_OBJECT_T *object
6754)
6755{
6756   SCIC_SDS_CONTROLLER_T *this_controller;
6757   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6758
6759   scic_sds_controller_set_base_state_handlers(
6760      this_controller, SCI_BASE_CONTROLLER_STATE_STOPPING);
6761
6762   // Stop all of the components for this controller in the reverse order
6763   // from which they are initialized.
6764   scic_sds_controller_stop_devices(this_controller);
6765   scic_sds_controller_stop_ports(this_controller);
6766
6767   if (!scic_sds_controller_has_remote_devices_stopping(this_controller))
6768   {
6769      sci_base_state_machine_change_state(
6770         &this_controller->parent.state_machine,
6771         SCI_BASE_CONTROLLER_STATE_STOPPED
6772      );
6773   }
6774}
6775
6776/**
6777 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on exit
6778 * from the SCI_BASE_CONTROLLER_STATE_STOPPING.
6779 *    - This function stops the controller stopping timeout timer.
6780 *
6781 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6782 *       SCIC_SDS_CONTROLLER object.
6783 *
6784 * @return none
6785 */
6786static
6787void scic_sds_controller_stopping_state_exit(
6788   SCI_BASE_OBJECT_T *object
6789)
6790{
6791   SCIC_SDS_CONTROLLER_T *this_controller;
6792   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6793
6794   scic_cb_timer_stop(this_controller, this_controller->timeout_timer);
6795}
6796
6797/**
6798 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
6799 * entry to the SCI_BASE_CONTROLLER_STATE_STOPPED.
6800 *    - Set the state handlers to the controllers stopped state.
6801 *
6802 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6803 *       SCIC_SDS_CONTROLLER object.
6804 *
6805 * @return none
6806 */
6807static
6808void scic_sds_controller_stopped_state_enter(
6809   SCI_BASE_OBJECT_T *object
6810)
6811{
6812   SCIC_SDS_CONTROLLER_T *this_controller;
6813   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6814
6815   scic_sds_controller_set_base_state_handlers(
6816      this_controller, SCI_BASE_CONTROLLER_STATE_STOPPED);
6817
6818   // We are done with this timer until the next timer we initialize
6819   scic_cb_timer_destroy(
6820      this_controller,
6821      this_controller->timeout_timer
6822   );
6823   this_controller->timeout_timer = NULL;
6824
6825   // Controller has stopped so disable all the phys on this controller
6826   scic_sds_controller_stop_phys(this_controller);
6827
6828   scic_sds_port_configuration_agent_destroy(
6829      this_controller,
6830      &this_controller->port_agent
6831   );
6832
6833   scic_cb_controller_stop_complete(this_controller, SCI_SUCCESS);
6834}
6835
6836/**
6837 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
6838 * entry to the SCI_BASE_CONTROLLER_STATE_RESETTING.
6839 *    - Set the state handlers to the controllers resetting state.
6840 *    - Write to the SCU hardware reset register to force a reset
6841 *    - Transition to the SCI_BASE_CONTROLLER_STATE_RESET
6842 *
6843 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6844 *       SCIC_SDS_CONTROLLER object.
6845 *
6846 * @return none
6847 */
6848static
6849void scic_sds_controller_resetting_state_enter(
6850   SCI_BASE_OBJECT_T *object
6851)
6852{
6853   SCIC_SDS_CONTROLLER_T *this_controller;
6854   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6855
6856   SCIC_LOG_TRACE((
6857      sci_base_object_get_logger(this_controller),
6858      SCIC_LOG_OBJECT_CONTROLLER,
6859      "scic_sds_controller_resetting_state_enter(0x%x) enter\n",
6860      this_controller
6861   ));
6862
6863   scic_sds_controller_set_base_state_handlers(
6864      this_controller, SCI_BASE_CONTROLLER_STATE_RESETTING);
6865
6866   scic_sds_controller_reset_hardware(this_controller);
6867
6868   sci_base_state_machine_change_state(
6869      scic_sds_controller_get_base_state_machine(this_controller),
6870      SCI_BASE_CONTROLLER_STATE_RESET
6871   );
6872}
6873
6874static
6875SCI_STATUS scic_sds_abort_reqests(
6876        SCIC_SDS_CONTROLLER_T * controller,
6877        SCIC_SDS_REMOTE_DEVICE_T * remote_device,
6878        SCIC_SDS_PORT_T * port
6879)
6880{
6881    SCI_STATUS          status           = SCI_SUCCESS;
6882    SCI_STATUS          terminate_status = SCI_SUCCESS;
6883    SCIC_SDS_REQUEST_T *the_request;
6884    U32                 index;
6885    U32                 request_count;
6886
6887    if (remote_device != NULL)
6888        request_count = remote_device->started_request_count;
6889    else if (port != NULL)
6890        request_count = port->started_request_count;
6891    else
6892        request_count = SCI_MAX_IO_REQUESTS;
6893
6894
6895    for (index = 0;
6896         (index < SCI_MAX_IO_REQUESTS) && (request_count > 0);
6897         index++)
6898    {
6899       the_request = controller->io_request_table[index];
6900
6901       if (the_request != NULL)
6902       {
6903           if (the_request->target_device == remote_device
6904                   || the_request->target_device->owning_port == port
6905                   || (remote_device == NULL && port == NULL))
6906           {
6907               terminate_status = scic_controller_terminate_request(
6908                                     controller,
6909                                     the_request->target_device,
6910                                     the_request
6911                                  );
6912
6913               if (terminate_status != SCI_SUCCESS)
6914                  status = terminate_status;
6915
6916               request_count--;
6917           }
6918       }
6919    }
6920
6921    return status;
6922}
6923
6924SCI_STATUS scic_sds_terminate_reqests(
6925        SCIC_SDS_CONTROLLER_T *this_controller,
6926        SCIC_SDS_REMOTE_DEVICE_T *this_remote_device,
6927        SCIC_SDS_PORT_T *this_port
6928)
6929{
6930    SCI_STATUS status = SCI_SUCCESS;
6931    SCI_STATUS abort_status = SCI_SUCCESS;
6932
6933    // move all request to abort state
6934    abort_status = scic_sds_abort_reqests(this_controller, this_remote_device, this_port);
6935
6936    if (abort_status != SCI_SUCCESS)
6937        status = abort_status;
6938
6939    //move all request to complete state
6940    if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR)
6941        abort_status = scic_sds_abort_reqests(this_controller, this_remote_device, this_port);
6942
6943    if (abort_status != SCI_SUCCESS)
6944        status = abort_status;
6945
6946    return status;
6947}
6948
6949static
6950SCI_STATUS scic_sds_terminate_all_requests(
6951        SCIC_SDS_CONTROLLER_T * controller
6952)
6953{
6954    return scic_sds_terminate_reqests(controller, NULL, NULL);
6955}
6956
6957/**
6958 * This method implements the actions taken by the SCIC_SDS_CONTROLLER on
6959 * entry to the SCI_BASE_CONTROLLER_STATE_FAILED.
6960 *    - Set the state handlers to the controllers failed state.
6961 *
6962 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
6963 *       SCIC_SDS_CONTROLLER object.
6964 *
6965 * @return none
6966 */
6967static
6968void scic_sds_controller_failed_state_enter(
6969   SCI_BASE_OBJECT_T *object
6970)
6971{
6972   SCIC_SDS_CONTROLLER_T *this_controller;
6973   this_controller= (SCIC_SDS_CONTROLLER_T *)object;
6974
6975   scic_sds_controller_set_base_state_handlers(
6976      this_controller, SCI_BASE_CONTROLLER_STATE_FAILED);
6977
6978   if (this_controller->parent.error == SCI_CONTROLLER_FATAL_MEMORY_ERROR)
6979   scic_sds_terminate_all_requests(this_controller);
6980   else
6981       scic_sds_controller_release_resource(this_controller);
6982
6983   //notify framework the controller failed.
6984   scic_cb_controller_error(this_controller,
6985           this_controller->parent.error);
6986}
6987
6988// ---------------------------------------------------------------------------
6989
6990SCI_BASE_STATE_T
6991   scic_sds_controller_state_table[SCI_BASE_CONTROLLER_MAX_STATES] =
6992{
6993   {
6994      SCI_BASE_CONTROLLER_STATE_INITIAL,
6995      scic_sds_controller_initial_state_enter,
6996      NULL,
6997   },
6998   {
6999      SCI_BASE_CONTROLLER_STATE_RESET,
7000      scic_sds_controller_reset_state_enter,
7001      NULL,
7002   },
7003   {
7004      SCI_BASE_CONTROLLER_STATE_INITIALIZING,
7005      scic_sds_controller_initializing_state_enter,
7006      NULL,
7007   },
7008   {
7009      SCI_BASE_CONTROLLER_STATE_INITIALIZED,
7010      scic_sds_controller_initialized_state_enter,
7011      NULL,
7012   },
7013   {
7014      SCI_BASE_CONTROLLER_STATE_STARTING,
7015      scic_sds_controller_starting_state_enter,
7016      scic_sds_controller_starting_state_exit,
7017   },
7018   {
7019      SCI_BASE_CONTROLLER_STATE_READY,
7020      scic_sds_controller_ready_state_enter,
7021      scic_sds_controller_ready_state_exit,
7022   },
7023   {
7024      SCI_BASE_CONTROLLER_STATE_RESETTING,
7025      scic_sds_controller_resetting_state_enter,
7026      NULL,
7027   },
7028   {
7029      SCI_BASE_CONTROLLER_STATE_STOPPING,
7030      scic_sds_controller_stopping_state_enter,
7031      scic_sds_controller_stopping_state_exit,
7032   },
7033   {
7034      SCI_BASE_CONTROLLER_STATE_STOPPED,
7035      scic_sds_controller_stopped_state_enter,
7036      NULL,
7037   },
7038   {
7039      SCI_BASE_CONTROLLER_STATE_FAILED,
7040      scic_sds_controller_failed_state_enter,
7041      NULL,
7042   }
7043};
7044
7045