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: head/sys/dev/isci/scil/scif_sas_domain.c 250460 2013-05-10 16:41:26Z eadler $");
55
56/**
57 * @file
58 *
59 * @brief This file contains the implementation of the SCIF_SAS_DOMAIN
60 * object.
61 */
62
63#include <dev/isci/scil/intel_sas.h>
64#include <dev/isci/scil/sci_fast_list.h>
65#include <dev/isci/scil/scic_controller.h>
66#include <dev/isci/scil/scic_port.h>
67#include <dev/isci/scil/scic_remote_device.h>
68#include <dev/isci/scil/scic_io_request.h>
69#include <dev/isci/scil/scic_user_callback.h>
70#include <dev/isci/scil/scif_user_callback.h>
71#include <dev/isci/scil/sci_abstract_list.h>
72#include <dev/isci/scil/sci_base_iterator.h>
73
74#include <dev/isci/scil/scif_sas_logger.h>
75#include <dev/isci/scil/scif_sas_domain.h>
76#include <dev/isci/scil/scif_sas_controller.h>
77#include <dev/isci/scil/scif_sas_remote_device.h>
78#include <dev/isci/scil/scif_sas_smp_remote_device.h>
79#include <dev/isci/scil/sci_util.h>
80
81//******************************************************************************
82//* P R I V A T E M E T H O D S
83//******************************************************************************
84
85/**
86 * @brief This method will attempt to handle an operation timeout (i.e.
87 * discovery or reset).
88 *
89 * @param[in] cookie This parameter specifies the domain in which the
90 * timeout occurred.
91 *
92 * @return none
93 */
94static
95void scif_sas_domain_operation_timeout_handler(
96 void * cookie
97)
98{
99 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) cookie;
100 U32 state;
101
102 state = sci_base_state_machine_get_state(&fw_domain->parent.state_machine);
103
104 // Based upon the state of the domain, we know whether we were in the
105 // process of performing discovery or a reset.
106 if (state == SCI_BASE_DOMAIN_STATE_DISCOVERING)
107 {
108 SCIF_LOG_WARNING((
109 sci_base_object_get_logger(fw_domain),
110 SCIF_LOG_OBJECT_DOMAIN,
111 "Domain:0x%x State:0x%x DISCOVER timeout!\n",
112 fw_domain, state
113 ));
114
115 fw_domain->operation.status = SCI_FAILURE_TIMEOUT;
116
117 //search all the smp devices in the domain and cancel their activities
118 //if there is any outstanding activity remained. The smp devices will terminate
119 //all the started internal IOs.
120 scif_sas_domain_cancel_smp_activities(fw_domain);
121
122 scif_sas_domain_continue_discover(fw_domain);
123 }
124 else
125 {
126 SCIF_LOG_ERROR((
127 sci_base_object_get_logger(fw_domain),
128 SCIF_LOG_OBJECT_DOMAIN,
129 "Domain:0x%x State:0x%x operation timeout in invalid state\n",
130 fw_domain, state
131 ));
132 }
133}
134
135//******************************************************************************
136//* P U B L I C M E T H O D S
137//******************************************************************************
138
139SCI_PORT_HANDLE_T scif_domain_get_scic_port_handle(
140 SCI_DOMAIN_HANDLE_T domain
141)
142{
143 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
144
145 if ( (fw_domain == NULL) || (fw_domain->core_object == SCI_INVALID_HANDLE) )
146 return SCI_INVALID_HANDLE;
147
148 SCIF_LOG_WARNING((
149 sci_base_object_get_logger(fw_domain),
150 SCIF_LOG_OBJECT_DOMAIN,
151 "Domain:0x%x no associated core port found\n",
152 fw_domain
153 ));
154
155 return fw_domain->core_object;
156}
157
158// ---------------------------------------------------------------------------
159
160SCI_REMOTE_DEVICE_HANDLE_T scif_domain_get_device_by_sas_address(
161 SCI_DOMAIN_HANDLE_T domain,
162 SCI_SAS_ADDRESS_T * sas_address
163)
164{
165 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
166 SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
167 &fw_domain->remote_device_list
168 );
169 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
170 SCI_SAS_ADDRESS_T fw_device_address;
171
172 SCIF_LOG_TRACE((
173 sci_base_object_get_logger(domain),
174 SCIF_LOG_OBJECT_DOMAIN,
175 "scif_domain_get_device_by_sas_address(0x%x, 0x%x) enter\n",
176 domain, sas_address
177 ));
178
179 // Search the abstract list to see if there is a remote device with the
180 // same SAS address.
181 while (element != NULL)
182 {
183 fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
184 sci_abstract_list_get_object(element);
185
186 scic_remote_device_get_sas_address(
187 fw_device->core_object, &fw_device_address
188 );
189
190 // Check to see if this is the device for which we are searching.
191 if ( (fw_device_address.low == sas_address->low)
192 && (fw_device_address.high == sas_address->high) )
193 {
194 return fw_device;
195 }
196
197 element = sci_abstract_list_get_next(element);
198 }
199
200 return SCI_INVALID_HANDLE;
201}
202
203// ---------------------------------------------------------------------------
204
205#if !defined(DISABLE_SCI_ITERATORS)
206
207SCI_ITERATOR_HANDLE_T scif_domain_get_remote_device_iterator(
208 SCI_DOMAIN_HANDLE_T domain,
209 void * iterator_buffer
210)
211{
212 SCI_ITERATOR_HANDLE_T iterator = (SCI_ITERATOR_HANDLE_T *)iterator_buffer;
213
214 sci_base_iterator_construct(
215 iterator, &((SCIF_SAS_DOMAIN_T*) domain)->remote_device_list
216 );
217
218
219 return iterator;
220}
221
222#endif // !defined(DISABLE_SCI_ITERATORS)
223
224// ---------------------------------------------------------------------------
225
226SCI_STATUS scif_domain_discover(
227 SCI_DOMAIN_HANDLE_T domain,
228 U32 discover_timeout,
229 U32 device_timeout
230)
231{
232 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
233 SCI_STATUS status = SCI_SUCCESS;
234 SCI_STATUS op_status = SCI_SUCCESS;
235
236 SCIF_LOG_TRACE((
237 sci_base_object_get_logger(domain),
238 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
239 "scif_domain_discover(0x%x, 0x%x, 0x%x) enter\n",
240 domain, discover_timeout, device_timeout
241 ));
242
243 // Check to make sure the size of the domain doesn't cause potential issues
244 // with the remote device timer and the domain timer.
245 if ((device_timeout * sci_abstract_list_size(&fw_domain->remote_device_list))
246 > discover_timeout)
247 status = SCI_WARNING_TIMER_CONFLICT;
248
249 op_status = fw_domain->state_handlers->discover_handler(
250 &fw_domain->parent, discover_timeout, device_timeout
251 );
252
253 // The status of the discover operation takes priority.
254 if ( (status == SCI_SUCCESS)
255 || (status != SCI_SUCCESS && op_status != SCI_SUCCESS) )
256 {
257 status = op_status;
258 }
259
260 return status;
261}
262
263// ---------------------------------------------------------------------------
264
265U32 scif_domain_get_suggested_discover_timeout(
266 SCI_DOMAIN_HANDLE_T domain
267)
268{
269 U32 suggested_timeout = SCIF_DOMAIN_DISCOVER_TIMEOUT; //milli-seconds
270 return suggested_timeout;
271}
272
273// ---------------------------------------------------------------------------
274
275void scic_cb_port_stop_complete(
276 SCI_CONTROLLER_HANDLE_T controller,
277 SCI_PORT_HANDLE_T port,
278 SCI_STATUS completion_status
279)
280{
281 SCIF_LOG_TRACE((
282 sci_base_object_get_logger((SCIF_SAS_DOMAIN_T*)sci_object_get_association(port)),
283 SCIF_LOG_OBJECT_DOMAIN,
284 "scic_cb_port_stop_complete(0x%x, 0x%x, 0x%x) enter\n",
285 controller, port, completion_status
286 ));
287}
288
289// ---------------------------------------------------------------------------
290
291void scic_cb_port_ready(
292 SCI_CONTROLLER_HANDLE_T controller,
293 SCI_PORT_HANDLE_T port
294)
295{
296 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
297 sci_object_get_association(port);
298
299 SCIF_LOG_TRACE((
300 sci_base_object_get_logger(fw_domain),
301 SCIF_LOG_OBJECT_DOMAIN,
302 "scic_cb_port_ready(0x%x, 0x%x) enter\n",
303 controller, port
304 ));
305
306 // The controller supplied with the port should match the controller
307 // saved in the domain.
308 ASSERT(sci_object_get_association(controller) == fw_domain->controller);
309
310 fw_domain->is_port_ready = TRUE;
311
312 fw_domain->state_handlers->port_ready_handler(&fw_domain->parent);
313}
314
315// ---------------------------------------------------------------------------
316
317void scic_cb_port_not_ready(
318 SCI_CONTROLLER_HANDLE_T controller,
319 SCI_PORT_HANDLE_T port,
320 U32 reason_code
321)
322{
323 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
324 sci_object_get_association(port);
325
326 SCIF_LOG_TRACE((
327 sci_base_object_get_logger(fw_domain),
328 SCIF_LOG_OBJECT_DOMAIN,
329 "scic_cb_port_not_ready(0x%x, 0x%x) enter\n",
330 controller, port
331 ));
332
333 // The controller supplied with the port should match the controller
334 // saved in the domain.
335 ASSERT(sci_object_get_association(controller) == fw_domain->controller);
336
337 // There is no need to take action on the port reconfiguring since it is
338 // just a change of the port width.
339 if (reason_code != SCIC_PORT_NOT_READY_RECONFIGURING)
340 {
341 fw_domain->is_port_ready = FALSE;
342
343 fw_domain->state_handlers->port_not_ready_handler(
344 &fw_domain->parent, reason_code);
345 }
346}
347
348// ---------------------------------------------------------------------------
349
350void scic_cb_port_hard_reset_complete(
351 SCI_CONTROLLER_HANDLE_T controller,
352 SCI_PORT_HANDLE_T port,
353 SCI_STATUS completion_status
354)
355{
356 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
357 sci_object_get_association(port);
358 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
359 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
360 SCIF_SAS_TASK_REQUEST_T * task_request = NULL;
361
362 SCIF_LOG_TRACE((
363 sci_base_object_get_logger(fw_domain),
364 SCIF_LOG_OBJECT_DOMAIN,
365 "scic_cb_port_hard_reset_complete(0x%x, 0x%x, 0x%x) enter\n",
366 controller, port, completion_status
367 ));
368
369 while (element != NULL)
370 {
371 task_request = (SCIF_SAS_TASK_REQUEST_T*) sci_fast_list_get_object(element);
372 element = sci_fast_list_get_next(element);
373
374 if (scif_sas_task_request_get_function(task_request)
375 == SCI_SAS_HARD_RESET)
376 {
377 fw_device = task_request->parent.device;
378
379 if (fw_device->domain == fw_domain)
380 {
381 scic_remote_device_reset_complete(fw_device->core_object);
382
383 scif_cb_task_request_complete(
384 sci_object_get_association(controller),
385 fw_device,
386 task_request,
387 (SCI_TASK_STATUS) completion_status
388 );
389
390 break;
391 }
392 }
393 }
394}
395
396// ---------------------------------------------------------------------------
397
398void scic_cb_port_bc_change_primitive_recieved(
399 SCI_CONTROLLER_HANDLE_T controller,
400 SCI_PORT_HANDLE_T port,
401 SCI_PHY_HANDLE_T phy
402)
403{
404 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
405 sci_object_get_association(port);
406
407 SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)
408 sci_object_get_association(controller);
409
410 SCIF_LOG_TRACE((
411 sci_base_object_get_logger(fw_domain),
412 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
413 "scic_cb_port_bc_change_primitive_recieved(0x%x, 0x%x, 0x%x) enter\n",
414 controller, port, phy
415 ));
416
417 if (fw_domain->broadcast_change_count == 0)
418 { // Enable the BCN detection only if the bcn_count is zero. If bcn_count is
419 // not zero at this time, we won't enable BCN detection since all non-zero
420 // BCN_count means same to us. Furthermore, we avoid BCN storm by not
421 // always enabling the BCN_detection.
422 scic_port_enable_broadcast_change_notification(fw_domain->core_object);
423 }
424
425 fw_domain->broadcast_change_count++;
426
427 //if there is smp device on this domain that is in the middle of discover
428 //process or smp target reset, don't notify the driver layer.
429 if( ! scif_sas_domain_is_in_smp_activity(fw_domain) )
430 // Notify the user that there is, potentially, a change to the domain.
431 scif_cb_domain_change_notification(fw_controller, fw_domain);
432}
433
434// ---------------------------------------------------------------------------
435
436void scic_cb_port_bc_ses_primitive_recieved(
437 SCI_CONTROLLER_HANDLE_T controller,
438 SCI_PORT_HANDLE_T port,
439 SCI_PHY_HANDLE_T phy
440)
441{
442 SCIF_LOG_TRACE((
443 sci_base_object_get_logger(sci_object_get_association(port)),
444 SCIF_LOG_OBJECT_DOMAIN,
445 "scic_cb_port_bc_ses_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
446 controller, port, phy
447 ));
448}
449
450// ---------------------------------------------------------------------------
451
452void scic_cb_port_bc_expander_primitive_recieved(
453 SCI_CONTROLLER_HANDLE_T controller,
454 SCI_PORT_HANDLE_T port,
455 SCI_PHY_HANDLE_T phy
456)
457{
458 SCIF_LOG_TRACE((
459 sci_base_object_get_logger(sci_object_get_association(port)),
460 SCIF_LOG_OBJECT_DOMAIN,
461 "scic_cb_port_bc_expander_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
462 controller, port, phy
463 ));
464}
465
466// ---------------------------------------------------------------------------
467
468void scic_cb_port_bc_aen_primitive_recieved(
469 SCI_CONTROLLER_HANDLE_T controller,
470 SCI_PORT_HANDLE_T port,
471 SCI_PHY_HANDLE_T phy
472)
473{
474 SCIF_LOG_TRACE((
475 sci_base_object_get_logger(sci_object_get_association(port)),
476 SCIF_LOG_OBJECT_DOMAIN,
477 "scic_cb_port_bc_aen_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
478 controller, port, phy
479 ));
480}
481
482// ---------------------------------------------------------------------------
483
484void scic_cb_port_link_up(
485 SCI_CONTROLLER_HANDLE_T controller,
486 SCI_PORT_HANDLE_T port,
487 SCI_PHY_HANDLE_T phy
488)
489{
490 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
491 sci_object_get_association(port);
492
493 SCIF_LOG_TRACE((
494 sci_base_object_get_logger(sci_object_get_association(port)),
495 SCIF_LOG_OBJECT_DOMAIN,
496 "scic_cb_port_link_up(0x%x, 0x%x, 0x%x) enter\n",
497 controller, port, phy
498 ));
499
500 scif_sas_domain_update_device_port_width(fw_domain, port);
501}
502
503// ---------------------------------------------------------------------------
504
505void scic_cb_port_link_down(
506 SCI_CONTROLLER_HANDLE_T controller,
507 SCI_PORT_HANDLE_T port,
508 SCI_PHY_HANDLE_T phy
509)
510{
511 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
512 sci_object_get_association(port);
513
514 SCIF_LOG_TRACE((
515 sci_base_object_get_logger(sci_object_get_association(port)),
516 SCIF_LOG_OBJECT_DOMAIN,
517 "scic_cb_port_link_down(0x%x, 0x%x, 0x%x) enter\n",
518 controller, port, phy
519 ));
520
521 scif_sas_domain_update_device_port_width(fw_domain, port);
522}
523
524//******************************************************************************
525//* P R O T E C T E D M E T H O D S
526//******************************************************************************
527
528/**
529 * @brief This method constructs the framework's SAS domain object. During
530 * the construction process a linkage to the corresponding core port
531 * object.
532 *
533 * @param[in] domain This parameter specifies the domain object to be
534 * constructed.
535 * @param[in] domain_id This parameter specifies the ID for the domain
536 * object.
537 * @param[in] fw_controller This parameter specifies the controller managing
538 * the domain being constructed.
539 *
540 * @return none
541 */
542void scif_sas_domain_construct(
543 SCIF_SAS_DOMAIN_T * fw_domain,
544 U8 domain_id,
545 SCIF_SAS_CONTROLLER_T * fw_controller
546)
547{
548 SCIF_LOG_TRACE((
549 sci_base_object_get_logger(fw_controller),
550 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
551 "scif_sas_domain_construct(0x%x, 0x%x, 0x%x) enter\n",
552 fw_domain, domain_id, fw_controller
553 ));
554
555 sci_base_domain_construct(
556 &fw_domain->parent,
557 sci_base_object_get_logger(fw_controller),
558 scif_sas_domain_state_table
559 );
560
561 scif_sas_domain_initialize_state_logging(fw_domain);
562
563 sci_abstract_list_construct(
564 &fw_domain->remote_device_list, &fw_controller->free_remote_device_pool
565 );
566
567 // Retrieve the core's port object that directly corresponds to this
568 // domain.
569 scic_controller_get_port_handle(
570 fw_controller->core_object, domain_id, &fw_domain->core_object
571 );
572
573 // Set the association in the core port to this framework domain object.
574 sci_object_set_association(
575 (SCI_OBJECT_HANDLE_T) fw_domain->core_object, fw_domain
576 );
577
578 sci_fast_list_init(&fw_domain->request_list);
579
580 fw_domain->operation.timer = NULL;
581
582 fw_domain->is_port_ready = FALSE;
583 fw_domain->device_start_count = 0;
584 fw_domain->controller = fw_controller;
585 fw_domain->operation.status = SCI_SUCCESS;
586 fw_domain->is_config_route_table_needed = FALSE;
587}
588
589/**
590 * @brief This method will terminate the requests outstanding in the core
591 * based on the supplied criteria.
592 * - if the all three parameters are specified then only the single
593 * SCIF_SAS_REQUEST object is terminated.
594 * - if only the SCIF_SAS_DOMAIN and SCIF_SAS_REMOTE_DEVICE are
595 * specified, then all SCIF_SAS_REQUEST objects outstanding at
596 * the device are terminated. The one exclusion to this rule is
597 * that the fw_requestor is not terminated.
598 * - if only the SCIF_SAS_DOMAIN object is specified, then all
599 * SCIF_SAS_REQUEST objects outstanding in the domain are
600 * terminated.
601 *
602 * @param[in] fw_domain This parameter specifies the domain in which to
603 * terminate requests.
604 * @param[in] fw_device This parameter specifies the remote device in
605 * which to terminate requests. This parameter can be NULL
606 * as long as the fw_request parameter is NULL. It is a
607 * required parameter if the fw_request parameter is not NULL.
608 * @param[in] fw_request This parameter specifies the request object to
609 * be terminated. This parameter can be NULL.
610 * @param[in] fw_requestor This parameter specifies the task management
611 * request that is responsible for the termination of requests.
612 *
613 * @return none
614 */
615void scif_sas_domain_terminate_requests(
616 SCIF_SAS_DOMAIN_T * fw_domain,
617 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
618 SCIF_SAS_REQUEST_T * fw_request,
619 SCIF_SAS_TASK_REQUEST_T * fw_requestor
620)
621{
622 SCIF_LOG_TRACE((
623 sci_base_object_get_logger(fw_domain),
624 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
625 "scif_sas_domain_terminate_requests(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
626 fw_domain, fw_device, fw_request, fw_requestor
627 ));
628
629 if (fw_request != NULL)
630 {
631 fw_request->terminate_requestor = fw_requestor;
632 fw_request->state_handlers->abort_handler(&fw_request->parent);
633 }
634 else
635 {
636 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
637 SCIF_SAS_REQUEST_T * request = NULL;
638
639 // Cycle through the fast list of IO requests. Terminate each
640 // outstanding requests that matches the criteria supplied by the
641 // caller.
642 while (element != NULL)
643 {
644 request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
645 // The current element may be deleted from the list becasue of
646 // IO completion so advance to the next element early
647 element = sci_fast_list_get_next(element);
648
649 // Ensure we pass the supplied criteria before terminating the
650 // request.
651 if (
652 (fw_device == NULL)
653 || (
654 (request->device == fw_device)
655 && (fw_requestor != (SCIF_SAS_TASK_REQUEST_T*) request)
656 )
657 )
658 {
659 if (
660 (request->is_waiting_for_abort_task_set == FALSE) ||
661 (request->terminate_requestor == NULL)
662 )
663 {
664 request->terminate_requestor = fw_requestor;
665 request->state_handlers->abort_handler(&request->parent);
666 }
667 }
668 }
669 }
670}
671
672/**
673 * @brief This method searches the domain object to find a
674 * SCIF_SAS_REQUEST object associated with the supplied IO tag.
675 *
676 * @param[in] fw_domain This parameter specifies the domain in which to
677 * to find the request object.
678 * @param[in] io_tag This parameter specifies the IO tag value for which
679 * to locate the corresponding request.
680 *
681 * @return This method returns a pointer to the SCIF_SAS_REQUEST object
682 * associated with the supplied IO tag.
683 * @retval NULL This value is returned if the IO tag does not resolve to
684 * a request.
685 */
686SCIF_SAS_REQUEST_T * scif_sas_domain_get_request_by_io_tag(
687 SCIF_SAS_DOMAIN_T * fw_domain,
688 U16 io_tag
689)
690{
691 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
692 SCIF_SAS_IO_REQUEST_T * io_request = NULL;
693
694 SCIF_LOG_TRACE((
695 sci_base_object_get_logger(fw_domain),
696 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
697 "scif_sas_domain_get_request_by_io_tag(0x%x, 0x%x) enter\n",
698 fw_domain, io_tag
699 ));
700
701 while (element != NULL)
702 {
703 io_request = (SCIF_SAS_IO_REQUEST_T*) sci_fast_list_get_object(element);
704
705 // Check to see if we located the request with an identical IO tag.
706 if (scic_io_request_get_io_tag(io_request->parent.core_object) == io_tag)
707 return &io_request->parent;
708
709 element = sci_fast_list_get_next(element);
710 }
711
712 return NULL;
713}
714
715/**
716 * @brief This method performs domain object initialization to be done
717 * when the scif_controller_initialize() method is invoked.
718 * This includes operation timeout creation.
719 *
720 * @param[in] fw_domain This parameter specifies the domain object for
721 * which to perform initialization.
722 *
723 * @return none
724 */
725void scif_sas_domain_initialize(
726 SCIF_SAS_DOMAIN_T * fw_domain
727)
728{
729 SCIF_LOG_TRACE((
730 sci_base_object_get_logger(fw_domain),
731 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
732 "scif_sas_domain_initialize(0x%x) enter\n",
733 fw_domain
734 ));
735
736 // Create the timer for each domain. It is too early in the process
737 // to allocate this during construction since the user didn't have
738 // a chance to set it's association.
739 if (fw_domain->operation.timer == 0)
740 {
741 fw_domain->operation.timer = scif_cb_timer_create(
742 fw_domain->controller,
743 scif_sas_domain_operation_timeout_handler,
744 fw_domain
745 );
746 }
747}
748
749/**
750 * @brief This method performs domain object handling for core remote
751 * device start complete notifications. Core remote device starts
752 * and start completes are only done during discovery. This could
753 * ultimately be wrapped into a handler method on the domain (they
754 * actually already exist). This method will decrement the number
755 * of device start operations ongoing and attempt to determine if
756 * discovery is complete.
757 *
758 * @param[in] fw_domain This parameter specifies the domain object for
759 * which to perform initialization.
760 *
761 * @return none
762 */
763void scif_sas_domain_remote_device_start_complete(
764 SCIF_SAS_DOMAIN_T * fw_domain,
765 SCIF_SAS_REMOTE_DEVICE_T * fw_device
766)
767{
768 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
769
770 SCIF_LOG_TRACE((
771 sci_base_object_get_logger(fw_domain),
772 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
773 "scif_sas_domain_remote_device_start_complete(0x%x, 0x%x) enter\n",
774 fw_domain, fw_device
775 ));
776
777 // If a device is being started/start completed, then we must be
778 // during discovery.
779 ASSERT(fw_domain->parent.state_machine.current_state_id
780 == SCI_BASE_DOMAIN_STATE_DISCOVERING);
781
782 scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
783
784 // Decrement the number of devices being started and check to see
785 // if all have finished being started or failed as the case may be.
786 fw_domain->device_start_in_progress_count--;
787
788 if ( dev_protocols.u.bits.attached_smp_target )
789 {
790 if ( fw_device->containing_device == NULL )
791 //kick off the smp discover process if this expander is direct attached.
792 scif_sas_smp_remote_device_start_discover(fw_device);
793 else
794 //mark this device, the discover process of this device will start after
795 //its containing smp device finish discover.
796 fw_device->protocol_device.smp_device.scheduled_activity =
797 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
798 }
799 else
800 {
801 fw_domain->state_handlers->device_start_complete_handler(
802 &fw_domain->parent, &fw_device->parent
803 );
804 }
805}
806
807
808/**
809 * @brief This methods check each smp device in this domain. If there is at
810 * least one smp device in discover or target reset activity, this
811 * domain is considered in smp activity. Note this routine is not
812 * called on fast IO path.
813 *
814 * @param[in] fw_domain The framework domain object
815 *
816 * @return BOOL value to indicate whether a domain is in SMP activity.
817 */
818BOOL scif_sas_domain_is_in_smp_activity(
819 SCIF_SAS_DOMAIN_T * fw_domain
820)
821{
822 SCI_ABSTRACT_ELEMENT_T * current_element =
823 sci_abstract_list_get_front(&fw_domain->remote_device_list);
824
825 SCIF_SAS_REMOTE_DEVICE_T * current_device;
826
827 while ( current_element != NULL )
828 {
829 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
830
831 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
832 sci_abstract_list_get_object(current_element);
833
834 scic_remote_device_get_protocols(current_device->core_object,
835 &dev_protocols
836 );
837
838 if (dev_protocols.u.bits.attached_smp_target &&
839 scif_sas_smp_remote_device_is_in_activity(current_device))
840 return TRUE;
841
842 current_element =
843 sci_abstract_list_get_next(current_element);
844 }
845
846 return FALSE;
847}
848
849
850/**
851 * @brief This methods finds a expander attached device by searching the domain's
852 * device list using connected expander device and expander phy id.
853 *
854 * @param[in] fw_domain The framework domain object
855 * @param[in] parent_device The expander device the target device attaches to.
856 * @param[in] expander_phy_id The expander phy id that the target device owns.
857 *
858 * @return found remote device or a NULL value if no device found.
859 */
860SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_get_device_by_containing_device(
861 SCIF_SAS_DOMAIN_T * fw_domain,
862 SCIF_SAS_REMOTE_DEVICE_T * containing_device,
863 U8 expander_phy_id
864)
865{
866 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
867 SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
868 &fw_domain->remote_device_list
869 );
870
871 //parent device must not be NULL.
872 ASSERT(containing_device != NULL);
873
874 // Search the abstract list to see if there is a remote device meets the
875 // search condition.
876 while (element != NULL)
877 {
878 fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
879 sci_abstract_list_get_object(element);
880
881 // Check to see if this is the device for which we are searching.
882 if (
883 (fw_device->containing_device == containing_device)
884 && (fw_device->expander_phy_identifier == expander_phy_id)
885 )
886 {
887 return fw_device;
888 }
889
890 element = sci_abstract_list_get_next(element);
891 }
892
893 return SCI_INVALID_HANDLE;
894}
895
896
897/**
898 * @brief This methods finds the first device that is in STOPPED state and its
899 * connection_rate is still in SPINUP_HOLD(value 3).
900 *
901 * @param[in] fw_domain The framework domain object
902 *
903 * @return SCIF_SAS_REMOTE_DEVICE_T The device that is in SPINUP_HOLD or NULL.
904 */
905SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_in_spinup_hold(
906 SCIF_SAS_DOMAIN_T * fw_domain
907)
908{
909 SCI_ABSTRACT_ELEMENT_T * current_element;
910 SCIF_SAS_REMOTE_DEVICE_T * current_device;
911
912 SCIF_LOG_TRACE((
913 sci_base_object_get_logger(fw_domain),
914 SCIF_LOG_OBJECT_DOMAIN,
915 "scif_sas_domain_find_device_in_spinup_hold(0x%x) enter\n",
916 fw_domain
917 ));
918
919 //search throught domain's device list to find the first sata device on spinup_hold
920 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
921 while (current_element != NULL )
922 {
923 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
924 sci_abstract_list_get_object(current_element);
925
926 //We must get the next element before we remove the current
927 //device. Or else, we will get wrong next_element, since the erased
928 //element has been put into free pool.
929 current_element = sci_abstract_list_get_next(current_element);
930
931 if ( sci_base_state_machine_get_state(¤t_device->parent.state_machine) ==
932 SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
933 && scic_remote_device_get_connection_rate(current_device->core_object) ==
934 SCI_SATA_SPINUP_HOLD )
935 {
936 return current_device;
937 }
938 }
939
940 return NULL;
941}
942
943
944/**
945 * @brief This methods finds the first device that has specific activity scheduled.
946 *
947 * @param[in] fw_domain The framework domain object
948 * @param[in] smp_activity A specified smp activity. The valid range is [1,5].
949 *
950 * @return SCIF_SAS_REMOTE_DEVICE_T The device that has specified smp activity scheduled.
951 */
952SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_has_scheduled_activity(
953 SCIF_SAS_DOMAIN_T * fw_domain,
954 U8 smp_activity
955)
956{
957 SCI_ABSTRACT_ELEMENT_T * current_element =
958 sci_abstract_list_get_front(&fw_domain->remote_device_list);
959
960 SCIF_SAS_REMOTE_DEVICE_T * current_device;
961 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
962
963 //config route table activity has higher priority than discover activity.
964 while ( current_element != NULL )
965 {
966 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
967 sci_abstract_list_get_object(current_element);
968
969 scic_remote_device_get_protocols(current_device->core_object,
970 &dev_protocols);
971
972 current_element =
973 sci_abstract_list_get_next(current_element);
974
975 if ( dev_protocols.u.bits.attached_smp_target
976 && current_device->protocol_device.smp_device.scheduled_activity ==
977 smp_activity)
978 {
979 return current_device;
980 }
981 }
982
983 return NULL;
984}
985
986
987/**
988 * @brief This methods finds the smp device that has is_config_route_table_scheduled
989 * flag set to TRUE, and start config route table on it. If there is no
990 * smp device scheduled to config route table, find the smp device has
991 * is_discover_scheduled and start the smp discover process on them.
992 *
993 * @param[in] fw_domain The framework domain that to start smp discover process.
994 *
995 * @return NONE
996 */
997void scif_sas_domain_start_smp_activity(
998 SCIF_SAS_DOMAIN_T * fw_domain
999)
1000{
1001 SCIF_SAS_REMOTE_DEVICE_T * device_has_scheduled_activity = NULL;
1002
1003 //first, find device that has config route table activity scheduled.
1004 //config route table activity has higher priority than Discover.
1005 device_has_scheduled_activity =
1006 scif_sas_domain_find_device_has_scheduled_activity(
1007 fw_domain,
1008 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE
1009 );
1010
1011 if (device_has_scheduled_activity != NULL)
1012 {
1013 scif_sas_smp_remote_device_configure_route_table(device_has_scheduled_activity);
1014 device_has_scheduled_activity->protocol_device.smp_device.scheduled_activity =
1015 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
1016 return;
1017 }
1018
1019 //if no device has config route table activity scheduled, search again, find
1020 //device has discover activity scheduled.
1021 device_has_scheduled_activity =
1022 scif_sas_domain_find_device_has_scheduled_activity(
1023 fw_domain,
1024 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER
1025 );
1026
1027 if (device_has_scheduled_activity != NULL)
1028 scif_sas_smp_remote_device_start_discover(device_has_scheduled_activity);
1029}
1030
1031
1032/**
1033 * @brief This method starts domain's smp discover process from the top level expander.
1034 *
1035 * @param[in] fw_domain The framework domain that to start smp discover process.
1036 @ @param[in] top_expander The top level expander device to start smp discover process.
1037 *
1038 * @return None
1039 */
1040void scif_sas_domain_start_smp_discover(
1041 SCIF_SAS_DOMAIN_T * fw_domain,
1042 SCIF_SAS_REMOTE_DEVICE_T * top_expander
1043)
1044{
1045 SCI_ABSTRACT_ELEMENT_T * current_element =
1046 sci_abstract_list_get_front(&fw_domain->remote_device_list);
1047
1048 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1049
1050 // something changed behind expander
1051 // mark all the device behind expander to be NOT
1052 // is_currently_discovered.
1053 while ( current_element != NULL )
1054 {
1055 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1056 sci_abstract_list_get_object(current_element);
1057
1058 current_device->is_currently_discovered = FALSE;
1059
1060 //reset all the devices' port witdh except the top expander.
1061 if (current_device->containing_device != NULL)
1062 current_device->device_port_width = 1;
1063
1064 current_element = sci_abstract_list_get_next(current_element);
1065 }
1066
1067 //expander device itself should be set to is_currently_discovered.
1068 top_expander->is_currently_discovered = TRUE;
1069
1070 //kick off the smp discover process.
1071 scif_sas_smp_remote_device_start_discover(top_expander);
1072}
1073
1074
1075/**
1076 * @brief This method continues domain's smp discover process and
1077 * may transit to READY state if all smp activities are done.
1078 *
1079 * @param[in] fw_domain The framework domain that to start smp discover process.
1080 *
1081 * @return None
1082 */
1083void scif_sas_domain_continue_discover(
1084 SCIF_SAS_DOMAIN_T * fw_domain
1085)
1086{
1087 SCIF_LOG_TRACE((
1088 sci_base_object_get_logger(fw_domain),
1089 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1090 "scif_sas_domain_continue_discover(0x%x) enter\n",
1091 fw_domain
1092 ));
1093
1094 if ( fw_domain->device_start_in_progress_count == 0
1095 && !scif_sas_domain_is_in_smp_activity(fw_domain) )
1096 {
1097 //domain scrub the remote device list to see if there is a need
1098 //to start smp discover on expander device. There may be no
1099 //need to start any smp discover.
1100 scif_sas_domain_start_smp_activity(fw_domain);
1101
1102 //In domain discovery timeout case, we cancel all
1103 //the smp activities, and terminate all the smp requests, then
1104 //this routine is called. But the smp request may not done
1105 //terminated. We want to guard the domain trasitting to READY
1106 //by checking outstanding smp request count. If there is outstanding
1107 //smp request, the domain will not transit to READY. Later when
1108 //the smp request is terminated at smp remote device, this routine
1109 //will be called then the domain will transit to READY state.
1110 if ( ! scif_sas_domain_is_in_smp_activity(fw_domain)
1111 && scif_sas_domain_get_smp_request_count(fw_domain) == 0)
1112 {
1113 //before domain transit to READY state, domain has some clean up
1114 //work to do, such like update domain's remote devcie list.
1115 scif_sas_domain_finish_discover(fw_domain);
1116 }
1117 }
1118}
1119
1120
1121/**
1122 * @brief This method finishes domain's smp discover process and
1123 * update domain's remote device list.
1124 *
1125 * @param[in] fw_domain The framework domain that's to finish smp discover process.
1126 *
1127 * @return None
1128 */
1129void scif_sas_domain_finish_discover(
1130 SCIF_SAS_DOMAIN_T * fw_domain
1131)
1132{
1133 SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
1134 SCI_ABSTRACT_ELEMENT_T * current_element = NULL;
1135
1136 SCIF_LOG_TRACE((
1137 sci_base_object_get_logger(fw_domain),
1138 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1139 "scif_sas_domain_finish_discover(0x%x) enter\n",
1140 fw_domain
1141 ));
1142
1143 //need to scrub all the devices behind the expander. Check each
1144 //device's discover_status. if the is_currently_discovered is FALSE, means
1145 //the device is not been rediscovered. this device needs to be removed.
1146 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
1147 while (current_element != NULL )
1148 {
1149 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1150 sci_abstract_list_get_object(current_element);
1151
1152 //We must get the next element before we remove the current
1153 //device. Or else, we will get wrong next_element, since the erased
1154 //element has been put into free pool.
1155 current_element = sci_abstract_list_get_next(current_element);
1156
1157 if ( current_device->is_currently_discovered == FALSE )
1158 {
1159 // Notify the framework user of the device removal.
1160 scif_cb_domain_device_removed(
1161 fw_domain->controller, fw_domain, current_device
1162 );
1163 }
1164 }
1165
1166 sci_base_state_machine_change_state(
1167 &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
1168 );
1169}
1170
1171
1172
1173/**
1174 * @brief This method remove an expander device and its child devices, in order to
1175 * deal with a detected illeagal phy connection.
1176 *
1177 * @param[in] fw_domain The domain that a expander belongs to.
1178 * @param[in] fw_device The expander device to be removed.
1179 *
1180 * @return none.
1181 */
1182void scif_sas_domain_remove_expander_device(
1183 SCIF_SAS_DOMAIN_T * fw_domain,
1184 SCIF_SAS_REMOTE_DEVICE_T * fw_device
1185)
1186{
1187 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
1188 &fw_device->protocol_device.smp_device;
1189
1190 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
1191 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1192 SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
1193
1194 while (element != NULL)
1195 {
1196 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1197 element = sci_fast_list_get_next(element);
1198
1199 if ( curr_smp_phy->attached_device_type != SMP_NO_DEVICE_ATTACHED
1200 && curr_smp_phy->u.end_device != NULL )
1201 {
1202 if (curr_smp_phy->attached_device_type == SMP_END_DEVICE_ONLY)
1203 current_device = curr_smp_phy->u.end_device;
1204 else
1205 current_device = curr_smp_phy->u.attached_phy->owning_device;
1206
1207 scif_cb_domain_device_removed(fw_domain->controller, fw_domain, current_device);
1208 }
1209 }
1210
1211 //remove device itself
1212 scif_cb_domain_device_removed(fw_domain->controller, fw_domain, fw_device);
1213}
1214
1215
1216/**
1217 * @brief This method searches the whole domain and finds all the smp devices to
1218 * cancel their smp activities if there is any.
1219 *
1220 * @param[in] fw_domain The domain that its smp activities are to be canceled.
1221 *
1222 * @return none.
1223 */
1224void scif_sas_domain_cancel_smp_activities(
1225 SCIF_SAS_DOMAIN_T * fw_domain
1226)
1227{
1228 SCI_ABSTRACT_ELEMENT_T * current_element =
1229 sci_abstract_list_get_front(&fw_domain->remote_device_list);
1230
1231 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1232
1233 //purge all the outstanding internal IOs in HPQ.
1234 scif_sas_high_priority_request_queue_purge_domain(
1235 &fw_domain->controller->hprq, fw_domain
1236 );
1237
1238 while ( current_element != NULL )
1239 {
1240 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
1241
1242 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1243 sci_abstract_list_get_object(current_element);
1244
1245 scic_remote_device_get_protocols(current_device->core_object,
1246 &dev_protocols
1247 );
1248
1249 if (dev_protocols.u.bits.attached_smp_target)
1250 {
1251 scif_sas_smp_remote_device_cancel_smp_activity(current_device);
1252 }
1253
1254 current_element =
1255 sci_abstract_list_get_next(current_element);
1256 }
1257}
1258
1259
1260/**
1261 * @brief This method searches the domain's request list and counts outstanding
1262 * smp IOs.
1263 *
1264 * @param[in] fw_domain The domain that its request list is to be searched.
1265 *
1266 * @return U8 The possible return value of this routine is 0 or 1.
1267 */
1268U8 scif_sas_domain_get_smp_request_count(
1269 SCIF_SAS_DOMAIN_T * fw_domain
1270)
1271{
1272 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
1273 SCIF_SAS_REQUEST_T * request = NULL;
1274 U8 count = 0;
1275 SCIC_TRANSPORT_PROTOCOL protocol;
1276
1277 // Cycle through the fast list of IO requests. Terminate each
1278 // outstanding requests that matches the criteria supplied by the
1279 // caller.
1280 while (element != NULL)
1281 {
1282 request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
1283 // The current element may be deleted from the list becasue of
1284 // IO completion so advance to the next element early
1285 element = sci_fast_list_get_next(element);
1286
1287 protocol = scic_io_request_get_protocol(request->core_object);
1288
1289 if ( protocol == SCIC_SMP_PROTOCOL)
1290 count++;
1291 }
1292
1293 return count;
1294}
1295
1296
1297/**
1298 * @brief This method start clear affiliation activities for smp devices in
1299 * this domain.
1300 *
1301 * @param[in] fw_domain The domain that its smp devices are scheduled to clear
1302 * affiliation for all the EA SATA devices.
1303 *
1304 * @return none.
1305 */
1306void scif_sas_domain_start_clear_affiliation(
1307 SCIF_SAS_DOMAIN_T * fw_domain
1308)
1309{
1310 scif_sas_domain_schedule_clear_affiliation(fw_domain);
1311 scif_sas_domain_continue_clear_affiliation(fw_domain);
1312}
1313
1314
1315/**
1316 * @brief This method schedule clear affiliation activities for smp devices in
1317 * this domain.
1318 *
1319 * @param[in] fw_domain The domain that its smp devices are scheduled to clear
1320 * affiliation for all the EA SATA devices.
1321 *
1322 * @return none.
1323 */
1324void scif_sas_domain_schedule_clear_affiliation(
1325 SCIF_SAS_DOMAIN_T * fw_domain
1326)
1327{
1328 SCI_ABSTRACT_ELEMENT_T * current_element =
1329 sci_abstract_list_get_front(&fw_domain->remote_device_list);
1330
1331 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1332 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
1333
1334 //config route table activity has higher priority than discover activity.
1335 while ( current_element != NULL )
1336 {
1337 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1338 sci_abstract_list_get_object(current_element);
1339
1340 scic_remote_device_get_protocols(current_device->core_object,
1341 &dev_protocols);
1342
1343 current_element =
1344 sci_abstract_list_get_next(current_element);
1345
1346 if ( dev_protocols.u.bits.attached_smp_target )
1347 {
1348 current_device->protocol_device.smp_device.scheduled_activity =
1349 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION;
1350 }
1351 }
1352}
1353
1354
1355/**
1356 * @brief This method carries clear affiliation activities for a smp devices in
1357 * this domain during controller stop process.
1358 *
1359 * @param[in] fw_domain The domain that its smp devices are to clear
1360 * affiliation for all the EA SATA devices.
1361 *
1362 * @return none.
1363 */
1364void scif_sas_domain_continue_clear_affiliation(
1365 SCIF_SAS_DOMAIN_T * fw_domain
1366)
1367{
1368 SCIF_SAS_REMOTE_DEVICE_T * smp_device =
1369 scif_sas_domain_find_device_has_scheduled_activity(
1370 fw_domain,
1371 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION
1372 );
1373
1374 if (smp_device != NULL)
1375 scif_sas_smp_remote_device_start_clear_affiliation(smp_device);
1376 else
1377 {
1378 //This domain has done clear affiliation.
1379 SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller;
1380 fw_controller->current_domain_to_clear_affiliation++;
1381
1382 //let controller continue to clear affiliation on other domains.
1383 scif_sas_controller_clear_affiliation(fw_domain->controller);
1384 }
1385}
1386
1387
1388/**
1389 * @brief This method releases resource for a framework domain.
1390 *
1391 * @param[in] fw_controller This parameter specifies the framework
1392 * controller, its associated domain's resources are to be released.
1393 * @param[in] fw_domain This parameter specifies the framework
1394 * domain whose resources are to be released.
1395 */
1396void scif_sas_domain_release_resource(
1397 SCIF_SAS_CONTROLLER_T * fw_controller,
1398 SCIF_SAS_DOMAIN_T * fw_domain
1399)
1400{
1401 if (fw_domain->operation.timer != NULL)
1402 {
1403 scif_cb_timer_destroy(fw_controller, fw_domain->operation.timer);
1404 fw_domain->operation.timer = NULL;
1405 }
1406}
1407
1408
1409/**
1410 * @brief This method finds the a EA device that has target reset scheduled.
1411 *
1412 * @param[in] fw_domain The framework domain object
1413 *
1414 * @return SCIF_SAS_REMOTE_DEVICE_T The EA device that has target reset scheduled.
1415 */
1416SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_next_ea_target_reset(
1417 SCIF_SAS_DOMAIN_T * fw_domain
1418)
1419{
1420 SCI_ABSTRACT_ELEMENT_T * current_element;
1421 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1422
1423 SCIF_LOG_TRACE((
1424 sci_base_object_get_logger(fw_domain),
1425 SCIF_LOG_OBJECT_DOMAIN,
1426 "scif_sas_domain_find_next_ea_target_reset(0x%x) enter\n",
1427 fw_domain
1428 ));
1429
1430 //search throught domain's device list to find the first sata device on spinup_hold
1431 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
1432 while (current_element != NULL )
1433 {
1434 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1435 sci_abstract_list_get_object(current_element);
1436
1437 current_element = sci_abstract_list_get_next(current_element);
1438
1439 if ( current_device->ea_target_reset_request_scheduled != NULL )
1440 {
1441 return current_device;
1442 }
1443 }
1444
1445 return NULL;
1446}
1447
1448#if !defined(DISABLE_WIDE_PORTED_TARGETS)
1449/**
1450 * @brief This method update the direct attached device port width.
1451 *
1452 * @param[in] fw_domain The framework domain object
1453 * @param[in] port The associated port object which recently has link up/down
1454 * event happened.
1455 *
1456 * @return none
1457 */
1458void scif_sas_domain_update_device_port_width(
1459 SCIF_SAS_DOMAIN_T * fw_domain,
1460 SCI_PORT_HANDLE_T port
1461)
1462{
1463 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
1464 SCIC_PORT_PROPERTIES_T properties;
1465 U8 new_port_width = 0;
1466
1467 SCIF_LOG_TRACE((
1468 sci_base_object_get_logger(fw_domain),
1469 SCIF_LOG_OBJECT_DOMAIN,
1470 "scif_sas_domain_update_device_port_width(0x%x, 0x%x) enter\n",
1471 fw_domain, port
1472 ));
1473
1474 scic_port_get_properties(port, &properties);
1475
1476 fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1477 scif_domain_get_device_by_sas_address(
1478 fw_domain, &properties.remote.sas_address
1479 );
1480
1481 // If the device already existed in the domain, it is a wide port SSP target,
1482 // we need to update its port width.
1483 if (fw_device != SCI_INVALID_HANDLE)
1484 {
1485 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
1486 scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
1487
1488 if (dev_protocols.u.bits.attached_ssp_target)
1489 {
1490 //Get accurate port width from port's phy mask for a DA device.
1491 SCI_GET_BITS_SET_COUNT(properties.phy_mask, new_port_width);
1492
1493 scif_sas_remote_device_update_port_width(fw_device, new_port_width);
1494 }
1495 }
1496}
1497#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
1498
1499
1500#ifdef SCI_LOGGING
1501/**
1502 * This method will turn on logging of domain state changes.
1503 *
1504 * @param[in] fw_domain The domain for which the state logging is to be turned
1505 * on.
1506 */
1507void scif_sas_domain_initialize_state_logging(
1508 SCIF_SAS_DOMAIN_T *fw_domain
1509)
1510{
1511 sci_base_state_machine_logger_initialize(
1512 &fw_domain->parent.state_machine_logger,
1513 &fw_domain->parent.state_machine,
1514 &fw_domain->parent.parent,
1515 scif_cb_logger_log_states,
1516 "SCIF_SAS_DOMAIN_T", "base state machine",
1517 SCIF_LOG_OBJECT_DOMAIN
1518 );
1519}
1520
1521/**
1522 * This method will turn off logging of domain state changes.
1523 *
1524 * @param[in] fw_domain The domain for which the state logging is to be turned
1525 * off.
1526 */
1527void scif_sas_domain_deinitialize_state_logging(
1528 SCIF_SAS_DOMAIN_T *fw_domain
1529)
1530{
1531 sci_base_state_machine_logger_deinitialize(
1532 &fw_domain->parent.state_machine_logger,
1533 &fw_domain->parent.state_machine
1534 );
1535}
1536#endif
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: head/sys/dev/isci/scil/scif_sas_domain.c 250460 2013-05-10 16:41:26Z eadler $");
55
56/**
57 * @file
58 *
59 * @brief This file contains the implementation of the SCIF_SAS_DOMAIN
60 * object.
61 */
62
63#include <dev/isci/scil/intel_sas.h>
64#include <dev/isci/scil/sci_fast_list.h>
65#include <dev/isci/scil/scic_controller.h>
66#include <dev/isci/scil/scic_port.h>
67#include <dev/isci/scil/scic_remote_device.h>
68#include <dev/isci/scil/scic_io_request.h>
69#include <dev/isci/scil/scic_user_callback.h>
70#include <dev/isci/scil/scif_user_callback.h>
71#include <dev/isci/scil/sci_abstract_list.h>
72#include <dev/isci/scil/sci_base_iterator.h>
73
74#include <dev/isci/scil/scif_sas_logger.h>
75#include <dev/isci/scil/scif_sas_domain.h>
76#include <dev/isci/scil/scif_sas_controller.h>
77#include <dev/isci/scil/scif_sas_remote_device.h>
78#include <dev/isci/scil/scif_sas_smp_remote_device.h>
79#include <dev/isci/scil/sci_util.h>
80
81//******************************************************************************
82//* P R I V A T E M E T H O D S
83//******************************************************************************
84
85/**
86 * @brief This method will attempt to handle an operation timeout (i.e.
87 * discovery or reset).
88 *
89 * @param[in] cookie This parameter specifies the domain in which the
90 * timeout occurred.
91 *
92 * @return none
93 */
94static
95void scif_sas_domain_operation_timeout_handler(
96 void * cookie
97)
98{
99 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) cookie;
100 U32 state;
101
102 state = sci_base_state_machine_get_state(&fw_domain->parent.state_machine);
103
104 // Based upon the state of the domain, we know whether we were in the
105 // process of performing discovery or a reset.
106 if (state == SCI_BASE_DOMAIN_STATE_DISCOVERING)
107 {
108 SCIF_LOG_WARNING((
109 sci_base_object_get_logger(fw_domain),
110 SCIF_LOG_OBJECT_DOMAIN,
111 "Domain:0x%x State:0x%x DISCOVER timeout!\n",
112 fw_domain, state
113 ));
114
115 fw_domain->operation.status = SCI_FAILURE_TIMEOUT;
116
117 //search all the smp devices in the domain and cancel their activities
118 //if there is any outstanding activity remained. The smp devices will terminate
119 //all the started internal IOs.
120 scif_sas_domain_cancel_smp_activities(fw_domain);
121
122 scif_sas_domain_continue_discover(fw_domain);
123 }
124 else
125 {
126 SCIF_LOG_ERROR((
127 sci_base_object_get_logger(fw_domain),
128 SCIF_LOG_OBJECT_DOMAIN,
129 "Domain:0x%x State:0x%x operation timeout in invalid state\n",
130 fw_domain, state
131 ));
132 }
133}
134
135//******************************************************************************
136//* P U B L I C M E T H O D S
137//******************************************************************************
138
139SCI_PORT_HANDLE_T scif_domain_get_scic_port_handle(
140 SCI_DOMAIN_HANDLE_T domain
141)
142{
143 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
144
145 if ( (fw_domain == NULL) || (fw_domain->core_object == SCI_INVALID_HANDLE) )
146 return SCI_INVALID_HANDLE;
147
148 SCIF_LOG_WARNING((
149 sci_base_object_get_logger(fw_domain),
150 SCIF_LOG_OBJECT_DOMAIN,
151 "Domain:0x%x no associated core port found\n",
152 fw_domain
153 ));
154
155 return fw_domain->core_object;
156}
157
158// ---------------------------------------------------------------------------
159
160SCI_REMOTE_DEVICE_HANDLE_T scif_domain_get_device_by_sas_address(
161 SCI_DOMAIN_HANDLE_T domain,
162 SCI_SAS_ADDRESS_T * sas_address
163)
164{
165 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
166 SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
167 &fw_domain->remote_device_list
168 );
169 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
170 SCI_SAS_ADDRESS_T fw_device_address;
171
172 SCIF_LOG_TRACE((
173 sci_base_object_get_logger(domain),
174 SCIF_LOG_OBJECT_DOMAIN,
175 "scif_domain_get_device_by_sas_address(0x%x, 0x%x) enter\n",
176 domain, sas_address
177 ));
178
179 // Search the abstract list to see if there is a remote device with the
180 // same SAS address.
181 while (element != NULL)
182 {
183 fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
184 sci_abstract_list_get_object(element);
185
186 scic_remote_device_get_sas_address(
187 fw_device->core_object, &fw_device_address
188 );
189
190 // Check to see if this is the device for which we are searching.
191 if ( (fw_device_address.low == sas_address->low)
192 && (fw_device_address.high == sas_address->high) )
193 {
194 return fw_device;
195 }
196
197 element = sci_abstract_list_get_next(element);
198 }
199
200 return SCI_INVALID_HANDLE;
201}
202
203// ---------------------------------------------------------------------------
204
205#if !defined(DISABLE_SCI_ITERATORS)
206
207SCI_ITERATOR_HANDLE_T scif_domain_get_remote_device_iterator(
208 SCI_DOMAIN_HANDLE_T domain,
209 void * iterator_buffer
210)
211{
212 SCI_ITERATOR_HANDLE_T iterator = (SCI_ITERATOR_HANDLE_T *)iterator_buffer;
213
214 sci_base_iterator_construct(
215 iterator, &((SCIF_SAS_DOMAIN_T*) domain)->remote_device_list
216 );
217
218
219 return iterator;
220}
221
222#endif // !defined(DISABLE_SCI_ITERATORS)
223
224// ---------------------------------------------------------------------------
225
226SCI_STATUS scif_domain_discover(
227 SCI_DOMAIN_HANDLE_T domain,
228 U32 discover_timeout,
229 U32 device_timeout
230)
231{
232 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*) domain;
233 SCI_STATUS status = SCI_SUCCESS;
234 SCI_STATUS op_status = SCI_SUCCESS;
235
236 SCIF_LOG_TRACE((
237 sci_base_object_get_logger(domain),
238 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
239 "scif_domain_discover(0x%x, 0x%x, 0x%x) enter\n",
240 domain, discover_timeout, device_timeout
241 ));
242
243 // Check to make sure the size of the domain doesn't cause potential issues
244 // with the remote device timer and the domain timer.
245 if ((device_timeout * sci_abstract_list_size(&fw_domain->remote_device_list))
246 > discover_timeout)
247 status = SCI_WARNING_TIMER_CONFLICT;
248
249 op_status = fw_domain->state_handlers->discover_handler(
250 &fw_domain->parent, discover_timeout, device_timeout
251 );
252
253 // The status of the discover operation takes priority.
254 if ( (status == SCI_SUCCESS)
255 || (status != SCI_SUCCESS && op_status != SCI_SUCCESS) )
256 {
257 status = op_status;
258 }
259
260 return status;
261}
262
263// ---------------------------------------------------------------------------
264
265U32 scif_domain_get_suggested_discover_timeout(
266 SCI_DOMAIN_HANDLE_T domain
267)
268{
269 U32 suggested_timeout = SCIF_DOMAIN_DISCOVER_TIMEOUT; //milli-seconds
270 return suggested_timeout;
271}
272
273// ---------------------------------------------------------------------------
274
275void scic_cb_port_stop_complete(
276 SCI_CONTROLLER_HANDLE_T controller,
277 SCI_PORT_HANDLE_T port,
278 SCI_STATUS completion_status
279)
280{
281 SCIF_LOG_TRACE((
282 sci_base_object_get_logger((SCIF_SAS_DOMAIN_T*)sci_object_get_association(port)),
283 SCIF_LOG_OBJECT_DOMAIN,
284 "scic_cb_port_stop_complete(0x%x, 0x%x, 0x%x) enter\n",
285 controller, port, completion_status
286 ));
287}
288
289// ---------------------------------------------------------------------------
290
291void scic_cb_port_ready(
292 SCI_CONTROLLER_HANDLE_T controller,
293 SCI_PORT_HANDLE_T port
294)
295{
296 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
297 sci_object_get_association(port);
298
299 SCIF_LOG_TRACE((
300 sci_base_object_get_logger(fw_domain),
301 SCIF_LOG_OBJECT_DOMAIN,
302 "scic_cb_port_ready(0x%x, 0x%x) enter\n",
303 controller, port
304 ));
305
306 // The controller supplied with the port should match the controller
307 // saved in the domain.
308 ASSERT(sci_object_get_association(controller) == fw_domain->controller);
309
310 fw_domain->is_port_ready = TRUE;
311
312 fw_domain->state_handlers->port_ready_handler(&fw_domain->parent);
313}
314
315// ---------------------------------------------------------------------------
316
317void scic_cb_port_not_ready(
318 SCI_CONTROLLER_HANDLE_T controller,
319 SCI_PORT_HANDLE_T port,
320 U32 reason_code
321)
322{
323 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
324 sci_object_get_association(port);
325
326 SCIF_LOG_TRACE((
327 sci_base_object_get_logger(fw_domain),
328 SCIF_LOG_OBJECT_DOMAIN,
329 "scic_cb_port_not_ready(0x%x, 0x%x) enter\n",
330 controller, port
331 ));
332
333 // The controller supplied with the port should match the controller
334 // saved in the domain.
335 ASSERT(sci_object_get_association(controller) == fw_domain->controller);
336
337 // There is no need to take action on the port reconfiguring since it is
338 // just a change of the port width.
339 if (reason_code != SCIC_PORT_NOT_READY_RECONFIGURING)
340 {
341 fw_domain->is_port_ready = FALSE;
342
343 fw_domain->state_handlers->port_not_ready_handler(
344 &fw_domain->parent, reason_code);
345 }
346}
347
348// ---------------------------------------------------------------------------
349
350void scic_cb_port_hard_reset_complete(
351 SCI_CONTROLLER_HANDLE_T controller,
352 SCI_PORT_HANDLE_T port,
353 SCI_STATUS completion_status
354)
355{
356 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
357 sci_object_get_association(port);
358 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
359 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
360 SCIF_SAS_TASK_REQUEST_T * task_request = NULL;
361
362 SCIF_LOG_TRACE((
363 sci_base_object_get_logger(fw_domain),
364 SCIF_LOG_OBJECT_DOMAIN,
365 "scic_cb_port_hard_reset_complete(0x%x, 0x%x, 0x%x) enter\n",
366 controller, port, completion_status
367 ));
368
369 while (element != NULL)
370 {
371 task_request = (SCIF_SAS_TASK_REQUEST_T*) sci_fast_list_get_object(element);
372 element = sci_fast_list_get_next(element);
373
374 if (scif_sas_task_request_get_function(task_request)
375 == SCI_SAS_HARD_RESET)
376 {
377 fw_device = task_request->parent.device;
378
379 if (fw_device->domain == fw_domain)
380 {
381 scic_remote_device_reset_complete(fw_device->core_object);
382
383 scif_cb_task_request_complete(
384 sci_object_get_association(controller),
385 fw_device,
386 task_request,
387 (SCI_TASK_STATUS) completion_status
388 );
389
390 break;
391 }
392 }
393 }
394}
395
396// ---------------------------------------------------------------------------
397
398void scic_cb_port_bc_change_primitive_recieved(
399 SCI_CONTROLLER_HANDLE_T controller,
400 SCI_PORT_HANDLE_T port,
401 SCI_PHY_HANDLE_T phy
402)
403{
404 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
405 sci_object_get_association(port);
406
407 SCIF_SAS_CONTROLLER_T * fw_controller = (SCIF_SAS_CONTROLLER_T *)
408 sci_object_get_association(controller);
409
410 SCIF_LOG_TRACE((
411 sci_base_object_get_logger(fw_domain),
412 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
413 "scic_cb_port_bc_change_primitive_recieved(0x%x, 0x%x, 0x%x) enter\n",
414 controller, port, phy
415 ));
416
417 if (fw_domain->broadcast_change_count == 0)
418 { // Enable the BCN detection only if the bcn_count is zero. If bcn_count is
419 // not zero at this time, we won't enable BCN detection since all non-zero
420 // BCN_count means same to us. Furthermore, we avoid BCN storm by not
421 // always enabling the BCN_detection.
422 scic_port_enable_broadcast_change_notification(fw_domain->core_object);
423 }
424
425 fw_domain->broadcast_change_count++;
426
427 //if there is smp device on this domain that is in the middle of discover
428 //process or smp target reset, don't notify the driver layer.
429 if( ! scif_sas_domain_is_in_smp_activity(fw_domain) )
430 // Notify the user that there is, potentially, a change to the domain.
431 scif_cb_domain_change_notification(fw_controller, fw_domain);
432}
433
434// ---------------------------------------------------------------------------
435
436void scic_cb_port_bc_ses_primitive_recieved(
437 SCI_CONTROLLER_HANDLE_T controller,
438 SCI_PORT_HANDLE_T port,
439 SCI_PHY_HANDLE_T phy
440)
441{
442 SCIF_LOG_TRACE((
443 sci_base_object_get_logger(sci_object_get_association(port)),
444 SCIF_LOG_OBJECT_DOMAIN,
445 "scic_cb_port_bc_ses_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
446 controller, port, phy
447 ));
448}
449
450// ---------------------------------------------------------------------------
451
452void scic_cb_port_bc_expander_primitive_recieved(
453 SCI_CONTROLLER_HANDLE_T controller,
454 SCI_PORT_HANDLE_T port,
455 SCI_PHY_HANDLE_T phy
456)
457{
458 SCIF_LOG_TRACE((
459 sci_base_object_get_logger(sci_object_get_association(port)),
460 SCIF_LOG_OBJECT_DOMAIN,
461 "scic_cb_port_bc_expander_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
462 controller, port, phy
463 ));
464}
465
466// ---------------------------------------------------------------------------
467
468void scic_cb_port_bc_aen_primitive_recieved(
469 SCI_CONTROLLER_HANDLE_T controller,
470 SCI_PORT_HANDLE_T port,
471 SCI_PHY_HANDLE_T phy
472)
473{
474 SCIF_LOG_TRACE((
475 sci_base_object_get_logger(sci_object_get_association(port)),
476 SCIF_LOG_OBJECT_DOMAIN,
477 "scic_cb_port_bc_aen_primitive_received(0x%x, 0x%x, 0x%x) enter\n",
478 controller, port, phy
479 ));
480}
481
482// ---------------------------------------------------------------------------
483
484void scic_cb_port_link_up(
485 SCI_CONTROLLER_HANDLE_T controller,
486 SCI_PORT_HANDLE_T port,
487 SCI_PHY_HANDLE_T phy
488)
489{
490 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
491 sci_object_get_association(port);
492
493 SCIF_LOG_TRACE((
494 sci_base_object_get_logger(sci_object_get_association(port)),
495 SCIF_LOG_OBJECT_DOMAIN,
496 "scic_cb_port_link_up(0x%x, 0x%x, 0x%x) enter\n",
497 controller, port, phy
498 ));
499
500 scif_sas_domain_update_device_port_width(fw_domain, port);
501}
502
503// ---------------------------------------------------------------------------
504
505void scic_cb_port_link_down(
506 SCI_CONTROLLER_HANDLE_T controller,
507 SCI_PORT_HANDLE_T port,
508 SCI_PHY_HANDLE_T phy
509)
510{
511 SCIF_SAS_DOMAIN_T * fw_domain = (SCIF_SAS_DOMAIN_T*)
512 sci_object_get_association(port);
513
514 SCIF_LOG_TRACE((
515 sci_base_object_get_logger(sci_object_get_association(port)),
516 SCIF_LOG_OBJECT_DOMAIN,
517 "scic_cb_port_link_down(0x%x, 0x%x, 0x%x) enter\n",
518 controller, port, phy
519 ));
520
521 scif_sas_domain_update_device_port_width(fw_domain, port);
522}
523
524//******************************************************************************
525//* P R O T E C T E D M E T H O D S
526//******************************************************************************
527
528/**
529 * @brief This method constructs the framework's SAS domain object. During
530 * the construction process a linkage to the corresponding core port
531 * object.
532 *
533 * @param[in] domain This parameter specifies the domain object to be
534 * constructed.
535 * @param[in] domain_id This parameter specifies the ID for the domain
536 * object.
537 * @param[in] fw_controller This parameter specifies the controller managing
538 * the domain being constructed.
539 *
540 * @return none
541 */
542void scif_sas_domain_construct(
543 SCIF_SAS_DOMAIN_T * fw_domain,
544 U8 domain_id,
545 SCIF_SAS_CONTROLLER_T * fw_controller
546)
547{
548 SCIF_LOG_TRACE((
549 sci_base_object_get_logger(fw_controller),
550 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
551 "scif_sas_domain_construct(0x%x, 0x%x, 0x%x) enter\n",
552 fw_domain, domain_id, fw_controller
553 ));
554
555 sci_base_domain_construct(
556 &fw_domain->parent,
557 sci_base_object_get_logger(fw_controller),
558 scif_sas_domain_state_table
559 );
560
561 scif_sas_domain_initialize_state_logging(fw_domain);
562
563 sci_abstract_list_construct(
564 &fw_domain->remote_device_list, &fw_controller->free_remote_device_pool
565 );
566
567 // Retrieve the core's port object that directly corresponds to this
568 // domain.
569 scic_controller_get_port_handle(
570 fw_controller->core_object, domain_id, &fw_domain->core_object
571 );
572
573 // Set the association in the core port to this framework domain object.
574 sci_object_set_association(
575 (SCI_OBJECT_HANDLE_T) fw_domain->core_object, fw_domain
576 );
577
578 sci_fast_list_init(&fw_domain->request_list);
579
580 fw_domain->operation.timer = NULL;
581
582 fw_domain->is_port_ready = FALSE;
583 fw_domain->device_start_count = 0;
584 fw_domain->controller = fw_controller;
585 fw_domain->operation.status = SCI_SUCCESS;
586 fw_domain->is_config_route_table_needed = FALSE;
587}
588
589/**
590 * @brief This method will terminate the requests outstanding in the core
591 * based on the supplied criteria.
592 * - if the all three parameters are specified then only the single
593 * SCIF_SAS_REQUEST object is terminated.
594 * - if only the SCIF_SAS_DOMAIN and SCIF_SAS_REMOTE_DEVICE are
595 * specified, then all SCIF_SAS_REQUEST objects outstanding at
596 * the device are terminated. The one exclusion to this rule is
597 * that the fw_requestor is not terminated.
598 * - if only the SCIF_SAS_DOMAIN object is specified, then all
599 * SCIF_SAS_REQUEST objects outstanding in the domain are
600 * terminated.
601 *
602 * @param[in] fw_domain This parameter specifies the domain in which to
603 * terminate requests.
604 * @param[in] fw_device This parameter specifies the remote device in
605 * which to terminate requests. This parameter can be NULL
606 * as long as the fw_request parameter is NULL. It is a
607 * required parameter if the fw_request parameter is not NULL.
608 * @param[in] fw_request This parameter specifies the request object to
609 * be terminated. This parameter can be NULL.
610 * @param[in] fw_requestor This parameter specifies the task management
611 * request that is responsible for the termination of requests.
612 *
613 * @return none
614 */
615void scif_sas_domain_terminate_requests(
616 SCIF_SAS_DOMAIN_T * fw_domain,
617 SCIF_SAS_REMOTE_DEVICE_T * fw_device,
618 SCIF_SAS_REQUEST_T * fw_request,
619 SCIF_SAS_TASK_REQUEST_T * fw_requestor
620)
621{
622 SCIF_LOG_TRACE((
623 sci_base_object_get_logger(fw_domain),
624 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
625 "scif_sas_domain_terminate_requests(0x%x, 0x%x, 0x%x, 0x%x) enter\n",
626 fw_domain, fw_device, fw_request, fw_requestor
627 ));
628
629 if (fw_request != NULL)
630 {
631 fw_request->terminate_requestor = fw_requestor;
632 fw_request->state_handlers->abort_handler(&fw_request->parent);
633 }
634 else
635 {
636 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
637 SCIF_SAS_REQUEST_T * request = NULL;
638
639 // Cycle through the fast list of IO requests. Terminate each
640 // outstanding requests that matches the criteria supplied by the
641 // caller.
642 while (element != NULL)
643 {
644 request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
645 // The current element may be deleted from the list becasue of
646 // IO completion so advance to the next element early
647 element = sci_fast_list_get_next(element);
648
649 // Ensure we pass the supplied criteria before terminating the
650 // request.
651 if (
652 (fw_device == NULL)
653 || (
654 (request->device == fw_device)
655 && (fw_requestor != (SCIF_SAS_TASK_REQUEST_T*) request)
656 )
657 )
658 {
659 if (
660 (request->is_waiting_for_abort_task_set == FALSE) ||
661 (request->terminate_requestor == NULL)
662 )
663 {
664 request->terminate_requestor = fw_requestor;
665 request->state_handlers->abort_handler(&request->parent);
666 }
667 }
668 }
669 }
670}
671
672/**
673 * @brief This method searches the domain object to find a
674 * SCIF_SAS_REQUEST object associated with the supplied IO tag.
675 *
676 * @param[in] fw_domain This parameter specifies the domain in which to
677 * to find the request object.
678 * @param[in] io_tag This parameter specifies the IO tag value for which
679 * to locate the corresponding request.
680 *
681 * @return This method returns a pointer to the SCIF_SAS_REQUEST object
682 * associated with the supplied IO tag.
683 * @retval NULL This value is returned if the IO tag does not resolve to
684 * a request.
685 */
686SCIF_SAS_REQUEST_T * scif_sas_domain_get_request_by_io_tag(
687 SCIF_SAS_DOMAIN_T * fw_domain,
688 U16 io_tag
689)
690{
691 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
692 SCIF_SAS_IO_REQUEST_T * io_request = NULL;
693
694 SCIF_LOG_TRACE((
695 sci_base_object_get_logger(fw_domain),
696 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_TASK_MANAGEMENT,
697 "scif_sas_domain_get_request_by_io_tag(0x%x, 0x%x) enter\n",
698 fw_domain, io_tag
699 ));
700
701 while (element != NULL)
702 {
703 io_request = (SCIF_SAS_IO_REQUEST_T*) sci_fast_list_get_object(element);
704
705 // Check to see if we located the request with an identical IO tag.
706 if (scic_io_request_get_io_tag(io_request->parent.core_object) == io_tag)
707 return &io_request->parent;
708
709 element = sci_fast_list_get_next(element);
710 }
711
712 return NULL;
713}
714
715/**
716 * @brief This method performs domain object initialization to be done
717 * when the scif_controller_initialize() method is invoked.
718 * This includes operation timeout creation.
719 *
720 * @param[in] fw_domain This parameter specifies the domain object for
721 * which to perform initialization.
722 *
723 * @return none
724 */
725void scif_sas_domain_initialize(
726 SCIF_SAS_DOMAIN_T * fw_domain
727)
728{
729 SCIF_LOG_TRACE((
730 sci_base_object_get_logger(fw_domain),
731 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_INITIALIZATION,
732 "scif_sas_domain_initialize(0x%x) enter\n",
733 fw_domain
734 ));
735
736 // Create the timer for each domain. It is too early in the process
737 // to allocate this during construction since the user didn't have
738 // a chance to set it's association.
739 if (fw_domain->operation.timer == 0)
740 {
741 fw_domain->operation.timer = scif_cb_timer_create(
742 fw_domain->controller,
743 scif_sas_domain_operation_timeout_handler,
744 fw_domain
745 );
746 }
747}
748
749/**
750 * @brief This method performs domain object handling for core remote
751 * device start complete notifications. Core remote device starts
752 * and start completes are only done during discovery. This could
753 * ultimately be wrapped into a handler method on the domain (they
754 * actually already exist). This method will decrement the number
755 * of device start operations ongoing and attempt to determine if
756 * discovery is complete.
757 *
758 * @param[in] fw_domain This parameter specifies the domain object for
759 * which to perform initialization.
760 *
761 * @return none
762 */
763void scif_sas_domain_remote_device_start_complete(
764 SCIF_SAS_DOMAIN_T * fw_domain,
765 SCIF_SAS_REMOTE_DEVICE_T * fw_device
766)
767{
768 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
769
770 SCIF_LOG_TRACE((
771 sci_base_object_get_logger(fw_domain),
772 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
773 "scif_sas_domain_remote_device_start_complete(0x%x, 0x%x) enter\n",
774 fw_domain, fw_device
775 ));
776
777 // If a device is being started/start completed, then we must be
778 // during discovery.
779 ASSERT(fw_domain->parent.state_machine.current_state_id
780 == SCI_BASE_DOMAIN_STATE_DISCOVERING);
781
782 scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
783
784 // Decrement the number of devices being started and check to see
785 // if all have finished being started or failed as the case may be.
786 fw_domain->device_start_in_progress_count--;
787
788 if ( dev_protocols.u.bits.attached_smp_target )
789 {
790 if ( fw_device->containing_device == NULL )
791 //kick off the smp discover process if this expander is direct attached.
792 scif_sas_smp_remote_device_start_discover(fw_device);
793 else
794 //mark this device, the discover process of this device will start after
795 //its containing smp device finish discover.
796 fw_device->protocol_device.smp_device.scheduled_activity =
797 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER;
798 }
799 else
800 {
801 fw_domain->state_handlers->device_start_complete_handler(
802 &fw_domain->parent, &fw_device->parent
803 );
804 }
805}
806
807
808/**
809 * @brief This methods check each smp device in this domain. If there is at
810 * least one smp device in discover or target reset activity, this
811 * domain is considered in smp activity. Note this routine is not
812 * called on fast IO path.
813 *
814 * @param[in] fw_domain The framework domain object
815 *
816 * @return BOOL value to indicate whether a domain is in SMP activity.
817 */
818BOOL scif_sas_domain_is_in_smp_activity(
819 SCIF_SAS_DOMAIN_T * fw_domain
820)
821{
822 SCI_ABSTRACT_ELEMENT_T * current_element =
823 sci_abstract_list_get_front(&fw_domain->remote_device_list);
824
825 SCIF_SAS_REMOTE_DEVICE_T * current_device;
826
827 while ( current_element != NULL )
828 {
829 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
830
831 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
832 sci_abstract_list_get_object(current_element);
833
834 scic_remote_device_get_protocols(current_device->core_object,
835 &dev_protocols
836 );
837
838 if (dev_protocols.u.bits.attached_smp_target &&
839 scif_sas_smp_remote_device_is_in_activity(current_device))
840 return TRUE;
841
842 current_element =
843 sci_abstract_list_get_next(current_element);
844 }
845
846 return FALSE;
847}
848
849
850/**
851 * @brief This methods finds a expander attached device by searching the domain's
852 * device list using connected expander device and expander phy id.
853 *
854 * @param[in] fw_domain The framework domain object
855 * @param[in] parent_device The expander device the target device attaches to.
856 * @param[in] expander_phy_id The expander phy id that the target device owns.
857 *
858 * @return found remote device or a NULL value if no device found.
859 */
860SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_get_device_by_containing_device(
861 SCIF_SAS_DOMAIN_T * fw_domain,
862 SCIF_SAS_REMOTE_DEVICE_T * containing_device,
863 U8 expander_phy_id
864)
865{
866 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
867 SCI_ABSTRACT_ELEMENT_T * element = sci_abstract_list_get_front(
868 &fw_domain->remote_device_list
869 );
870
871 //parent device must not be NULL.
872 ASSERT(containing_device != NULL);
873
874 // Search the abstract list to see if there is a remote device meets the
875 // search condition.
876 while (element != NULL)
877 {
878 fw_device = (SCIF_SAS_REMOTE_DEVICE_T*)
879 sci_abstract_list_get_object(element);
880
881 // Check to see if this is the device for which we are searching.
882 if (
883 (fw_device->containing_device == containing_device)
884 && (fw_device->expander_phy_identifier == expander_phy_id)
885 )
886 {
887 return fw_device;
888 }
889
890 element = sci_abstract_list_get_next(element);
891 }
892
893 return SCI_INVALID_HANDLE;
894}
895
896
897/**
898 * @brief This methods finds the first device that is in STOPPED state and its
899 * connection_rate is still in SPINUP_HOLD(value 3).
900 *
901 * @param[in] fw_domain The framework domain object
902 *
903 * @return SCIF_SAS_REMOTE_DEVICE_T The device that is in SPINUP_HOLD or NULL.
904 */
905SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_in_spinup_hold(
906 SCIF_SAS_DOMAIN_T * fw_domain
907)
908{
909 SCI_ABSTRACT_ELEMENT_T * current_element;
910 SCIF_SAS_REMOTE_DEVICE_T * current_device;
911
912 SCIF_LOG_TRACE((
913 sci_base_object_get_logger(fw_domain),
914 SCIF_LOG_OBJECT_DOMAIN,
915 "scif_sas_domain_find_device_in_spinup_hold(0x%x) enter\n",
916 fw_domain
917 ));
918
919 //search throught domain's device list to find the first sata device on spinup_hold
920 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
921 while (current_element != NULL )
922 {
923 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
924 sci_abstract_list_get_object(current_element);
925
926 //We must get the next element before we remove the current
927 //device. Or else, we will get wrong next_element, since the erased
928 //element has been put into free pool.
929 current_element = sci_abstract_list_get_next(current_element);
930
931 if ( sci_base_state_machine_get_state(¤t_device->parent.state_machine) ==
932 SCI_BASE_REMOTE_DEVICE_STATE_STOPPED
933 && scic_remote_device_get_connection_rate(current_device->core_object) ==
934 SCI_SATA_SPINUP_HOLD )
935 {
936 return current_device;
937 }
938 }
939
940 return NULL;
941}
942
943
944/**
945 * @brief This methods finds the first device that has specific activity scheduled.
946 *
947 * @param[in] fw_domain The framework domain object
948 * @param[in] smp_activity A specified smp activity. The valid range is [1,5].
949 *
950 * @return SCIF_SAS_REMOTE_DEVICE_T The device that has specified smp activity scheduled.
951 */
952SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_device_has_scheduled_activity(
953 SCIF_SAS_DOMAIN_T * fw_domain,
954 U8 smp_activity
955)
956{
957 SCI_ABSTRACT_ELEMENT_T * current_element =
958 sci_abstract_list_get_front(&fw_domain->remote_device_list);
959
960 SCIF_SAS_REMOTE_DEVICE_T * current_device;
961 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
962
963 //config route table activity has higher priority than discover activity.
964 while ( current_element != NULL )
965 {
966 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
967 sci_abstract_list_get_object(current_element);
968
969 scic_remote_device_get_protocols(current_device->core_object,
970 &dev_protocols);
971
972 current_element =
973 sci_abstract_list_get_next(current_element);
974
975 if ( dev_protocols.u.bits.attached_smp_target
976 && current_device->protocol_device.smp_device.scheduled_activity ==
977 smp_activity)
978 {
979 return current_device;
980 }
981 }
982
983 return NULL;
984}
985
986
987/**
988 * @brief This methods finds the smp device that has is_config_route_table_scheduled
989 * flag set to TRUE, and start config route table on it. If there is no
990 * smp device scheduled to config route table, find the smp device has
991 * is_discover_scheduled and start the smp discover process on them.
992 *
993 * @param[in] fw_domain The framework domain that to start smp discover process.
994 *
995 * @return NONE
996 */
997void scif_sas_domain_start_smp_activity(
998 SCIF_SAS_DOMAIN_T * fw_domain
999)
1000{
1001 SCIF_SAS_REMOTE_DEVICE_T * device_has_scheduled_activity = NULL;
1002
1003 //first, find device that has config route table activity scheduled.
1004 //config route table activity has higher priority than Discover.
1005 device_has_scheduled_activity =
1006 scif_sas_domain_find_device_has_scheduled_activity(
1007 fw_domain,
1008 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CONFIG_ROUTE_TABLE
1009 );
1010
1011 if (device_has_scheduled_activity != NULL)
1012 {
1013 scif_sas_smp_remote_device_configure_route_table(device_has_scheduled_activity);
1014 device_has_scheduled_activity->protocol_device.smp_device.scheduled_activity =
1015 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_NONE;
1016 return;
1017 }
1018
1019 //if no device has config route table activity scheduled, search again, find
1020 //device has discover activity scheduled.
1021 device_has_scheduled_activity =
1022 scif_sas_domain_find_device_has_scheduled_activity(
1023 fw_domain,
1024 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_DISCOVER
1025 );
1026
1027 if (device_has_scheduled_activity != NULL)
1028 scif_sas_smp_remote_device_start_discover(device_has_scheduled_activity);
1029}
1030
1031
1032/**
1033 * @brief This method starts domain's smp discover process from the top level expander.
1034 *
1035 * @param[in] fw_domain The framework domain that to start smp discover process.
1036 @ @param[in] top_expander The top level expander device to start smp discover process.
1037 *
1038 * @return None
1039 */
1040void scif_sas_domain_start_smp_discover(
1041 SCIF_SAS_DOMAIN_T * fw_domain,
1042 SCIF_SAS_REMOTE_DEVICE_T * top_expander
1043)
1044{
1045 SCI_ABSTRACT_ELEMENT_T * current_element =
1046 sci_abstract_list_get_front(&fw_domain->remote_device_list);
1047
1048 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1049
1050 // something changed behind expander
1051 // mark all the device behind expander to be NOT
1052 // is_currently_discovered.
1053 while ( current_element != NULL )
1054 {
1055 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1056 sci_abstract_list_get_object(current_element);
1057
1058 current_device->is_currently_discovered = FALSE;
1059
1060 //reset all the devices' port witdh except the top expander.
1061 if (current_device->containing_device != NULL)
1062 current_device->device_port_width = 1;
1063
1064 current_element = sci_abstract_list_get_next(current_element);
1065 }
1066
1067 //expander device itself should be set to is_currently_discovered.
1068 top_expander->is_currently_discovered = TRUE;
1069
1070 //kick off the smp discover process.
1071 scif_sas_smp_remote_device_start_discover(top_expander);
1072}
1073
1074
1075/**
1076 * @brief This method continues domain's smp discover process and
1077 * may transit to READY state if all smp activities are done.
1078 *
1079 * @param[in] fw_domain The framework domain that to start smp discover process.
1080 *
1081 * @return None
1082 */
1083void scif_sas_domain_continue_discover(
1084 SCIF_SAS_DOMAIN_T * fw_domain
1085)
1086{
1087 SCIF_LOG_TRACE((
1088 sci_base_object_get_logger(fw_domain),
1089 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1090 "scif_sas_domain_continue_discover(0x%x) enter\n",
1091 fw_domain
1092 ));
1093
1094 if ( fw_domain->device_start_in_progress_count == 0
1095 && !scif_sas_domain_is_in_smp_activity(fw_domain) )
1096 {
1097 //domain scrub the remote device list to see if there is a need
1098 //to start smp discover on expander device. There may be no
1099 //need to start any smp discover.
1100 scif_sas_domain_start_smp_activity(fw_domain);
1101
1102 //In domain discovery timeout case, we cancel all
1103 //the smp activities, and terminate all the smp requests, then
1104 //this routine is called. But the smp request may not done
1105 //terminated. We want to guard the domain trasitting to READY
1106 //by checking outstanding smp request count. If there is outstanding
1107 //smp request, the domain will not transit to READY. Later when
1108 //the smp request is terminated at smp remote device, this routine
1109 //will be called then the domain will transit to READY state.
1110 if ( ! scif_sas_domain_is_in_smp_activity(fw_domain)
1111 && scif_sas_domain_get_smp_request_count(fw_domain) == 0)
1112 {
1113 //before domain transit to READY state, domain has some clean up
1114 //work to do, such like update domain's remote devcie list.
1115 scif_sas_domain_finish_discover(fw_domain);
1116 }
1117 }
1118}
1119
1120
1121/**
1122 * @brief This method finishes domain's smp discover process and
1123 * update domain's remote device list.
1124 *
1125 * @param[in] fw_domain The framework domain that's to finish smp discover process.
1126 *
1127 * @return None
1128 */
1129void scif_sas_domain_finish_discover(
1130 SCIF_SAS_DOMAIN_T * fw_domain
1131)
1132{
1133 SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
1134 SCI_ABSTRACT_ELEMENT_T * current_element = NULL;
1135
1136 SCIF_LOG_TRACE((
1137 sci_base_object_get_logger(fw_domain),
1138 SCIF_LOG_OBJECT_DOMAIN | SCIF_LOG_OBJECT_DOMAIN_DISCOVERY,
1139 "scif_sas_domain_finish_discover(0x%x) enter\n",
1140 fw_domain
1141 ));
1142
1143 //need to scrub all the devices behind the expander. Check each
1144 //device's discover_status. if the is_currently_discovered is FALSE, means
1145 //the device is not been rediscovered. this device needs to be removed.
1146 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
1147 while (current_element != NULL )
1148 {
1149 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1150 sci_abstract_list_get_object(current_element);
1151
1152 //We must get the next element before we remove the current
1153 //device. Or else, we will get wrong next_element, since the erased
1154 //element has been put into free pool.
1155 current_element = sci_abstract_list_get_next(current_element);
1156
1157 if ( current_device->is_currently_discovered == FALSE )
1158 {
1159 // Notify the framework user of the device removal.
1160 scif_cb_domain_device_removed(
1161 fw_domain->controller, fw_domain, current_device
1162 );
1163 }
1164 }
1165
1166 sci_base_state_machine_change_state(
1167 &fw_domain->parent.state_machine, SCI_BASE_DOMAIN_STATE_READY
1168 );
1169}
1170
1171
1172
1173/**
1174 * @brief This method remove an expander device and its child devices, in order to
1175 * deal with a detected illeagal phy connection.
1176 *
1177 * @param[in] fw_domain The domain that a expander belongs to.
1178 * @param[in] fw_device The expander device to be removed.
1179 *
1180 * @return none.
1181 */
1182void scif_sas_domain_remove_expander_device(
1183 SCIF_SAS_DOMAIN_T * fw_domain,
1184 SCIF_SAS_REMOTE_DEVICE_T * fw_device
1185)
1186{
1187 SCIF_SAS_SMP_REMOTE_DEVICE_T * smp_remote_device =
1188 &fw_device->protocol_device.smp_device;
1189
1190 SCI_FAST_LIST_ELEMENT_T * element = smp_remote_device->smp_phy_list.list_head;
1191 SCIF_SAS_SMP_PHY_T * curr_smp_phy = NULL;
1192 SCIF_SAS_REMOTE_DEVICE_T * current_device = NULL;
1193
1194 while (element != NULL)
1195 {
1196 curr_smp_phy = (SCIF_SAS_SMP_PHY_T*) sci_fast_list_get_object(element);
1197 element = sci_fast_list_get_next(element);
1198
1199 if ( curr_smp_phy->attached_device_type != SMP_NO_DEVICE_ATTACHED
1200 && curr_smp_phy->u.end_device != NULL )
1201 {
1202 if (curr_smp_phy->attached_device_type == SMP_END_DEVICE_ONLY)
1203 current_device = curr_smp_phy->u.end_device;
1204 else
1205 current_device = curr_smp_phy->u.attached_phy->owning_device;
1206
1207 scif_cb_domain_device_removed(fw_domain->controller, fw_domain, current_device);
1208 }
1209 }
1210
1211 //remove device itself
1212 scif_cb_domain_device_removed(fw_domain->controller, fw_domain, fw_device);
1213}
1214
1215
1216/**
1217 * @brief This method searches the whole domain and finds all the smp devices to
1218 * cancel their smp activities if there is any.
1219 *
1220 * @param[in] fw_domain The domain that its smp activities are to be canceled.
1221 *
1222 * @return none.
1223 */
1224void scif_sas_domain_cancel_smp_activities(
1225 SCIF_SAS_DOMAIN_T * fw_domain
1226)
1227{
1228 SCI_ABSTRACT_ELEMENT_T * current_element =
1229 sci_abstract_list_get_front(&fw_domain->remote_device_list);
1230
1231 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1232
1233 //purge all the outstanding internal IOs in HPQ.
1234 scif_sas_high_priority_request_queue_purge_domain(
1235 &fw_domain->controller->hprq, fw_domain
1236 );
1237
1238 while ( current_element != NULL )
1239 {
1240 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
1241
1242 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1243 sci_abstract_list_get_object(current_element);
1244
1245 scic_remote_device_get_protocols(current_device->core_object,
1246 &dev_protocols
1247 );
1248
1249 if (dev_protocols.u.bits.attached_smp_target)
1250 {
1251 scif_sas_smp_remote_device_cancel_smp_activity(current_device);
1252 }
1253
1254 current_element =
1255 sci_abstract_list_get_next(current_element);
1256 }
1257}
1258
1259
1260/**
1261 * @brief This method searches the domain's request list and counts outstanding
1262 * smp IOs.
1263 *
1264 * @param[in] fw_domain The domain that its request list is to be searched.
1265 *
1266 * @return U8 The possible return value of this routine is 0 or 1.
1267 */
1268U8 scif_sas_domain_get_smp_request_count(
1269 SCIF_SAS_DOMAIN_T * fw_domain
1270)
1271{
1272 SCI_FAST_LIST_ELEMENT_T * element = fw_domain->request_list.list_head;
1273 SCIF_SAS_REQUEST_T * request = NULL;
1274 U8 count = 0;
1275 SCIC_TRANSPORT_PROTOCOL protocol;
1276
1277 // Cycle through the fast list of IO requests. Terminate each
1278 // outstanding requests that matches the criteria supplied by the
1279 // caller.
1280 while (element != NULL)
1281 {
1282 request = (SCIF_SAS_REQUEST_T*) sci_fast_list_get_object(element);
1283 // The current element may be deleted from the list becasue of
1284 // IO completion so advance to the next element early
1285 element = sci_fast_list_get_next(element);
1286
1287 protocol = scic_io_request_get_protocol(request->core_object);
1288
1289 if ( protocol == SCIC_SMP_PROTOCOL)
1290 count++;
1291 }
1292
1293 return count;
1294}
1295
1296
1297/**
1298 * @brief This method start clear affiliation activities for smp devices in
1299 * this domain.
1300 *
1301 * @param[in] fw_domain The domain that its smp devices are scheduled to clear
1302 * affiliation for all the EA SATA devices.
1303 *
1304 * @return none.
1305 */
1306void scif_sas_domain_start_clear_affiliation(
1307 SCIF_SAS_DOMAIN_T * fw_domain
1308)
1309{
1310 scif_sas_domain_schedule_clear_affiliation(fw_domain);
1311 scif_sas_domain_continue_clear_affiliation(fw_domain);
1312}
1313
1314
1315/**
1316 * @brief This method schedule clear affiliation activities for smp devices in
1317 * this domain.
1318 *
1319 * @param[in] fw_domain The domain that its smp devices are scheduled to clear
1320 * affiliation for all the EA SATA devices.
1321 *
1322 * @return none.
1323 */
1324void scif_sas_domain_schedule_clear_affiliation(
1325 SCIF_SAS_DOMAIN_T * fw_domain
1326)
1327{
1328 SCI_ABSTRACT_ELEMENT_T * current_element =
1329 sci_abstract_list_get_front(&fw_domain->remote_device_list);
1330
1331 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1332 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
1333
1334 //config route table activity has higher priority than discover activity.
1335 while ( current_element != NULL )
1336 {
1337 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1338 sci_abstract_list_get_object(current_element);
1339
1340 scic_remote_device_get_protocols(current_device->core_object,
1341 &dev_protocols);
1342
1343 current_element =
1344 sci_abstract_list_get_next(current_element);
1345
1346 if ( dev_protocols.u.bits.attached_smp_target )
1347 {
1348 current_device->protocol_device.smp_device.scheduled_activity =
1349 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION;
1350 }
1351 }
1352}
1353
1354
1355/**
1356 * @brief This method carries clear affiliation activities for a smp devices in
1357 * this domain during controller stop process.
1358 *
1359 * @param[in] fw_domain The domain that its smp devices are to clear
1360 * affiliation for all the EA SATA devices.
1361 *
1362 * @return none.
1363 */
1364void scif_sas_domain_continue_clear_affiliation(
1365 SCIF_SAS_DOMAIN_T * fw_domain
1366)
1367{
1368 SCIF_SAS_REMOTE_DEVICE_T * smp_device =
1369 scif_sas_domain_find_device_has_scheduled_activity(
1370 fw_domain,
1371 SCIF_SAS_SMP_REMOTE_DEVICE_ACTIVITY_CLEAR_AFFILIATION
1372 );
1373
1374 if (smp_device != NULL)
1375 scif_sas_smp_remote_device_start_clear_affiliation(smp_device);
1376 else
1377 {
1378 //This domain has done clear affiliation.
1379 SCIF_SAS_CONTROLLER_T * fw_controller = fw_domain->controller;
1380 fw_controller->current_domain_to_clear_affiliation++;
1381
1382 //let controller continue to clear affiliation on other domains.
1383 scif_sas_controller_clear_affiliation(fw_domain->controller);
1384 }
1385}
1386
1387
1388/**
1389 * @brief This method releases resource for a framework domain.
1390 *
1391 * @param[in] fw_controller This parameter specifies the framework
1392 * controller, its associated domain's resources are to be released.
1393 * @param[in] fw_domain This parameter specifies the framework
1394 * domain whose resources are to be released.
1395 */
1396void scif_sas_domain_release_resource(
1397 SCIF_SAS_CONTROLLER_T * fw_controller,
1398 SCIF_SAS_DOMAIN_T * fw_domain
1399)
1400{
1401 if (fw_domain->operation.timer != NULL)
1402 {
1403 scif_cb_timer_destroy(fw_controller, fw_domain->operation.timer);
1404 fw_domain->operation.timer = NULL;
1405 }
1406}
1407
1408
1409/**
1410 * @brief This method finds the a EA device that has target reset scheduled.
1411 *
1412 * @param[in] fw_domain The framework domain object
1413 *
1414 * @return SCIF_SAS_REMOTE_DEVICE_T The EA device that has target reset scheduled.
1415 */
1416SCIF_SAS_REMOTE_DEVICE_T * scif_sas_domain_find_next_ea_target_reset(
1417 SCIF_SAS_DOMAIN_T * fw_domain
1418)
1419{
1420 SCI_ABSTRACT_ELEMENT_T * current_element;
1421 SCIF_SAS_REMOTE_DEVICE_T * current_device;
1422
1423 SCIF_LOG_TRACE((
1424 sci_base_object_get_logger(fw_domain),
1425 SCIF_LOG_OBJECT_DOMAIN,
1426 "scif_sas_domain_find_next_ea_target_reset(0x%x) enter\n",
1427 fw_domain
1428 ));
1429
1430 //search throught domain's device list to find the first sata device on spinup_hold
1431 current_element = sci_abstract_list_get_front(&fw_domain->remote_device_list);
1432 while (current_element != NULL )
1433 {
1434 current_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1435 sci_abstract_list_get_object(current_element);
1436
1437 current_element = sci_abstract_list_get_next(current_element);
1438
1439 if ( current_device->ea_target_reset_request_scheduled != NULL )
1440 {
1441 return current_device;
1442 }
1443 }
1444
1445 return NULL;
1446}
1447
1448#if !defined(DISABLE_WIDE_PORTED_TARGETS)
1449/**
1450 * @brief This method update the direct attached device port width.
1451 *
1452 * @param[in] fw_domain The framework domain object
1453 * @param[in] port The associated port object which recently has link up/down
1454 * event happened.
1455 *
1456 * @return none
1457 */
1458void scif_sas_domain_update_device_port_width(
1459 SCIF_SAS_DOMAIN_T * fw_domain,
1460 SCI_PORT_HANDLE_T port
1461)
1462{
1463 SCIF_SAS_REMOTE_DEVICE_T * fw_device;
1464 SCIC_PORT_PROPERTIES_T properties;
1465 U8 new_port_width = 0;
1466
1467 SCIF_LOG_TRACE((
1468 sci_base_object_get_logger(fw_domain),
1469 SCIF_LOG_OBJECT_DOMAIN,
1470 "scif_sas_domain_update_device_port_width(0x%x, 0x%x) enter\n",
1471 fw_domain, port
1472 ));
1473
1474 scic_port_get_properties(port, &properties);
1475
1476 fw_device = (SCIF_SAS_REMOTE_DEVICE_T *)
1477 scif_domain_get_device_by_sas_address(
1478 fw_domain, &properties.remote.sas_address
1479 );
1480
1481 // If the device already existed in the domain, it is a wide port SSP target,
1482 // we need to update its port width.
1483 if (fw_device != SCI_INVALID_HANDLE)
1484 {
1485 SMP_DISCOVER_RESPONSE_PROTOCOLS_T dev_protocols;
1486 scic_remote_device_get_protocols(fw_device->core_object, &dev_protocols);
1487
1488 if (dev_protocols.u.bits.attached_ssp_target)
1489 {
1490 //Get accurate port width from port's phy mask for a DA device.
1491 SCI_GET_BITS_SET_COUNT(properties.phy_mask, new_port_width);
1492
1493 scif_sas_remote_device_update_port_width(fw_device, new_port_width);
1494 }
1495 }
1496}
1497#endif //#if !defined(DISABLE_WIDE_PORTED_TARGETS)
1498
1499
1500#ifdef SCI_LOGGING
1501/**
1502 * This method will turn on logging of domain state changes.
1503 *
1504 * @param[in] fw_domain The domain for which the state logging is to be turned
1505 * on.
1506 */
1507void scif_sas_domain_initialize_state_logging(
1508 SCIF_SAS_DOMAIN_T *fw_domain
1509)
1510{
1511 sci_base_state_machine_logger_initialize(
1512 &fw_domain->parent.state_machine_logger,
1513 &fw_domain->parent.state_machine,
1514 &fw_domain->parent.parent,
1515 scif_cb_logger_log_states,
1516 "SCIF_SAS_DOMAIN_T", "base state machine",
1517 SCIF_LOG_OBJECT_DOMAIN
1518 );
1519}
1520
1521/**
1522 * This method will turn off logging of domain state changes.
1523 *
1524 * @param[in] fw_domain The domain for which the state logging is to be turned
1525 * off.
1526 */
1527void scif_sas_domain_deinitialize_state_logging(
1528 SCIF_SAS_DOMAIN_T *fw_domain
1529)
1530{
1531 sci_base_state_machine_logger_deinitialize(
1532 &fw_domain->parent.state_machine_logger,
1533 &fw_domain->parent.state_machine
1534 );
1535}
1536#endif