2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
4 * This file is provided under a dual BSD/GPLv2 license. When using or
5 * redistributing this file, you may do so under either license.
9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23 * The full GNU General Public License is included in this distribution
24 * in the file called LICENSE.GPL.
28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29 * All rights reserved.
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
35 * * Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * * Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in
39 * the documentation and/or other materials provided with the
42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 #include <sys/cdefs.h>
56 __FBSDID("$FreeBSD$");
61 * @brief This file contains the implementation for the public and protected
62 * methods for the SCIC_SDS_PORT object.
65 #include <dev/isci/scil/scic_phy.h>
66 #include <dev/isci/scil/scic_port.h>
67 #include <dev/isci/scil/scic_controller.h>
68 #include <dev/isci/scil/scic_user_callback.h>
70 #include <dev/isci/scil/scic_sds_controller.h>
71 #include <dev/isci/scil/scic_sds_port.h>
72 #include <dev/isci/scil/scic_sds_phy.h>
73 #include <dev/isci/scil/scic_sds_remote_device.h>
74 #include <dev/isci/scil/scic_sds_request.h>
75 #include <dev/isci/scil/scic_sds_port_registers.h>
76 #include <dev/isci/scil/scic_sds_logger.h>
77 #include <dev/isci/scil/scic_sds_phy_registers.h>
79 #include <dev/isci/scil/intel_sas.h>
80 #include <dev/isci/scil/scic_sds_remote_node_context.h>
81 #include <dev/isci/scil/sci_util.h>
83 #define SCIC_SDS_PORT_MIN_TIMER_COUNT (SCI_MAX_PORTS)
84 #define SCIC_SDS_PORT_MAX_TIMER_COUNT (SCI_MAX_PORTS)
86 #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000)
87 #define SCU_DUMMY_INDEX (0xFFFF)
90 * This method will return a TRUE value if the specified phy can be assigned
93 * The following is a list of phys for each port that are allowed:
99 * This method doesn't preclude all configurations. It merely ensures
100 * that a phy is part of the allowable set of phy identifiers for
101 * that port. For example, one could assign phy 3 to port 0 and no other
102 * phys. Please refer to scic_sds_port_is_phy_mask_valid() for
103 * information regarding whether the phy_mask for a port can be supported.
105 * @param[in] this_port This is the port object to which the phy is being
107 * @param[in] phy_index This is the phy index that is being assigned to the
111 * @retval TRUE if this is a valid phy assignment for the port
112 * @retval FALSE if this is not a valid phy assignment for the port
114 BOOL scic_sds_port_is_valid_phy_assignment(
115 SCIC_SDS_PORT_T *this_port,
119 // Initialize to invalid value.
120 U32 existing_phy_index = SCI_MAX_PHYS;
123 if ((this_port->physical_port_index == 1) && (phy_index != 1))
128 if (this_port->physical_port_index == 3 && phy_index != 3)
134 (this_port->physical_port_index == 2)
135 && ((phy_index == 0) || (phy_index == 1))
141 for (index = 0; index < SCI_MAX_PHYS; index++)
143 if ( (this_port->phy_table[index] != NULL)
144 && (index != phy_index) )
146 existing_phy_index = index;
150 // Ensure that all of the phys in the port are capable of
151 // operating at the same maximum link rate.
153 (existing_phy_index < SCI_MAX_PHYS)
154 && (this_port->owning_controller->user_parameters.sds1.phys[
155 phy_index].max_speed_generation !=
156 this_port->owning_controller->user_parameters.sds1.phys[
157 existing_phy_index].max_speed_generation)
165 * @brief This method requests a list (mask) of the phys contained in the
168 * @param[in] this_port a handle corresponding to the SAS port for which
169 * to return the phy mask.
171 * @return Return a bit mask indicating which phys are a part of this port.
172 * Each bit corresponds to a phy identifier (e.g. bit 0 = phy id 0).
174 U32 scic_sds_port_get_phys(
175 SCIC_SDS_PORT_T * this_port
182 sci_base_object_get_logger(this_port),
183 SCIC_LOG_OBJECT_PORT,
184 "scic_sds_port_get_phys(0x%x) enter\n",
190 for (index = 0; index < SCI_MAX_PHYS; index++)
192 if (this_port->phy_table[index] != NULL)
194 mask |= (1 << index);
202 * This method will return a TRUE value if the port's phy mask can be
203 * supported by the SCU.
205 * The following is a list of valid PHY mask configurations for each
207 * - Port 0 - [[3 2] 1] 0
212 * @param[in] this_port This is the port object for which to determine
213 * if the phy mask can be supported.
215 * @return This method returns a boolean indication specifying if the
216 * phy mask can be supported.
217 * @retval TRUE if this is a valid phy assignment for the port
218 * @retval FALSE if this is not a valid phy assignment for the port
220 BOOL scic_sds_port_is_phy_mask_valid(
221 SCIC_SDS_PORT_T *this_port,
225 if (this_port->physical_port_index == 0)
227 if ( ((phy_mask & 0x0F) == 0x0F)
228 || ((phy_mask & 0x03) == 0x03)
229 || ((phy_mask & 0x01) == 0x01)
233 else if (this_port->physical_port_index == 1)
235 if ( ((phy_mask & 0x02) == 0x02)
239 else if (this_port->physical_port_index == 2)
241 if ( ((phy_mask & 0x0C) == 0x0C)
242 || ((phy_mask & 0x04) == 0x04)
246 else if (this_port->physical_port_index == 3)
248 if ( ((phy_mask & 0x08) == 0x08)
257 * This method retrieves a currently active (i.e. connected) phy
258 * contained in the port. Currently, the lowest order phy that is
259 * connected is returned.
261 * @param[in] this_port This parameter specifies the port from which
262 * to return a connected phy.
264 * @return This method returns a pointer to a SCIS_SDS_PHY object.
265 * @retval NULL This value is returned if there are no currently
266 * active (i.e. connected to a remote end point) phys
267 * contained in the port.
268 * @retval All other values specify a SCIC_SDS_PHY object that is
269 * active in the port.
271 SCIC_SDS_PHY_T * scic_sds_port_get_a_connected_phy(
272 SCIC_SDS_PORT_T *this_port
278 for (index = 0; index < SCI_MAX_PHYS; index++)
280 // Ensure that the phy is both part of the port and currently
281 // connected to the remote end-point.
282 phy = this_port->phy_table[index];
285 && scic_sds_port_active_phy(this_port, phy)
296 * This method attempts to make the assignment of the phy to the port.
297 * If successful the phy is assigned to the ports phy table.
299 * @param[in, out] port The port object to which the phy assignement
301 * @param[in, out] phy The phy which is being assigned to the port.
304 * @retval TRUE if the phy assignment can be made.
305 * @retval FALSE if the phy assignement can not be made.
307 * @note This is a functional test that only fails if the phy is currently
308 * assigned to a different port.
310 SCI_STATUS scic_sds_port_set_phy(
311 SCIC_SDS_PORT_T *port,
315 // Check to see if we can add this phy to a port
316 // that means that the phy is not part of a port and that the port does
317 // not already have a phy assinged to the phy index.
319 (port->phy_table[phy->phy_index] == SCI_INVALID_HANDLE)
320 && (scic_sds_phy_get_port(phy) == SCI_INVALID_HANDLE)
321 && scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)
324 // Phy is being added in the stopped state so we are in MPC mode
325 // make logical port index = physical port index
326 port->logical_port_index = port->physical_port_index;
327 port->phy_table[phy->phy_index] = phy;
328 scic_sds_phy_set_port(phy, port);
337 * This method will clear the phy assigned to this port. This method fails
338 * if this phy is not currently assinged to this port.
340 * @param[in, out] port The port from which the phy is being cleared.
341 * @param[in, out] phy The phy being cleared from the port.
344 * @retval TRUE if the phy is removed from the port.
345 * @retval FALSE if this phy is not assined to this port.
347 SCI_STATUS scic_sds_port_clear_phy(
348 SCIC_SDS_PORT_T *port,
352 // Make sure that this phy is part of this port
354 (port->phy_table[phy->phy_index] == phy)
355 && (scic_sds_phy_get_port(phy) == port)
358 // Yep it is assigned to this port so remove it
359 scic_sds_phy_set_port(
361 &scic_sds_port_get_controller(port)->port_table[SCI_MAX_PORTS]
364 port->phy_table[phy->phy_index] = SCI_INVALID_HANDLE;
373 * This method will add a PHY to the selected port.
375 * @param[in] this_port This parameter specifies the port in which the phy will
378 * @param[in] the_phy This parameter is the phy which is to be added to the
381 * @return This method returns an SCI_STATUS.
382 * @retval SCI_SUCCESS the phy has been added to the port.
383 * @retval Any other status is failre to add the phy to the port.
385 SCI_STATUS scic_sds_port_add_phy(
386 SCIC_SDS_PORT_T * this_port,
387 SCIC_SDS_PHY_T * the_phy
390 return this_port->state_handlers->parent.add_phy_handler(
391 &this_port->parent, &the_phy->parent);
396 * This method will remove the PHY from the selected PORT.
398 * @param[in] this_port This parameter specifies the port in which the phy will
401 * @param[in] the_phy This parameter is the phy which is to be added to the
404 * @return This method returns an SCI_STATUS.
405 * @retval SCI_SUCCESS the phy has been removed from the port.
406 * @retval Any other status is failre to add the phy to the port.
408 SCI_STATUS scic_sds_port_remove_phy(
409 SCIC_SDS_PORT_T * this_port,
410 SCIC_SDS_PHY_T * the_phy
413 return this_port->state_handlers->parent.remove_phy_handler(
414 &this_port->parent, &the_phy->parent);
418 * @brief This method requests the SAS address for the supplied SAS port
419 * from the SCI implementation.
421 * @param[in] this_port a handle corresponding to the SAS port for which
422 * to return the SAS address.
423 * @param[out] sas_address This parameter specifies a pointer to a SAS
424 * address structure into which the core will copy the SAS
425 * address for the port.
429 void scic_sds_port_get_sas_address(
430 SCIC_SDS_PORT_T * this_port,
431 SCI_SAS_ADDRESS_T * sas_address
437 sci_base_object_get_logger(this_port),
438 SCIC_LOG_OBJECT_PORT,
439 "scic_sds_port_get_sas_address(0x%x, 0x%x) enter\n",
440 this_port, sas_address
443 sas_address->high = 0;
444 sas_address->low = 0;
446 for (index = 0; index < SCI_MAX_PHYS; index++)
448 if (this_port->phy_table[index] != NULL)
450 scic_sds_phy_get_sas_address(this_port->phy_table[index], sas_address);
456 * @brief This method will indicate which protocols are supported by this
459 * @param[in] this_port a handle corresponding to the SAS port for which
460 * to return the supported protocols.
461 * @param[out] protocols This parameter specifies a pointer to an IAF
462 * protocol field structure into which the core will copy
463 * the protocol values for the port. The values are
464 * returned as part of a bit mask in order to allow for
465 * multi-protocol support.
470 void scic_sds_port_get_protocols(
471 SCIC_SDS_PORT_T * this_port,
472 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
478 sci_base_object_get_logger(this_port),
479 SCIC_LOG_OBJECT_PORT,
480 "scic_sds_port_get_protocols(0x%x, 0x%x) enter\n",
484 protocols->u.all = 0;
486 for (index = 0; index < SCI_MAX_PHYS; index++)
488 if (this_port->phy_table[index] != NULL)
490 scic_sds_phy_get_protocols(this_port->phy_table[index], protocols);
496 * @brief This method requests the SAS address for the device directly
497 * attached to this SAS port.
499 * @param[in] this_port a handle corresponding to the SAS port for which
500 * to return the SAS address.
501 * @param[out] sas_address This parameter specifies a pointer to a SAS
502 * address structure into which the core will copy the SAS
503 * address for the device directly attached to the port.
507 void scic_sds_port_get_attached_sas_address(
508 SCIC_SDS_PORT_T * this_port,
509 SCI_SAS_ADDRESS_T * sas_address
512 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
516 sci_base_object_get_logger(this_port),
517 SCIC_LOG_OBJECT_PORT,
518 "scic_sds_port_get_attached_sas_address(0x%x, 0x%x) enter\n",
519 this_port, sas_address
522 // Ensure that the phy is both part of the port and currently
523 // connected to the remote end-point.
524 phy = scic_sds_port_get_a_connected_phy(this_port);
527 scic_sds_phy_get_attached_phy_protocols(phy, &protocols);
529 if (!protocols.u.bits.stp_target)
531 scic_sds_phy_get_attached_sas_address(phy, sas_address);
535 scic_sds_phy_get_sas_address(phy, sas_address);
536 sas_address->low += phy->phy_index;
538 //Need to make up attached STP device's SAS address in
539 //the same order as recorded IAF from SSP device.
540 sas_address->high = SCIC_SWAP_DWORD(sas_address->high);
541 sas_address->low = SCIC_SWAP_DWORD(sas_address->low);
546 sas_address->high = 0;
547 sas_address->low = 0;
552 * @brief This method will indicate which protocols are supported by this
555 * @param[in] this_port a handle corresponding to the SAS port for which
556 * to return the supported protocols.
557 * @param[out] protocols This parameter specifies a pointer to an IAF
558 * protocol field structure into which the core will copy
559 * the protocol values for the port. The values are
560 * returned as part of a bit mask in order to allow for
561 * multi-protocol support.
565 void scic_sds_port_get_attached_protocols(
566 SCIC_SDS_PORT_T * this_port,
567 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
573 sci_base_object_get_logger(this_port),
574 SCIC_LOG_OBJECT_PORT,
575 "scic_sds_port_get_attached_protocols(0x%x, 0x%x) enter\n",
579 // Ensure that the phy is both part of the port and currently
580 // connected to the remote end-point.
581 phy = scic_sds_port_get_a_connected_phy(this_port);
583 scic_sds_phy_get_attached_phy_protocols(phy, protocols);
585 protocols->u.all = 0;
589 * @brief This method returns the amount of memory required for a port
594 U32 scic_sds_port_get_object_size(void)
596 return sizeof(SCIC_SDS_PORT_T);
600 * @brief This method returns the minimum number of timers required for all
605 U32 scic_sds_port_get_min_timer_count(void)
607 return SCIC_SDS_PORT_MIN_TIMER_COUNT;
611 * @brief This method returns the maximum number of timers required for all
616 U32 scic_sds_port_get_max_timer_count(void)
618 return SCIC_SDS_PORT_MAX_TIMER_COUNT;
622 void scic_sds_port_initialize_state_logging(
623 SCIC_SDS_PORT_T *this_port
626 sci_base_state_machine_logger_initialize(
627 &this_port->parent.state_machine_logger,
628 &this_port->parent.state_machine,
629 &this_port->parent.parent,
630 scic_cb_logger_log_states,
631 "SCIC_SDS_PORT_T", "base state machine",
635 sci_base_state_machine_logger_initialize(
636 &this_port->ready_substate_machine_logger,
637 &this_port->ready_substate_machine,
638 &this_port->parent.parent,
639 scic_cb_logger_log_states,
640 "SCIC_SDS_PORT_T", "ready substate machine",
647 * This routine will construct a dummy remote node context data structure
648 * This structure will be posted to the hardware to work around a scheduler
649 * error in the hardware.
651 * @param[in] this_port The logical port on which we need to create the
652 * remote node context.
653 * @param[in] rni The remote node index for this remote node context.
658 void scic_sds_port_construct_dummy_rnc(
659 SCIC_SDS_PORT_T *this_port,
663 SCU_REMOTE_NODE_CONTEXT_T * rnc;
665 rnc = &(this_port->owning_controller->remote_node_context_table[rni]);
667 memset(rnc, 0, sizeof(SCU_REMOTE_NODE_CONTEXT_T));
669 rnc->ssp.remote_sas_address_hi = 0;
670 rnc->ssp.remote_sas_address_lo = 0;
672 rnc->ssp.remote_node_index = rni;
673 rnc->ssp.remote_node_port_width = 1;
674 rnc->ssp.logical_port_index = this_port->physical_port_index;
676 rnc->ssp.nexus_loss_timer_enable = FALSE;
677 rnc->ssp.check_bit = FALSE;
678 rnc->ssp.is_valid = TRUE;
679 rnc->ssp.is_remote_node_context = TRUE;
680 rnc->ssp.function_number = 0;
681 rnc->ssp.arbitration_wait_time = 0;
685 * This routine will construct a dummy task context data structure. This
686 * structure will be posted to the hardwre to work around a scheduler error
689 * @param[in] this_port The logical port on which we need to create the
690 * remote node context.
692 * @param[in] tci The remote node index for this remote node context.
696 void scic_sds_port_construct_dummy_task(
697 SCIC_SDS_PORT_T *this_port,
701 SCU_TASK_CONTEXT_T * task_context;
703 task_context = scic_sds_controller_get_task_context_buffer(this_port->owning_controller, tci);
705 memset(task_context, 0, sizeof(SCU_TASK_CONTEXT_T));
707 task_context->abort = 0;
708 task_context->priority = 0;
709 task_context->initiator_request = 1;
710 task_context->connection_rate = 1;
711 task_context->protocol_engine_index = 0;
712 task_context->logical_port_index = this_port->physical_port_index;
713 task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP;
714 task_context->task_index = scic_sds_io_tag_get_index(tci);
715 task_context->valid = SCU_TASK_CONTEXT_VALID;
716 task_context->context_type = SCU_TASK_CONTEXT_TYPE;
718 task_context->remote_node_index = this_port->reserved_rni;
719 task_context->command_code = 0;
721 task_context->link_layer_control = 0;
722 task_context->do_not_dma_ssp_good_response = 1;
723 task_context->strict_ordering = 0;
724 task_context->control_frame = 0;
725 task_context->timeout_enable = 0;
726 task_context->block_guard_enable = 0;
728 task_context->address_modifier = 0;
730 task_context->task_phase = 0x01;
734 * This routine will free any allocated dummy resources for this port.
736 * @param[in, out] this_port The port on which the resources are being destroyed.
739 void scic_sds_port_destroy_dummy_resources(
740 SCIC_SDS_PORT_T * this_port
743 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
745 scic_controller_free_io_tag(
746 this_port->owning_controller, this_port->reserved_tci
750 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
752 scic_sds_remote_node_table_release_remote_node_index(
753 &this_port->owning_controller->available_remote_nodes, 1, this_port->reserved_rni
757 this_port->reserved_rni = SCU_DUMMY_INDEX;
758 this_port->reserved_tci = SCU_DUMMY_INDEX;
764 * @param[in] this_port
765 * @param[in] port_index
766 * @param[in] owning_controller
768 void scic_sds_port_construct(
769 SCIC_SDS_PORT_T *this_port,
771 SCIC_SDS_CONTROLLER_T *owning_controller
776 sci_base_port_construct(
778 sci_base_object_get_logger(owning_controller),
779 scic_sds_port_state_table
782 sci_base_state_machine_construct(
783 scic_sds_port_get_ready_substate_machine(this_port),
784 &this_port->parent.parent,
785 scic_sds_port_ready_substate_table,
786 SCIC_SDS_PORT_READY_SUBSTATE_WAITING
789 scic_sds_port_initialize_state_logging(this_port);
791 this_port->logical_port_index = SCIC_SDS_DUMMY_PORT;
792 this_port->physical_port_index = port_index;
793 this_port->active_phy_mask = 0;
794 this_port->enabled_phy_mask = 0;
795 this_port->owning_controller = owning_controller;
797 this_port->started_request_count = 0;
798 this_port->assigned_device_count = 0;
800 this_port->reserved_rni = SCU_DUMMY_INDEX;
801 this_port->reserved_tci = SCU_DUMMY_INDEX;
803 this_port->timer_handle = SCI_INVALID_HANDLE;
805 this_port->port_task_scheduler_registers = NULL;
807 for (index = 0; index < SCI_MAX_PHYS; index++)
809 this_port->phy_table[index] = NULL;
814 * @brief This method performs initialization of the supplied port.
815 * Initialization includes:
816 * - state machine initialization
817 * - member variable initialization
818 * - configuring the phy_mask
820 * @param[in] this_port
821 * @param[in] transport_layer_registers
822 * @param[in] port_task_scheduler_registers
823 * @param[in] port_configuration_regsiter
826 * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This value is
827 * returned if the phy being added to the port
829 SCI_STATUS scic_sds_port_initialize(
830 SCIC_SDS_PORT_T *this_port,
831 void *port_task_scheduler_registers,
832 void *port_configuration_regsiter,
836 this_port->port_task_scheduler_registers = port_task_scheduler_registers;
837 this_port->port_pe_configuration_register = port_configuration_regsiter;
838 this_port->viit_registers = viit_registers;
844 * This method is the a general link up handler for the SCIC_SDS_PORT object.
845 * This function will determine if this SCIC_SDS_PHY can
846 * be assigned to this SCIC_SDS_PORT object. If the SCIC_SDS_PHY object can
847 * is not a valid PHY for this port then the function will notify the SCIC_USER.
848 * A PHY can only be part of a port if it's attached SAS ADDRESS is the same as
849 * all other PHYs in the same port.
851 * @param[in] this_port This is the SCIC_SDS_PORT object for which has a phy
852 * that has gone link up.
853 * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
854 * @param[in] do_notify_user This parameter specifies whether to inform
855 * the user (via scic_cb_port_link_up()) as to the fact that
856 * a new phy as become ready.
857 * @param[in] do_resume_phy This parameter specifies whether to resume the phy.
858 * If this function is called from MPC mode, it will be always true.
859 * for APC, this will be false, so that phys could be resumed later
863 void scic_sds_port_general_link_up_handler(
864 SCIC_SDS_PORT_T * this_port,
865 SCIC_SDS_PHY_T * the_phy,
870 SCI_SAS_ADDRESS_T port_sas_address;
871 SCI_SAS_ADDRESS_T phy_sas_address;
873 scic_sds_port_get_attached_sas_address(this_port, &port_sas_address);
874 scic_sds_phy_get_attached_sas_address(the_phy, &phy_sas_address);
876 // If the SAS address of the new phy matches the SAS address of
877 // other phys in the port OR this is the first phy in the port,
878 // then activate the phy and allow it to be used for operations
882 (phy_sas_address.high == port_sas_address.high)
883 && (phy_sas_address.low == port_sas_address.low )
885 || (this_port->active_phy_mask == 0)
888 scic_sds_port_activate_phy(this_port, the_phy, do_notify_user, do_resume_phy);
890 if (this_port->parent.state_machine.current_state_id
891 == SCI_BASE_PORT_STATE_RESETTING)
893 sci_base_state_machine_change_state(
894 &this_port->parent.state_machine, SCI_BASE_PORT_STATE_READY
900 scic_sds_port_invalid_link_up(this_port, the_phy);
904 // ---------------------------------------------------------------------------
906 SCI_STATUS scic_port_add_phy(
907 SCI_PORT_HANDLE_T handle,
911 #if defined (SCI_LOGGING)
912 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)handle;
913 #endif // defined (SCI_LOGGING)
916 sci_base_object_get_logger(this_port),
917 SCIC_LOG_OBJECT_PORT,
918 "scic_port_add_phy(0x%x, 0x%x) enter\n",
923 sci_base_object_get_logger(this_port),
924 SCIC_LOG_OBJECT_PORT,
925 "Interface function scic_port_add_phy() has been deprecated. "
926 "PORT configuration is handled through the OEM parameters.\n"
929 return SCI_FAILURE_ADDING_PHY_UNSUPPORTED;
933 // ---------------------------------------------------------------------------
935 SCI_STATUS scic_port_remove_phy(
936 SCI_PORT_HANDLE_T handle,
940 #if defined (SCI_LOGGING)
941 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)handle;
942 #endif // defined (SCI_LOGGING)
945 sci_base_object_get_logger(this_port),
946 SCIC_LOG_OBJECT_PORT,
947 "scic_port_remove_phy(0x%x, 0x%x) enter\n",
952 sci_base_object_get_logger(this_port),
953 SCIC_LOG_OBJECT_PORT,
954 "Interface function scic_port_remove_phy() has been deprecated. "
955 "PORT configuration is handled through the OEM parameters.\n"
958 return SCI_FAILURE_ADDING_PHY_UNSUPPORTED;
961 // ---------------------------------------------------------------------------
963 SCI_STATUS scic_port_get_properties(
964 SCI_PORT_HANDLE_T port,
965 SCIC_PORT_PROPERTIES_T * properties
968 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
971 sci_base_object_get_logger(this_port),
972 SCIC_LOG_OBJECT_PORT,
973 "scic_port_get_properties(0x%x, 0x%x) enter\n",
978 (port == SCI_INVALID_HANDLE)
979 || (this_port->logical_port_index == SCIC_SDS_DUMMY_PORT)
982 return SCI_FAILURE_INVALID_PORT;
985 properties->index = this_port->logical_port_index;
986 properties->phy_mask = scic_sds_port_get_phys(this_port);
987 scic_sds_port_get_sas_address(this_port, &properties->local.sas_address);
988 scic_sds_port_get_protocols(this_port, &properties->local.protocols);
989 scic_sds_port_get_attached_sas_address(this_port, &properties->remote.sas_address);
990 scic_sds_port_get_attached_protocols(this_port, &properties->remote.protocols);
995 // ---------------------------------------------------------------------------
997 SCI_STATUS scic_port_hard_reset(
998 SCI_PORT_HANDLE_T handle,
1002 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)handle;
1005 sci_base_object_get_logger(this_port),
1006 SCIC_LOG_OBJECT_PORT,
1007 "scic_port_hard_reset(0x%x, 0x%x) enter\n",
1008 handle, reset_timeout
1011 return this_port->state_handlers->parent.reset_handler(
1018 * This method assigns the direct attached device ID for this port.
1020 * @param[in] this_port The port for which the direct attached device id is to
1022 * @param[in] device_id The direct attached device ID to assign to the port.
1023 * This will be the RNi for the device
1025 void scic_sds_port_setup_transports(
1026 SCIC_SDS_PORT_T * this_port,
1032 for (index = 0; index < SCI_MAX_PHYS; index++)
1034 if (this_port->active_phy_mask & (1 << index))
1036 scic_sds_phy_setup_transport(this_port->phy_table[index], device_id);
1042 * This method will resume the phy which is already added in the port.
1043 * Activation includes:
1044 * - enabling the Protocol Engine in the silicon.
1045 * - update the reay mask.
1047 * @param[in] this_port This is the port on which the phy should be enabled.
1051 void scic_sds_port_resume_phy(
1052 SCIC_SDS_PORT_T * this_port,
1053 SCIC_SDS_PHY_T * the_phy
1056 scic_sds_phy_resume (the_phy);
1057 this_port->enabled_phy_mask |= 1 << the_phy->phy_index;
1060 * This method will activate the phy in the port.
1061 * Activation includes:
1062 * - adding the phy to the port
1063 * - enabling the Protocol Engine in the silicon.
1064 * - notifying the user that the link is up.
1066 * @param[in] this_port This is the port on which the phy should be enabled.
1067 * @param[in] the_phy This is the specific phy which to enable.
1068 * @param[in] do_notify_user This parameter specifies whether to inform
1069 * the user (via scic_cb_port_link_up()) as to the fact that
1070 * a new phy as become ready.
1071 * @param[in] do_resume_phy This parameter specifies whether to resume the phy.
1072 * If this function is called from MPC mode, it will be always true.
1073 * for APC, this will be false, so that phys could be resumed later
1078 void scic_sds_port_activate_phy(
1079 SCIC_SDS_PORT_T * this_port,
1080 SCIC_SDS_PHY_T * the_phy,
1081 BOOL do_notify_user,
1085 SCIC_SDS_CONTROLLER_T * controller;
1086 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
1089 sci_base_object_get_logger(this_port),
1090 SCIC_LOG_OBJECT_PORT,
1091 "scic_sds_port_activate_phy(0x%x,0x%x,0x%x) enter\n",
1092 this_port, the_phy, do_notify_user
1095 controller = scic_sds_port_get_controller(this_port);
1096 scic_sds_phy_get_attached_phy_protocols(the_phy, &protocols);
1098 // If this is sata port then the phy has already been resumed
1099 if (!protocols.u.bits.stp_target)
1101 if (do_resume_phy == TRUE)
1103 scic_sds_port_resume_phy(this_port, the_phy);
1107 this_port->active_phy_mask |= 1 << the_phy->phy_index;
1109 scic_sds_controller_clear_invalid_phy(controller, the_phy);
1111 if (do_notify_user == TRUE)
1112 scic_cb_port_link_up(this_port->owning_controller, this_port, the_phy);
1116 * This method will deactivate the supplied phy in the port.
1118 * @param[in] this_port This is the port on which the phy should be
1120 * @param[in] the_phy This is the specific phy that is no longer
1121 * active in the port.
1122 * @param[in] do_notify_user This parameter specifies whether to inform
1123 * the user (via scic_cb_port_link_down()) as to the fact that
1124 * a new phy as become ready.
1128 void scic_sds_port_deactivate_phy(
1129 SCIC_SDS_PORT_T * this_port,
1130 SCIC_SDS_PHY_T * the_phy,
1135 sci_base_object_get_logger(this_port),
1136 SCIC_LOG_OBJECT_PORT,
1137 "scic_sds_port_deactivate_phy(0x%x,0x%x,0x%x) enter\n",
1138 this_port, the_phy, do_notify_user
1141 this_port->active_phy_mask &= ~(1 << the_phy->phy_index);
1142 this_port->enabled_phy_mask &= ~(1 << the_phy->phy_index);
1144 the_phy->max_negotiated_speed = SCI_SAS_NO_LINK_RATE;
1146 // Re-assign the phy back to the LP as if it were a narrow port for APC mode.
1147 // For MPC mode, the phy will remain in the port
1148 if (this_port->owning_controller->oem_parameters.sds1.controller.mode_type
1149 == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE)
1151 SCU_PCSPExCR_WRITE(this_port, the_phy->phy_index, the_phy->phy_index);
1154 if (do_notify_user == TRUE)
1155 scic_cb_port_link_down(this_port->owning_controller, this_port, the_phy);
1159 * This method will disable the phy and report that the phy is not valid for this
1162 * @param[in] this_port This is the port on which the phy should be disabled.
1163 * @param[in] the_phy This is the specific phy which to disabled.
1167 void scic_sds_port_invalid_link_up(
1168 SCIC_SDS_PORT_T * this_port,
1169 SCIC_SDS_PHY_T * the_phy
1172 SCIC_SDS_CONTROLLER_T * controller = scic_sds_port_get_controller(this_port);
1174 // Check to see if we have alreay reported this link as bad and if not go
1175 // ahead and tell the SCI_USER that we have discovered an invalid link.
1176 if ((controller->invalid_phy_mask & (1 << the_phy->phy_index)) == 0)
1178 scic_sds_controller_set_invalid_phy(controller, the_phy);
1180 scic_cb_port_invalid_link_up(controller, this_port, the_phy);
1185 * @brief This method returns FALSE if the port only has a single phy object
1186 * assigned. If there are no phys or more than one phy then the
1187 * method will return TRUE.
1189 * @param[in] this_port The port for which the wide port condition is to be
1193 * @retval TRUE Is returned if this is a wide ported port.
1194 * @retval FALSE Is returned if this is a narrow port.
1197 BOOL scic_sds_port_is_wide(
1198 SCIC_SDS_PORT_T *this_port
1204 for (index = 0; index < SCI_MAX_PHYS; index++)
1206 if (this_port->phy_table[index] != NULL)
1212 return (phy_count != 1);
1216 * @brief This method is called by the PHY object when the link is detected.
1217 * if the port wants the PHY to continue on to the link up state then
1218 * the port layer must return TRUE. If the port object returns FALSE
1219 * the phy object must halt its attempt to go link up.
1221 * @param[in] this_port The port associated with the phy object.
1222 * @param[in] the_phy The phy object that is trying to go link up.
1224 * @return TRUE if the phy object can continue to the link up condition.
1225 * @retval TRUE Is returned if this phy can continue to the ready state.
1226 * @retval FALSE Is returned if can not continue on to the ready state.
1228 * @note This notification is in place for wide ports and direct attached
1229 * phys. Since there are no wide ported SATA devices this could
1230 * become an invalid port configuration.
1232 BOOL scic_sds_port_link_detected(
1233 SCIC_SDS_PORT_T *this_port,
1234 SCIC_SDS_PHY_T *the_phy
1237 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
1239 scic_sds_phy_get_attached_phy_protocols(the_phy, &protocols);
1242 (this_port->logical_port_index != SCIC_SDS_DUMMY_PORT)
1243 && (protocols.u.bits.stp_target)
1246 if (scic_sds_port_is_wide(this_port))
1248 //direct attached Sata phy cannot be in wide port.
1249 scic_sds_port_invalid_link_up( this_port, the_phy);
1254 SCIC_SDS_PORT_T *destination_port = &(this_port->owning_controller->port_table[the_phy->phy_index]);
1256 //add the phy to the its logical port for direct attached SATA. The phy will be added
1257 //to port whose port_index will be the phy_index.
1258 SCU_PCSPExCR_WRITE( destination_port, the_phy->phy_index, the_phy->phy_index);
1266 * @brief This method is the entry point for the phy to inform
1267 * the port that it is now in a ready state
1269 * @param[in] this_port
1272 void scic_sds_port_link_up(
1273 SCIC_SDS_PORT_T *this_port,
1274 SCIC_SDS_PHY_T *the_phy
1277 the_phy->is_in_link_training = FALSE;
1279 this_port->state_handlers->link_up_handler(this_port, the_phy);
1283 * @brief This method is the entry point for the phy to inform
1284 * the port that it is no longer in a ready state
1286 * @param[in] this_port
1289 void scic_sds_port_link_down(
1290 SCIC_SDS_PORT_T *this_port,
1291 SCIC_SDS_PHY_T *the_phy
1294 this_port->state_handlers->link_down_handler(this_port, the_phy);
1298 * @brief This method is called to start an IO request on this port.
1300 * @param[in] this_port
1301 * @param[in] the_device
1302 * @param[in] the_io_request
1304 * @return SCI_STATUS
1306 SCI_STATUS scic_sds_port_start_io(
1307 SCIC_SDS_PORT_T *this_port,
1308 SCIC_SDS_REMOTE_DEVICE_T *the_device,
1309 SCIC_SDS_REQUEST_T *the_io_request
1312 return this_port->state_handlers->start_io_handler(
1313 this_port, the_device, the_io_request);
1317 * @brief This method is called to complete an IO request to the port.
1319 * @param[in] this_port
1320 * @param[in] the_device
1321 * @param[in] the_io_request
1323 * @return SCI_STATUS
1325 SCI_STATUS scic_sds_port_complete_io(
1326 SCIC_SDS_PORT_T *this_port,
1327 SCIC_SDS_REMOTE_DEVICE_T *the_device,
1328 SCIC_SDS_REQUEST_T *the_io_request
1331 return this_port->state_handlers->complete_io_handler(
1332 this_port, the_device, the_io_request);
1336 * @brief This method is provided to timeout requests for port operations.
1337 * Mostly its for the port reset operation.
1339 * @param[in] port This is the parameter or cookie value that is provided
1340 * to the timer construct operation.
1342 void scic_sds_port_timeout_handler(
1347 SCIC_SDS_PORT_T * this_port;
1349 this_port = (SCIC_SDS_PORT_T *)port;
1350 current_state = sci_base_state_machine_get_state(
1351 &this_port->parent.state_machine);
1353 if (current_state == SCI_BASE_PORT_STATE_RESETTING)
1355 // if the port is still in the resetting state then the timeout fired
1356 // before the reset completed.
1357 sci_base_state_machine_change_state(
1358 &this_port->parent.state_machine,
1359 SCI_BASE_PORT_STATE_FAILED
1362 else if (current_state == SCI_BASE_PORT_STATE_STOPPED)
1364 // if the port is stopped then the start request failed
1365 // In this case stay in the stopped state.
1367 sci_base_object_get_logger(this_port),
1368 SCIC_LOG_OBJECT_PORT,
1369 "SCIC Port 0x%x failed to stop before tiemout.\n",
1373 else if (current_state == SCI_BASE_PORT_STATE_STOPPING)
1375 // if the port is still stopping then the stop has not completed
1376 scic_cb_port_stop_complete(
1377 scic_sds_port_get_controller(this_port),
1384 // The port is in the ready state and we have a timer reporting a timeout
1385 // this should not happen.
1387 sci_base_object_get_logger(this_port),
1388 SCIC_LOG_OBJECT_PORT,
1389 "SCIC Port 0x%x is processing a timeout operation in state %d.\n",
1390 this_port, current_state
1395 // ---------------------------------------------------------------------------
1397 #ifdef SCIC_DEBUG_ENABLED
1398 void scic_sds_port_decrement_request_count(
1399 SCIC_SDS_PORT_T *this_port
1402 if (this_port->started_request_count == 0)
1405 sci_base_object_get_logger(this_port),
1406 SCIC_LOG_OBJECT_PORT,
1407 "SCIC Port object requested to decrement started io count past zero.\n"
1412 this_port->started_request_count--;
1418 * @brief This function updates the hardwares VIIT entry for this port.
1420 * @param[in] this_port
1422 void scic_sds_port_update_viit_entry(
1423 SCIC_SDS_PORT_T *this_port
1426 SCI_SAS_ADDRESS_T sas_address;
1428 scic_sds_port_get_sas_address(this_port, &sas_address);
1430 scu_port_viit_register_write(
1431 this_port, initiator_sas_address_hi, sas_address.high);
1433 scu_port_viit_register_write(
1434 this_port, initiator_sas_address_lo, sas_address.low);
1436 // This value get cleared just in case its not already cleared
1437 scu_port_viit_register_write(
1438 this_port, reserved, 0);
1441 // We are required to update the status register last
1442 scu_port_viit_register_write(
1443 this_port, status, (
1444 SCU_VIIT_ENTRY_ID_VIIT
1445 | SCU_VIIT_IPPT_INITIATOR
1446 | ((1UL << this_port->physical_port_index) << SCU_VIIT_ENTRY_LPVIE_SHIFT)
1447 | SCU_VIIT_STATUS_ALL_VALID
1453 * @brief This method returns the maximum allowed speed for data transfers
1454 * on this port. This maximum allowed speed evaluates to the maximum
1455 * speed of the slowest phy in the port.
1457 * @param[in] this_port This parameter specifies the port for which to
1458 * retrieve the maximum allowed speed.
1460 * @return This method returns the maximum negotiated speed of the slowest
1463 SCI_SAS_LINK_RATE scic_sds_port_get_max_allowed_speed(
1464 SCIC_SDS_PORT_T * this_port
1468 SCI_SAS_LINK_RATE max_allowed_speed = SCI_SAS_600_GB;
1469 SCIC_SDS_PHY_T * phy = NULL;
1471 // Loop through all of the phys in this port and find the phy with the
1472 // lowest maximum link rate.
1473 for (index = 0; index < SCI_MAX_PHYS; index++)
1475 phy = this_port->phy_table[index];
1478 && (scic_sds_port_active_phy(this_port, phy) == TRUE)
1479 && (phy->max_negotiated_speed < max_allowed_speed)
1481 max_allowed_speed = phy->max_negotiated_speed;
1484 return max_allowed_speed;
1489 * @brief This method passes the event to core user.
1490 * @param[in] this_port The port that a BCN happens.
1491 * @param[in] this_phy The phy that receives BCN.
1495 void scic_sds_port_broadcast_change_received(
1496 SCIC_SDS_PORT_T * this_port,
1497 SCIC_SDS_PHY_T * this_phy
1501 scic_cb_port_bc_change_primitive_recieved(
1502 this_port->owning_controller, this_port, this_phy
1508 * @brief This API methhod enables the broadcast change notification from
1509 * underneath hardware.
1510 * @param[in] this_port The port that a BCN had been disabled from.
1514 void scic_port_enable_broadcast_change_notification(
1515 SCI_PORT_HANDLE_T port
1518 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
1519 SCIC_SDS_PHY_T * phy;
1523 // Loop through all of the phys to enable BCN.
1524 for (index = 0; index < SCI_MAX_PHYS; index++)
1526 phy = this_port->phy_table[index];
1529 register_value = SCU_SAS_LLCTL_READ(phy);
1531 // clear the bit by writing 1.
1532 SCU_SAS_LLCTL_WRITE(phy, register_value);
1538 * @brief This method release resources in for a scic port.
1540 * @param[in] controller This parameter specifies the core controller, one of
1541 * its phy's resources are to be released.
1542 * @param[in] this_port This parameter specifies the port whose resource is to
1545 void scic_sds_port_release_resource(
1546 SCIC_SDS_CONTROLLER_T * controller,
1547 SCIC_SDS_PORT_T *this_port
1551 sci_base_object_get_logger(this_port),
1552 SCIC_LOG_OBJECT_PORT,
1553 "scic_sds_port_release_resource(0x%x, 0x%x)\n",
1554 controller, this_port
1557 //Currently, the only resource to be released is a timer.
1558 if (this_port->timer_handle != NULL)
1560 scic_cb_timer_destroy(controller, this_port->timer_handle);
1561 this_port->timer_handle = NULL;
1566 //******************************************************************************
1567 //* PORT STATE MACHINE
1568 //******************************************************************************
1570 //***************************************************************************
1571 //* DEFAULT HANDLERS
1572 //***************************************************************************
1575 * This is the default method for port a start request. It will report a
1578 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1579 * SCIC_SDS_PORT object.
1581 * @return SCI_STATUS
1582 * @retval SCI_FAILURE_INVALID_STATE
1584 SCI_STATUS scic_sds_port_default_start_handler(
1585 SCI_BASE_PORT_T *port
1589 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1590 SCIC_LOG_OBJECT_PORT,
1591 "SCIC Port 0x%08x requested to start while in invalid state %d\n",
1593 sci_base_state_machine_get_state(
1594 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1597 return SCI_FAILURE_INVALID_STATE;
1601 * This is the default method for a port stop request. It will report a
1604 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1605 * SCIC_SDS_PORT object.
1607 * @return SCI_STATUS
1608 * @retval SCI_FAILURE_INVALID_STATE
1610 SCI_STATUS scic_sds_port_default_stop_handler(
1611 SCI_BASE_PORT_T *port
1615 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1616 SCIC_LOG_OBJECT_PORT,
1617 "SCIC Port 0x%08x requested to stop while in invalid state %d\n",
1619 sci_base_state_machine_get_state(
1620 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1623 return SCI_FAILURE_INVALID_STATE;
1627 * This is the default method for a port destruct request. It will report a
1630 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1631 * SCIC_SDS_PORT object.
1633 * @return SCI_STATUS
1634 * @retval SCI_FAILURE_INVALID_STATE
1636 SCI_STATUS scic_sds_port_default_destruct_handler(
1637 SCI_BASE_PORT_T *port
1641 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1642 SCIC_LOG_OBJECT_PORT,
1643 "SCIC Port 0x%08x requested to destruct while in invalid state %d\n",
1645 sci_base_state_machine_get_state(
1646 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1649 return SCI_FAILURE_INVALID_STATE;
1653 * This is the default method for a port reset request. It will report a
1656 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1657 * SCIC_SDS_PORT object.
1658 * @param[in] timeout This is the timeout for the reset request to complete.
1660 * @return SCI_STATUS
1661 * @retval SCI_FAILURE_INVALID_STATE
1663 SCI_STATUS scic_sds_port_default_reset_handler(
1664 SCI_BASE_PORT_T * port,
1669 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1670 SCIC_LOG_OBJECT_PORT,
1671 "SCIC Port 0x%08x requested to reset while in invalid state %d\n",
1673 sci_base_state_machine_get_state(
1674 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1677 return SCI_FAILURE_INVALID_STATE;
1681 * This is the default method for a port add phy request. It will report a
1684 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1685 * SCIC_SDS_PORT object.
1687 * @return SCI_STATUS
1688 * @retval SCI_FAILURE_INVALID_STATE
1690 SCI_STATUS scic_sds_port_default_add_phy_handler(
1691 SCI_BASE_PORT_T *port,
1696 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1697 SCIC_LOG_OBJECT_PORT,
1698 "SCIC Port 0x%08x requested to add phy 0x%08x while in invalid state %d\n",
1700 sci_base_state_machine_get_state(
1701 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1704 return SCI_FAILURE_INVALID_STATE;
1708 * This is the default method for a port remove phy request. It will report a
1711 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1712 * SCIC_SDS_PORT object.
1714 * @return SCI_STATUS
1715 * @retval SCI_FAILURE_INVALID_STATE
1717 SCI_STATUS scic_sds_port_default_remove_phy_handler(
1718 SCI_BASE_PORT_T *port,
1723 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1724 SCIC_LOG_OBJECT_PORT,
1725 "SCIC Port 0x%08x requested to remove phy 0x%08x while in invalid state %d\n",
1727 sci_base_state_machine_get_state(
1728 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1731 return SCI_FAILURE_INVALID_STATE;
1735 * This is the default method for a port unsolicited frame request. It will
1736 * report a warning and exit.
1738 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1739 * SCIC_SDS_PORT object.
1741 * @return SCI_STATUS
1742 * @retval SCI_FAILURE_INVALID_STATE
1744 * @todo Is it even possible to receive an unsolicited frame directed to a
1745 * port object? It seems possible if we implementing virtual functions
1748 SCI_STATUS scic_sds_port_default_frame_handler(
1749 SCIC_SDS_PORT_T * port,
1753 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
1756 sci_base_object_get_logger(this_port),
1757 SCIC_LOG_OBJECT_PORT,
1758 "SCIC Port 0x%08x requested to process frame %d while in invalid state %d\n",
1760 sci_base_state_machine_get_state(
1761 scic_sds_port_get_base_state_machine(this_port))
1764 scic_sds_controller_release_frame(
1765 scic_sds_port_get_controller(this_port), frame_index
1768 return SCI_FAILURE_INVALID_STATE;
1772 * This is the default method for a port event request. It will report a
1775 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1776 * SCIC_SDS_PORT object.
1778 * @return SCI_STATUS
1779 * @retval SCI_FAILURE_INVALID_STATE
1781 SCI_STATUS scic_sds_port_default_event_handler(
1782 SCIC_SDS_PORT_T * port,
1787 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1788 SCIC_LOG_OBJECT_PORT,
1789 "SCIC Port 0x%08x requested to process event 0x%08x while in invalid state %d\n",
1791 sci_base_state_machine_get_state(
1792 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1795 return SCI_FAILURE_INVALID_STATE;
1799 * This is the default method for a port link up notification. It will report
1800 * a warning and exit.
1802 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1803 * SCIC_SDS_PORT object.
1805 * @return SCI_STATUS
1806 * @retval SCI_FAILURE_INVALID_STATE
1808 void scic_sds_port_default_link_up_handler(
1809 SCIC_SDS_PORT_T *this_port,
1814 sci_base_object_get_logger(this_port),
1815 SCIC_LOG_OBJECT_PORT,
1816 "SCIC Port 0x%08x received link_up notification from phy 0x%08x while in invalid state %d\n",
1818 sci_base_state_machine_get_state(
1819 scic_sds_port_get_base_state_machine(this_port))
1824 * This is the default method for a port link down notification. It will
1825 * report a warning and exit.
1827 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1828 * SCIC_SDS_PORT object.
1830 * @return SCI_STATUS
1831 * @retval SCI_FAILURE_INVALID_STATE
1833 void scic_sds_port_default_link_down_handler(
1834 SCIC_SDS_PORT_T *this_port,
1839 sci_base_object_get_logger(this_port),
1840 SCIC_LOG_OBJECT_PORT,
1841 "SCIC Port 0x%08x received link down notification from phy 0x%08x while in invalid state %d\n",
1843 sci_base_state_machine_get_state(
1844 scic_sds_port_get_base_state_machine(this_port))
1849 * This is the default method for a port start io request. It will report a
1852 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1853 * SCIC_SDS_PORT object.
1855 * @return SCI_STATUS
1856 * @retval SCI_FAILURE_INVALID_STATE
1858 SCI_STATUS scic_sds_port_default_start_io_handler(
1859 SCIC_SDS_PORT_T *this_port,
1860 SCIC_SDS_REMOTE_DEVICE_T *device,
1861 SCIC_SDS_REQUEST_T *io_request
1865 sci_base_object_get_logger(this_port),
1866 SCIC_LOG_OBJECT_PORT,
1867 "SCIC Port 0x%08x requested to start io request 0x%08x while in invalid state %d\n",
1868 this_port, io_request,
1869 sci_base_state_machine_get_state(
1870 scic_sds_port_get_base_state_machine(this_port))
1873 return SCI_FAILURE_INVALID_STATE;
1877 * This is the default method for a port complete io request. It will report
1878 * a warning and exit.
1880 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1881 * SCIC_SDS_PORT object.
1883 * @return SCI_STATUS
1884 * @retval SCI_FAILURE_INVALID_STATE
1886 SCI_STATUS scic_sds_port_default_complete_io_handler(
1887 SCIC_SDS_PORT_T *this_port,
1888 SCIC_SDS_REMOTE_DEVICE_T *device,
1889 SCIC_SDS_REQUEST_T *io_request
1893 sci_base_object_get_logger(this_port),
1894 SCIC_LOG_OBJECT_PORT,
1895 "SCIC Port 0x%08x requested to complete io request 0x%08x while in invalid state %d\n",
1896 this_port, io_request,
1897 sci_base_state_machine_get_state(
1898 scic_sds_port_get_base_state_machine(this_port))
1901 return SCI_FAILURE_INVALID_STATE;
1904 //****************************************************************************
1905 //* GENERAL STATE HANDLERS
1906 //****************************************************************************
1909 * This is a general complete io request handler for the SCIC_SDS_PORT object.
1911 * @param[in] port This is the SCIC_SDS_PORT object on which the io request
1912 * count will be decremented.
1913 * @param[in] device This is the SCIC_SDS_REMOTE_DEVICE object to which the io
1914 * request is being directed. This parameter is not required to
1915 * complete this operation.
1916 * @param[in] io_request This is the request that is being completed on this
1917 * port object. This parameter is not required to complete this
1920 * @return SCI_STATUS
1921 * @retval SCI_SUCCESS
1924 SCI_STATUS scic_sds_port_general_complete_io_handler(
1925 SCIC_SDS_PORT_T *port,
1926 SCIC_SDS_REMOTE_DEVICE_T *device,
1927 SCIC_SDS_REQUEST_T *io_request
1930 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
1932 scic_sds_port_decrement_request_count(this_port);
1937 //****************************************************************************
1938 //* STOPPED STATE HANDLERS
1939 //****************************************************************************
1941 BOOL scic_sds_port_requires_scheduler_workaround(
1942 SCIC_SDS_PORT_T * this_port
1947 this_port->owning_controller->logical_port_entries
1948 < this_port->owning_controller->task_context_entries
1951 this_port->owning_controller->logical_port_entries
1952 < this_port->owning_controller->remote_node_entries
1964 * This method takes the SCIC_SDS_PORT from a stopped state and attempts to
1965 * start it. To start a port it must have no assiged devices and it must have
1966 * at least one phy assigned to it. If those conditions are met then the port
1967 * can transition to the ready state.
1969 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1970 * SCIC_SDS_PORT object.
1972 * @return SCI_STATUS
1973 * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This SCIC_SDS_PORT
1974 * object could not be started because the port configuration is not
1976 * @retval SCI_SUCCESS the start request is successful and the SCIC_SDS_PORT
1977 * object has transitioned to the SCI_BASE_PORT_STATE_READY.
1980 SCI_STATUS scic_sds_port_stopped_state_start_handler(
1981 SCI_BASE_PORT_T *port
1985 SCI_STATUS status = SCI_SUCCESS;
1986 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
1988 if (this_port->assigned_device_count > 0)
1990 /// @todo This is a start failure operation because there are still
1991 /// devices assigned to this port. There must be no devices
1992 /// assigned to a port on a start operation.
1993 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
1996 this_port->timer_handle = scic_cb_timer_create(
1997 scic_sds_port_get_controller(this_port),
1998 scic_sds_port_timeout_handler,
2002 if (this_port->timer_handle == SCI_INVALID_HANDLE)
2004 return SCI_FAILURE_INSUFFICIENT_RESOURCES;
2007 if (scic_sds_port_requires_scheduler_workaround(this_port))
2009 if (this_port->reserved_rni == SCU_DUMMY_INDEX)
2011 this_port->reserved_rni =
2012 scic_sds_remote_node_table_allocate_remote_node(
2013 &this_port->owning_controller->available_remote_nodes, 1
2016 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
2018 scic_sds_port_construct_dummy_rnc(
2020 this_port->reserved_rni
2025 status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
2029 if (this_port->reserved_tci == SCU_DUMMY_INDEX)
2031 // Allocate a TCI and remove the sequence nibble
2032 this_port->reserved_tci =
2033 scic_controller_allocate_io_tag(this_port->owning_controller);
2035 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
2037 scic_sds_port_construct_dummy_task(this_port, this_port->reserved_tci);
2041 status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
2046 if (status == SCI_SUCCESS)
2048 phy_mask = scic_sds_port_get_phys(this_port);
2050 // There are one or more phys assigned to this port. Make sure
2051 // the port's phy mask is in fact legal and supported by the
2053 if (scic_sds_port_is_phy_mask_valid(this_port, phy_mask) == TRUE)
2055 sci_base_state_machine_change_state(
2056 scic_sds_port_get_base_state_machine(this_port),
2057 SCI_BASE_PORT_STATE_READY
2062 status = SCI_FAILURE;
2066 if (status != SCI_SUCCESS)
2068 scic_sds_port_destroy_dummy_resources(this_port);
2075 * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
2076 * a stop request. This function takes no action.
2078 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2079 * SCIC_SDS_PORT object.
2081 * @return SCI_STATUS
2082 * @retval SCI_SUCCESS the stop request is successful as the SCIC_SDS_PORT
2083 * object is already stopped.
2086 SCI_STATUS scic_sds_port_stopped_state_stop_handler(
2087 SCI_BASE_PORT_T *port
2090 // We are already stopped so there is nothing to do here
2095 * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
2096 * the destruct request. The stopped state is the only state in which the
2097 * SCIC_SDS_PORT can be destroyed. This function causes the port object to
2098 * transition to the SCI_BASE_PORT_STATE_FINAL.
2100 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2101 * SCIC_SDS_PORT object.
2103 * @return SCI_STATUS
2104 * @retval SCI_SUCCESS
2107 SCI_STATUS scic_sds_port_stopped_state_destruct_handler(
2108 SCI_BASE_PORT_T *port
2111 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2113 sci_base_state_machine_stop(&this_port->parent.state_machine);
2119 * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
2120 * the add phy request. In MPC mode the only time a phy can be added to a
2121 * port is in the SCI_BASE_PORT_STATE_STOPPED.
2123 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2124 * SCIC_SDS_PORT object.
2125 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
2126 * SCIC_SDS_PHY object.
2128 * @return SCI_STATUS
2129 * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy
2130 * can not be added to the port.
2131 * @retval SCI_SUCCESS if the phy is added to the port.
2134 SCI_STATUS scic_sds_port_stopped_state_add_phy_handler(
2135 SCI_BASE_PORT_T *port,
2139 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
2140 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
2141 SCI_SAS_ADDRESS_T port_sas_address;
2143 // Read the port assigned SAS Address if there is one
2144 scic_sds_port_get_sas_address(this_port, &port_sas_address);
2146 if (port_sas_address.high != 0 && port_sas_address.low != 0)
2148 SCI_SAS_ADDRESS_T phy_sas_address;
2150 // Make sure that the PHY SAS Address matches the SAS Address
2152 scic_sds_phy_get_sas_address(this_phy, &phy_sas_address);
2155 (port_sas_address.high != phy_sas_address.high)
2156 || (port_sas_address.low != phy_sas_address.low)
2159 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
2163 return scic_sds_port_set_phy(this_port, this_phy);
2168 * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
2169 * the remove phy request. In MPC mode the only time a phy can be removed
2170 * from a port is in the SCI_BASE_PORT_STATE_STOPPED.
2172 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2173 * SCIC_SDS_PORT object.
2174 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
2175 * SCIC_SDS_PHY object.
2177 * @return SCI_STATUS
2178 * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy
2179 * can not be added to the port.
2180 * @retval SCI_SUCCESS if the phy is added to the port.
2183 SCI_STATUS scic_sds_port_stopped_state_remove_phy_handler(
2184 SCI_BASE_PORT_T *port,
2188 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2189 SCIC_SDS_PHY_T *this_phy = (SCIC_SDS_PHY_T *)phy;
2191 return scic_sds_port_clear_phy(this_port, this_phy);
2194 //****************************************************************************
2195 //* READY STATE HANDLERS
2196 //****************************************************************************
2198 //****************************************************************************
2199 //* RESETTING STATE HANDLERS
2200 //****************************************************************************
2202 //****************************************************************************
2203 //* STOPPING STATE HANDLERS
2204 //****************************************************************************
2207 * This method takes the SCIC_SDS_PORT that is in a stopping state and handles
2208 * the complete io request. Should the request count reach 0 then the port
2209 * object will transition to the stopped state.
2211 * @param[in] port This is the SCIC_SDS_PORT object on which the io request
2212 * count will be decremented.
2213 * @param[in] device This is the SCIC_SDS_REMOTE_DEVICE object to which the io
2214 * request is being directed. This parameter is not required to
2215 * complete this operation.
2216 * @param[in] io_request This is the request that is being completed on this
2217 * port object. This parameter is not required to complete this
2220 * @return SCI_STATUS
2221 * @retval SCI_SUCCESS
2224 SCI_STATUS scic_sds_port_stopping_state_complete_io_handler(
2225 SCIC_SDS_PORT_T *port,
2226 SCIC_SDS_REMOTE_DEVICE_T *device,
2227 SCIC_SDS_REQUEST_T *io_request
2230 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2232 scic_sds_port_decrement_request_count(this_port);
2234 if (this_port->started_request_count == 0)
2236 sci_base_state_machine_change_state(
2237 scic_sds_port_get_base_state_machine(this_port),
2238 SCI_BASE_PORT_STATE_STOPPED
2245 //****************************************************************************
2246 //* RESETTING STATE HANDLERS
2247 //****************************************************************************
2250 * This method will stop a failed port. This causes a transition to the
2253 * @param[in] port This is the port object which is being requested to stop.
2255 * @return SCI_STATUS
2256 * @retval SCI_SUCCESS
2259 SCI_STATUS scic_sds_port_reset_state_stop_handler(
2260 SCI_BASE_PORT_T *port
2263 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2265 sci_base_state_machine_change_state(
2266 &this_port->parent.state_machine,
2267 SCI_BASE_PORT_STATE_STOPPING
2274 * This method will transition a failed port to its ready state. The port
2275 * failed because a hard reset request timed out but at some time later one or
2276 * more phys in the port became ready.
2278 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2279 * SCIC_SDS_PORT object.
2281 * @return SCI_STATUS
2282 * @retval SCI_SUCCESS
2285 void scic_sds_port_reset_state_link_up_handler(
2286 SCIC_SDS_PORT_T *this_port,
2290 /// @todo We should make sure that the phy that has gone link up is the same
2291 /// one on which we sent the reset. It is possible that the phy on
2292 /// which we sent the reset is not the one that has gone link up and we
2293 /// want to make sure that phy being reset comes back. Consider the
2294 /// case where a reset is sent but before the hardware processes the
2295 /// reset it get a link up on the port because of a hot plug event.
2296 /// because of the reset request this phy will go link down almost
2299 // In the resetting state we don't notify the user regarding
2300 // link up and link down notifications.
2301 scic_sds_port_general_link_up_handler(this_port, phy, FALSE, TRUE);
2305 * This method process link down notifications that occur during a
2306 * port reset operation. Link downs can occur during the reset operation.
2308 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2309 * SCIC_SDS_PORT object.
2311 * @return SCI_STATUS
2312 * @retval SCI_SUCCESS
2315 void scic_sds_port_reset_state_link_down_handler(
2316 SCIC_SDS_PORT_T *this_port,
2320 // In the resetting state we don't notify the user regarding
2321 // link up and link down notifications.
2322 scic_sds_port_deactivate_phy(this_port, phy, FALSE);
2325 // ---------------------------------------------------------------------------
2327 SCIC_SDS_PORT_STATE_HANDLER_T
2328 scic_sds_port_state_handler_table[SCI_BASE_PORT_MAX_STATES] =
2330 // SCI_BASE_PORT_STATE_STOPPED
2333 scic_sds_port_stopped_state_start_handler,
2334 scic_sds_port_stopped_state_stop_handler,
2335 scic_sds_port_stopped_state_destruct_handler,
2336 scic_sds_port_default_reset_handler,
2337 scic_sds_port_stopped_state_add_phy_handler,
2338 scic_sds_port_stopped_state_remove_phy_handler
2340 scic_sds_port_default_frame_handler,
2341 scic_sds_port_default_event_handler,
2342 scic_sds_port_default_link_up_handler,
2343 scic_sds_port_default_link_down_handler,
2344 scic_sds_port_default_start_io_handler,
2345 scic_sds_port_default_complete_io_handler
2347 // SCI_BASE_PORT_STATE_STOPPING
2350 scic_sds_port_default_start_handler,
2351 scic_sds_port_default_stop_handler,
2352 scic_sds_port_default_destruct_handler,
2353 scic_sds_port_default_reset_handler,
2354 scic_sds_port_default_add_phy_handler,
2355 scic_sds_port_default_remove_phy_handler
2357 scic_sds_port_default_frame_handler,
2358 scic_sds_port_default_event_handler,
2359 scic_sds_port_default_link_up_handler,
2360 scic_sds_port_default_link_down_handler,
2361 scic_sds_port_default_start_io_handler,
2362 scic_sds_port_stopping_state_complete_io_handler
2364 // SCI_BASE_PORT_STATE_READY
2367 scic_sds_port_default_start_handler,
2368 scic_sds_port_default_stop_handler,
2369 scic_sds_port_default_destruct_handler,
2370 scic_sds_port_default_reset_handler,
2371 scic_sds_port_default_add_phy_handler,
2372 scic_sds_port_default_remove_phy_handler
2374 scic_sds_port_default_frame_handler,
2375 scic_sds_port_default_event_handler,
2376 scic_sds_port_default_link_up_handler,
2377 scic_sds_port_default_link_down_handler,
2378 scic_sds_port_default_start_io_handler,
2379 scic_sds_port_general_complete_io_handler
2381 // SCI_BASE_PORT_STATE_RESETTING
2384 scic_sds_port_default_start_handler,
2385 scic_sds_port_reset_state_stop_handler,
2386 scic_sds_port_default_destruct_handler,
2387 scic_sds_port_default_reset_handler,
2388 scic_sds_port_default_add_phy_handler,
2389 scic_sds_port_default_remove_phy_handler
2391 scic_sds_port_default_frame_handler,
2392 scic_sds_port_default_event_handler,
2393 scic_sds_port_reset_state_link_up_handler,
2394 scic_sds_port_reset_state_link_down_handler,
2395 scic_sds_port_default_start_io_handler,
2396 scic_sds_port_general_complete_io_handler
2398 // SCI_BASE_PORT_STATE_FAILED
2401 scic_sds_port_default_start_handler,
2402 scic_sds_port_default_stop_handler,
2403 scic_sds_port_default_destruct_handler,
2404 scic_sds_port_default_reset_handler,
2405 scic_sds_port_default_add_phy_handler,
2406 scic_sds_port_default_remove_phy_handler
2408 scic_sds_port_default_frame_handler,
2409 scic_sds_port_default_event_handler,
2410 scic_sds_port_default_link_up_handler,
2411 scic_sds_port_default_link_down_handler,
2412 scic_sds_port_default_start_io_handler,
2413 scic_sds_port_general_complete_io_handler
2417 //******************************************************************************
2418 //* PORT STATE PRIVATE METHODS
2419 //******************************************************************************
2422 * This method will enable the SCU Port Task Scheduler for this port object
2423 * but will leave the port task scheduler in a suspended state.
2425 * @param[in] this_port This is the port object which to suspend.
2430 void scic_sds_port_enable_port_task_scheduler(
2431 SCIC_SDS_PORT_T *this_port
2434 U32 pts_control_value;
2436 pts_control_value = scu_port_task_scheduler_read(this_port, control);
2438 pts_control_value |= SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND);
2440 scu_port_task_scheduler_write(this_port, control, pts_control_value);
2444 * This method will disable the SCU port task scheduler for this port
2447 * @param[in] this_port This is the port object which to resume.
2452 void scic_sds_port_disable_port_task_scheduler(
2453 SCIC_SDS_PORT_T *this_port
2456 U32 pts_control_value;
2458 pts_control_value = scu_port_task_scheduler_read(this_port, control);
2460 pts_control_value &= ~( SCU_PTSxCR_GEN_BIT(ENABLE)
2461 | SCU_PTSxCR_GEN_BIT(SUSPEND) );
2463 scu_port_task_scheduler_write(this_port, control, pts_control_value);
2470 void scic_sds_port_post_dummy_remote_node(
2471 SCIC_SDS_PORT_T *this_port
2475 SCU_REMOTE_NODE_CONTEXT_T * rnc;
2477 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
2479 rnc = &(this_port->owning_controller->remote_node_context_table[this_port->reserved_rni]);
2481 rnc->ssp.is_valid = TRUE;
2484 (SCU_CONTEXT_COMMAND_POST_RNC_32)
2485 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
2486 | (this_port->reserved_rni)
2489 scic_sds_controller_post_request(this_port->owning_controller, command);
2491 scic_cb_stall_execution(10);
2494 (SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX)
2495 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
2496 | (this_port->reserved_rni)
2499 scic_sds_controller_post_request(this_port->owning_controller, command);
2507 void scic_sds_port_invalidate_dummy_remote_node(
2508 SCIC_SDS_PORT_T *this_port
2512 SCU_REMOTE_NODE_CONTEXT_T * rnc;
2514 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
2516 rnc = &(this_port->owning_controller->remote_node_context_table[this_port->reserved_rni]);
2518 rnc->ssp.is_valid = FALSE;
2520 scic_cb_stall_execution(10);
2523 (SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE)
2524 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
2525 | (this_port->reserved_rni)
2528 scic_sds_controller_post_request(this_port->owning_controller, command);
2532 //******************************************************************************
2533 //* PORT STATE METHODS
2534 //******************************************************************************
2537 * This method will perform the actions required by the SCIC_SDS_PORT on
2538 * entering the SCI_BASE_PORT_STATE_STOPPED. This function sets the stopped
2539 * state handlers for the SCIC_SDS_PORT object and disables the port task
2540 * scheduler in the hardware.
2542 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2543 * SCIC_SDS_PORT object.
2548 void scic_sds_port_stopped_state_enter(
2549 SCI_BASE_OBJECT_T *object
2552 SCIC_SDS_PORT_T *this_port;
2553 this_port = (SCIC_SDS_PORT_T *)object;
2555 scic_sds_port_set_base_state_handlers(
2556 this_port, SCI_BASE_PORT_STATE_STOPPED
2560 SCI_BASE_PORT_STATE_STOPPING
2561 == this_port->parent.state_machine.previous_state_id
2564 // If we enter this state becasuse of a request to stop
2565 // the port then we want to disable the hardwares port
2567 scic_sds_port_disable_port_task_scheduler(this_port);
2572 * This method will perform the actions required by the SCIC_SDS_PORT on
2573 * exiting the SCI_BASE_STATE_STOPPED. This function enables the SCU hardware
2574 * port task scheduler.
2576 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2577 * SCIC_SDS_PORT object.
2582 void scic_sds_port_stopped_state_exit(
2583 SCI_BASE_OBJECT_T *object
2586 SCIC_SDS_PORT_T *this_port;
2587 this_port = (SCIC_SDS_PORT_T *)object;
2589 // Enable and suspend the port task scheduler
2590 scic_sds_port_enable_port_task_scheduler(this_port);
2594 * This method will perform the actions required by the SCIC_SDS_PORT on
2595 * entering the SCI_BASE_PORT_STATE_READY. This function sets the ready state
2596 * handlers for the SCIC_SDS_PORT object, reports the port object as not ready
2597 * and starts the ready substate machine.
2599 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2600 * SCIC_SDS_PORT object.
2605 void scic_sds_port_ready_state_enter(
2606 SCI_BASE_OBJECT_T *object
2609 SCIC_SDS_PORT_T *this_port;
2610 this_port = (SCIC_SDS_PORT_T *)object;
2612 // Put the ready state handlers in place though they will not be there long
2613 scic_sds_port_set_base_state_handlers(
2614 this_port, SCI_BASE_PORT_STATE_READY
2618 SCI_BASE_PORT_STATE_RESETTING
2619 == this_port->parent.state_machine.previous_state_id
2622 scic_cb_port_hard_reset_complete(
2623 scic_sds_port_get_controller(this_port),
2630 // Notify the caller that the port is not yet ready
2631 scic_cb_port_not_ready(
2632 scic_sds_port_get_controller(this_port),
2634 SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS
2638 // Post and suspend the dummy remote node context for this
2640 scic_sds_port_post_dummy_remote_node(this_port);
2642 // Start the ready substate machine
2643 sci_base_state_machine_start(
2644 scic_sds_port_get_ready_substate_machine(this_port)
2649 * This method will perform the actions required by the SCIC_SDS_PORT on
2650 * exiting the SCI_BASE_STATE_READY. This function does nothing.
2652 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2653 * SCIC_SDS_PORT object.
2658 void scic_sds_port_ready_state_exit(
2659 SCI_BASE_OBJECT_T *object
2662 SCIC_SDS_PORT_T *this_port;
2663 this_port = (SCIC_SDS_PORT_T *)object;
2665 sci_base_state_machine_stop(&this_port->ready_substate_machine);
2667 scic_cb_stall_execution(10);
2668 scic_sds_port_invalidate_dummy_remote_node(this_port);
2672 * This method will perform the actions required by the SCIC_SDS_PORT on
2673 * entering the SCI_BASE_PORT_STATE_RESETTING. This function sets the
2674 * resetting state handlers for the SCIC_SDS_PORT object.
2676 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2677 * SCIC_SDS_PORT object.
2682 void scic_sds_port_resetting_state_enter(
2683 SCI_BASE_OBJECT_T *object
2686 SCIC_SDS_PORT_T *this_port;
2687 this_port = (SCIC_SDS_PORT_T *)object;
2689 scic_sds_port_set_base_state_handlers(
2690 this_port, SCI_BASE_PORT_STATE_RESETTING
2695 * This method will perform the actions required by the SCIC_SDS_PORT on
2696 * exiting the SCI_BASE_STATE_RESETTING. This function does nothing.
2698 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2699 * SCIC_SDS_PORT object.
2704 void scic_sds_port_resetting_state_exit(
2705 SCI_BASE_OBJECT_T *object
2708 SCIC_SDS_PORT_T *this_port;
2709 this_port = (SCIC_SDS_PORT_T *)object;
2712 scic_sds_port_get_controller(this_port),
2713 this_port->timer_handle
2718 * This method will perform the actions required by the SCIC_SDS_PORT on
2719 * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping
2720 * state handlers for the SCIC_SDS_PORT object.
2722 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2723 * SCIC_SDS_PORT object.
2728 void scic_sds_port_stopping_state_enter(
2729 SCI_BASE_OBJECT_T *object
2732 SCIC_SDS_PORT_T *this_port;
2733 this_port = (SCIC_SDS_PORT_T *)object;
2735 scic_sds_port_set_base_state_handlers(
2736 this_port, SCI_BASE_PORT_STATE_STOPPING
2739 if (this_port->started_request_count == 0)
2741 sci_base_state_machine_change_state(
2742 &this_port->parent.state_machine,
2743 SCI_BASE_PORT_STATE_STOPPED
2749 * This method will perform the actions required by the SCIC_SDS_PORT on
2750 * exiting the SCI_BASE_STATE_STOPPING. This function does nothing.
2752 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2753 * SCIC_SDS_PORT object.
2758 void scic_sds_port_stopping_state_exit(
2759 SCI_BASE_OBJECT_T *object
2762 SCIC_SDS_PORT_T *this_port;
2763 this_port = (SCIC_SDS_PORT_T *)object;
2766 scic_sds_port_get_controller(this_port),
2767 this_port->timer_handle
2770 scic_cb_timer_destroy(
2771 scic_sds_port_get_controller(this_port),
2772 this_port->timer_handle
2774 this_port->timer_handle = NULL;
2776 scic_sds_port_destroy_dummy_resources(this_port);
2780 * This method will perform the actions required by the SCIC_SDS_PORT on
2781 * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping
2782 * state handlers for the SCIC_SDS_PORT object.
2784 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2785 * SCIC_SDS_PORT object.
2790 void scic_sds_port_failed_state_enter(
2791 SCI_BASE_OBJECT_T *object
2794 SCIC_SDS_PORT_T *this_port;
2795 this_port = (SCIC_SDS_PORT_T *)object;
2797 scic_sds_port_set_base_state_handlers(
2799 SCI_BASE_PORT_STATE_FAILED
2802 scic_cb_port_hard_reset_complete(
2803 scic_sds_port_get_controller(this_port),
2809 // ---------------------------------------------------------------------------
2811 SCI_BASE_STATE_T scic_sds_port_state_table[SCI_BASE_PORT_MAX_STATES] =
2814 SCI_BASE_PORT_STATE_STOPPED,
2815 scic_sds_port_stopped_state_enter,
2816 scic_sds_port_stopped_state_exit
2819 SCI_BASE_PORT_STATE_STOPPING,
2820 scic_sds_port_stopping_state_enter,
2821 scic_sds_port_stopping_state_exit
2824 SCI_BASE_PORT_STATE_READY,
2825 scic_sds_port_ready_state_enter,
2826 scic_sds_port_ready_state_exit
2829 SCI_BASE_PORT_STATE_RESETTING,
2830 scic_sds_port_resetting_state_enter,
2831 scic_sds_port_resetting_state_exit
2834 SCI_BASE_PORT_STATE_FAILED,
2835 scic_sds_port_failed_state_enter,
2840 //******************************************************************************
2841 //* PORT READY SUB-STATE MACHINE
2842 //******************************************************************************
2844 //****************************************************************************
2845 //* READY SUBSTATE HANDLERS
2846 //****************************************************************************
2849 * This method is the general ready state stop handler for the SCIC_SDS_PORT
2850 * object. This function will transition the ready substate machine to its
2853 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2854 * SCIC_SDS_PORT object.
2856 * @return SCI_STATUS
2857 * @retval SCI_SUCCESS
2860 SCI_STATUS scic_sds_port_ready_substate_stop_handler(
2861 SCI_BASE_PORT_T *port
2864 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2866 sci_base_state_machine_change_state(
2867 &this_port->parent.state_machine,
2868 SCI_BASE_PORT_STATE_STOPPING
2875 * This method is the general ready substate complete io handler for the
2876 * SCIC_SDS_PORT object. This function decrments the outstanding request
2877 * count for this port object.
2879 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2880 * SCIC_SDS_PORT object.
2881 * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
2882 * used in this function.
2883 * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
2886 * @return SCI_STATUS
2887 * @retval SCI_SUCCESS
2890 SCI_STATUS scic_sds_port_ready_substate_complete_io_handler(
2891 SCIC_SDS_PORT_T *port,
2892 struct SCIC_SDS_REMOTE_DEVICE *device,
2893 struct SCIC_SDS_REQUEST *io_request
2896 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2898 scic_sds_port_decrement_request_count(this_port);
2904 SCI_STATUS scic_sds_port_ready_substate_add_phy_handler(
2905 SCI_BASE_PORT_T *port,
2909 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
2910 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
2913 status = scic_sds_port_set_phy(this_port, this_phy);
2915 if (status == SCI_SUCCESS)
2917 scic_sds_port_general_link_up_handler(this_port, this_phy, TRUE, FALSE);
2919 this_port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING;
2921 sci_base_state_machine_change_state(
2922 &this_port->ready_substate_machine,
2923 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
2931 SCI_STATUS scic_sds_port_ready_substate_remove_phy_handler(
2932 SCI_BASE_PORT_T *port,
2936 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
2937 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
2940 status = scic_sds_port_clear_phy(this_port, this_phy);
2942 if (status == SCI_SUCCESS)
2944 scic_sds_port_deactivate_phy(this_port, this_phy, TRUE);
2946 this_port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING;
2948 sci_base_state_machine_change_state(
2949 &this_port->ready_substate_machine,
2950 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
2957 //****************************************************************************
2958 //* READY SUBSTATE WAITING HANDLERS
2959 //****************************************************************************
2962 * This method is the ready waiting substate link up handler for the
2963 * SCIC_SDS_PORT object. This methos will report the link up condition for
2964 * this port and will transition to the ready operational substate.
2966 * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
2967 * that has gone link up.
2968 * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
2973 void scic_sds_port_ready_waiting_substate_link_up_handler(
2974 SCIC_SDS_PORT_T *this_port,
2975 SCIC_SDS_PHY_T *the_phy
2978 // Since this is the first phy going link up for the port we can just enable
2980 scic_sds_port_activate_phy(this_port, the_phy, TRUE, TRUE);
2982 sci_base_state_machine_change_state(
2983 &this_port->ready_substate_machine,
2984 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
2989 * This method is the ready waiting substate start io handler for the
2990 * SCIC_SDS_PORT object. The port object can not accept new requests so the
2991 * request is failed.
2993 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2994 * SCIC_SDS_PORT object.
2995 * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
2996 * used in this request.
2997 * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
3000 * @return SCI_STATUS
3001 * @retval SCI_FAILURE_INVALID_STATE
3004 SCI_STATUS scic_sds_port_ready_waiting_substate_start_io_handler(
3005 SCIC_SDS_PORT_T *port,
3006 SCIC_SDS_REMOTE_DEVICE_T *device,
3007 SCIC_SDS_REQUEST_T *io_request
3010 return SCI_FAILURE_INVALID_STATE;
3013 //****************************************************************************
3014 //* READY SUBSTATE OPERATIONAL HANDLERS
3015 //****************************************************************************
3018 * This method will cause the port to reset.
3020 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
3021 * SCIC_SDS_PORT object.
3022 * @param[in] timeout This is the timeout for the reset request to complete.
3024 * @return SCI_STATUS
3025 * @retval SCI_SUCCESS
3028 SCI_STATUS scic_sds_port_ready_operational_substate_reset_handler(
3029 SCI_BASE_PORT_T * port,
3033 SCI_STATUS status = SCI_FAILURE_INVALID_PHY;
3035 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
3036 SCIC_SDS_PHY_T * selected_phy = SCI_INVALID_HANDLE;
3039 // Select a phy on which we can send the hard reset request.
3042 (phy_index < SCI_MAX_PHYS)
3043 && (selected_phy == SCI_INVALID_HANDLE);
3047 selected_phy = this_port->phy_table[phy_index];
3050 (selected_phy != SCI_INVALID_HANDLE)
3051 && !scic_sds_port_active_phy(this_port, selected_phy)
3054 // We found a phy but it is not ready select different phy
3055 selected_phy = SCI_INVALID_HANDLE;
3059 // If we have a phy then go ahead and start the reset procedure
3060 if (selected_phy != SCI_INVALID_HANDLE)
3062 status = scic_sds_phy_reset(selected_phy);
3064 if (status == SCI_SUCCESS)
3066 scic_cb_timer_start(
3067 scic_sds_port_get_controller(this_port),
3068 this_port->timer_handle,
3072 this_port->not_ready_reason = SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED;
3074 sci_base_state_machine_change_state(
3075 &this_port->parent.state_machine,
3076 SCI_BASE_PORT_STATE_RESETTING
3085 * This method is the ready operational substate link up handler for the
3086 * SCIC_SDS_PORT object. This function notifies the SCI User that the phy has
3089 * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
3090 * that has gone link up.
3091 * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
3096 void scic_sds_port_ready_operational_substate_link_up_handler(
3097 SCIC_SDS_PORT_T *this_port,
3098 SCIC_SDS_PHY_T *the_phy
3101 scic_sds_port_general_link_up_handler(this_port, the_phy, TRUE, TRUE);
3105 * This method is the ready operational substate link down handler for the
3106 * SCIC_SDS_PORT object. This function notifies the SCI User that the phy has
3107 * gone link down and if this is the last phy in the port the port will change
3108 * state to the ready waiting substate.
3110 * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
3111 * that has gone link down.
3112 * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link down.
3117 void scic_sds_port_ready_operational_substate_link_down_handler(
3118 SCIC_SDS_PORT_T *this_port,
3119 SCIC_SDS_PHY_T *the_phy
3122 scic_sds_port_deactivate_phy(this_port, the_phy, TRUE);
3124 // If there are no active phys left in the port, then transition
3125 // the port to the WAITING state until such time as a phy goes
3127 if (this_port->active_phy_mask == 0)
3129 sci_base_state_machine_change_state(
3130 scic_sds_port_get_ready_substate_machine(this_port),
3131 SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3137 * This method is the ready operational substate start io handler for the
3138 * SCIC_SDS_PORT object. This function incremetns the outstanding request
3139 * count for this port object.
3141 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
3142 * SCIC_SDS_PORT object.
3143 * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
3144 * used in this function.
3145 * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
3148 * @return SCI_STATUS
3149 * @retval SCI_SUCCESS
3152 SCI_STATUS scic_sds_port_ready_operational_substate_start_io_handler(
3153 SCIC_SDS_PORT_T *port,
3154 SCIC_SDS_REMOTE_DEVICE_T *device,
3155 SCIC_SDS_REQUEST_T *io_request
3158 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
3160 scic_sds_port_increment_request_count(this_port);
3165 //****************************************************************************
3166 //* READY SUBSTATE OPERATIONAL HANDLERS
3167 //****************************************************************************
3170 * This is the default method for a port add phy request. It will report a
3173 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
3174 * SCIC_SDS_PORT object.
3176 * @return SCI_STATUS
3177 * @retval SCI_FAILURE_INVALID_STATE
3180 SCI_STATUS scic_sds_port_ready_configuring_substate_add_phy_handler(
3181 SCI_BASE_PORT_T *port,
3185 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
3186 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
3189 status = scic_sds_port_set_phy(this_port, this_phy);
3191 if (status == SCI_SUCCESS)
3193 scic_sds_port_general_link_up_handler(this_port, this_phy, TRUE, FALSE);
3195 // Re-enter the configuring state since this may be the last phy in
3197 sci_base_state_machine_change_state(
3198 &this_port->ready_substate_machine,
3199 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3207 * This is the default method for a port remove phy request. It will report a
3210 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
3211 * SCIC_SDS_PORT object.
3213 * @return SCI_STATUS
3214 * @retval SCI_FAILURE_INVALID_STATE
3217 SCI_STATUS scic_sds_port_ready_configuring_substate_remove_phy_handler(
3218 SCI_BASE_PORT_T *port,
3222 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
3223 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
3226 status = scic_sds_port_clear_phy(this_port, this_phy);
3228 if (status == SCI_SUCCESS)
3230 scic_sds_port_deactivate_phy(this_port, this_phy, TRUE);
3232 // Re-enter the configuring state since this may be the last phy in
3234 sci_base_state_machine_change_state(
3235 &this_port->ready_substate_machine,
3236 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3244 * This method will decrement the outstanding request count for this port.
3245 * If the request count goes to 0 then the port can be reprogrammed with
3248 * @param[in] port This is the port that is being requested to complete
3250 * @param[in] device This is the device on which the io is completing.
3251 * @param[in] io_request This is the io request that is completing.
3254 SCI_STATUS scic_sds_port_ready_configuring_substate_complete_io_handler(
3255 SCIC_SDS_PORT_T *port,
3256 SCIC_SDS_REMOTE_DEVICE_T *device,
3257 SCIC_SDS_REQUEST_T *io_request
3260 scic_sds_port_decrement_request_count(port);
3262 if (port->started_request_count == 0)
3264 sci_base_state_machine_change_state(
3265 &port->ready_substate_machine,
3266 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3273 // ---------------------------------------------------------------------------
3275 SCIC_SDS_PORT_STATE_HANDLER_T
3276 scic_sds_port_ready_substate_handler_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] =
3278 // SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3281 scic_sds_port_default_start_handler,
3282 scic_sds_port_ready_substate_stop_handler,
3283 scic_sds_port_default_destruct_handler,
3284 scic_sds_port_default_reset_handler,
3285 scic_sds_port_ready_substate_add_phy_handler,
3286 scic_sds_port_default_remove_phy_handler
3288 scic_sds_port_default_frame_handler,
3289 scic_sds_port_default_event_handler,
3290 scic_sds_port_ready_waiting_substate_link_up_handler,
3291 scic_sds_port_default_link_down_handler,
3292 scic_sds_port_ready_waiting_substate_start_io_handler,
3293 scic_sds_port_ready_substate_complete_io_handler,
3295 // SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3298 scic_sds_port_default_start_handler,
3299 scic_sds_port_ready_substate_stop_handler,
3300 scic_sds_port_default_destruct_handler,
3301 scic_sds_port_ready_operational_substate_reset_handler,
3302 scic_sds_port_ready_substate_add_phy_handler,
3303 scic_sds_port_ready_substate_remove_phy_handler
3305 scic_sds_port_default_frame_handler,
3306 scic_sds_port_default_event_handler,
3307 scic_sds_port_ready_operational_substate_link_up_handler,
3308 scic_sds_port_ready_operational_substate_link_down_handler,
3309 scic_sds_port_ready_operational_substate_start_io_handler,
3310 scic_sds_port_ready_substate_complete_io_handler
3312 // SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3315 scic_sds_port_default_start_handler,
3316 scic_sds_port_ready_substate_stop_handler,
3317 scic_sds_port_default_destruct_handler,
3318 scic_sds_port_default_reset_handler,
3319 scic_sds_port_ready_configuring_substate_add_phy_handler,
3320 scic_sds_port_ready_configuring_substate_remove_phy_handler
3322 scic_sds_port_default_frame_handler,
3323 scic_sds_port_default_event_handler,
3324 scic_sds_port_default_link_up_handler,
3325 scic_sds_port_default_link_down_handler,
3326 scic_sds_port_default_start_io_handler,
3327 scic_sds_port_ready_configuring_substate_complete_io_handler
3332 * This macro sets the port ready substate handlers.
3334 #define scic_sds_port_set_ready_state_handlers(port, state_id) \
3335 scic_sds_port_set_state_handlers( \
3336 port, &scic_sds_port_ready_substate_handler_table[(state_id)] \
3339 //******************************************************************************
3340 //* PORT STATE PRIVATE METHODS
3341 //******************************************************************************
3344 * This method will susped the port task scheduler for this port object.
3346 * @param[in] this_port This is the SCIC_SDS_PORT object to suspend.
3350 void scic_sds_port_suspend_port_task_scheduler(
3351 SCIC_SDS_PORT_T *this_port
3354 U32 pts_control_value;
3356 pts_control_value = scu_port_task_scheduler_read(this_port, control);
3357 pts_control_value |= SCU_PTSxCR_GEN_BIT(SUSPEND);
3358 scu_port_task_scheduler_write(this_port, control, pts_control_value);
3362 * This method will resume the port task scheduler for this port object.
3364 * @param[in] this_port This is the SCIC_SDS_PORT object to resume.
3368 void scic_sds_port_resume_port_task_scheduler(
3369 SCIC_SDS_PORT_T *this_port
3372 U32 pts_control_value;
3374 pts_control_value = scu_port_task_scheduler_read(this_port, control);
3376 pts_control_value &= ~SCU_PTSxCR_GEN_BIT(SUSPEND);
3378 scu_port_task_scheduler_write(this_port, control, pts_control_value);
3382 * This routine will post the dummy request. This will prevent the hardware
3383 * scheduler from posting new requests to the front of the scheduler queue
3384 * causing a starvation problem for currently ongoing requests.
3386 * @parm[in] this_port The port on which the task must be posted.
3391 void scic_sds_port_post_dummy_request(
3392 SCIC_SDS_PORT_T *this_port
3396 SCU_TASK_CONTEXT_T * task_context;
3398 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
3400 task_context = scic_sds_controller_get_task_context_buffer(
3401 this_port->owning_controller,
3402 this_port->reserved_tci
3405 task_context->abort = 0;
3408 (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC)
3409 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
3410 | (this_port->reserved_tci)
3413 scic_sds_controller_post_request(this_port->owning_controller, command);
3418 * This routine will abort the dummy request. This will alow the hardware to
3419 * power down parts of the silicon to save power.
3421 * @parm[in] this_port The port on which the task must be aborted.
3426 void scic_sds_port_abort_dummy_request(
3427 SCIC_SDS_PORT_T *this_port
3431 SCU_TASK_CONTEXT_T * task_context;
3433 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
3435 task_context = scic_sds_controller_get_task_context_buffer(
3436 this_port->owning_controller,
3437 this_port->reserved_tci
3440 task_context->abort = 1;
3443 (SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT)
3444 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
3445 | (this_port->reserved_tci)
3448 scic_sds_controller_post_request(this_port->owning_controller, command);
3452 //******************************************************************************
3453 //* PORT READY SUBSTATE METHODS
3454 //******************************************************************************
3457 * This method will perform the actions required by the SCIC_SDS_PORT on
3458 * entering the SCIC_SDS_PORT_READY_SUBSTATE_WAITING. This function checks the
3459 * port for any ready phys. If there is at least one phy in a ready state
3460 * then the port transitions to the ready operational substate.
3462 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3463 * SCIC_SDS_PORT object.
3468 void scic_sds_port_ready_substate_waiting_enter(
3469 SCI_BASE_OBJECT_T *object
3472 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3474 scic_sds_port_set_ready_state_handlers(
3475 this_port, SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3478 scic_sds_port_suspend_port_task_scheduler(this_port);
3481 this_port->not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS;
3483 if (this_port->active_phy_mask != 0)
3485 // At least one of the phys on the port is ready
3486 sci_base_state_machine_change_state(
3487 &this_port->ready_substate_machine,
3488 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3494 * This method will perform the actions required by the SCIC_SDS_PORT on
3495 * exiting the SCIC_SDS_PORT_READY_SUBSTATE_WAITING. This function resume the
3496 * PTSG that was suspended at the entry of this state.
3498 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3499 * SCIC_SDS_PORT object.
3504 void scic_sds_port_ready_substate_waiting_exit(
3505 SCI_BASE_OBJECT_T *object
3508 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3509 scic_sds_port_resume_port_task_scheduler(this_port);
3513 * This method will perform the actions required by the SCIC_SDS_PORT on
3514 * entering the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function sets
3515 * the state handlers for the port object, notifies the SCI User that the port
3516 * is ready, and resumes port operations.
3518 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3519 * SCIC_SDS_PORT object.
3524 void scic_sds_port_ready_substate_operational_enter(
3525 SCI_BASE_OBJECT_T *object
3529 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3531 scic_sds_port_set_ready_state_handlers(
3532 this_port, SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3536 scic_sds_port_get_controller(this_port), this_port
3539 for (index = 0; index < SCI_MAX_PHYS; index++)
3541 if (this_port->phy_table[index] != NULL)
3543 scic_sds_port_write_phy_assignment(
3544 this_port, this_port->phy_table[index]
3547 //if the bit at the index location for active phy mask is set and
3548 //enabled_phy_mask is not set then resume the phy
3549 if ( ( (this_port->active_phy_mask ^ this_port->enabled_phy_mask) & (1 << index) ) != 0)
3551 scic_sds_port_resume_phy (
3553 this_port->phy_table[index]
3559 scic_sds_port_update_viit_entry(this_port);
3561 // Post the dummy task for the port so the hardware can schedule
3563 scic_sds_port_post_dummy_request(this_port);
3567 * This method will perform the actions required by the SCIC_SDS_PORT on
3568 * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports
3569 * the port not ready and suspends the port task scheduler.
3571 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3572 * SCIC_SDS_PORT object.
3577 void scic_sds_port_ready_substate_operational_exit(
3578 SCI_BASE_OBJECT_T *object
3581 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3583 // Kill the dummy task for this port if it has not yet posted
3584 // the hardware will treat this as a NOP and just return abort
3586 scic_sds_port_abort_dummy_request(this_port);
3588 scic_cb_port_not_ready(
3589 scic_sds_port_get_controller(this_port),
3591 this_port->not_ready_reason
3595 //******************************************************************************
3596 //* PORT READY CONFIGURING METHODS
3597 //******************************************************************************
3600 * This method will perform the actions required by the SCIC_SDS_PORT on
3601 * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports
3602 * the port not ready and suspends the port task scheduler.
3604 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3605 * SCIC_SDS_PORT object.
3610 void scic_sds_port_ready_substate_configuring_enter(
3611 SCI_BASE_OBJECT_T *object
3614 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3616 scic_sds_port_set_ready_state_handlers(
3617 this_port, SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3620 if (this_port->active_phy_mask == 0)
3622 scic_cb_port_not_ready(
3623 scic_sds_port_get_controller(this_port),
3625 SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS
3628 sci_base_state_machine_change_state(
3629 &this_port->ready_substate_machine,
3630 SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3633 //do not wait for IO to go to 0 in this state.
3636 sci_base_state_machine_change_state(
3637 &this_port->ready_substate_machine,
3638 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3643 // ---------------------------------------------------------------------------
3646 scic_sds_port_ready_substate_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] =
3649 SCIC_SDS_PORT_READY_SUBSTATE_WAITING,
3650 scic_sds_port_ready_substate_waiting_enter,
3651 scic_sds_port_ready_substate_waiting_exit
3654 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL,
3655 scic_sds_port_ready_substate_operational_enter,
3656 scic_sds_port_ready_substate_operational_exit
3659 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING,
3660 scic_sds_port_ready_substate_configuring_enter,