1/*-
2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3 *
4 * This file is provided under a dual BSD/GPLv2 license.  When using or
5 * redistributing this file, you may do so under either license.
6 *
7 * GPL LICENSE SUMMARY
8 *
9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23 * The full GNU General Public License is included in this distribution
24 * in the file called LICENSE.GPL.
25 *
26 * BSD LICENSE
27 *
28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 *
35 *   * Redistributions of source code must retain the above copyright
36 *     notice, this list of conditions and the following disclaimer.
37 *   * Redistributions in binary form must reproduce the above copyright
38 *     notice, this list of conditions and the following disclaimer in
39 *     the documentation and/or other materials provided with the
40 *     distribution.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 */
54
55#include <sys/cdefs.h>
56__FBSDID("$FreeBSD$");
57
58/**
59 * @file
60 *
61 * @brief This file contains the implementation of the SCIF_SAS_CONTROLLER
62 *        object.
63 */
64
65
66#include <dev/isci/scil/sci_status.h>
67#include <dev/isci/scil/sci_util.h>
68#include <dev/isci/scil/sci_controller.h>
69#include <dev/isci/scil/scic_controller.h>
70#include <dev/isci/scil/scic_user_callback.h>
71#include <dev/isci/scil/scif_user_callback.h>
72
73#include <dev/isci/scil/scif_sas_controller.h>
74#include <dev/isci/scil/scif_sas_library.h>
75#include <dev/isci/scil/scif_sas_logger.h>
76
77
78//******************************************************************************
79//* P U B L I C   M E T H O D S
80//******************************************************************************
81
82SCI_STATUS scif_controller_construct(
83   SCI_LIBRARY_HANDLE_T      library,
84   SCI_CONTROLLER_HANDLE_T   controller,
85   void *                    user_object
86)
87{
88   SCI_STATUS              status        = SCI_SUCCESS;
89   SCIF_SAS_LIBRARY_T    * fw_library    = (SCIF_SAS_LIBRARY_T*) library;
90   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
91
92   // Validate the user supplied parameters.
93   if ((library == SCI_INVALID_HANDLE) || (controller == SCI_INVALID_HANDLE))
94      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
95
96   SCIF_LOG_TRACE((
97      sci_base_object_get_logger(library),
98      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
99      "scif_controller_construct(0x%x, 0x%x) enter\n",
100      library, controller
101   ));
102
103   // Construct the base controller.  As part of constructing the base
104   // controller we ask it to also manage the MDL iteration for the Core.
105   sci_base_controller_construct(
106      &fw_controller->parent,
107      sci_base_object_get_logger(fw_library),
108      scif_sas_controller_state_table,
109      fw_controller->mdes,
110      SCIF_SAS_MAX_MEMORY_DESCRIPTORS,
111      sci_controller_get_memory_descriptor_list_handle(fw_controller->core_object)
112   );
113
114   scif_sas_controller_initialize_state_logging(fw_controller);
115
116   sci_object_set_association(fw_controller, user_object);
117
118   status = scic_controller_construct(
119               fw_library->core_object, fw_controller->core_object, fw_controller
120            );
121
122   // If the core controller was successfully constructed, then
123   // finish construction of the framework controller.
124   if (status == SCI_SUCCESS)
125   {
126      // Set the association in the core controller to this framework
127      // controller.
128      sci_object_set_association(
129         (SCI_OBJECT_HANDLE_T) fw_controller->core_object, fw_controller
130      );
131
132      sci_base_state_machine_change_state(
133        &fw_controller->parent.state_machine,
134         SCI_BASE_CONTROLLER_STATE_RESET
135      );
136   }
137
138   return status;
139}
140
141// ---------------------------------------------------------------------------
142
143SCI_STATUS scif_controller_initialize(
144   SCI_CONTROLLER_HANDLE_T   controller
145)
146{
147   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
148
149   // Validate the user supplied parameters.
150   if (controller == SCI_INVALID_HANDLE)
151      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
152
153   SCIF_LOG_TRACE((
154      sci_base_object_get_logger(controller),
155      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
156      "scif_controller_initialize(0x%x) enter\n",
157      controller
158   ));
159
160   return fw_controller->state_handlers->initialize_handler(
161             &fw_controller->parent
162          );
163}
164
165// ---------------------------------------------------------------------------
166
167U32 scif_controller_get_suggested_start_timeout(
168   SCI_CONTROLLER_HANDLE_T  controller
169)
170{
171   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
172
173   // Validate the user supplied parameters.
174   if (controller == SCI_INVALID_HANDLE)
175      return 0;
176
177   // Currently we aren't adding any additional time into the suggested
178   // timeout value for the start operation.  Simply utilize the core
179   // value.
180   return scic_controller_get_suggested_start_timeout(fw_controller->core_object);
181}
182
183// ---------------------------------------------------------------------------
184
185SCI_STATUS scif_controller_start(
186   SCI_CONTROLLER_HANDLE_T  controller,
187   U32                      timeout
188)
189{
190   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
191
192   // Validate the user supplied parameters.
193   if (controller == SCI_INVALID_HANDLE)
194      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
195
196   SCIF_LOG_TRACE((
197      sci_base_object_get_logger(controller),
198      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
199      "scif_controller_start(0x%x, 0x%x) enter\n",
200      controller, timeout
201   ));
202
203   return fw_controller->state_handlers->
204          start_handler(&fw_controller->parent, timeout);
205}
206
207// ---------------------------------------------------------------------------
208
209SCI_STATUS scif_controller_stop(
210   SCI_CONTROLLER_HANDLE_T  controller,
211   U32                      timeout
212)
213{
214   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
215
216   // Validate the user supplied parameters.
217   if (controller == SCI_INVALID_HANDLE)
218      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
219
220   SCIF_LOG_TRACE((
221      sci_base_object_get_logger(controller),
222      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
223      "scif_controller_stop(0x%x, 0x%x) enter\n",
224      controller, timeout
225   ));
226
227   return fw_controller->state_handlers->
228          stop_handler(&fw_controller->parent, timeout);
229
230}
231
232// ---------------------------------------------------------------------------
233
234SCI_STATUS scif_controller_reset(
235   SCI_CONTROLLER_HANDLE_T  controller
236)
237{
238   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
239
240   // Validate the user supplied parameters.
241   if (controller == SCI_INVALID_HANDLE)
242      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
243
244   SCIF_LOG_TRACE((
245      sci_base_object_get_logger(controller),
246      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_CONTROLLER_RESET,
247      "scif_controller_reset(0x%x) enter\n",
248      controller
249   ));
250
251   return fw_controller->state_handlers->
252          reset_handler(&fw_controller->parent);
253}
254
255// ---------------------------------------------------------------------------
256
257SCI_CONTROLLER_HANDLE_T scif_controller_get_scic_handle(
258   SCI_CONTROLLER_HANDLE_T   controller
259)
260{
261   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
262
263   return fw_controller->core_object;
264}
265
266// ---------------------------------------------------------------------------
267
268SCI_IO_STATUS scif_controller_start_io(
269   SCI_CONTROLLER_HANDLE_T     controller,
270   SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
271   SCI_IO_REQUEST_HANDLE_T     io_request,
272   U16                         io_tag
273)
274{
275   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
276   SCI_STATUS              status;
277
278   SCIF_LOG_TRACE((
279      sci_base_object_get_logger(controller),
280      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
281      "scif_controller_start_io(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
282      controller, remote_device, io_request, io_tag
283   ));
284
285   if (
286         sci_pool_empty(fw_controller->hprq.pool)
287      || scif_sas_controller_sufficient_resource(controller)
288      )
289   {
290      status = fw_controller->state_handlers->start_io_handler(
291                (SCI_BASE_CONTROLLER_T*) controller,
292                (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
293                (SCI_BASE_REQUEST_T*) io_request,
294                io_tag
295             );
296   }
297   else
298      status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
299
300   return (SCI_IO_STATUS)status;
301}
302
303// ---------------------------------------------------------------------------
304
305SCI_TASK_STATUS scif_controller_start_task(
306   SCI_CONTROLLER_HANDLE_T     controller,
307   SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
308   SCI_TASK_REQUEST_HANDLE_T   task_request,
309   U16                         io_tag
310)
311{
312   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
313   SCI_STATUS              status;
314
315   // Validate the user supplied parameters.
316   if (  (controller == SCI_INVALID_HANDLE)
317      || (remote_device == SCI_INVALID_HANDLE)
318      || (task_request == SCI_INVALID_HANDLE) )
319   {
320      return SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE;
321   }
322
323   SCIF_LOG_TRACE((
324      sci_base_object_get_logger(controller),
325      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
326      "scif_controller_start_task(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
327      controller, remote_device, task_request, io_tag
328   ));
329
330   if (scif_sas_controller_sufficient_resource(controller))
331   {
332      status = fw_controller->state_handlers->start_task_handler(
333             (SCI_BASE_CONTROLLER_T*) controller,
334             (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
335             (SCI_BASE_REQUEST_T*) task_request,
336             io_tag
337          );
338   }
339   else
340      status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
341
342   return (SCI_TASK_STATUS)status;
343}
344
345// ---------------------------------------------------------------------------
346
347SCI_STATUS scif_controller_complete_io(
348   SCI_CONTROLLER_HANDLE_T     controller,
349   SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
350   SCI_IO_REQUEST_HANDLE_T     io_request
351)
352{
353   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
354
355   SCIF_LOG_TRACE((
356      sci_base_object_get_logger(controller),
357      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
358      "scif_controller_complete_io(0x%x, 0x%x, 0x%x) enter\n",
359      controller, remote_device, io_request
360   ));
361
362   return fw_controller->state_handlers->complete_io_handler(
363             (SCI_BASE_CONTROLLER_T*) controller,
364             (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
365             (SCI_BASE_REQUEST_T*) io_request
366          );
367}
368
369// ---------------------------------------------------------------------------
370
371SCI_STATUS scif_controller_complete_task(
372   SCI_CONTROLLER_HANDLE_T     controller,
373   SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
374   SCI_TASK_REQUEST_HANDLE_T   task_request
375)
376{
377   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
378
379   // Validate the user supplied parameters.
380   if (  (controller == SCI_INVALID_HANDLE)
381      || (remote_device == SCI_INVALID_HANDLE)
382      || (task_request == SCI_INVALID_HANDLE) )
383   {
384      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
385   }
386
387   SCIF_LOG_TRACE((
388      sci_base_object_get_logger(controller),
389      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
390      "scif_controller_complete_task(0x%x, 0x%x, 0x%x) enter\n",
391      controller, remote_device, task_request
392   ));
393
394   return fw_controller->state_handlers->complete_task_handler(
395             (SCI_BASE_CONTROLLER_T*) controller,
396             (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
397             (SCI_BASE_REQUEST_T*) task_request
398          );
399}
400
401// ---------------------------------------------------------------------------
402
403SCI_STATUS scif_controller_get_domain_handle(
404   SCI_CONTROLLER_HANDLE_T   controller,
405   U8                        port_index,
406   SCI_DOMAIN_HANDLE_T     * domain_handle
407)
408{
409   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
410
411   // Validate the user supplied parameters.
412   if (controller == SCI_INVALID_HANDLE)
413      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
414
415   // Retrieve the domain handle if the supplied index is legitimate.
416   if (port_index < SCI_MAX_PORTS)
417   {
418      *domain_handle = &fw_controller->domains[port_index];
419      return SCI_SUCCESS;
420   }
421
422   return SCI_FAILURE_INVALID_PORT;
423}
424
425/**
426 * @brief This method builds the memory descriptor list for this
427 *        controller.
428 *
429 * @param[in] fw_controller This parameter specifies the framework
430 *            controller object for which to build the MDL.
431 *
432 * @return none
433 */
434void scif_sas_controller_build_mdl(
435   SCIF_SAS_CONTROLLER_T * fw_controller
436)
437{
438   // one internal request for each domain.
439   sci_base_mde_construct(
440      &fw_controller->mdes[SCIF_SAS_MDE_INTERNAL_IO],
441      4,
442      fw_controller->internal_request_entries *
443         scif_sas_internal_request_get_object_size(),
444      SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
445   );
446}
447
448// ---------------------------------------------------------------------------
449
450SCI_STATUS scif_controller_set_mode(
451   SCI_CONTROLLER_HANDLE_T   controller,
452   SCI_CONTROLLER_MODE       mode
453)
454{
455   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
456   SCI_STATUS              status          = SCI_SUCCESS;
457
458   if (
459         (fw_controller->parent.state_machine.current_state_id
460          == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
461      || (fw_controller->parent.state_machine.current_state_id
462          == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
463      )
464   {
465      switch (mode)
466      {
467      case SCI_MODE_SPEED:
468         fw_controller->internal_request_entries =
469            MIN(fw_controller->internal_request_entries, SCIF_SAS_MAX_INTERNAL_REQUEST_COUNT);
470         scif_sas_controller_build_mdl(fw_controller);
471      break;
472
473      case SCI_MODE_SIZE:
474         fw_controller->internal_request_entries =
475            MIN(fw_controller->internal_request_entries, SCIF_SAS_MIN_INTERNAL_REQUEST_COUNT);
476         scif_sas_controller_build_mdl(fw_controller);
477      break;
478
479      default:
480         status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
481      break;
482      }
483   }
484   else
485      status = SCI_FAILURE_INVALID_STATE;
486
487   if (status != SCI_SUCCESS)
488   {
489      return status;
490   }
491   else
492   {
493      // Currently, the framework doesn't change any configurations for
494      // speed or size modes.  Default to speed mode basically.
495      return scic_controller_set_mode(fw_controller->core_object, mode);
496   }
497}
498
499// ---------------------------------------------------------------------------
500
501U32 scif_controller_get_sat_compliance_version(
502   void
503)
504{
505   /// @todo Fix return of SAT compliance version.
506   return 0;
507}
508
509// ---------------------------------------------------------------------------
510
511U32 scif_controller_get_sat_compliance_version_revision(
512   void
513)
514{
515   /// @todo Fix return of SAT compliance revision.
516   return 0;
517}
518
519// ---------------------------------------------------------------------------
520
521SCI_STATUS scif_user_parameters_set(
522   SCI_CONTROLLER_HANDLE_T   controller,
523   SCIF_USER_PARAMETERS_T  * scif_parms
524)
525{
526   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
527
528   //validate all the registry entries before overwriting the default parameter
529   //values.
530   if (scif_parms->sas.is_sata_ncq_enabled != 1 && scif_parms->sas.is_sata_ncq_enabled != 0)
531      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
532
533   if (scif_parms->sas.max_ncq_depth < 1 || scif_parms->sas.max_ncq_depth > 32)
534      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
535
536   if (scif_parms->sas.is_sata_standby_timer_enabled != 1
537       && scif_parms->sas.is_sata_standby_timer_enabled != 0)
538      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
539
540   if (scif_parms->sas.is_non_zero_buffer_offsets_enabled != 1
541       && scif_parms->sas.is_non_zero_buffer_offsets_enabled != 0)
542      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
543
544   if (scif_parms->sas.reset_type != SCI_SAS_ABORT_TASK
545       && scif_parms->sas.reset_type != SCI_SAS_ABORT_TASK_SET
546       && scif_parms->sas.reset_type != SCI_SAS_CLEAR_TASK_SET
547       && scif_parms->sas.reset_type != SCI_SAS_LOGICAL_UNIT_RESET
548       && scif_parms->sas.reset_type != SCI_SAS_I_T_NEXUS_RESET
549       && scif_parms->sas.reset_type != SCI_SAS_CLEAR_ACA
550       && scif_parms->sas.reset_type != SCI_SAS_QUERY_TASK
551       && scif_parms->sas.reset_type != SCI_SAS_QUERY_TASK_SET
552       && scif_parms->sas.reset_type != SCI_SAS_QUERY_ASYNCHRONOUS_EVENT
553       && scif_parms->sas.reset_type != SCI_SAS_HARD_RESET)
554      return SCI_FAILURE_INVALID_PARAMETER_VALUE;
555
556   if (scif_parms->sas.clear_affiliation_during_controller_stop != 1
557       && scif_parms->sas.clear_affiliation_during_controller_stop !=0)
558       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
559
560   memcpy((&fw_controller->user_parameters), scif_parms, sizeof(*scif_parms));
561
562   // In the future more could be done to prevent setting parameters at the
563   // wrong time, but for now we'll simply set the values even if it is too
564   // late for them to take affect.
565   return SCI_SUCCESS;
566}
567
568// ---------------------------------------------------------------------------
569
570#if !defined(DISABLE_INTERRUPTS)
571
572/**
573 * @brief This routine check each domain of the controller to see if
574 *           any domain is overriding interrupt coalescence.
575 *
576 * @param[in] fw_controller frame controller
577 * @param[in] fw_smp_phy The smp phy to be freed.
578 *
579 * @return none
580 */
581static
582BOOL scif_sas_controller_is_overriding_interrupt_coalescence(
583   SCIF_SAS_CONTROLLER_T * fw_controller
584)
585{
586   U8 index;
587
588   for(index = 0; index < SCI_MAX_DOMAINS; index++)
589   {
590      if(fw_controller->domains[index].parent.state_machine.current_state_id ==
591            SCI_BASE_DOMAIN_STATE_DISCOVERING)
592         return TRUE;
593   }
594
595   return FALSE;
596}
597
598SCI_STATUS scif_controller_set_interrupt_coalescence(
599   SCI_CONTROLLER_HANDLE_T controller,
600   U32                     coalesce_number,
601   U32                     coalesce_timeout
602)
603{
604   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T * )controller;
605
606   ///when framework is in the middle of temporarily overriding the interrupt
607   ///coalescence values, user's request of setting interrupt coalescence
608   ///will be saved. As soon as the framework done the temporary overriding,
609   ///it will serve user's request to set new interrupt coalescence.
610   if (scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller))
611   {
612      U32 curr_coalesce_number;
613      U32 curr_coalesce_timeout;
614      SCI_STATUS core_status;
615
616      // save current interrupt coalescence info.
617      scic_controller_get_interrupt_coalescence (
618         fw_controller->core_object, &curr_coalesce_number, &curr_coalesce_timeout);
619
620      //try user's request out in the core, but immediately restore core's
621      //current setting.
622      core_status = scic_controller_set_interrupt_coalescence(
623                       fw_controller->core_object, coalesce_number, coalesce_timeout);
624
625      if ( core_status == SCI_SUCCESS )
626      {
627         fw_controller->saved_interrupt_coalesce_number = (U16)coalesce_number;
628         fw_controller->saved_interrupt_coalesce_timeout = coalesce_timeout;
629      }
630
631       //restore current interrupt coalescence.
632      scic_controller_set_interrupt_coalescence(
633         fw_controller->core_object, curr_coalesce_number, curr_coalesce_timeout);
634
635      return core_status;
636   }
637   else
638   {
639      ///If framework is not internally overriding the interrupt coalescence,
640      ///serve user's request immediately by passing the reqeust to core.
641      return scic_controller_set_interrupt_coalescence(
642                fw_controller->core_object, coalesce_number, coalesce_timeout);
643   }
644}
645
646// ---------------------------------------------------------------------------
647
648void scif_controller_get_interrupt_coalescence(
649   SCI_CONTROLLER_HANDLE_T controller,
650   U32                   * coalesce_number,
651   U32                   * coalesce_timeout
652)
653{
654   SCIF_SAS_CONTROLLER_T * scif_controller = (SCIF_SAS_CONTROLLER_T * )controller;
655
656   scic_controller_get_interrupt_coalescence(
657      scif_controller->core_object, coalesce_number, coalesce_timeout);
658}
659
660/**
661 * @brief This method will save the interrupt coalescence values.  If
662 *        the interrupt coalescence values have already been saved,
663 *        then this method performs no operations.
664 *
665 * @param[in,out] fw_controller This parameter specifies the controller
666 *                for which to save the interrupt coalescence values.
667 *
668 * @return none
669 */
670void scif_sas_controller_save_interrupt_coalescence(
671   SCIF_SAS_CONTROLLER_T * fw_controller
672)
673{
674   if ( !scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller))
675   {
676      // Override core's interrupt coalescing settings during SMP
677      // DISCOVER process cause' there is only 1 outstanding SMP
678      // request per domain is allowed.
679      scic_controller_get_interrupt_coalescence(
680         fw_controller->core_object,
681         (U32*)&(fw_controller->saved_interrupt_coalesce_number),
682         &(fw_controller->saved_interrupt_coalesce_timeout)
683      );
684
685      // Temporarily disable the interrupt coalescing.
686      scic_controller_set_interrupt_coalescence(fw_controller->core_object,0,0);
687   }
688}
689
690/**
691 * @brief This method will restore the interrupt coalescence values.  If
692 *        the interrupt coalescence values have not already been saved,
693 *        then this method performs no operations.
694 *
695 * @param[in,out] fw_controller This parameter specifies the controller
696 *                for which to restore the interrupt coalescence values.
697 *
698 * @return none
699 */
700void scif_sas_controller_restore_interrupt_coalescence(
701   SCIF_SAS_CONTROLLER_T * fw_controller
702)
703{
704   if ( !scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller))
705      scic_controller_set_interrupt_coalescence(
706         fw_controller->core_object,
707         fw_controller->saved_interrupt_coalesce_number,
708         fw_controller->saved_interrupt_coalesce_timeout
709      );
710}
711
712#endif // !defined(DISABLE_INTERRUPTS)
713
714// ---------------------------------------------------------------------------
715
716void scic_cb_controller_start_complete(
717   SCI_CONTROLLER_HANDLE_T  controller,
718   SCI_STATUS               completion_status
719)
720{
721   SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)
722                                         sci_object_get_association(controller);
723
724   SCIF_LOG_TRACE((
725      sci_base_object_get_logger(controller),
726      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
727      "scic_cb_controller_start_complete(0x%x, 0x%x) enter\n",
728      controller, completion_status
729   ));
730
731   if (completion_status == SCI_SUCCESS
732       || completion_status == SCI_FAILURE_TIMEOUT)
733   {
734      // Even the initialization of the core controller timed out, framework
735      // controller should still transit to READY state.
736      sci_base_state_machine_change_state(
737         &fw_controller->parent.state_machine,
738         SCI_BASE_CONTROLLER_STATE_READY
739      );
740   }
741
742   scif_cb_controller_start_complete(fw_controller, completion_status);
743}
744
745// ---------------------------------------------------------------------------
746
747void scic_cb_controller_stop_complete(
748   SCI_CONTROLLER_HANDLE_T  controller,
749   SCI_STATUS               completion_status
750)
751{
752   SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)
753                                         sci_object_get_association(controller);
754
755   SCIF_LOG_TRACE((
756      sci_base_object_get_logger(controller),
757      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
758      "scic_cb_controller_stop_complete(0x%x, 0x%x) enter\n",
759      controller, completion_status
760   ));
761
762   if (completion_status == SCI_SUCCESS)
763   {
764      sci_base_state_machine_change_state(
765         &fw_controller->parent.state_machine,
766         SCI_BASE_CONTROLLER_STATE_STOPPED
767      );
768   }
769   else
770   {
771      sci_base_state_machine_change_state(
772         &fw_controller->parent.state_machine,
773         SCI_BASE_CONTROLLER_STATE_FAILED
774      );
775   }
776
777   scif_cb_controller_stop_complete(fw_controller, completion_status);
778}
779
780
781// ---------------------------------------------------------------------------
782
783void scic_cb_controller_error(
784   SCI_CONTROLLER_HANDLE_T  controller,
785   SCI_CONTROLLER_ERROR error
786)
787{
788   SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)
789                                         sci_object_get_association(controller);
790
791   fw_controller->parent.error = error;
792
793   SCIF_LOG_TRACE((
794      sci_base_object_get_logger(controller),
795      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
796      "scic_cb_controller_not_ready(0x%x) enter\n",
797      controller
798   ));
799
800   sci_base_state_machine_change_state(
801      &fw_controller->parent.state_machine,
802      SCI_BASE_CONTROLLER_STATE_FAILED
803   );
804}
805
806//******************************************************************************
807//* P R O T E C T E D    M E T H O D S
808//******************************************************************************
809
810/**
811 * @brief This method is utilized to continue an internal IO operation
812 *        on the controller.  This method is utilized for SAT translated
813 *        requests that generate multiple ATA commands in order to fulfill
814 *        the original SCSI request.
815 *
816 * @param[in]  controller This parameter specifies the controller on which
817 *             to continue an internal IO request.
818 * @param[in]  remote_device This parameter specifies the remote device
819 *             on which to continue an internal IO request.
820 * @param[in]  io_request This parameter specifies the IO request to be
821 *             continue.
822 *
823 * @return Indicate if the continue operation was successful.
824 * @retval SCI_SUCCESS This value is returned if the operation succeeded.
825 */
826SCI_STATUS scif_sas_controller_continue_io(
827   SCI_CONTROLLER_HANDLE_T     controller,
828   SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
829   SCI_IO_REQUEST_HANDLE_T     io_request
830)
831{
832   SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
833
834   return fw_controller->state_handlers->continue_io_handler(
835             (SCI_BASE_CONTROLLER_T*) controller,
836             (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
837             (SCI_BASE_REQUEST_T*) io_request
838          );
839}
840
841/**
842 * @brief This method will attempt to destruct a framework controller.
843 *        This includes free any resources retreived from the user (e.g.
844 *        timers).
845 *
846 * @param[in]  fw_controller This parameter specifies the framework
847 *             controller to destructed.
848 *
849 * @return none
850 */
851void scif_sas_controller_destruct(
852   SCIF_SAS_CONTROLLER_T * fw_controller
853)
854{
855   SCIF_LOG_TRACE((
856      sci_base_object_get_logger(fw_controller),
857      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
858      "scif_sas_controller_destruct(0x%x) enter\n",
859      fw_controller
860   ));
861}
862
863//-----------------------------------------------------------------------------
864// INTERNAL REQUEST RELATED METHODS
865//-----------------------------------------------------------------------------
866
867/**
868 * @brief This routine is to allocate the memory for creating a new internal
869 *        request.
870 *
871 * @param[in] scif_controller handle to frame controller
872 *
873 * @return void* address to internal request memory
874 */
875void * scif_sas_controller_allocate_internal_request(
876   SCIF_SAS_CONTROLLER_T * fw_controller
877)
878{
879   POINTER_UINT internal_io_address;
880
881   if( !sci_pool_empty(fw_controller->internal_request_memory_pool) )
882   {
883      sci_pool_get(
884         fw_controller->internal_request_memory_pool, internal_io_address
885      );
886
887      //clean the memory.
888      memset((char*)internal_io_address, 0, scif_sas_internal_request_get_object_size());
889
890      return (void *) internal_io_address;
891   }
892   else
893      return NULL;
894}
895
896/**
897 * @brief This routine is to free the memory for a completed internal request.
898 *
899 * @param[in] scif_controller handle to frame controller
900 * @param[in] fw_internal_io The internal IO to be freed.
901 *
902 * @return none
903 */
904void scif_sas_controller_free_internal_request(
905   SCIF_SAS_CONTROLLER_T * fw_controller,
906   void                  * fw_internal_request_buffer
907)
908{
909   SCIF_LOG_TRACE((
910      sci_base_object_get_logger(fw_controller),
911      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
912      "scif_controller_free_internal_request(0x%x, 0x%x) enter\n",
913      fw_controller, fw_internal_request_buffer
914   ));
915
916   //return the memory to the pool.
917   if( !sci_pool_full(fw_controller->internal_request_memory_pool) )
918   {
919      sci_pool_put(
920         fw_controller->internal_request_memory_pool,
921         (POINTER_UINT) fw_internal_request_buffer
922      );
923   }
924}
925
926
927/**
928 * @brief this routine is called by OS' DPC to start io requests from internal
929 *        high priority request queue
930 * @param[in] fw_controller The framework controller.
931 *
932 * @return none
933 */
934void scif_sas_controller_start_high_priority_io(
935   SCIF_SAS_CONTROLLER_T * fw_controller
936)
937{
938   POINTER_UINT            io_address;
939   SCIF_SAS_IO_REQUEST_T * fw_io;
940   SCI_STATUS              status;
941
942   SCIF_LOG_TRACE((
943      sci_base_object_get_logger(fw_controller),
944      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
945      "scif_controller_start_high_priority_io(0x%x) enter\n",
946      fw_controller
947   ));
948
949   while ( !sci_pool_empty(fw_controller->hprq.pool) )
950   {
951      sci_pool_get(fw_controller->hprq.pool, io_address);
952
953      fw_io = (SCIF_SAS_IO_REQUEST_T *)io_address;
954
955      status = fw_controller->state_handlers->start_high_priority_io_handler(
956         (SCI_BASE_CONTROLLER_T*) fw_controller,
957         (SCI_BASE_REMOTE_DEVICE_T*) fw_io->parent.device,
958         (SCI_BASE_REQUEST_T*) fw_io,
959         SCI_CONTROLLER_INVALID_IO_TAG
960      );
961   }
962}
963
964/**
965 * @brief This method will check how many outstanding IOs currently and number
966 * of IOs in high priority queue, if the overall number exceeds the max_tc,
967 * return FALSE.
968 *
969 * @param[in] fw_controller The framework controller.
970 *
971 * @return BOOL Indicate whether there is sufficient resource to start an IO.
972 * @retvalue TRUE The controller has sufficient resource.
973 * @retvalue FALSE There is not sufficient resource available.
974 */
975BOOL scif_sas_controller_sufficient_resource(
976   SCIF_SAS_CONTROLLER_T *fw_controller
977)
978{
979   SCIF_SAS_DOMAIN_T * fw_domain;
980   U32 domain_index;
981   U32 outstanding_io_count = 0;
982   U32 high_priority_io_count = 0;
983
984   for(domain_index = 0; domain_index < SCI_MAX_DOMAINS; domain_index++)
985   {
986      fw_domain = &fw_controller->domains[domain_index];
987      outstanding_io_count += fw_domain->request_list.element_count;
988   }
989
990   high_priority_io_count = sci_pool_count(fw_controller->hprq.pool);
991
992   if ( (outstanding_io_count + high_priority_io_count) > SCI_MAX_IO_REQUESTS )
993      return FALSE;
994
995   return TRUE;
996}
997
998
999/**
1000 * @brief This method is the starting point to complete high prority io for a
1001 *        controller then down to domain, device.
1002 *
1003 * @param[in] fw_controller The framework controller
1004 * @param[in] remote_device  The framework remote device.
1005 * @param[in] io_request The high priority io request to be completed.
1006 *
1007 * @return SCI_STATUS indicate the completion status from framework down to the
1008 *         core.
1009 */
1010SCI_STATUS scif_sas_controller_complete_high_priority_io(
1011   SCIF_SAS_CONTROLLER_T    *fw_controller,
1012   SCIF_SAS_REMOTE_DEVICE_T *remote_device,
1013   SCIF_SAS_REQUEST_T       *io_request
1014)
1015{
1016   SCIF_LOG_TRACE((
1017      sci_base_object_get_logger(fw_controller),
1018      SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
1019      "scif_sas_controller_complete_high_priority_io(0x%x, 0x%x, 0x%x) enter\n",
1020      fw_controller, remote_device, io_request
1021   ));
1022
1023   //call controller's new added complete_high_priority_io_handler
1024   return fw_controller->state_handlers->complete_high_priority_io_handler(
1025             (SCI_BASE_CONTROLLER_T*) fw_controller,
1026             (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
1027             (SCI_BASE_REQUEST_T*) io_request
1028          );
1029}
1030
1031/**
1032
1033 * @brief This routine is to allocate the memory for creating a smp phy object.
1034 *
1035 * @param[in] scif_controller handle to frame controller
1036 *
1037 * @return SCIF_SAS_SMP_PHY_T * An allocated space for smp phy. If failed to allocate,
1038 *            return NULL.
1039 */
1040SCIF_SAS_SMP_PHY_T * scif_sas_controller_allocate_smp_phy(
1041   SCIF_SAS_CONTROLLER_T * fw_controller
1042)
1043{
1044   SCIF_SAS_SMP_PHY_T * smp_phy;
1045
1046   SCIF_LOG_TRACE((
1047      sci_base_object_get_logger(fw_controller),
1048      SCIF_LOG_OBJECT_CONTROLLER,
1049      "scif_controller_allocate_smp_phy(0x%x) enter\n",
1050      fw_controller
1051   ));
1052
1053   if( !sci_fast_list_is_empty(&fw_controller->smp_phy_memory_list) )
1054   {
1055      smp_phy = (SCIF_SAS_SMP_PHY_T *)
1056         sci_fast_list_remove_head(&fw_controller->smp_phy_memory_list);
1057
1058      //clean the memory.
1059      memset((char*)smp_phy,
1060             0,
1061             sizeof(SCIF_SAS_SMP_PHY_T)
1062            );
1063
1064      return smp_phy;
1065   }
1066   else
1067      return NULL;
1068}
1069
1070/**
1071 * @brief This routine is to free the memory for a released smp phy.
1072 *
1073 * @param[in] fw_controller The framework controller, a smp phy is released
1074 *                to its memory.
1075 * @param[in] fw_smp_phy The smp phy to be freed.
1076 *
1077 * @return none
1078 */
1079void scif_sas_controller_free_smp_phy(
1080   SCIF_SAS_CONTROLLER_T * fw_controller,
1081   SCIF_SAS_SMP_PHY_T    * smp_phy
1082)
1083{
1084   SCIF_LOG_TRACE((
1085      sci_base_object_get_logger(fw_controller),
1086      SCIF_LOG_OBJECT_CONTROLLER,
1087      "scif_controller_free_smp_phy(0x%x, 0x%x) enter\n",
1088      fw_controller, smp_phy
1089   ));
1090
1091   //return the memory to the list.
1092   sci_fast_list_insert_tail(
1093      &fw_controller->smp_phy_memory_list,
1094      &smp_phy->list_element
1095   );
1096}
1097
1098
1099/**
1100 * @brief This method clear affiliation for all the EA SATA devices associated
1101 *        to this controller.
1102 *
1103 * @param[in] fw_controller This parameter specifies the framework
1104 *            controller object for whose remote devices are to be stopped.
1105 *
1106 * @return This method returns a value indicating if the operation completed.
1107 * @retval SCI_COMPLETE This value indicates that all the EA SATA devices'
1108 *         affiliation was cleared.
1109 * @retval SCI_INCOMPLETE This value indicates clear affiliation activity is
1110 *         yet to be completed.
1111 */
1112SCI_STATUS scif_sas_controller_clear_affiliation(
1113   SCIF_SAS_CONTROLLER_T * fw_controller
1114)
1115{
1116   U8 index;
1117   SCI_STATUS status;
1118   SCIF_SAS_DOMAIN_T * fw_domain;
1119
1120   SCIF_LOG_TRACE((
1121      sci_base_object_get_logger(fw_controller),
1122      SCIF_LOG_OBJECT_CONTROLLER,
1123      "scif_sas_controller_clear_affiliation(0x%x) enter\n",
1124      fw_controller
1125   ));
1126
1127   index = fw_controller->current_domain_to_clear_affiliation;
1128
1129   if (index < SCI_MAX_DOMAINS)
1130   {
1131      fw_domain = &fw_controller->domains[index];
1132
1133      //Need to stop all the on-going smp activities before clearing affiliation.
1134      scif_sas_domain_cancel_smp_activities(fw_domain);
1135
1136      scif_sas_domain_start_clear_affiliation(fw_domain);
1137
1138      status = SCI_WARNING_SEQUENCE_INCOMPLETE;
1139   }
1140   else
1141   {  //the controller has done clear affiliation work to all its domains.
1142      scif_sas_controller_continue_to_stop(fw_controller);
1143      status = SCI_SUCCESS;
1144   }
1145
1146   return status;
1147}
1148
1149
1150/**
1151 * @brief This method sets SCIF user parameters to
1152 *        default values.  Users can override these values utilizing
1153 *        the sciF_user_parameters_set() methods.
1154 *
1155 * @param[in] controller This parameter specifies the controller for
1156 *            which to set the configuration parameters to their
1157 *            default values.
1158 *
1159 * @return none
1160 */
1161void scif_sas_controller_set_default_config_parameters(
1162   SCIF_SAS_CONTROLLER_T * this_controller
1163)
1164{
1165   SCIF_USER_PARAMETERS_T * scif_parms = &(this_controller->user_parameters);
1166
1167   scif_parms->sas.is_sata_ncq_enabled = TRUE;
1168   scif_parms->sas.max_ncq_depth = 32;
1169   scif_parms->sas.is_sata_standby_timer_enabled = FALSE;
1170   scif_parms->sas.is_non_zero_buffer_offsets_enabled = FALSE;
1171   scif_parms->sas.reset_type = SCI_SAS_LOGICAL_UNIT_RESET;
1172   scif_parms->sas.clear_affiliation_during_controller_stop = TRUE;
1173   scif_parms->sas.ignore_fua = FALSE;
1174
1175}
1176
1177
1178/**
1179 * @brief This method releases resource for framework controller and associated
1180 *        objects.
1181 *
1182 * @param[in] fw_controller This parameter specifies the framework
1183 *            controller and associated objects whose resources are to be released.
1184 *
1185 * @return This method returns a value indicating if the operation succeeded.
1186 * @retval SCI_SUCCESS This value indicates that resource release succeeded.
1187 * @retval SCI_FAILURE This value indicates certain failure during the process
1188 *            of resource release.
1189 */
1190SCI_STATUS scif_sas_controller_release_resource(
1191   SCIF_SAS_CONTROLLER_T * fw_controller
1192)
1193{
1194   U8 index;
1195   SCIF_SAS_DOMAIN_T * fw_domain;
1196
1197   SCIF_LOG_TRACE((
1198      sci_base_object_get_logger(fw_controller),
1199      SCIF_LOG_OBJECT_CONTROLLER,
1200      "scif_sas_controller_release_resource(0x%x) enter\n",
1201      fw_controller
1202   ));
1203
1204   //currently the only resource to be released is domain's timer.
1205   for (index = 0; index < SCI_MAX_DOMAINS; index++)
1206   {
1207      fw_domain = &fw_controller->domains[index];
1208
1209      scif_sas_domain_release_resource(fw_controller, fw_domain);
1210   }
1211
1212   return SCI_SUCCESS;
1213}
1214
1215
1216#ifdef SCI_LOGGING
1217/**
1218 * This method will start state transition logging for the framework
1219 * controller object.
1220 *
1221 * @param[in] fw_controller The framework controller object on which to
1222 *       observe state changes.
1223 *
1224 * @return none
1225 */
1226void scif_sas_controller_initialize_state_logging(
1227   SCIF_SAS_CONTROLLER_T * fw_controller
1228)
1229{
1230   sci_base_state_machine_logger_initialize(
1231      &fw_controller->parent.state_machine_logger,
1232      &fw_controller->parent.state_machine,
1233      &fw_controller->parent.parent,
1234      scif_cb_logger_log_states,
1235      "SCIF_SAS_CONTROLLER_T", "base state machine",
1236      SCIF_LOG_OBJECT_CONTROLLER
1237   );
1238}
1239
1240/**
1241 * This method will remove the logging of state transitions from the framework
1242 * controller object.
1243 *
1244 * @param[in] fw_controller The framework controller to change.
1245 *
1246 * @return none
1247 */
1248void scif_sas_controller_deinitialize_state_logging(
1249   SCIF_SAS_CONTROLLER_T * fw_controller
1250)
1251{
1252   sci_base_state_machine_logger_deinitialize(
1253      &fw_controller->parent.state_machine_logger,
1254      &fw_controller->parent.state_machine
1255   );
1256}
1257#endif // SCI_LOGGING
1258