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