1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3 *
4 * This file is provided under a dual BSD/GPLv2 license. When using or
5 * redistributing this file, you may do so under either license.
6 *
7 * GPL LICENSE SUMMARY
8 *
9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23 * The full GNU General Public License is included in this distribution
24 * in the file called LICENSE.GPL.
25 *
26 * BSD LICENSE
27 *
28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 *
35 * * Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * * Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in
39 * the documentation and/or other materials provided with the
40 * distribution.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 */
54
55 #include <sys/cdefs.h>
56 __FBSDID("$FreeBSD$");
57
58 /**
59 * @file
60 *
61 * @brief This file contains the implementation for the public and protected
62 * methods for the SCIC_SDS_PORT object.
63 */
64
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>
69
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>
78
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>
82
83 #define SCIC_SDS_PORT_MIN_TIMER_COUNT (SCI_MAX_PORTS)
84 #define SCIC_SDS_PORT_MAX_TIMER_COUNT (SCI_MAX_PORTS)
85
86 #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000)
87 #define SCU_DUMMY_INDEX (0xFFFF)
88
89 /**
90 * This method will return a TRUE value if the specified phy can be assigned
91 * to this port
92 *
93 * The following is a list of phys for each port that are allowed:
94 * - Port 0 - 3 2 1 0
95 * - Port 1 - 1
96 * - Port 2 - 3 2
97 * - Port 3 - 3
98 *
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.
104 *
105 * @param[in] this_port This is the port object to which the phy is being
106 * assigned.
107 * @param[in] phy_index This is the phy index that is being assigned to the
108 * port.
109 *
110 * @return BOOL
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
113 */
114 BOOL scic_sds_port_is_valid_phy_assignment(
115 SCIC_SDS_PORT_T *this_port,
116 U32 phy_index
117 )
118 {
119 // Initialize to invalid value.
120 U32 existing_phy_index = SCI_MAX_PHYS;
121 U32 index;
122
123 if ((this_port->physical_port_index == 1) && (phy_index != 1))
124 {
125 return FALSE;
126 }
127
128 if (this_port->physical_port_index == 3 && phy_index != 3)
129 {
130 return FALSE;
131 }
132
133 if (
134 (this_port->physical_port_index == 2)
135 && ((phy_index == 0) || (phy_index == 1))
136 )
137 {
138 return FALSE;
139 }
140
141 for (index = 0; index < SCI_MAX_PHYS; index++)
142 {
143 if ( (this_port->phy_table[index] != NULL)
144 && (index != phy_index) )
145 {
146 existing_phy_index = index;
147 }
148 }
149
150 // Ensure that all of the phys in the port are capable of
151 // operating at the same maximum link rate.
152 if (
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)
158 )
159 return FALSE;
160
161 return TRUE;
162 }
163
164 /**
165 * @brief This method requests a list (mask) of the phys contained in the
166 * supplied SAS port.
167 *
168 * @param[in] this_port a handle corresponding to the SAS port for which
169 * to return the phy mask.
170 *
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).
173 */
174 U32 scic_sds_port_get_phys(
175 SCIC_SDS_PORT_T * this_port
176 )
177 {
178 U32 index;
179 U32 mask;
180
181 SCIC_LOG_TRACE((
182 sci_base_object_get_logger(this_port),
183 SCIC_LOG_OBJECT_PORT,
184 "scic_sds_port_get_phys(0x%x) enter\n",
185 this_port
186 ));
187
188 mask = 0;
189
190 for (index = 0; index < SCI_MAX_PHYS; index++)
191 {
192 if (this_port->phy_table[index] != NULL)
193 {
194 mask |= (1 << index);
195 }
196 }
197
198 return mask;
199 }
200
201 /**
202 * This method will return a TRUE value if the port's phy mask can be
203 * supported by the SCU.
204 *
205 * The following is a list of valid PHY mask configurations for each
206 * port:
207 * - Port 0 - [[3 2] 1] 0
208 * - Port 1 - [1]
209 * - Port 2 - [[3] 2]
210 * - Port 3 - [3]
211 *
212 * @param[in] this_port This is the port object for which to determine
213 * if the phy mask can be supported.
214 *
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
219 */
220 BOOL scic_sds_port_is_phy_mask_valid(
221 SCIC_SDS_PORT_T *this_port,
222 U32 phy_mask
223 )
224 {
225 if (this_port->physical_port_index == 0)
226 {
227 if ( ((phy_mask & 0x0F) == 0x0F)
228 || ((phy_mask & 0x03) == 0x03)
229 || ((phy_mask & 0x01) == 0x01)
230 || (phy_mask == 0) )
231 return TRUE;
232 }
233 else if (this_port->physical_port_index == 1)
234 {
235 if ( ((phy_mask & 0x02) == 0x02)
236 || (phy_mask == 0) )
237 return TRUE;
238 }
239 else if (this_port->physical_port_index == 2)
240 {
241 if ( ((phy_mask & 0x0C) == 0x0C)
242 || ((phy_mask & 0x04) == 0x04)
243 || (phy_mask == 0) )
244 return TRUE;
245 }
246 else if (this_port->physical_port_index == 3)
247 {
248 if ( ((phy_mask & 0x08) == 0x08)
249 || (phy_mask == 0) )
250 return TRUE;
251 }
252
253 return FALSE;
254 }
255
256 /**
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.
260 *
261 * @param[in] this_port This parameter specifies the port from which
262 * to return a connected phy.
263 *
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.
270 */
271 SCIC_SDS_PHY_T * scic_sds_port_get_a_connected_phy(
272 SCIC_SDS_PORT_T *this_port
273 )
274 {
275 U32 index;
276 SCIC_SDS_PHY_T *phy;
277
278 for (index = 0; index < SCI_MAX_PHYS; index++)
279 {
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];
283 if (
284 (phy != NULL)
285 && scic_sds_port_active_phy(this_port, phy)
286 )
287 {
288 return phy;
289 }
290 }
291
292 return NULL;
293 }
294
295 /**
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.
298 *
299 * @param[in, out] port The port object to which the phy assignement
300 * is being made.
301 * @param[in, out] phy The phy which is being assigned to the port.
302 *
303 * @return BOOL
304 * @retval TRUE if the phy assignment can be made.
305 * @retval FALSE if the phy assignement can not be made.
306 *
307 * @note This is a functional test that only fails if the phy is currently
308 * assigned to a different port.
309 */
310 SCI_STATUS scic_sds_port_set_phy(
311 SCIC_SDS_PORT_T *port,
312 SCIC_SDS_PHY_T *phy
313 )
314 {
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 assigned to the phy index.
318 if (
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)
322 )
323 {
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);
329
330 return SCI_SUCCESS;
331 }
332
333 return SCI_FAILURE;
334 }
335
336 /**
337 * This method will clear the phy assigned to this port. This method fails
338 * if this phy is not currently assigned to this port.
339 *
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.
342 *
343 * @return BOOL
344 * @retval TRUE if the phy is removed from the port.
345 * @retval FALSE if this phy is not assined to this port.
346 */
347 SCI_STATUS scic_sds_port_clear_phy(
348 SCIC_SDS_PORT_T *port,
349 SCIC_SDS_PHY_T *phy
350 )
351 {
352 // Make sure that this phy is part of this port
353 if (
354 (port->phy_table[phy->phy_index] == phy)
355 && (scic_sds_phy_get_port(phy) == port)
356 )
357 {
358 // Yep it is assigned to this port so remove it
359 scic_sds_phy_set_port(
360 phy,
361 &scic_sds_port_get_controller(port)->port_table[SCI_MAX_PORTS]
362 );
363
364 port->phy_table[phy->phy_index] = SCI_INVALID_HANDLE;
365
366 return SCI_SUCCESS;
367 }
368
369 return SCI_FAILURE;
370 }
371
372 /**
373 * This method will add a PHY to the selected port.
374 *
375 * @param[in] this_port This parameter specifies the port in which the phy will
376 * be added.
377 *
378 * @param[in] the_phy This parameter is the phy which is to be added to the
379 * port.
380 *
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.
384 */
385 SCI_STATUS scic_sds_port_add_phy(
386 SCIC_SDS_PORT_T * this_port,
387 SCIC_SDS_PHY_T * the_phy
388 )
389 {
390 return this_port->state_handlers->parent.add_phy_handler(
391 &this_port->parent, &the_phy->parent);
392 }
393
394
395 /**
396 * This method will remove the PHY from the selected PORT.
397 *
398 * @param[in] this_port This parameter specifies the port in which the phy will
399 * be added.
400 *
401 * @param[in] the_phy This parameter is the phy which is to be added to the
402 * port.
403 *
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.
407 */
408 SCI_STATUS scic_sds_port_remove_phy(
409 SCIC_SDS_PORT_T * this_port,
410 SCIC_SDS_PHY_T * the_phy
411 )
412 {
413 return this_port->state_handlers->parent.remove_phy_handler(
414 &this_port->parent, &the_phy->parent);
415 }
416
417 /**
418 * @brief This method requests the SAS address for the supplied SAS port
419 * from the SCI implementation.
420 *
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.
426 *
427 * @return none
428 */
429 void scic_sds_port_get_sas_address(
430 SCIC_SDS_PORT_T * this_port,
431 SCI_SAS_ADDRESS_T * sas_address
432 )
433 {
434 U32 index;
435
436 SCIC_LOG_TRACE((
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
441 ));
442
443 sas_address->high = 0;
444 sas_address->low = 0;
445
446 for (index = 0; index < SCI_MAX_PHYS; index++)
447 {
448 if (this_port->phy_table[index] != NULL)
449 {
450 scic_sds_phy_get_sas_address(this_port->phy_table[index], sas_address);
451 }
452 }
453 }
454
455 /**
456 * @brief This method will indicate which protocols are supported by this
457 * port.
458 *
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.
466 *
467 * @return none
468 */
469 static
470 void scic_sds_port_get_protocols(
471 SCIC_SDS_PORT_T * this_port,
472 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
473 )
474 {
475 U8 index;
476
477 SCIC_LOG_TRACE((
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",
481 this_port, protocols
482 ));
483
484 protocols->u.all = 0;
485
486 for (index = 0; index < SCI_MAX_PHYS; index++)
487 {
488 if (this_port->phy_table[index] != NULL)
489 {
490 scic_sds_phy_get_protocols(this_port->phy_table[index], protocols);
491 }
492 }
493 }
494
495 /**
496 * @brief This method requests the SAS address for the device directly
497 * attached to this SAS port.
498 *
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.
504 *
505 * @return none
506 */
507 void scic_sds_port_get_attached_sas_address(
508 SCIC_SDS_PORT_T * this_port,
509 SCI_SAS_ADDRESS_T * sas_address
510 )
511 {
512 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
513 SCIC_SDS_PHY_T *phy;
514
515 SCIC_LOG_TRACE((
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
520 ));
521
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);
525 if (phy != NULL)
526 {
527 scic_sds_phy_get_attached_phy_protocols(phy, &protocols);
528
529 if (!protocols.u.bits.stp_target)
530 {
531 scic_sds_phy_get_attached_sas_address(phy, sas_address);
532 }
533 else
534 {
535 scic_sds_phy_get_sas_address(phy, sas_address);
536 sas_address->low += phy->phy_index;
537
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);
542 }
543 }
544 else
545 {
546 sas_address->high = 0;
547 sas_address->low = 0;
548 }
549 }
550
551 /**
552 * @brief This method will indicate which protocols are supported by this
553 * remote device.
554 *
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.
562 *
563 * @return none
564 */
565 void scic_sds_port_get_attached_protocols(
566 SCIC_SDS_PORT_T * this_port,
567 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
568 )
569 {
570 SCIC_SDS_PHY_T *phy;
571
572 SCIC_LOG_TRACE((
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",
576 this_port, protocols
577 ));
578
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);
582 if (phy != NULL)
583 scic_sds_phy_get_attached_phy_protocols(phy, protocols);
584 else
585 protocols->u.all = 0;
586 }
587
588 /**
589 * @brief This method returns the amount of memory required for a port
590 * object.
591 *
592 * @return U32
593 */
594 U32 scic_sds_port_get_object_size(void)
595 {
596 return sizeof(SCIC_SDS_PORT_T);
597 }
598
599 /**
600 * @brief This method returns the minimum number of timers required for all
601 * port objects.
602 *
603 * @return U32
604 */
605 U32 scic_sds_port_get_min_timer_count(void)
606 {
607 return SCIC_SDS_PORT_MIN_TIMER_COUNT;
608 }
609
610 /**
611 * @brief This method returns the maximum number of timers required for all
612 * port objects.
613 *
614 * @return U32
615 */
616 U32 scic_sds_port_get_max_timer_count(void)
617 {
618 return SCIC_SDS_PORT_MAX_TIMER_COUNT;
619 }
620
621 #ifdef SCI_LOGGING
622 void scic_sds_port_initialize_state_logging(
623 SCIC_SDS_PORT_T *this_port
624 )
625 {
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",
632 SCIC_LOG_OBJECT_PORT
633 );
634
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",
641 SCIC_LOG_OBJECT_PORT
642 );
643 }
644 #endif
645
646 /**
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.
650 *
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.
654 *
655 * @return none
656 */
657 static
658 void scic_sds_port_construct_dummy_rnc(
659 SCIC_SDS_PORT_T *this_port,
660 U16 rni
661 )
662 {
663 SCU_REMOTE_NODE_CONTEXT_T * rnc;
664
665 rnc = &(this_port->owning_controller->remote_node_context_table[rni]);
666
667 memset(rnc, 0, sizeof(SCU_REMOTE_NODE_CONTEXT_T));
668
669 rnc->ssp.remote_sas_address_hi = 0;
670 rnc->ssp.remote_sas_address_lo = 0;
671
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;
675
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;
682 }
683
684 /**
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
687 * in the hardware.
688 *
689 * @param[in] this_port The logical port on which we need to create the
690 * remote node context.
691 * context.
692 * @param[in] tci The remote node index for this remote node context.
693 *
694 */
695 static
696 void scic_sds_port_construct_dummy_task(
697 SCIC_SDS_PORT_T *this_port,
698 U16 tci
699 )
700 {
701 SCU_TASK_CONTEXT_T * task_context;
702
703 task_context = scic_sds_controller_get_task_context_buffer(this_port->owning_controller, tci);
704
705 memset(task_context, 0, sizeof(SCU_TASK_CONTEXT_T));
706
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;
717
718 task_context->remote_node_index = this_port->reserved_rni;
719 task_context->command_code = 0;
720
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;
727
728 task_context->address_modifier = 0;
729
730 task_context->task_phase = 0x01;
731 }
732
733 /**
734 * This routine will free any allocated dummy resources for this port.
735 *
736 * @param[in, out] this_port The port on which the resources are being destroyed.
737 */
738 static
739 void scic_sds_port_destroy_dummy_resources(
740 SCIC_SDS_PORT_T * this_port
741 )
742 {
743 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
744 {
745 scic_controller_free_io_tag(
746 this_port->owning_controller, this_port->reserved_tci
747 );
748 }
749
750 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
751 {
752 scic_sds_remote_node_table_release_remote_node_index(
753 &this_port->owning_controller->available_remote_nodes, 1, this_port->reserved_rni
754 );
755 }
756
757 this_port->reserved_rni = SCU_DUMMY_INDEX;
758 this_port->reserved_tci = SCU_DUMMY_INDEX;
759 }
760
761 /**
762 * @brief
763 *
764 * @param[in] this_port
765 * @param[in] port_index
766 * @param[in] owning_controller
767 */
768 void scic_sds_port_construct(
769 SCIC_SDS_PORT_T *this_port,
770 U8 port_index,
771 SCIC_SDS_CONTROLLER_T *owning_controller
772 )
773 {
774 U32 index;
775
776 sci_base_port_construct(
777 &this_port->parent,
778 sci_base_object_get_logger(owning_controller),
779 scic_sds_port_state_table
780 );
781
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
787 );
788
789 scic_sds_port_initialize_state_logging(this_port);
790
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;
796
797 this_port->started_request_count = 0;
798 this_port->assigned_device_count = 0;
799
800 this_port->reserved_rni = SCU_DUMMY_INDEX;
801 this_port->reserved_tci = SCU_DUMMY_INDEX;
802
803 this_port->timer_handle = SCI_INVALID_HANDLE;
804
805 this_port->port_task_scheduler_registers = NULL;
806
807 for (index = 0; index < SCI_MAX_PHYS; index++)
808 {
809 this_port->phy_table[index] = NULL;
810 }
811 }
812
813 /**
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
819 *
820 * @param[in] this_port
821 * @param[in] transport_layer_registers
822 * @param[in] port_task_scheduler_registers
823 * @param[in] port_configuration_regsiter
824 *
825 * @return SCI_STATUS
826 * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This value is
827 * returned if the phy being added to the port
828 */
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,
833 void *viit_registers
834 )
835 {
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;
839
840 return SCI_SUCCESS;
841 }
842
843 /**
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.
850 *
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
860 *
861 * @return none
862 */
863 void scic_sds_port_general_link_up_handler(
864 SCIC_SDS_PORT_T * this_port,
865 SCIC_SDS_PHY_T * the_phy,
866 BOOL do_notify_user,
867 BOOL do_resume_phy
868 )
869 {
870 SCI_SAS_ADDRESS_T port_sas_address;
871 SCI_SAS_ADDRESS_T phy_sas_address;
872
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);
875
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
879 // in this port.
880 if (
881 (
882 (phy_sas_address.high == port_sas_address.high)
883 && (phy_sas_address.low == port_sas_address.low )
884 )
885 || (this_port->active_phy_mask == 0)
886 )
887 {
888 scic_sds_port_activate_phy(this_port, the_phy, do_notify_user, do_resume_phy);
889
890 if (this_port->parent.state_machine.current_state_id
891 == SCI_BASE_PORT_STATE_RESETTING)
892 {
893 sci_base_state_machine_change_state(
894 &this_port->parent.state_machine, SCI_BASE_PORT_STATE_READY
895 );
896 }
897 }
898 else
899 {
900 scic_sds_port_invalid_link_up(this_port, the_phy);
901 }
902 }
903
904 // ---------------------------------------------------------------------------
905
906 SCI_STATUS scic_port_add_phy(
907 SCI_PORT_HANDLE_T handle,
908 SCI_PHY_HANDLE_T phy
909 )
910 {
911 #if defined (SCI_LOGGING)
912 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)handle;
913 #endif // defined (SCI_LOGGING)
914
915 SCIC_LOG_TRACE((
916 sci_base_object_get_logger(this_port),
917 SCIC_LOG_OBJECT_PORT,
918 "scic_port_add_phy(0x%x, 0x%x) enter\n",
919 handle, phy
920 ));
921
922 SCIC_LOG_ERROR((
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"
927 ));
928
929 return SCI_FAILURE_ADDING_PHY_UNSUPPORTED;
930
931 }
932
933 // ---------------------------------------------------------------------------
934
935 SCI_STATUS scic_port_remove_phy(
936 SCI_PORT_HANDLE_T handle,
937 SCI_PHY_HANDLE_T phy
938 )
939 {
940 #if defined (SCI_LOGGING)
941 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)handle;
942 #endif // defined (SCI_LOGGING)
943
944 SCIC_LOG_TRACE((
945 sci_base_object_get_logger(this_port),
946 SCIC_LOG_OBJECT_PORT,
947 "scic_port_remove_phy(0x%x, 0x%x) enter\n",
948 handle, phy
949 ));
950
951 SCIC_LOG_ERROR((
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"
956 ));
957
958 return SCI_FAILURE_ADDING_PHY_UNSUPPORTED;
959 }
960
961 // ---------------------------------------------------------------------------
962
963 SCI_STATUS scic_port_get_properties(
964 SCI_PORT_HANDLE_T port,
965 SCIC_PORT_PROPERTIES_T * properties
966 )
967 {
968 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
969
970 SCIC_LOG_TRACE((
971 sci_base_object_get_logger(this_port),
972 SCIC_LOG_OBJECT_PORT,
973 "scic_port_get_properties(0x%x, 0x%x) enter\n",
974 port, properties
975 ));
976
977 if (
978 (port == SCI_INVALID_HANDLE)
979 || (this_port->logical_port_index == SCIC_SDS_DUMMY_PORT)
980 )
981 {
982 return SCI_FAILURE_INVALID_PORT;
983 }
984
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);
991
992 return SCI_SUCCESS;
993 }
994
995 // ---------------------------------------------------------------------------
996
997 SCI_STATUS scic_port_hard_reset(
998 SCI_PORT_HANDLE_T handle,
999 U32 reset_timeout
1000 )
1001 {
1002 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)handle;
1003
1004 SCIC_LOG_TRACE((
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
1009 ));
1010
1011 return this_port->state_handlers->parent.reset_handler(
1012 &this_port->parent,
1013 reset_timeout
1014 );
1015 }
1016
1017 /**
1018 * This method assigns the direct attached device ID for this port.
1019 *
1020 * @param[in] this_port The port for which the direct attached device id is to
1021 * be assigned.
1022 * @param[in] device_id The direct attached device ID to assign to the port.
1023 * This will be the RNi for the device
1024 */
1025 void scic_sds_port_setup_transports(
1026 SCIC_SDS_PORT_T * this_port,
1027 U32 device_id
1028 )
1029 {
1030 U8 index;
1031
1032 for (index = 0; index < SCI_MAX_PHYS; index++)
1033 {
1034 if (this_port->active_phy_mask & (1 << index))
1035 {
1036 scic_sds_phy_setup_transport(this_port->phy_table[index], device_id);
1037 }
1038 }
1039 }
1040
1041 /**
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.
1046 *
1047 * @param[in] this_port This is the port on which the phy should be enabled.
1048 * @return none
1049 */
1050 static
1051 void scic_sds_port_resume_phy(
1052 SCIC_SDS_PORT_T * this_port,
1053 SCIC_SDS_PHY_T * the_phy
1054 )
1055 {
1056 scic_sds_phy_resume (the_phy);
1057 this_port->enabled_phy_mask |= 1 << the_phy->phy_index;
1058 }
1059 /**
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.
1065 *
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
1074 *
1075
1076 * @return none
1077 */
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,
1082 BOOL do_resume_phy
1083 )
1084 {
1085 SCIC_SDS_CONTROLLER_T * controller;
1086 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
1087
1088 SCIC_LOG_TRACE((
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
1093 ));
1094
1095 controller = scic_sds_port_get_controller(this_port);
1096 scic_sds_phy_get_attached_phy_protocols(the_phy, &protocols);
1097
1098 // If this is sata port then the phy has already been resumed
1099 if (!protocols.u.bits.stp_target)
1100 {
1101 if (do_resume_phy == TRUE)
1102 {
1103 scic_sds_port_resume_phy(this_port, the_phy);
1104 }
1105 }
1106
1107 this_port->active_phy_mask |= 1 << the_phy->phy_index;
1108
1109 scic_sds_controller_clear_invalid_phy(controller, the_phy);
1110
1111 if (do_notify_user == TRUE)
1112 scic_cb_port_link_up(this_port->owning_controller, this_port, the_phy);
1113 }
1114
1115 /**
1116 * This method will deactivate the supplied phy in the port.
1117 *
1118 * @param[in] this_port This is the port on which the phy should be
1119 * deactivated.
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.
1125 *
1126 * @return none
1127 */
1128 void scic_sds_port_deactivate_phy(
1129 SCIC_SDS_PORT_T * this_port,
1130 SCIC_SDS_PHY_T * the_phy,
1131 BOOL do_notify_user
1132 )
1133 {
1134 SCIC_LOG_TRACE((
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
1139 ));
1140
1141 this_port->active_phy_mask &= ~(1 << the_phy->phy_index);
1142 this_port->enabled_phy_mask &= ~(1 << the_phy->phy_index);
1143
1144 the_phy->max_negotiated_speed = SCI_SAS_NO_LINK_RATE;
1145
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)
1150 {
1151 SCU_PCSPExCR_WRITE(this_port, the_phy->phy_index, the_phy->phy_index);
1152 }
1153
1154 if (do_notify_user == TRUE)
1155 scic_cb_port_link_down(this_port->owning_controller, this_port, the_phy);
1156 }
1157
1158 /**
1159 * This method will disable the phy and report that the phy is not valid for this
1160 * port object.
1161 *
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.
1164 *
1165 * @return None
1166 */
1167 void scic_sds_port_invalid_link_up(
1168 SCIC_SDS_PORT_T * this_port,
1169 SCIC_SDS_PHY_T * the_phy
1170 )
1171 {
1172 SCIC_SDS_CONTROLLER_T * controller = scic_sds_port_get_controller(this_port);
1173
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)
1177 {
1178 scic_sds_controller_set_invalid_phy(controller, the_phy);
1179
1180 scic_cb_port_invalid_link_up(controller, this_port, the_phy);
1181 }
1182 }
1183
1184 /**
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.
1188 *
1189 * @param[in] this_port The port for which the wide port condition is to be
1190 * checked.
1191 *
1192 * @return BOOL
1193 * @retval TRUE Is returned if this is a wide ported port.
1194 * @retval FALSE Is returned if this is a narrow port.
1195 */
1196 static
1197 BOOL scic_sds_port_is_wide(
1198 SCIC_SDS_PORT_T *this_port
1199 )
1200 {
1201 U32 index;
1202 U32 phy_count = 0;
1203
1204 for (index = 0; index < SCI_MAX_PHYS; index++)
1205 {
1206 if (this_port->phy_table[index] != NULL)
1207 {
1208 phy_count++;
1209 }
1210 }
1211
1212 return (phy_count != 1);
1213 }
1214
1215 /**
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.
1220 *
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.
1223 *
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.
1227 *
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.
1231 */
1232 BOOL scic_sds_port_link_detected(
1233 SCIC_SDS_PORT_T *this_port,
1234 SCIC_SDS_PHY_T *the_phy
1235 )
1236 {
1237 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
1238
1239 scic_sds_phy_get_attached_phy_protocols(the_phy, &protocols);
1240
1241 if (
1242 (this_port->logical_port_index != SCIC_SDS_DUMMY_PORT)
1243 && (protocols.u.bits.stp_target)
1244 )
1245 {
1246 if (scic_sds_port_is_wide(this_port))
1247 {
1248 //direct attached Sata phy cannot be in wide port.
1249 scic_sds_port_invalid_link_up( this_port, the_phy);
1250 return FALSE;
1251 }
1252 else
1253 {
1254 SCIC_SDS_PORT_T *destination_port = &(this_port->owning_controller->port_table[the_phy->phy_index]);
1255
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);
1259 }
1260 }
1261
1262 return TRUE;
1263 }
1264
1265 /**
1266 * @brief This method is the entry point for the phy to inform
1267 * the port that it is now in a ready state
1268 *
1269 * @param[in] this_port
1270 * @param[in] phy
1271 */
1272 void scic_sds_port_link_up(
1273 SCIC_SDS_PORT_T *this_port,
1274 SCIC_SDS_PHY_T *the_phy
1275 )
1276 {
1277 the_phy->is_in_link_training = FALSE;
1278
1279 this_port->state_handlers->link_up_handler(this_port, the_phy);
1280 }
1281
1282 /**
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
1285 *
1286 * @param[in] this_port
1287 * @param[in] phy
1288 */
1289 void scic_sds_port_link_down(
1290 SCIC_SDS_PORT_T *this_port,
1291 SCIC_SDS_PHY_T *the_phy
1292 )
1293 {
1294 this_port->state_handlers->link_down_handler(this_port, the_phy);
1295 }
1296
1297 /**
1298 * @brief This method is called to start an IO request on this port.
1299 *
1300 * @param[in] this_port
1301 * @param[in] the_device
1302 * @param[in] the_io_request
1303 *
1304 * @return SCI_STATUS
1305 */
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
1310 )
1311 {
1312 return this_port->state_handlers->start_io_handler(
1313 this_port, the_device, the_io_request);
1314 }
1315
1316 /**
1317 * @brief This method is called to complete an IO request to the port.
1318 *
1319 * @param[in] this_port
1320 * @param[in] the_device
1321 * @param[in] the_io_request
1322 *
1323 * @return SCI_STATUS
1324 */
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
1329 )
1330 {
1331 return this_port->state_handlers->complete_io_handler(
1332 this_port, the_device, the_io_request);
1333 }
1334
1335 /**
1336 * @brief This method is provided to timeout requests for port operations.
1337 * Mostly its for the port reset operation.
1338 *
1339 * @param[in] port This is the parameter or cookie value that is provided
1340 * to the timer construct operation.
1341 */
1342 void scic_sds_port_timeout_handler(
1343 void *port
1344 )
1345 {
1346 U32 current_state;
1347 SCIC_SDS_PORT_T * this_port;
1348
1349 this_port = (SCIC_SDS_PORT_T *)port;
1350 current_state = sci_base_state_machine_get_state(
1351 &this_port->parent.state_machine);
1352
1353 if (current_state == SCI_BASE_PORT_STATE_RESETTING)
1354 {
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
1360 );
1361 }
1362 else if (current_state == SCI_BASE_PORT_STATE_STOPPED)
1363 {
1364 // if the port is stopped then the start request failed
1365 // In this case stay in the stopped state.
1366 SCIC_LOG_ERROR((
1367 sci_base_object_get_logger(this_port),
1368 SCIC_LOG_OBJECT_PORT,
1369 "SCIC Port 0x%x failed to stop before tiemout.\n",
1370 this_port
1371 ));
1372 }
1373 else if (current_state == SCI_BASE_PORT_STATE_STOPPING)
1374 {
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),
1378 port,
1379 SCI_FAILURE_TIMEOUT
1380 );
1381 }
1382 else
1383 {
1384 // The port is in the ready state and we have a timer reporting a timeout
1385 // this should not happen.
1386 SCIC_LOG_ERROR((
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
1391 ));
1392 }
1393 }
1394
1395 // ---------------------------------------------------------------------------
1396
1397 #ifdef SCIC_DEBUG_ENABLED
1398 void scic_sds_port_decrement_request_count(
1399 SCIC_SDS_PORT_T *this_port
1400 )
1401 {
1402 if (this_port->started_request_count == 0)
1403 {
1404 SCIC_LOG_WARNING((
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"
1408 ));
1409 }
1410 else
1411 {
1412 this_port->started_request_count--;
1413 }
1414 }
1415 #endif
1416
1417 /**
1418 * @brief This function updates the hardwares VIIT entry for this port.
1419 *
1420 * @param[in] this_port
1421 */
1422 void scic_sds_port_update_viit_entry(
1423 SCIC_SDS_PORT_T *this_port
1424 )
1425 {
1426 SCI_SAS_ADDRESS_T sas_address;
1427
1428 scic_sds_port_get_sas_address(this_port, &sas_address);
1429
1430 scu_port_viit_register_write(
1431 this_port, initiator_sas_address_hi, sas_address.high);
1432
1433 scu_port_viit_register_write(
1434 this_port, initiator_sas_address_lo, sas_address.low);
1435
1436 // This value get cleared just in case its not already cleared
1437 scu_port_viit_register_write(
1438 this_port, reserved, 0);
1439
1440
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
1448 )
1449 );
1450 }
1451
1452 /**
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.
1456 *
1457 * @param[in] this_port This parameter specifies the port for which to
1458 * retrieve the maximum allowed speed.
1459 *
1460 * @return This method returns the maximum negotiated speed of the slowest
1461 * phy in the port.
1462 */
1463 SCI_SAS_LINK_RATE scic_sds_port_get_max_allowed_speed(
1464 SCIC_SDS_PORT_T * this_port
1465 )
1466 {
1467 U16 index = 0;
1468 SCI_SAS_LINK_RATE max_allowed_speed = SCI_SAS_600_GB;
1469 SCIC_SDS_PHY_T * phy = NULL;
1470
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++)
1474 {
1475 phy = this_port->phy_table[index];
1476 if (
1477 (phy != NULL)
1478 && (scic_sds_port_active_phy(this_port, phy) == TRUE)
1479 && (phy->max_negotiated_speed < max_allowed_speed)
1480 )
1481 max_allowed_speed = phy->max_negotiated_speed;
1482 }
1483
1484 return max_allowed_speed;
1485 }
1486
1487
1488 /**
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.
1492 *
1493 * @return none
1494 */
1495 void scic_sds_port_broadcast_change_received(
1496 SCIC_SDS_PORT_T * this_port,
1497 SCIC_SDS_PHY_T * this_phy
1498 )
1499 {
1500 //notify the user.
1501 scic_cb_port_bc_change_primitive_recieved(
1502 this_port->owning_controller, this_port, this_phy
1503 );
1504 }
1505
1506
1507 /**
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.
1511 *
1512 * @return none
1513 */
1514 void scic_port_enable_broadcast_change_notification(
1515 SCI_PORT_HANDLE_T port
1516 )
1517 {
1518 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
1519 SCIC_SDS_PHY_T * phy;
1520 U32 register_value;
1521 U8 index;
1522
1523 // Loop through all of the phys to enable BCN.
1524 for (index = 0; index < SCI_MAX_PHYS; index++)
1525 {
1526 phy = this_port->phy_table[index];
1527 if ( phy != NULL)
1528 {
1529 register_value = SCU_SAS_LLCTL_READ(phy);
1530
1531 // clear the bit by writing 1.
1532 SCU_SAS_LLCTL_WRITE(phy, register_value);
1533 }
1534 }
1535 }
1536
1537 /**
1538 * @brief This method release resources in for a scic port.
1539 *
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
1543 * be released.
1544 */
1545 void scic_sds_port_release_resource(
1546 SCIC_SDS_CONTROLLER_T * controller,
1547 SCIC_SDS_PORT_T *this_port
1548 )
1549 {
1550 SCIC_LOG_TRACE((
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
1555 ));
1556
1557 //Currently, the only resource to be released is a timer.
1558 if (this_port->timer_handle != NULL)
1559 {
1560 scic_cb_timer_destroy(controller, this_port->timer_handle);
1561 this_port->timer_handle = NULL;
1562 }
1563 }
1564
1565
1566 //******************************************************************************
1567 //* PORT STATE MACHINE
1568 //******************************************************************************
1569
1570 //***************************************************************************
1571 //* DEFAULT HANDLERS
1572 //***************************************************************************
1573
1574 /**
1575 * This is the default method for port a start request. It will report a
1576 * warning and exit.
1577 *
1578 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1579 * SCIC_SDS_PORT object.
1580 *
1581 * @return SCI_STATUS
1582 * @retval SCI_FAILURE_INVALID_STATE
1583 */
1584 SCI_STATUS scic_sds_port_default_start_handler(
1585 SCI_BASE_PORT_T *port
1586 )
1587 {
1588 SCIC_LOG_WARNING((
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",
1592 port,
1593 sci_base_state_machine_get_state(
1594 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1595 ));
1596
1597 return SCI_FAILURE_INVALID_STATE;
1598 }
1599
1600 /**
1601 * This is the default method for a port stop request. It will report a
1602 * warning and exit.
1603 *
1604 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1605 * SCIC_SDS_PORT object.
1606 *
1607 * @return SCI_STATUS
1608 * @retval SCI_FAILURE_INVALID_STATE
1609 */
1610 SCI_STATUS scic_sds_port_default_stop_handler(
1611 SCI_BASE_PORT_T *port
1612 )
1613 {
1614 SCIC_LOG_WARNING((
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",
1618 port,
1619 sci_base_state_machine_get_state(
1620 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1621 ));
1622
1623 return SCI_FAILURE_INVALID_STATE;
1624 }
1625
1626 /**
1627 * This is the default method for a port destruct request. It will report a
1628 * warning and exit.
1629 *
1630 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1631 * SCIC_SDS_PORT object.
1632 *
1633 * @return SCI_STATUS
1634 * @retval SCI_FAILURE_INVALID_STATE
1635 */
1636 SCI_STATUS scic_sds_port_default_destruct_handler(
1637 SCI_BASE_PORT_T *port
1638 )
1639 {
1640 SCIC_LOG_WARNING((
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",
1644 port,
1645 sci_base_state_machine_get_state(
1646 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1647 ));
1648
1649 return SCI_FAILURE_INVALID_STATE;
1650 }
1651
1652 /**
1653 * This is the default method for a port reset request. It will report a
1654 * warning and exit.
1655 *
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.
1659 *
1660 * @return SCI_STATUS
1661 * @retval SCI_FAILURE_INVALID_STATE
1662 */
1663 SCI_STATUS scic_sds_port_default_reset_handler(
1664 SCI_BASE_PORT_T * port,
1665 U32 timeout
1666 )
1667 {
1668 SCIC_LOG_WARNING((
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",
1672 port,
1673 sci_base_state_machine_get_state(
1674 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1675 ));
1676
1677 return SCI_FAILURE_INVALID_STATE;
1678 }
1679
1680 /**
1681 * This is the default method for a port add phy request. It will report a
1682 * warning and exit.
1683 *
1684 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1685 * SCIC_SDS_PORT object.
1686 *
1687 * @return SCI_STATUS
1688 * @retval SCI_FAILURE_INVALID_STATE
1689 */
1690 SCI_STATUS scic_sds_port_default_add_phy_handler(
1691 SCI_BASE_PORT_T *port,
1692 SCI_BASE_PHY_T *phy
1693 )
1694 {
1695 SCIC_LOG_WARNING((
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",
1699 port, phy,
1700 sci_base_state_machine_get_state(
1701 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1702 ));
1703
1704 return SCI_FAILURE_INVALID_STATE;
1705 }
1706
1707 /**
1708 * This is the default method for a port remove phy request. It will report a
1709 * warning and exit.
1710 *
1711 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1712 * SCIC_SDS_PORT object.
1713 *
1714 * @return SCI_STATUS
1715 * @retval SCI_FAILURE_INVALID_STATE
1716 */
1717 SCI_STATUS scic_sds_port_default_remove_phy_handler(
1718 SCI_BASE_PORT_T *port,
1719 SCI_BASE_PHY_T *phy
1720 )
1721 {
1722 SCIC_LOG_WARNING((
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",
1726 port, phy,
1727 sci_base_state_machine_get_state(
1728 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1729 ));
1730
1731 return SCI_FAILURE_INVALID_STATE;
1732 }
1733
1734 /**
1735 * This is the default method for a port unsolicited frame request. It will
1736 * report a warning and exit.
1737 *
1738 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1739 * SCIC_SDS_PORT object.
1740 *
1741 * @return SCI_STATUS
1742 * @retval SCI_FAILURE_INVALID_STATE
1743 *
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
1746 * but until then?
1747 */
1748 SCI_STATUS scic_sds_port_default_frame_handler(
1749 SCIC_SDS_PORT_T * port,
1750 U32 frame_index
1751 )
1752 {
1753 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
1754
1755 SCIC_LOG_WARNING((
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",
1759 port, frame_index,
1760 sci_base_state_machine_get_state(
1761 scic_sds_port_get_base_state_machine(this_port))
1762 ));
1763
1764 scic_sds_controller_release_frame(
1765 scic_sds_port_get_controller(this_port), frame_index
1766 );
1767
1768 return SCI_FAILURE_INVALID_STATE;
1769 }
1770
1771 /**
1772 * This is the default method for a port event request. It will report a
1773 * warning and exit.
1774 *
1775 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1776 * SCIC_SDS_PORT object.
1777 *
1778 * @return SCI_STATUS
1779 * @retval SCI_FAILURE_INVALID_STATE
1780 */
1781 SCI_STATUS scic_sds_port_default_event_handler(
1782 SCIC_SDS_PORT_T * port,
1783 U32 event_code
1784 )
1785 {
1786 SCIC_LOG_WARNING((
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",
1790 port, event_code,
1791 sci_base_state_machine_get_state(
1792 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1793 ));
1794
1795 return SCI_FAILURE_INVALID_STATE;
1796 }
1797
1798 /**
1799 * This is the default method for a port link up notification. It will report
1800 * a warning and exit.
1801 *
1802 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1803 * SCIC_SDS_PORT object.
1804 *
1805 * @return SCI_STATUS
1806 * @retval SCI_FAILURE_INVALID_STATE
1807 */
1808 void scic_sds_port_default_link_up_handler(
1809 SCIC_SDS_PORT_T *this_port,
1810 SCIC_SDS_PHY_T *phy
1811 )
1812 {
1813 SCIC_LOG_WARNING((
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",
1817 this_port, phy,
1818 sci_base_state_machine_get_state(
1819 scic_sds_port_get_base_state_machine(this_port))
1820 ));
1821 }
1822
1823 /**
1824 * This is the default method for a port link down notification. It will
1825 * report a warning and exit.
1826 *
1827 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1828 * SCIC_SDS_PORT object.
1829 *
1830 * @return SCI_STATUS
1831 * @retval SCI_FAILURE_INVALID_STATE
1832 */
1833 void scic_sds_port_default_link_down_handler(
1834 SCIC_SDS_PORT_T *this_port,
1835 SCIC_SDS_PHY_T *phy
1836 )
1837 {
1838 SCIC_LOG_WARNING((
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",
1842 this_port, phy,
1843 sci_base_state_machine_get_state(
1844 scic_sds_port_get_base_state_machine(this_port))
1845 ));
1846 }
1847
1848 /**
1849 * This is the default method for a port start io request. It will report a
1850 * warning and exit.
1851 *
1852 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1853 * SCIC_SDS_PORT object.
1854 *
1855 * @return SCI_STATUS
1856 * @retval SCI_FAILURE_INVALID_STATE
1857 */
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
1862 )
1863 {
1864 SCIC_LOG_WARNING((
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))
1871 ));
1872
1873 return SCI_FAILURE_INVALID_STATE;
1874 }
1875
1876 /**
1877 * This is the default method for a port complete io request. It will report
1878 * a warning and exit.
1879 *
1880 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1881 * SCIC_SDS_PORT object.
1882 *
1883 * @return SCI_STATUS
1884 * @retval SCI_FAILURE_INVALID_STATE
1885 */
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
1890 )
1891 {
1892 SCIC_LOG_WARNING((
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))
1899 ));
1900
1901 return SCI_FAILURE_INVALID_STATE;
1902 }
1903
1904 //****************************************************************************
1905 //* GENERAL STATE HANDLERS
1906 //****************************************************************************
1907
1908 /**
1909 * This is a general complete io request handler for the SCIC_SDS_PORT object.
1910 *
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
1918 * operation.
1919 *
1920 * @return SCI_STATUS
1921 * @retval SCI_SUCCESS
1922 */
1923 static
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
1928 )
1929 {
1930 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
1931
1932 scic_sds_port_decrement_request_count(this_port);
1933
1934 return SCI_SUCCESS;
1935 }
1936
1937 //****************************************************************************
1938 //* STOPPED STATE HANDLERS
1939 //****************************************************************************
1940 static
1941 BOOL scic_sds_port_requires_scheduler_workaround(
1942 SCIC_SDS_PORT_T * this_port
1943 )
1944 {
1945 if (
1946 (
1947 this_port->owning_controller->logical_port_entries
1948 < this_port->owning_controller->task_context_entries
1949 )
1950 && (
1951 this_port->owning_controller->logical_port_entries
1952 < this_port->owning_controller->remote_node_entries
1953 )
1954 )
1955 {
1956 return TRUE;
1957 }
1958
1959 return FALSE;
1960 }
1961
1962
1963 /**
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.
1968 *
1969 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1970 * SCIC_SDS_PORT object.
1971 *
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
1975 * valid.
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.
1978 */
1979 static
1980 SCI_STATUS scic_sds_port_stopped_state_start_handler(
1981 SCI_BASE_PORT_T *port
1982 )
1983 {
1984 U32 phy_mask;
1985 SCI_STATUS status = SCI_SUCCESS;
1986 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
1987
1988 if (this_port->assigned_device_count > 0)
1989 {
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;
1994 }
1995
1996 this_port->timer_handle = scic_cb_timer_create(
1997 scic_sds_port_get_controller(this_port),
1998 scic_sds_port_timeout_handler,
1999 this_port
2000 );
2001
2002 if (this_port->timer_handle == SCI_INVALID_HANDLE)
2003 {
2004 return SCI_FAILURE_INSUFFICIENT_RESOURCES;
2005 }
2006
2007 if (scic_sds_port_requires_scheduler_workaround(this_port))
2008 {
2009 if (this_port->reserved_rni == SCU_DUMMY_INDEX)
2010 {
2011 this_port->reserved_rni =
2012 scic_sds_remote_node_table_allocate_remote_node(
2013 &this_port->owning_controller->available_remote_nodes, 1
2014 );
2015
2016 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
2017 {
2018 scic_sds_port_construct_dummy_rnc(
2019 this_port,
2020 this_port->reserved_rni
2021 );
2022 }
2023 else
2024 {
2025 status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
2026 }
2027 }
2028
2029 if (this_port->reserved_tci == SCU_DUMMY_INDEX)
2030 {
2031 // Allocate a TCI and remove the sequence nibble
2032 this_port->reserved_tci =
2033 scic_controller_allocate_io_tag(this_port->owning_controller);
2034
2035 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
2036 {
2037 scic_sds_port_construct_dummy_task(this_port, this_port->reserved_tci);
2038 }
2039 else
2040 {
2041 status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
2042 }
2043 }
2044 }
2045
2046 if (status == SCI_SUCCESS)
2047 {
2048 phy_mask = scic_sds_port_get_phys(this_port);
2049
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
2052 // silicon.
2053 if (scic_sds_port_is_phy_mask_valid(this_port, phy_mask) == TRUE)
2054 {
2055 sci_base_state_machine_change_state(
2056 scic_sds_port_get_base_state_machine(this_port),
2057 SCI_BASE_PORT_STATE_READY
2058 );
2059 }
2060 else
2061 {
2062 status = SCI_FAILURE;
2063 }
2064 }
2065
2066 if (status != SCI_SUCCESS)
2067 {
2068 scic_sds_port_destroy_dummy_resources(this_port);
2069 }
2070
2071 return status;
2072 }
2073
2074 /**
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.
2077 *
2078 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2079 * SCIC_SDS_PORT object.
2080 *
2081 * @return SCI_STATUS
2082 * @retval SCI_SUCCESS the stop request is successful as the SCIC_SDS_PORT
2083 * object is already stopped.
2084 */
2085 static
2086 SCI_STATUS scic_sds_port_stopped_state_stop_handler(
2087 SCI_BASE_PORT_T *port
2088 )
2089 {
2090 // We are already stopped so there is nothing to do here
2091 return SCI_SUCCESS;
2092 }
2093
2094 /**
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.
2099 *
2100 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2101 * SCIC_SDS_PORT object.
2102 *
2103 * @return SCI_STATUS
2104 * @retval SCI_SUCCESS
2105 */
2106 static
2107 SCI_STATUS scic_sds_port_stopped_state_destruct_handler(
2108 SCI_BASE_PORT_T *port
2109 )
2110 {
2111 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2112
2113 sci_base_state_machine_stop(&this_port->parent.state_machine);
2114
2115 return SCI_SUCCESS;
2116 }
2117
2118 /**
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.
2122 *
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.
2127 *
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.
2132 */
2133 static
2134 SCI_STATUS scic_sds_port_stopped_state_add_phy_handler(
2135 SCI_BASE_PORT_T *port,
2136 SCI_BASE_PHY_T *phy
2137 )
2138 {
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;
2142
2143 // Read the port assigned SAS Address if there is one
2144 scic_sds_port_get_sas_address(this_port, &port_sas_address);
2145
2146 if (port_sas_address.high != 0 && port_sas_address.low != 0)
2147 {
2148 SCI_SAS_ADDRESS_T phy_sas_address;
2149
2150 // Make sure that the PHY SAS Address matches the SAS Address
2151 // for this port.
2152 scic_sds_phy_get_sas_address(this_phy, &phy_sas_address);
2153
2154 if (
2155 (port_sas_address.high != phy_sas_address.high)
2156 || (port_sas_address.low != phy_sas_address.low)
2157 )
2158 {
2159 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
2160 }
2161 }
2162
2163 return scic_sds_port_set_phy(this_port, this_phy);
2164 }
2165
2166
2167 /**
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.
2171 *
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.
2176 *
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.
2181 */
2182 static
2183 SCI_STATUS scic_sds_port_stopped_state_remove_phy_handler(
2184 SCI_BASE_PORT_T *port,
2185 SCI_BASE_PHY_T *phy
2186 )
2187 {
2188 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2189 SCIC_SDS_PHY_T *this_phy = (SCIC_SDS_PHY_T *)phy;
2190
2191 return scic_sds_port_clear_phy(this_port, this_phy);
2192 }
2193
2194 //****************************************************************************
2195 //* READY STATE HANDLERS
2196 //****************************************************************************
2197
2198 //****************************************************************************
2199 //* RESETTING STATE HANDLERS
2200 //****************************************************************************
2201
2202 //****************************************************************************
2203 //* STOPPING STATE HANDLERS
2204 //****************************************************************************
2205
2206 /**
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.
2210 *
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
2218 * operation.
2219 *
2220 * @return SCI_STATUS
2221 * @retval SCI_SUCCESS
2222 */
2223 static
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
2228 )
2229 {
2230 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2231
2232 scic_sds_port_decrement_request_count(this_port);
2233
2234 if (this_port->started_request_count == 0)
2235 {
2236 sci_base_state_machine_change_state(
2237 scic_sds_port_get_base_state_machine(this_port),
2238 SCI_BASE_PORT_STATE_STOPPED
2239 );
2240 }
2241
2242 return SCI_SUCCESS;
2243 }
2244
2245 //****************************************************************************
2246 //* RESETTING STATE HANDLERS
2247 //****************************************************************************
2248
2249 /**
2250 * This method will stop a failed port. This causes a transition to the
2251 * stopping state.
2252 *
2253 * @param[in] port This is the port object which is being requested to stop.
2254 *
2255 * @return SCI_STATUS
2256 * @retval SCI_SUCCESS
2257 */
2258 static
2259 SCI_STATUS scic_sds_port_reset_state_stop_handler(
2260 SCI_BASE_PORT_T *port
2261 )
2262 {
2263 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2264
2265 sci_base_state_machine_change_state(
2266 &this_port->parent.state_machine,
2267 SCI_BASE_PORT_STATE_STOPPING
2268 );
2269
2270 return SCI_SUCCESS;
2271 }
2272
2273 /**
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.
2277 *
2278 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2279 * SCIC_SDS_PORT object.
2280 *
2281 * @return SCI_STATUS
2282 * @retval SCI_SUCCESS
2283 */
2284 static
2285 void scic_sds_port_reset_state_link_up_handler(
2286 SCIC_SDS_PORT_T *this_port,
2287 SCIC_SDS_PHY_T *phy
2288 )
2289 {
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
2297 /// immediately.
2298
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);
2302 }
2303
2304 /**
2305 * This method process link down notifications that occur during a
2306 * port reset operation. Link downs can occur during the reset operation.
2307 *
2308 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2309 * SCIC_SDS_PORT object.
2310 *
2311 * @return SCI_STATUS
2312 * @retval SCI_SUCCESS
2313 */
2314 static
2315 void scic_sds_port_reset_state_link_down_handler(
2316 SCIC_SDS_PORT_T *this_port,
2317 SCIC_SDS_PHY_T *phy
2318 )
2319 {
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);
2323 }
2324
2325 // ---------------------------------------------------------------------------
2326
2327 SCIC_SDS_PORT_STATE_HANDLER_T
2328 scic_sds_port_state_handler_table[SCI_BASE_PORT_MAX_STATES] =
2329 {
2330 // SCI_BASE_PORT_STATE_STOPPED
2331 {
2332 {
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
2339 },
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
2346 },
2347 // SCI_BASE_PORT_STATE_STOPPING
2348 {
2349 {
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
2356 },
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
2363 },
2364 // SCI_BASE_PORT_STATE_READY
2365 {
2366 {
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
2373 },
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
2380 },
2381 // SCI_BASE_PORT_STATE_RESETTING
2382 {
2383 {
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
2390 },
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
2397 },
2398 // SCI_BASE_PORT_STATE_FAILED
2399 {
2400 {
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
2407 },
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
2414 }
2415 };
2416
2417 //******************************************************************************
2418 //* PORT STATE PRIVATE METHODS
2419 //******************************************************************************
2420
2421 /**
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.
2424 *
2425 * @param[in] this_port This is the port object which to suspend.
2426 *
2427 * @return none
2428 */
2429 static
2430 void scic_sds_port_enable_port_task_scheduler(
2431 SCIC_SDS_PORT_T *this_port
2432 )
2433 {
2434 U32 pts_control_value;
2435
2436 pts_control_value = scu_port_task_scheduler_read(this_port, control);
2437
2438 pts_control_value |= SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND);
2439
2440 scu_port_task_scheduler_write(this_port, control, pts_control_value);
2441 }
2442
2443 /**
2444 * This method will disable the SCU port task scheduler for this port
2445 * object.
2446 *
2447 * @param[in] this_port This is the port object which to resume.
2448 *
2449 * @return none
2450 */
2451 static
2452 void scic_sds_port_disable_port_task_scheduler(
2453 SCIC_SDS_PORT_T *this_port
2454 )
2455 {
2456 U32 pts_control_value;
2457
2458 pts_control_value = scu_port_task_scheduler_read(this_port, control);
2459
2460 pts_control_value &= ~( SCU_PTSxCR_GEN_BIT(ENABLE)
2461 | SCU_PTSxCR_GEN_BIT(SUSPEND) );
2462
2463 scu_port_task_scheduler_write(this_port, control, pts_control_value);
2464 }
2465
2466 /**
2467 *
2468 */
2469 static
2470 void scic_sds_port_post_dummy_remote_node(
2471 SCIC_SDS_PORT_T *this_port
2472 )
2473 {
2474 U32 command;
2475 SCU_REMOTE_NODE_CONTEXT_T * rnc;
2476
2477 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
2478 {
2479 rnc = &(this_port->owning_controller->remote_node_context_table[this_port->reserved_rni]);
2480
2481 rnc->ssp.is_valid = TRUE;
2482
2483 command = (
2484 (SCU_CONTEXT_COMMAND_POST_RNC_32)
2485 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
2486 | (this_port->reserved_rni)
2487 );
2488
2489 scic_sds_controller_post_request(this_port->owning_controller, command);
2490
2491 scic_cb_stall_execution(10);
2492
2493 command = (
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)
2497 );
2498
2499 scic_sds_controller_post_request(this_port->owning_controller, command);
2500 }
2501 }
2502
2503 /**
2504 *
2505 */
2506 static
2507 void scic_sds_port_invalidate_dummy_remote_node(
2508 SCIC_SDS_PORT_T *this_port
2509 )
2510 {
2511 U32 command;
2512 SCU_REMOTE_NODE_CONTEXT_T * rnc;
2513
2514 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
2515 {
2516 rnc = &(this_port->owning_controller->remote_node_context_table[this_port->reserved_rni]);
2517
2518 rnc->ssp.is_valid = FALSE;
2519
2520 scic_cb_stall_execution(10);
2521
2522 command = (
2523 (SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE)
2524 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
2525 | (this_port->reserved_rni)
2526 );
2527
2528 scic_sds_controller_post_request(this_port->owning_controller, command);
2529 }
2530 }
2531
2532 //******************************************************************************
2533 //* PORT STATE METHODS
2534 //******************************************************************************
2535
2536 /**
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.
2541 *
2542 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2543 * SCIC_SDS_PORT object.
2544 *
2545 * @return none
2546 */
2547 static
2548 void scic_sds_port_stopped_state_enter(
2549 SCI_BASE_OBJECT_T *object
2550 )
2551 {
2552 SCIC_SDS_PORT_T *this_port;
2553 this_port = (SCIC_SDS_PORT_T *)object;
2554
2555 scic_sds_port_set_base_state_handlers(
2556 this_port, SCI_BASE_PORT_STATE_STOPPED
2557 );
2558
2559 if (
2560 SCI_BASE_PORT_STATE_STOPPING
2561 == this_port->parent.state_machine.previous_state_id
2562 )
2563 {
2564 // If we enter this state becasuse of a request to stop
2565 // the port then we want to disable the hardwares port
2566 // task scheduler.
2567 scic_sds_port_disable_port_task_scheduler(this_port);
2568 }
2569 }
2570
2571 /**
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.
2575 *
2576 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2577 * SCIC_SDS_PORT object.
2578 *
2579 * @return none
2580 */
2581 static
2582 void scic_sds_port_stopped_state_exit(
2583 SCI_BASE_OBJECT_T *object
2584 )
2585 {
2586 SCIC_SDS_PORT_T *this_port;
2587 this_port = (SCIC_SDS_PORT_T *)object;
2588
2589 // Enable and suspend the port task scheduler
2590 scic_sds_port_enable_port_task_scheduler(this_port);
2591 }
2592
2593 /**
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.
2598 *
2599 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2600 * SCIC_SDS_PORT object.
2601 *
2602 * @return none
2603 */
2604 static
2605 void scic_sds_port_ready_state_enter(
2606 SCI_BASE_OBJECT_T *object
2607 )
2608 {
2609 SCIC_SDS_PORT_T *this_port;
2610 this_port = (SCIC_SDS_PORT_T *)object;
2611
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
2615 );
2616
2617 if (
2618 SCI_BASE_PORT_STATE_RESETTING
2619 == this_port->parent.state_machine.previous_state_id
2620 )
2621 {
2622 scic_cb_port_hard_reset_complete(
2623 scic_sds_port_get_controller(this_port),
2624 this_port,
2625 SCI_SUCCESS
2626 );
2627 }
2628 else
2629 {
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),
2633 this_port,
2634 SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS
2635 );
2636 }
2637
2638 // Post and suspend the dummy remote node context for this
2639 // port.
2640 scic_sds_port_post_dummy_remote_node(this_port);
2641
2642 // Start the ready substate machine
2643 sci_base_state_machine_start(
2644 scic_sds_port_get_ready_substate_machine(this_port)
2645 );
2646 }
2647
2648 /**
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.
2651 *
2652 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2653 * SCIC_SDS_PORT object.
2654 *
2655 * @return none
2656 */
2657 static
2658 void scic_sds_port_ready_state_exit(
2659 SCI_BASE_OBJECT_T *object
2660 )
2661 {
2662 SCIC_SDS_PORT_T *this_port;
2663 this_port = (SCIC_SDS_PORT_T *)object;
2664
2665 sci_base_state_machine_stop(&this_port->ready_substate_machine);
2666
2667 scic_cb_stall_execution(10);
2668 scic_sds_port_invalidate_dummy_remote_node(this_port);
2669 }
2670
2671 /**
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.
2675 *
2676 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2677 * SCIC_SDS_PORT object.
2678 *
2679 * @return none
2680 */
2681 static
2682 void scic_sds_port_resetting_state_enter(
2683 SCI_BASE_OBJECT_T *object
2684 )
2685 {
2686 SCIC_SDS_PORT_T *this_port;
2687 this_port = (SCIC_SDS_PORT_T *)object;
2688
2689 scic_sds_port_set_base_state_handlers(
2690 this_port, SCI_BASE_PORT_STATE_RESETTING
2691 );
2692 }
2693
2694 /**
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.
2697 *
2698 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2699 * SCIC_SDS_PORT object.
2700 *
2701 * @return none
2702 */
2703 static
2704 void scic_sds_port_resetting_state_exit(
2705 SCI_BASE_OBJECT_T *object
2706 )
2707 {
2708 SCIC_SDS_PORT_T *this_port;
2709 this_port = (SCIC_SDS_PORT_T *)object;
2710
2711 scic_cb_timer_stop(
2712 scic_sds_port_get_controller(this_port),
2713 this_port->timer_handle
2714 );
2715 }
2716
2717 /**
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.
2721 *
2722 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2723 * SCIC_SDS_PORT object.
2724 *
2725 * @return none
2726 */
2727 static
2728 void scic_sds_port_stopping_state_enter(
2729 SCI_BASE_OBJECT_T *object
2730 )
2731 {
2732 SCIC_SDS_PORT_T *this_port;
2733 this_port = (SCIC_SDS_PORT_T *)object;
2734
2735 scic_sds_port_set_base_state_handlers(
2736 this_port, SCI_BASE_PORT_STATE_STOPPING
2737 );
2738
2739 if (this_port->started_request_count == 0)
2740 {
2741 sci_base_state_machine_change_state(
2742 &this_port->parent.state_machine,
2743 SCI_BASE_PORT_STATE_STOPPED
2744 );
2745 }
2746 }
2747
2748 /**
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.
2751 *
2752 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2753 * SCIC_SDS_PORT object.
2754 *
2755 * @return none
2756 */
2757 static
2758 void scic_sds_port_stopping_state_exit(
2759 SCI_BASE_OBJECT_T *object
2760 )
2761 {
2762 SCIC_SDS_PORT_T *this_port;
2763 this_port = (SCIC_SDS_PORT_T *)object;
2764
2765 scic_cb_timer_stop(
2766 scic_sds_port_get_controller(this_port),
2767 this_port->timer_handle
2768 );
2769
2770 scic_cb_timer_destroy(
2771 scic_sds_port_get_controller(this_port),
2772 this_port->timer_handle
2773 );
2774 this_port->timer_handle = NULL;
2775
2776 scic_sds_port_destroy_dummy_resources(this_port);
2777 }
2778
2779 /**
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.
2783 *
2784 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2785 * SCIC_SDS_PORT object.
2786 *
2787 * @return none
2788 */
2789 static
2790 void scic_sds_port_failed_state_enter(
2791 SCI_BASE_OBJECT_T *object
2792 )
2793 {
2794 SCIC_SDS_PORT_T *this_port;
2795 this_port = (SCIC_SDS_PORT_T *)object;
2796
2797 scic_sds_port_set_base_state_handlers(
2798 this_port,
2799 SCI_BASE_PORT_STATE_FAILED
2800 );
2801
2802 scic_cb_port_hard_reset_complete(
2803 scic_sds_port_get_controller(this_port),
2804 this_port,
2805 SCI_FAILURE_TIMEOUT
2806 );
2807 }
2808
2809 // ---------------------------------------------------------------------------
2810
2811 SCI_BASE_STATE_T scic_sds_port_state_table[SCI_BASE_PORT_MAX_STATES] =
2812 {
2813 {
2814 SCI_BASE_PORT_STATE_STOPPED,
2815 scic_sds_port_stopped_state_enter,
2816 scic_sds_port_stopped_state_exit
2817 },
2818 {
2819 SCI_BASE_PORT_STATE_STOPPING,
2820 scic_sds_port_stopping_state_enter,
2821 scic_sds_port_stopping_state_exit
2822 },
2823 {
2824 SCI_BASE_PORT_STATE_READY,
2825 scic_sds_port_ready_state_enter,
2826 scic_sds_port_ready_state_exit
2827 },
2828 {
2829 SCI_BASE_PORT_STATE_RESETTING,
2830 scic_sds_port_resetting_state_enter,
2831 scic_sds_port_resetting_state_exit
2832 },
2833 {
2834 SCI_BASE_PORT_STATE_FAILED,
2835 scic_sds_port_failed_state_enter,
2836 NULL
2837 }
2838 };
2839
2840 //******************************************************************************
2841 //* PORT READY SUB-STATE MACHINE
2842 //******************************************************************************
2843
2844 //****************************************************************************
2845 //* READY SUBSTATE HANDLERS
2846 //****************************************************************************
2847
2848 /**
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
2851 * final state.
2852 *
2853 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2854 * SCIC_SDS_PORT object.
2855 *
2856 * @return SCI_STATUS
2857 * @retval SCI_SUCCESS
2858 */
2859 static
2860 SCI_STATUS scic_sds_port_ready_substate_stop_handler(
2861 SCI_BASE_PORT_T *port
2862 )
2863 {
2864 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2865
2866 sci_base_state_machine_change_state(
2867 &this_port->parent.state_machine,
2868 SCI_BASE_PORT_STATE_STOPPING
2869 );
2870
2871 return SCI_SUCCESS;
2872 }
2873
2874 /**
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.
2878 *
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
2884 * in this function.
2885 *
2886 * @return SCI_STATUS
2887 * @retval SCI_SUCCESS
2888 */
2889 static
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
2894 )
2895 {
2896 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2897
2898 scic_sds_port_decrement_request_count(this_port);
2899
2900 return SCI_SUCCESS;
2901 }
2902
2903 static
2904 SCI_STATUS scic_sds_port_ready_substate_add_phy_handler(
2905 SCI_BASE_PORT_T *port,
2906 SCI_BASE_PHY_T *phy
2907 )
2908 {
2909 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
2910 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
2911 SCI_STATUS status;
2912
2913 status = scic_sds_port_set_phy(this_port, this_phy);
2914
2915 if (status == SCI_SUCCESS)
2916 {
2917 scic_sds_port_general_link_up_handler(this_port, this_phy, TRUE, FALSE);
2918
2919 this_port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING;
2920
2921 sci_base_state_machine_change_state(
2922 &this_port->ready_substate_machine,
2923 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
2924 );
2925 }
2926
2927 return status;
2928 }
2929
2930 static
2931 SCI_STATUS scic_sds_port_ready_substate_remove_phy_handler(
2932 SCI_BASE_PORT_T *port,
2933 SCI_BASE_PHY_T *phy
2934 )
2935 {
2936 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
2937 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
2938 SCI_STATUS status;
2939
2940 status = scic_sds_port_clear_phy(this_port, this_phy);
2941
2942 if (status == SCI_SUCCESS)
2943 {
2944 scic_sds_port_deactivate_phy(this_port, this_phy, TRUE);
2945
2946 this_port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING;
2947
2948 sci_base_state_machine_change_state(
2949 &this_port->ready_substate_machine,
2950 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
2951 );
2952 }
2953
2954 return status;
2955 }
2956
2957 //****************************************************************************
2958 //* READY SUBSTATE WAITING HANDLERS
2959 //****************************************************************************
2960
2961 /**
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.
2965 *
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.
2969 *
2970 * @return none
2971 */
2972 static
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
2976 )
2977 {
2978 // Since this is the first phy going link up for the port we can just enable
2979 // it and continue.
2980 scic_sds_port_activate_phy(this_port, the_phy, TRUE, TRUE);
2981
2982 sci_base_state_machine_change_state(
2983 &this_port->ready_substate_machine,
2984 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
2985 );
2986 }
2987
2988 /**
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.
2992 *
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
2998 * in this function.
2999 *
3000 * @return SCI_STATUS
3001 * @retval SCI_FAILURE_INVALID_STATE
3002 */
3003 static
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
3008 )
3009 {
3010 return SCI_FAILURE_INVALID_STATE;
3011 }
3012
3013 //****************************************************************************
3014 //* READY SUBSTATE OPERATIONAL HANDLERS
3015 //****************************************************************************
3016
3017 /**
3018 * This method will cause the port to reset.
3019 *
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.
3023 *
3024 * @return SCI_STATUS
3025 * @retval SCI_SUCCESS
3026 */
3027 static
3028 SCI_STATUS scic_sds_port_ready_operational_substate_reset_handler(
3029 SCI_BASE_PORT_T * port,
3030 U32 timeout
3031 )
3032 {
3033 SCI_STATUS status = SCI_FAILURE_INVALID_PHY;
3034 U32 phy_index;
3035 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
3036 SCIC_SDS_PHY_T * selected_phy = SCI_INVALID_HANDLE;
3037
3038
3039 // Select a phy on which we can send the hard reset request.
3040 for (
3041 phy_index = 0;
3042 (phy_index < SCI_MAX_PHYS)
3043 && (selected_phy == SCI_INVALID_HANDLE);
3044 phy_index++
3045 )
3046 {
3047 selected_phy = this_port->phy_table[phy_index];
3048
3049 if (
3050 (selected_phy != SCI_INVALID_HANDLE)
3051 && !scic_sds_port_active_phy(this_port, selected_phy)
3052 )
3053 {
3054 // We found a phy but it is not ready select different phy
3055 selected_phy = SCI_INVALID_HANDLE;
3056 }
3057 }
3058
3059 // If we have a phy then go ahead and start the reset procedure
3060 if (selected_phy != SCI_INVALID_HANDLE)
3061 {
3062 status = scic_sds_phy_reset(selected_phy);
3063
3064 if (status == SCI_SUCCESS)
3065 {
3066 scic_cb_timer_start(
3067 scic_sds_port_get_controller(this_port),
3068 this_port->timer_handle,
3069 timeout
3070 );
3071
3072 this_port->not_ready_reason = SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED;
3073
3074 sci_base_state_machine_change_state(
3075 &this_port->parent.state_machine,
3076 SCI_BASE_PORT_STATE_RESETTING
3077 );
3078 }
3079 }
3080
3081 return status;
3082 }
3083
3084 /**
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
3087 * gone link up.
3088 *
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.
3092 *
3093 * @return none
3094 */
3095 static
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
3099 )
3100 {
3101 scic_sds_port_general_link_up_handler(this_port, the_phy, TRUE, TRUE);
3102 }
3103
3104 /**
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.
3109 *
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.
3113 *
3114 * @return none
3115 */
3116 static
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
3120 )
3121 {
3122 scic_sds_port_deactivate_phy(this_port, the_phy, TRUE);
3123
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
3126 // link up.
3127 if (this_port->active_phy_mask == 0)
3128 {
3129 sci_base_state_machine_change_state(
3130 scic_sds_port_get_ready_substate_machine(this_port),
3131 SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3132 );
3133 }
3134 }
3135
3136 /**
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.
3140 *
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
3146 * in this function.
3147 *
3148 * @return SCI_STATUS
3149 * @retval SCI_SUCCESS
3150 */
3151 static
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
3156 )
3157 {
3158 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
3159
3160 scic_sds_port_increment_request_count(this_port);
3161
3162 return SCI_SUCCESS;
3163 }
3164
3165 //****************************************************************************
3166 //* READY SUBSTATE OPERATIONAL HANDLERS
3167 //****************************************************************************
3168
3169 /**
3170 * This is the default method for a port add phy request. It will report a
3171 * warning and exit.
3172 *
3173 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
3174 * SCIC_SDS_PORT object.
3175 *
3176 * @return SCI_STATUS
3177 * @retval SCI_FAILURE_INVALID_STATE
3178 */
3179 static
3180 SCI_STATUS scic_sds_port_ready_configuring_substate_add_phy_handler(
3181 SCI_BASE_PORT_T *port,
3182 SCI_BASE_PHY_T *phy
3183 )
3184 {
3185 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
3186 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
3187 SCI_STATUS status;
3188
3189 status = scic_sds_port_set_phy(this_port, this_phy);
3190
3191 if (status == SCI_SUCCESS)
3192 {
3193 scic_sds_port_general_link_up_handler(this_port, this_phy, TRUE, FALSE);
3194
3195 // Re-enter the configuring state since this may be the last phy in
3196 // the port.
3197 sci_base_state_machine_change_state(
3198 &this_port->ready_substate_machine,
3199 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3200 );
3201 }
3202
3203 return status;
3204 }
3205
3206 /**
3207 * This is the default method for a port remove phy request. It will report a
3208 * warning and exit.
3209 *
3210 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
3211 * SCIC_SDS_PORT object.
3212 *
3213 * @return SCI_STATUS
3214 * @retval SCI_FAILURE_INVALID_STATE
3215 */
3216 static
3217 SCI_STATUS scic_sds_port_ready_configuring_substate_remove_phy_handler(
3218 SCI_BASE_PORT_T *port,
3219 SCI_BASE_PHY_T *phy
3220 )
3221 {
3222 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
3223 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
3224 SCI_STATUS status;
3225
3226 status = scic_sds_port_clear_phy(this_port, this_phy);
3227
3228 if (status == SCI_SUCCESS)
3229 {
3230 scic_sds_port_deactivate_phy(this_port, this_phy, TRUE);
3231
3232 // Re-enter the configuring state since this may be the last phy in
3233 // the port.
3234 sci_base_state_machine_change_state(
3235 &this_port->ready_substate_machine,
3236 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3237 );
3238 }
3239
3240 return status;
3241 }
3242
3243 /**
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
3246 * its new phy data.
3247 *
3248 * @param[in] port This is the port that is being requested to complete
3249 * the io request.
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.
3252 */
3253 static
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
3258 )
3259 {
3260 scic_sds_port_decrement_request_count(port);
3261
3262 if (port->started_request_count == 0)
3263 {
3264 sci_base_state_machine_change_state(
3265 &port->ready_substate_machine,
3266 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3267 );
3268 }
3269
3270 return SCI_SUCCESS;
3271 }
3272
3273 // ---------------------------------------------------------------------------
3274
3275 SCIC_SDS_PORT_STATE_HANDLER_T
3276 scic_sds_port_ready_substate_handler_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] =
3277 {
3278 // SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3279 {
3280 {
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
3287 },
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,
3294 },
3295 // SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3296 {
3297 {
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
3304 },
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
3311 },
3312 // SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3313 {
3314 {
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
3321 },
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
3328 }
3329 };
3330
3331 /**
3332 * This macro sets the port ready substate handlers.
3333 */
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)] \
3337 )
3338
3339 //******************************************************************************
3340 //* PORT STATE PRIVATE METHODS
3341 //******************************************************************************
3342
3343 /**
3344 * This method will susped the port task scheduler for this port object.
3345 *
3346 * @param[in] this_port This is the SCIC_SDS_PORT object to suspend.
3347 *
3348 * @return none
3349 */
3350 void scic_sds_port_suspend_port_task_scheduler(
3351 SCIC_SDS_PORT_T *this_port
3352 )
3353 {
3354 U32 pts_control_value;
3355
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);
3359 }
3360
3361 /**
3362 * This method will resume the port task scheduler for this port object.
3363 *
3364 * @param[in] this_port This is the SCIC_SDS_PORT object to resume.
3365 *
3366 * @return none
3367 */
3368 void scic_sds_port_resume_port_task_scheduler(
3369 SCIC_SDS_PORT_T *this_port
3370 )
3371 {
3372 U32 pts_control_value;
3373
3374 pts_control_value = scu_port_task_scheduler_read(this_port, control);
3375
3376 pts_control_value &= ~SCU_PTSxCR_GEN_BIT(SUSPEND);
3377
3378 scu_port_task_scheduler_write(this_port, control, pts_control_value);
3379 }
3380
3381 /**
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.
3385 *
3386 * @parm[in] this_port The port on which the task must be posted.
3387 *
3388 * @return none
3389 */
3390 static
3391 void scic_sds_port_post_dummy_request(
3392 SCIC_SDS_PORT_T *this_port
3393 )
3394 {
3395 U32 command;
3396 SCU_TASK_CONTEXT_T * task_context;
3397
3398 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
3399 {
3400 task_context = scic_sds_controller_get_task_context_buffer(
3401 this_port->owning_controller,
3402 this_port->reserved_tci
3403 );
3404
3405 task_context->abort = 0;
3406
3407 command = (
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)
3411 );
3412
3413 scic_sds_controller_post_request(this_port->owning_controller, command);
3414 }
3415 }
3416
3417 /**
3418 * This routine will abort the dummy request. This will alow the hardware to
3419 * power down parts of the silicon to save power.
3420 *
3421 * @parm[in] this_port The port on which the task must be aborted.
3422 *
3423 * @return none
3424 */
3425 static
3426 void scic_sds_port_abort_dummy_request(
3427 SCIC_SDS_PORT_T *this_port
3428 )
3429 {
3430 U32 command;
3431 SCU_TASK_CONTEXT_T * task_context;
3432
3433 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
3434 {
3435 task_context = scic_sds_controller_get_task_context_buffer(
3436 this_port->owning_controller,
3437 this_port->reserved_tci
3438 );
3439
3440 task_context->abort = 1;
3441
3442 command = (
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)
3446 );
3447
3448 scic_sds_controller_post_request(this_port->owning_controller, command);
3449 }
3450 }
3451
3452 //******************************************************************************
3453 //* PORT READY SUBSTATE METHODS
3454 //******************************************************************************
3455
3456 /**
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.
3461 *
3462 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3463 * SCIC_SDS_PORT object.
3464 *
3465 * @return none
3466 */
3467 static
3468 void scic_sds_port_ready_substate_waiting_enter(
3469 SCI_BASE_OBJECT_T *object
3470 )
3471 {
3472 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3473
3474 scic_sds_port_set_ready_state_handlers(
3475 this_port, SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3476 );
3477
3478 scic_sds_port_suspend_port_task_scheduler(this_port);
3479
3480
3481 this_port->not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS;
3482
3483 if (this_port->active_phy_mask != 0)
3484 {
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
3489 );
3490 }
3491 }
3492
3493 /**
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.
3497 *
3498 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3499 * SCIC_SDS_PORT object.
3500 *
3501 * @return none
3502 */
3503 static
3504 void scic_sds_port_ready_substate_waiting_exit(
3505 SCI_BASE_OBJECT_T *object
3506 )
3507 {
3508 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3509 scic_sds_port_resume_port_task_scheduler(this_port);
3510 }
3511
3512 /**
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.
3517 *
3518 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3519 * SCIC_SDS_PORT object.
3520 *
3521 * @return none
3522 */
3523 static
3524 void scic_sds_port_ready_substate_operational_enter(
3525 SCI_BASE_OBJECT_T *object
3526 )
3527 {
3528 U32 index;
3529 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3530
3531 scic_sds_port_set_ready_state_handlers(
3532 this_port, SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3533 );
3534
3535 scic_cb_port_ready(
3536 scic_sds_port_get_controller(this_port), this_port
3537 );
3538
3539 for (index = 0; index < SCI_MAX_PHYS; index++)
3540 {
3541 if (this_port->phy_table[index] != NULL)
3542 {
3543 scic_sds_port_write_phy_assignment(
3544 this_port, this_port->phy_table[index]
3545 );
3546
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)
3550 {
3551 scic_sds_port_resume_phy (
3552 this_port,
3553 this_port->phy_table[index]
3554 );
3555 }
3556 }
3557 }
3558
3559 scic_sds_port_update_viit_entry(this_port);
3560
3561 // Post the dummy task for the port so the hardware can schedule
3562 // io correctly
3563 scic_sds_port_post_dummy_request(this_port);
3564 }
3565
3566 /**
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.
3570 *
3571 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3572 * SCIC_SDS_PORT object.
3573 *
3574 * @return none
3575 */
3576 static
3577 void scic_sds_port_ready_substate_operational_exit(
3578 SCI_BASE_OBJECT_T *object
3579 )
3580 {
3581 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3582
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
3585 // complete.
3586 scic_sds_port_abort_dummy_request(this_port);
3587
3588 scic_cb_port_not_ready(
3589 scic_sds_port_get_controller(this_port),
3590 this_port,
3591 this_port->not_ready_reason
3592 );
3593 }
3594
3595 //******************************************************************************
3596 //* PORT READY CONFIGURING METHODS
3597 //******************************************************************************
3598
3599 /**
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.
3603 *
3604 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3605 * SCIC_SDS_PORT object.
3606 *
3607 * @return none
3608 */
3609 static
3610 void scic_sds_port_ready_substate_configuring_enter(
3611 SCI_BASE_OBJECT_T *object
3612 )
3613 {
3614 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3615
3616 scic_sds_port_set_ready_state_handlers(
3617 this_port, SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3618 );
3619
3620 if (this_port->active_phy_mask == 0)
3621 {
3622 scic_cb_port_not_ready(
3623 scic_sds_port_get_controller(this_port),
3624 this_port,
3625 SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS
3626 );
3627
3628 sci_base_state_machine_change_state(
3629 &this_port->ready_substate_machine,
3630 SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3631 );
3632 }
3633 //do not wait for IO to go to 0 in this state.
3634 else
3635 {
3636 sci_base_state_machine_change_state(
3637 &this_port->ready_substate_machine,
3638 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3639 );
3640 }
3641 }
3642
3643 // ---------------------------------------------------------------------------
3644
3645 SCI_BASE_STATE_T
3646 scic_sds_port_ready_substate_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] =
3647 {
3648 {
3649 SCIC_SDS_PORT_READY_SUBSTATE_WAITING,
3650 scic_sds_port_ready_substate_waiting_enter,
3651 scic_sds_port_ready_substate_waiting_exit
3652 },
3653 {
3654 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL,
3655 scic_sds_port_ready_substate_operational_enter,
3656 scic_sds_port_ready_substate_operational_exit
3657 },
3658 {
3659 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING,
3660 scic_sds_port_ready_substate_configuring_enter,
3661 NULL
3662 }
3663 };
3664
Cache object: 18e3ea226e41b73645a927a08ed69756
|