xref: /freebsd/sys/dev/isci/scil/scif_sas_controller.c (revision b7c60aadbbd5c846a250c05791fe7406d6d78bf4)
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 
80 SCI_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    SCIF_LOG_TRACE((
91       sci_base_object_get_logger(library),
92       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
93       "scif_controller_construct(0x%x, 0x%x) enter\n",
94       library, controller
95    ));
96 
97    // Validate the user supplied parameters.
98    if ((library == SCI_INVALID_HANDLE) || (controller == SCI_INVALID_HANDLE))
99       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
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 
141 SCI_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    SCIF_LOG_TRACE((
148       sci_base_object_get_logger(controller),
149       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
150       "scif_controller_initialize(0x%x) enter\n",
151       controller
152    ));
153 
154    // Validate the user supplied parameters.
155    if (controller == SCI_INVALID_HANDLE)
156       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
157 
158    return fw_controller->state_handlers->initialize_handler(
159              &fw_controller->parent
160           );
161 }
162 
163 // ---------------------------------------------------------------------------
164 
165 U32 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 
183 SCI_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    SCIF_LOG_TRACE((
191       sci_base_object_get_logger(controller),
192       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
193       "scif_controller_start(0x%x, 0x%x) enter\n",
194       controller, timeout
195    ));
196 
197    // Validate the user supplied parameters.
198    if (controller == SCI_INVALID_HANDLE)
199       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
200 
201    return fw_controller->state_handlers->
202           start_handler(&fw_controller->parent, timeout);
203 }
204 
205 // ---------------------------------------------------------------------------
206 
207 SCI_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    SCIF_LOG_TRACE((
215       sci_base_object_get_logger(controller),
216       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
217       "scif_controller_stop(0x%x, 0x%x) enter\n",
218       controller, timeout
219    ));
220 
221    // Validate the user supplied parameters.
222    if (controller == SCI_INVALID_HANDLE)
223       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
224 
225    return fw_controller->state_handlers->
226           stop_handler(&fw_controller->parent, timeout);
227 
228 }
229 
230 // ---------------------------------------------------------------------------
231 
232 SCI_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    SCIF_LOG_TRACE((
239       sci_base_object_get_logger(controller),
240       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_CONTROLLER_RESET,
241       "scif_controller_reset(0x%x) enter\n",
242       controller
243    ));
244 
245    // Validate the user supplied parameters.
246    if (controller == SCI_INVALID_HANDLE)
247       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
248 
249    return fw_controller->state_handlers->
250           reset_handler(&fw_controller->parent);
251 }
252 
253 // ---------------------------------------------------------------------------
254 
255 SCI_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 
266 SCI_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 
275    SCIF_LOG_TRACE((
276       sci_base_object_get_logger(controller),
277       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
278       "scif_controller_start_io(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
279       controller, remote_device, io_request, io_tag
280    ));
281 
282    if (
283          sci_pool_empty(fw_controller->hprq.pool)
284       || scif_sas_controller_sufficient_resource(controller)
285       )
286    {
287       return fw_controller->state_handlers->start_io_handler(
288                 (SCI_BASE_CONTROLLER_T*) controller,
289                 (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
290                 (SCI_BASE_REQUEST_T*) io_request,
291                 io_tag
292              );
293    }
294    else
295       return SCI_FAILURE_INSUFFICIENT_RESOURCES;
296 }
297 
298 // ---------------------------------------------------------------------------
299 
300 SCI_TASK_STATUS scif_controller_start_task(
301    SCI_CONTROLLER_HANDLE_T     controller,
302    SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
303    SCI_TASK_REQUEST_HANDLE_T   task_request,
304    U16                         io_tag
305 )
306 {
307    SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
308 
309    SCIF_LOG_TRACE((
310       sci_base_object_get_logger(controller),
311       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
312       "scif_controller_start_task(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
313       controller, remote_device, task_request, io_tag
314    ));
315 
316    // Validate the user supplied parameters.
317    if (  (controller == SCI_INVALID_HANDLE)
318       || (remote_device == SCI_INVALID_HANDLE)
319       || (task_request == SCI_INVALID_HANDLE) )
320    {
321       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
322    }
323 
324    if (scif_sas_controller_sufficient_resource(controller))
325    {
326       return fw_controller->state_handlers->start_task_handler(
327              (SCI_BASE_CONTROLLER_T*) controller,
328              (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
329              (SCI_BASE_REQUEST_T*) task_request,
330              io_tag
331           );
332    }
333    else
334       return SCI_FAILURE_INSUFFICIENT_RESOURCES;
335 }
336 
337 // ---------------------------------------------------------------------------
338 
339 SCI_STATUS scif_controller_complete_io(
340    SCI_CONTROLLER_HANDLE_T     controller,
341    SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
342    SCI_IO_REQUEST_HANDLE_T     io_request
343 )
344 {
345    SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
346 
347    SCIF_LOG_TRACE((
348       sci_base_object_get_logger(controller),
349       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
350       "scif_controller_complete_io(0x%x, 0x%x, 0x%x) enter\n",
351       controller, remote_device, io_request
352    ));
353 
354    return fw_controller->state_handlers->complete_io_handler(
355              (SCI_BASE_CONTROLLER_T*) controller,
356              (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
357              (SCI_BASE_REQUEST_T*) io_request
358           );
359 }
360 
361 // ---------------------------------------------------------------------------
362 
363 SCI_STATUS scif_controller_complete_task(
364    SCI_CONTROLLER_HANDLE_T     controller,
365    SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
366    SCI_TASK_REQUEST_HANDLE_T   task_request
367 )
368 {
369    SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
370 
371    SCIF_LOG_TRACE((
372       sci_base_object_get_logger(controller),
373       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
374       "scif_controller_complete_task(0x%x, 0x%x, 0x%x) enter\n",
375       controller, remote_device, task_request
376    ));
377 
378    // Validate the user supplied parameters.
379    if (  (controller == SCI_INVALID_HANDLE)
380       || (remote_device == SCI_INVALID_HANDLE)
381       || (task_request == SCI_INVALID_HANDLE) )
382    {
383       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
384    }
385 
386    return fw_controller->state_handlers->complete_task_handler(
387              (SCI_BASE_CONTROLLER_T*) controller,
388              (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
389              (SCI_BASE_REQUEST_T*) task_request
390           );
391 }
392 
393 // ---------------------------------------------------------------------------
394 
395 SCI_STATUS scif_controller_get_domain_handle(
396    SCI_CONTROLLER_HANDLE_T   controller,
397    U8                        port_index,
398    SCI_DOMAIN_HANDLE_T     * domain_handle
399 )
400 {
401    SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
402 
403    // Validate the user supplied parameters.
404    if (controller == SCI_INVALID_HANDLE)
405       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
406 
407    // Retrieve the domain handle if the supplied index is legitimate.
408    if (port_index < SCI_MAX_PORTS)
409    {
410       *domain_handle = &fw_controller->domains[port_index];
411       return SCI_SUCCESS;
412    }
413 
414    return SCI_FAILURE_INVALID_PORT;
415 }
416 
417 /**
418  * @brief This method builds the memory descriptor list for this
419  *        controller.
420  *
421  * @param[in] fw_controller This parameter specifies the framework
422  *            controller object for which to build the MDL.
423  *
424  * @return none
425  */
426 void scif_sas_controller_build_mdl(
427    SCIF_SAS_CONTROLLER_T * fw_controller
428 )
429 {
430    // one internal request for each domain.
431    sci_base_mde_construct(
432       &fw_controller->mdes[SCIF_SAS_MDE_INTERNAL_IO],
433       4,
434       fw_controller->internal_request_entries *
435          scif_sas_internal_request_get_object_size(),
436       SCI_MDE_ATTRIBUTE_PHYSICALLY_CONTIGUOUS
437    );
438 }
439 
440 // ---------------------------------------------------------------------------
441 
442 SCI_STATUS scif_controller_set_mode(
443    SCI_CONTROLLER_HANDLE_T   controller,
444    SCI_CONTROLLER_MODE       mode
445 )
446 {
447    SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
448    SCI_STATUS              status          = SCI_SUCCESS;
449 
450    if (
451          (fw_controller->parent.state_machine.current_state_id
452           == SCI_BASE_CONTROLLER_STATE_INITIALIZING)
453       || (fw_controller->parent.state_machine.current_state_id
454           == SCI_BASE_CONTROLLER_STATE_INITIALIZED)
455       )
456    {
457       switch (mode)
458       {
459       case SCI_MODE_SPEED:
460          fw_controller->internal_request_entries =
461             MIN(fw_controller->internal_request_entries, SCIF_SAS_MAX_INTERNAL_REQUEST_COUNT);
462          scif_sas_controller_build_mdl(fw_controller);
463       break;
464 
465       case SCI_MODE_SIZE:
466          fw_controller->internal_request_entries =
467             MIN(fw_controller->internal_request_entries, SCIF_SAS_MIN_INTERNAL_REQUEST_COUNT);
468          scif_sas_controller_build_mdl(fw_controller);
469       break;
470 
471       default:
472          status = SCI_FAILURE_INVALID_PARAMETER_VALUE;
473       break;
474       }
475    }
476    else
477       status = SCI_FAILURE_INVALID_STATE;
478 
479    if (status != SCI_SUCCESS)
480    {
481       return status;
482    }
483    else
484    {
485       // Currently, the framework doesn't change any configurations for
486       // speed or size modes.  Default to speed mode basically.
487       return scic_controller_set_mode(fw_controller->core_object, mode);
488    }
489 }
490 
491 // ---------------------------------------------------------------------------
492 
493 U32 scif_controller_get_sat_compliance_version(
494    void
495 )
496 {
497    /// @todo Fix return of SAT compliance version.
498    return 0;
499 }
500 
501 // ---------------------------------------------------------------------------
502 
503 U32 scif_controller_get_sat_compliance_version_revision(
504    void
505 )
506 {
507    /// @todo Fix return of SAT compliance revision.
508    return 0;
509 }
510 
511 // ---------------------------------------------------------------------------
512 
513 SCI_STATUS scif_user_parameters_set(
514    SCI_CONTROLLER_HANDLE_T   controller,
515    SCIF_USER_PARAMETERS_T  * scif_parms
516 )
517 {
518    SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
519 
520    //validate all the registry entries before overwriting the default parameter
521    //values.
522    if (scif_parms->sas.is_sata_ncq_enabled != 1 && scif_parms->sas.is_sata_ncq_enabled != 0)
523       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
524 
525    if (scif_parms->sas.max_ncq_depth < 1 && scif_parms->sas.max_ncq_depth > 32)
526       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
527 
528    if (scif_parms->sas.is_sata_standby_timer_enabled != 1
529        && scif_parms->sas.is_sata_standby_timer_enabled != 0)
530       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
531 
532    if (scif_parms->sas.is_non_zero_buffer_offsets_enabled != 1
533        && scif_parms->sas.is_non_zero_buffer_offsets_enabled != 0)
534       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
535 
536    if (scif_parms->sas.reset_type != SCI_SAS_ABORT_TASK
537        && scif_parms->sas.reset_type != SCI_SAS_ABORT_TASK_SET
538        && scif_parms->sas.reset_type != SCI_SAS_CLEAR_TASK_SET
539        && scif_parms->sas.reset_type != SCI_SAS_LOGICAL_UNIT_RESET
540        && scif_parms->sas.reset_type != SCI_SAS_I_T_NEXUS_RESET
541        && scif_parms->sas.reset_type != SCI_SAS_CLEAR_ACA
542        && scif_parms->sas.reset_type != SCI_SAS_QUERY_TASK
543        && scif_parms->sas.reset_type != SCI_SAS_QUERY_TASK_SET
544        && scif_parms->sas.reset_type != SCI_SAS_QUERY_ASYNCHRONOUS_EVENT
545        && scif_parms->sas.reset_type != SCI_SAS_HARD_RESET)
546       return SCI_FAILURE_INVALID_PARAMETER_VALUE;
547 
548    if (scif_parms->sas.clear_affiliation_during_controller_stop != 1
549        && scif_parms->sas.clear_affiliation_during_controller_stop !=0)
550        return SCI_FAILURE_INVALID_PARAMETER_VALUE;
551 
552    memcpy((&fw_controller->user_parameters), scif_parms, sizeof(*scif_parms));
553 
554    // In the future more could be done to prevent setting parameters at the
555    // wrong time, but for now we'll simply set the values even if it is too
556    // late for them to take affect.
557    return SCI_SUCCESS;
558 }
559 
560 // ---------------------------------------------------------------------------
561 
562 #if !defined(DISABLE_INTERRUPTS)
563 
564 /**
565  * @brief This routine check each domain of the controller to see if
566  *           any domain is overriding interrupt coalescence.
567  *
568  * @param[in] fw_controller frame controller
569  * @param[in] fw_smp_phy The smp phy to be freed.
570  *
571  * @return none
572  */
573 static
574 BOOL scif_sas_controller_is_overriding_interrupt_coalescence(
575    SCIF_SAS_CONTROLLER_T * fw_controller
576 )
577 {
578    U8 index;
579 
580    for(index = 0; index < SCI_MAX_DOMAINS; index++)
581    {
582       if(fw_controller->domains[index].parent.state_machine.current_state_id ==
583             SCI_BASE_DOMAIN_STATE_DISCOVERING)
584          return TRUE;
585    }
586 
587    return FALSE;
588 }
589 
590 SCI_STATUS scif_controller_set_interrupt_coalescence(
591    SCI_CONTROLLER_HANDLE_T controller,
592    U32                     coalesce_number,
593    U32                     coalesce_timeout
594 )
595 {
596    SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T * )controller;
597 
598    ///when framework is in the middle of temporarily overriding the interrupt
599    ///coalescence values, user's request of setting interrupt coalescence
600    ///will be saved. As soon as the framework done the temporary overriding,
601    ///it will serve user's request to set new interrupt coalescence.
602    if (scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller))
603    {
604       U32 curr_coalesce_number;
605       U32 curr_coalesce_timeout;
606       SCI_STATUS core_status;
607 
608       // save current interrupt coalescence info.
609       scic_controller_get_interrupt_coalescence (
610          fw_controller->core_object, &curr_coalesce_number, &curr_coalesce_timeout);
611 
612       //try user's request out in the core, but immediately restore core's
613       //current setting.
614       core_status = scic_controller_set_interrupt_coalescence(
615                        fw_controller->core_object, coalesce_number, coalesce_timeout);
616 
617       if ( core_status == SCI_SUCCESS )
618       {
619          fw_controller->saved_interrupt_coalesce_number = (U16)coalesce_number;
620          fw_controller->saved_interrupt_coalesce_timeout = coalesce_timeout;
621       }
622 
623        //restore current interrupt coalescence.
624       scic_controller_set_interrupt_coalescence(
625          fw_controller->core_object, curr_coalesce_number, curr_coalesce_timeout);
626 
627       return core_status;
628    }
629    else
630    {
631       ///If framework is not internally overriding the interrupt coalescence,
632       ///serve user's request immediately by passing the reqeust to core.
633       return scic_controller_set_interrupt_coalescence(
634                 fw_controller->core_object, coalesce_number, coalesce_timeout);
635    }
636 }
637 
638 // ---------------------------------------------------------------------------
639 
640 void scif_controller_get_interrupt_coalescence(
641    SCI_CONTROLLER_HANDLE_T controller,
642    U32                   * coalesce_number,
643    U32                   * coalesce_timeout
644 )
645 {
646    SCIF_SAS_CONTROLLER_T * scif_controller = (SCIF_SAS_CONTROLLER_T * )controller;
647 
648    scic_controller_get_interrupt_coalescence(
649       scif_controller->core_object, coalesce_number, coalesce_timeout);
650 }
651 
652 /**
653  * @brief This method will save the interrupt coalescence values.  If
654  *        the interrupt coalescence values have already been saved,
655  *        then this method performs no operations.
656  *
657  * @param[in,out] fw_controller This parameter specifies the controller
658  *                for which to save the interrupt coalescence values.
659  *
660  * @return none
661  */
662 void scif_sas_controller_save_interrupt_coalescence(
663    SCIF_SAS_CONTROLLER_T * fw_controller
664 )
665 {
666    if ( !scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller))
667    {
668       // Override core's interrupt coalescing settings during SMP
669       // DISCOVER process cause' there is only 1 outstanding SMP
670       // request per domain is allowed.
671       scic_controller_get_interrupt_coalescence(
672          fw_controller->core_object,
673          (U32*)&(fw_controller->saved_interrupt_coalesce_number),
674          &(fw_controller->saved_interrupt_coalesce_timeout)
675       );
676 
677       // Temporarily disable the interrupt coalescing.
678       scic_controller_set_interrupt_coalescence(fw_controller->core_object,0,0);
679    }
680 }
681 
682 /**
683  * @brief This method will restore the interrupt coalescence values.  If
684  *        the interrupt coalescence values have not already been saved,
685  *        then this method performs no operations.
686  *
687  * @param[in,out] fw_controller This parameter specifies the controller
688  *                for which to restore the interrupt coalescence values.
689  *
690  * @return none
691  */
692 void scif_sas_controller_restore_interrupt_coalescence(
693    SCIF_SAS_CONTROLLER_T * fw_controller
694 )
695 {
696    if ( !scif_sas_controller_is_overriding_interrupt_coalescence(fw_controller))
697       scic_controller_set_interrupt_coalescence(
698          fw_controller->core_object,
699          fw_controller->saved_interrupt_coalesce_number,
700          fw_controller->saved_interrupt_coalesce_timeout
701       );
702 }
703 
704 #endif // !defined(DISABLE_INTERRUPTS)
705 
706 // ---------------------------------------------------------------------------
707 
708 void scic_cb_controller_start_complete(
709    SCI_CONTROLLER_HANDLE_T  controller,
710    SCI_STATUS               completion_status
711 )
712 {
713    SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)
714                                          sci_object_get_association(controller);
715 
716    SCIF_LOG_TRACE((
717       sci_base_object_get_logger(controller),
718       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_INITIALIZATION,
719       "scic_cb_controller_start_complete(0x%x, 0x%x) enter\n",
720       controller, completion_status
721    ));
722 
723    if (completion_status == SCI_SUCCESS
724        || completion_status == SCI_FAILURE_TIMEOUT)
725    {
726       // Even the initialization of the core controller timed out, framework
727       // controller should still transit to READY state.
728       sci_base_state_machine_change_state(
729          &fw_controller->parent.state_machine,
730          SCI_BASE_CONTROLLER_STATE_READY
731       );
732    }
733 
734    scif_cb_controller_start_complete(fw_controller, completion_status);
735 }
736 
737 // ---------------------------------------------------------------------------
738 
739 void scic_cb_controller_stop_complete(
740    SCI_CONTROLLER_HANDLE_T  controller,
741    SCI_STATUS               completion_status
742 )
743 {
744    SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)
745                                          sci_object_get_association(controller);
746 
747    SCIF_LOG_TRACE((
748       sci_base_object_get_logger(controller),
749       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
750       "scic_cb_controller_stop_complete(0x%x, 0x%x) enter\n",
751       controller, completion_status
752    ));
753 
754    if (completion_status == SCI_SUCCESS)
755    {
756       sci_base_state_machine_change_state(
757          &fw_controller->parent.state_machine,
758          SCI_BASE_CONTROLLER_STATE_STOPPED
759       );
760    }
761    else
762    {
763       sci_base_state_machine_change_state(
764          &fw_controller->parent.state_machine,
765          SCI_BASE_CONTROLLER_STATE_FAILED
766       );
767    }
768 
769    scif_cb_controller_stop_complete(fw_controller, completion_status);
770 }
771 
772 
773 // ---------------------------------------------------------------------------
774 
775 void scic_cb_controller_error(
776    SCI_CONTROLLER_HANDLE_T  controller,
777    SCI_CONTROLLER_ERROR error
778 )
779 {
780    SCIF_SAS_CONTROLLER_T *fw_controller = (SCIF_SAS_CONTROLLER_T*)
781                                          sci_object_get_association(controller);
782 
783    fw_controller->parent.error = error;
784 
785    SCIF_LOG_TRACE((
786       sci_base_object_get_logger(controller),
787       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
788       "scic_cb_controller_not_ready(0x%x) enter\n",
789       controller
790    ));
791 
792    sci_base_state_machine_change_state(
793       &fw_controller->parent.state_machine,
794       SCI_BASE_CONTROLLER_STATE_FAILED
795    );
796 }
797 
798 //******************************************************************************
799 //* P R O T E C T E D    M E T H O D S
800 //******************************************************************************
801 
802 /**
803  * @brief This method is utilized to continue an internal IO operation
804  *        on the controller.  This method is utilized for SAT translated
805  *        requests that generate multiple ATA commands in order to fulfill
806  *        the original SCSI request.
807  *
808  * @param[in]  controller This parameter specifies the controller on which
809  *             to continue an internal IO request.
810  * @param[in]  remote_device This parameter specifies the remote device
811  *             on which to continue an internal IO request.
812  * @param[in]  io_request This parameter specifies the IO request to be
813  *             continue.
814  *
815  * @return Indicate if the continue operation was successful.
816  * @retval SCI_SUCCESS This value is returned if the operation succeeded.
817  */
818 SCI_STATUS scif_sas_controller_continue_io(
819    SCI_CONTROLLER_HANDLE_T     controller,
820    SCI_REMOTE_DEVICE_HANDLE_T  remote_device,
821    SCI_IO_REQUEST_HANDLE_T     io_request
822 )
823 {
824    SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T*) controller;
825 
826    return fw_controller->state_handlers->continue_io_handler(
827              (SCI_BASE_CONTROLLER_T*) controller,
828              (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
829              (SCI_BASE_REQUEST_T*) io_request
830           );
831 }
832 
833 /**
834  * @brief This method will attempt to destruct a framework controller.
835  *        This includes free any resources retreived from the user (e.g.
836  *        timers).
837  *
838  * @param[in]  fw_controller This parameter specifies the framework
839  *             controller to destructed.
840  *
841  * @return none
842  */
843 void scif_sas_controller_destruct(
844    SCIF_SAS_CONTROLLER_T * fw_controller
845 )
846 {
847    SCIF_LOG_TRACE((
848       sci_base_object_get_logger(fw_controller),
849       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_SHUTDOWN,
850       "scif_sas_controller_destruct(0x%x) enter\n",
851       fw_controller
852    ));
853 }
854 
855 //-----------------------------------------------------------------------------
856 // INTERNAL REQUEST RELATED METHODS
857 //-----------------------------------------------------------------------------
858 
859 /**
860  * @brief This routine is to allocate the memory for creating a new internal
861  *        request.
862  *
863  * @param[in] scif_controller handle to frame controller
864  *
865  * @return void* address to internal request memory
866  */
867 void * scif_sas_controller_allocate_internal_request(
868    SCIF_SAS_CONTROLLER_T * fw_controller
869 )
870 {
871    POINTER_UINT internal_io_address;
872 
873    if( !sci_pool_empty(fw_controller->internal_request_memory_pool) )
874    {
875       sci_pool_get(
876          fw_controller->internal_request_memory_pool, internal_io_address
877       );
878 
879       //clean the memory.
880       memset((char*)internal_io_address, 0, scif_sas_internal_request_get_object_size());
881 
882       return (void *) internal_io_address;
883    }
884    else
885       return NULL;
886 }
887 
888 /**
889  * @brief This routine is to free the memory for a completed internal request.
890  *
891  * @param[in] scif_controller handle to frame controller
892  * @param[in] fw_internal_io The internal IO to be freed.
893  *
894  * @return none
895  */
896 void scif_sas_controller_free_internal_request(
897    SCIF_SAS_CONTROLLER_T * fw_controller,
898    void                  * fw_internal_request_buffer
899 )
900 {
901    SCIF_LOG_TRACE((
902       sci_base_object_get_logger(fw_controller),
903       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
904       "scif_controller_free_internal_request(0x%x, 0x%x) enter\n",
905       fw_controller, fw_internal_request_buffer
906    ));
907 
908    //return the memory to to pool.
909    if( !sci_pool_full(fw_controller->internal_request_memory_pool) )
910    {
911       sci_pool_put(
912          fw_controller->internal_request_memory_pool,
913          (POINTER_UINT) fw_internal_request_buffer
914       );
915    }
916 }
917 
918 
919 /**
920  * @brief this routine is called by OS' DPC to start io requests from internal
921  *        high priority request queue
922  * @param[in] fw_controller The framework controller.
923  *
924  * @return none
925  */
926 void scif_sas_controller_start_high_priority_io(
927    SCIF_SAS_CONTROLLER_T * fw_controller
928 )
929 {
930    POINTER_UINT            io_address;
931    SCIF_SAS_IO_REQUEST_T * fw_io;
932    SCI_STATUS              status;
933 
934    SCIF_LOG_TRACE((
935       sci_base_object_get_logger(fw_controller),
936       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
937       "scif_controller_start_high_priority_io(0x%x) enter\n",
938       fw_controller
939    ));
940 
941    while ( !sci_pool_empty(fw_controller->hprq.pool) )
942    {
943       sci_pool_get(fw_controller->hprq.pool, io_address);
944 
945       fw_io = (SCIF_SAS_IO_REQUEST_T *)io_address;
946 
947       status = fw_controller->state_handlers->start_high_priority_io_handler(
948          (SCI_BASE_CONTROLLER_T*) fw_controller,
949          (SCI_BASE_REMOTE_DEVICE_T*) fw_io->parent.device,
950          (SCI_BASE_REQUEST_T*) fw_io,
951          SCI_CONTROLLER_INVALID_IO_TAG
952       );
953    }
954 }
955 
956 /**
957  * @brief This method will check how many outstanding IOs currently and number
958  * of IOs in high priority queue, if the overall number exceeds the max_tc,
959  * return FALSE.
960  *
961  * @param[in] fw_controller The framework controller.
962  *
963  * @return BOOL Indicate whether there is sufficient resource to start an IO.
964  * @retvalue TRUE The controller has sufficient resource.
965  * @retvalue FALSE There is not sufficient resource available.
966  */
967 BOOL scif_sas_controller_sufficient_resource(
968    SCIF_SAS_CONTROLLER_T *fw_controller
969 )
970 {
971    SCIF_SAS_DOMAIN_T * fw_domain;
972    U32 domain_index;
973    U32 outstanding_io_count = 0;
974    U32 high_priority_io_count = 0;
975 
976    for(domain_index = 0; domain_index < SCI_MAX_DOMAINS; domain_index++)
977    {
978       fw_domain = &fw_controller->domains[domain_index];
979       outstanding_io_count += fw_domain->request_list.element_count;
980    }
981 
982    high_priority_io_count = sci_pool_count(fw_controller->hprq.pool);
983 
984    if ( (outstanding_io_count + high_priority_io_count) > SCI_MAX_IO_REQUESTS )
985       return FALSE;
986 
987    return TRUE;
988 }
989 
990 
991 /**
992  * @brief This method is the starting point to complete high prority io for a
993  *        controller then down to domain, device.
994  *
995  * @param[in] fw_controller The framework controller
996  * @param[in] remote_device  The framework remote device.
997  * @param[in] io_request The high priority io request to be completed.
998  *
999  * @return SCI_STATUS indicate the completion status from framework down to the
1000  *         core.
1001  */
1002 SCI_STATUS scif_sas_controller_complete_high_priority_io(
1003    SCIF_SAS_CONTROLLER_T    *fw_controller,
1004    SCIF_SAS_REMOTE_DEVICE_T *remote_device,
1005    SCIF_SAS_REQUEST_T       *io_request
1006 )
1007 {
1008    SCIF_LOG_TRACE((
1009       sci_base_object_get_logger(fw_controller),
1010       SCIF_LOG_OBJECT_CONTROLLER | SCIF_LOG_OBJECT_IO_REQUEST,
1011       "scif_sas_controller_complete_high_priority_io(0x%x, 0x%x, 0x%x) enter\n",
1012       fw_controller, remote_device, io_request
1013    ));
1014 
1015    //call controller's new added complete_high_priority_io_handler
1016    return fw_controller->state_handlers->complete_high_priority_io_handler(
1017              (SCI_BASE_CONTROLLER_T*) fw_controller,
1018              (SCI_BASE_REMOTE_DEVICE_T*) remote_device,
1019              (SCI_BASE_REQUEST_T*) io_request
1020           );
1021 }
1022 
1023 /**
1024 
1025  * @brief This routine is to allocate the memory for creating a smp phy object.
1026  *
1027  * @param[in] scif_controller handle to frame controller
1028  *
1029  * @return SCIF_SAS_SMP_PHY_T * An allocated space for smp phy. If failed to allocate,
1030  *            return NULL.
1031  */
1032 SCIF_SAS_SMP_PHY_T * scif_sas_controller_allocate_smp_phy(
1033    SCIF_SAS_CONTROLLER_T * fw_controller
1034 )
1035 {
1036    SCIF_SAS_SMP_PHY_T * smp_phy;
1037 
1038    SCIF_LOG_TRACE((
1039       sci_base_object_get_logger(fw_controller),
1040       SCIF_LOG_OBJECT_CONTROLLER,
1041       "scif_controller_allocate_smp_phy(0x%x) enter\n",
1042       fw_controller
1043    ));
1044 
1045    if( !sci_fast_list_is_empty(&fw_controller->smp_phy_memory_list) )
1046    {
1047       smp_phy = (SCIF_SAS_SMP_PHY_T *)
1048          sci_fast_list_remove_head(&fw_controller->smp_phy_memory_list);
1049 
1050       //clean the memory.
1051       memset((char*)smp_phy,
1052              0,
1053              sizeof(SCIF_SAS_SMP_PHY_T)
1054             );
1055 
1056       return smp_phy;
1057    }
1058    else
1059       return NULL;
1060 }
1061 
1062 /**
1063  * @brief This routine is to free the memory for a released smp phy.
1064  *
1065  * @param[in] fw_controller The framework controller, a smp phy is released
1066  *                to its memory.
1067  * @param[in] fw_smp_phy The smp phy to be freed.
1068  *
1069  * @return none
1070  */
1071 void scif_sas_controller_free_smp_phy(
1072    SCIF_SAS_CONTROLLER_T * fw_controller,
1073    SCIF_SAS_SMP_PHY_T    * smp_phy
1074 )
1075 {
1076    SCIF_LOG_TRACE((
1077       sci_base_object_get_logger(fw_controller),
1078       SCIF_LOG_OBJECT_CONTROLLER,
1079       "scif_controller_free_smp_phy(0x%x, 0x%x) enter\n",
1080       fw_controller, smp_phy
1081    ));
1082 
1083    //return the memory to the list.
1084    sci_fast_list_insert_tail(
1085       &fw_controller->smp_phy_memory_list,
1086       &smp_phy->list_element
1087    );
1088 }
1089 
1090 
1091 /**
1092  * @brief This method clear affiliation for all the EA SATA devices associated
1093  *        to this controller.
1094  *
1095  * @param[in] fw_controller This parameter specifies the framework
1096  *            controller object for whose remote devices are to be stopped.
1097  *
1098  * @return This method returns a value indicating if the operation completed.
1099  * @retval SCI_COMPLETE This value indicates that all the EA SATA devices'
1100  *         affiliation was cleared.
1101  * @retval SCI_INCOMPLETE This value indicates clear affiliation activity is
1102  *         yet to be completed.
1103  */
1104 SCI_STATUS scif_sas_controller_clear_affiliation(
1105    SCIF_SAS_CONTROLLER_T * fw_controller
1106 )
1107 {
1108    U8 index;
1109    SCI_STATUS status;
1110    SCIF_SAS_DOMAIN_T * fw_domain;
1111 
1112    SCIF_LOG_TRACE((
1113       sci_base_object_get_logger(fw_controller),
1114       SCIF_LOG_OBJECT_CONTROLLER,
1115       "scif_sas_controller_clear_affiliation(0x%x) enter\n",
1116       fw_controller
1117    ));
1118 
1119    index = fw_controller->current_domain_to_clear_affiliation;
1120 
1121    if (index < SCI_MAX_DOMAINS)
1122    {
1123       fw_domain = &fw_controller->domains[index];
1124 
1125       //Need to stop all the on-going smp activities before clearing affiliation.
1126       scif_sas_domain_cancel_smp_activities(fw_domain);
1127 
1128       scif_sas_domain_start_clear_affiliation(fw_domain);
1129 
1130       status = SCI_WARNING_SEQUENCE_INCOMPLETE;
1131    }
1132    else
1133    {  //the controller has done clear affiliation work to all its domains.
1134       scif_sas_controller_continue_to_stop(fw_controller);
1135       status = SCI_SUCCESS;
1136    }
1137 
1138    return status;
1139 }
1140 
1141 
1142 /**
1143  * @brief This method sets SCIF user parameters to
1144  *        default values.  Users can override these values utilizing
1145  *        the sciF_user_parameters_set() methods.
1146  *
1147  * @param[in] controller This parameter specifies the controller for
1148  *            which to set the configuration parameters to their
1149  *            default values.
1150  *
1151  * @return none
1152  */
1153 void scif_sas_controller_set_default_config_parameters(
1154    SCIF_SAS_CONTROLLER_T * this_controller
1155 )
1156 {
1157    SCIF_USER_PARAMETERS_T * scif_parms = &(this_controller->user_parameters);
1158 
1159    scif_parms->sas.is_sata_ncq_enabled = TRUE;
1160    scif_parms->sas.max_ncq_depth = 32;
1161    scif_parms->sas.is_sata_standby_timer_enabled = FALSE;
1162    scif_parms->sas.is_non_zero_buffer_offsets_enabled = FALSE;
1163    scif_parms->sas.reset_type = SCI_SAS_LOGICAL_UNIT_RESET;
1164    scif_parms->sas.clear_affiliation_during_controller_stop = TRUE;
1165    scif_parms->sas.ignore_fua = FALSE;
1166 
1167 }
1168 
1169 
1170 /**
1171  * @brief This method releases resource for framework controller and associated
1172  *        objects.
1173  *
1174  * @param[in] fw_controller This parameter specifies the framework
1175  *            controller and associated objects whose resources are to be released.
1176  *
1177  * @return This method returns a value indicating if the operation succeeded.
1178  * @retval SCI_SUCCESS This value indicates that resource release succeeded.
1179  * @retval SCI_FAILURE This value indicates certain failure during the process
1180  *            of resource release.
1181  */
1182 SCI_STATUS scif_sas_controller_release_resource(
1183    SCIF_SAS_CONTROLLER_T * fw_controller
1184 )
1185 {
1186    U8 index;
1187    SCIF_SAS_DOMAIN_T * fw_domain;
1188 
1189    SCIF_LOG_TRACE((
1190       sci_base_object_get_logger(fw_controller),
1191       SCIF_LOG_OBJECT_CONTROLLER,
1192       "scif_sas_controller_release_resource(0x%x) enter\n",
1193       fw_controller
1194    ));
1195 
1196    //currently the only resource to be released is domain's timer.
1197    for (index = 0; index < SCI_MAX_DOMAINS; index++)
1198    {
1199       fw_domain = &fw_controller->domains[index];
1200 
1201       scif_sas_domain_release_resource(fw_controller, fw_domain);
1202    }
1203 
1204    return SCI_SUCCESS;
1205 }
1206 
1207 
1208 #ifdef SCI_LOGGING
1209 /**
1210  * This method will start state transition logging for the framework
1211  * controller object.
1212  *
1213  * @param[in] fw_controller The framework controller object on which to
1214  *       observe state changes.
1215  *
1216  * @return none
1217  */
1218 void scif_sas_controller_initialize_state_logging(
1219    SCIF_SAS_CONTROLLER_T * fw_controller
1220 )
1221 {
1222    sci_base_state_machine_logger_initialize(
1223       &fw_controller->parent.state_machine_logger,
1224       &fw_controller->parent.state_machine,
1225       &fw_controller->parent.parent,
1226       scif_cb_logger_log_states,
1227       "SCIF_SAS_CONTROLLER_T", "base state machine",
1228       SCIF_LOG_OBJECT_CONTROLLER
1229    );
1230 }
1231 
1232 /**
1233  * This method will remove the logging of state transitions from the framework
1234  * controller object.
1235  *
1236  * @param[in] fw_controller The framework controller to change.
1237  *
1238  * @return none
1239  */
1240 void scif_sas_controller_deinitialize_state_logging(
1241    SCIF_SAS_CONTROLLER_T * fw_controller
1242 )
1243 {
1244    sci_base_state_machine_logger_deinitialize(
1245       &fw_controller->parent.state_machine_logger,
1246       &fw_controller->parent.state_machine
1247    );
1248 }
1249 #endif // SCI_LOGGING
1250