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