xref: /freebsd/sys/dev/isci/scil/scif_sas_controller.c (revision 2da066ef6d85d3f7cd8aaec14369d66254836536)
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 /**
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    // 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 
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    // 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 
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    // 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 
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    // 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 
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    // 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 
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    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 
303 SCI_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 
345 SCI_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 
369 SCI_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 
401 SCI_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  */
432 void 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 
448 SCI_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 
499 U32 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 
509 U32 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 
519 SCI_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 effect.
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  */
579 static
580 BOOL 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 
596 SCI_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 
646 void 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  */
668 void 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  */
698 void 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 
714 void 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 
745 void 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 
781 void 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  */
824 SCI_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  */
849 void 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  */
873 void * 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  */
902 void 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 the 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  */
932 void 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  */
973 BOOL 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  */
1008 SCI_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  */
1038 SCIF_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  */
1077 void 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  */
1110 SCI_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  */
1159 void 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  */
1188 SCI_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  */
1224 void 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  */
1246 void 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