1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3 *
4 * This file is provided under a dual BSD/GPLv2 license. When using or
5 * redistributing this file, you may do so under either license.
6 *
7 * GPL LICENSE SUMMARY
8 *
9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of version 2 of the GNU General Public License as
13 * published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23 * The full GNU General Public License is included in this distribution
24 * in the file called LICENSE.GPL.
25 *
26 * BSD LICENSE
27 *
28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 *
35 * * Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * * Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in
39 * the documentation and/or other materials provided with the
40 * distribution.
41 *
42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 */
54
55 #include <sys/cdefs.h>
56 /**
57 * @file
58 *
59 * @brief This file contains the implementation for the public and protected
60 * methods for the SCIC_SDS_PORT object.
61 */
62
63 #include <dev/isci/scil/scic_phy.h>
64 #include <dev/isci/scil/scic_port.h>
65 #include <dev/isci/scil/scic_controller.h>
66 #include <dev/isci/scil/scic_user_callback.h>
67
68 #include <dev/isci/scil/scic_sds_controller.h>
69 #include <dev/isci/scil/scic_sds_port.h>
70 #include <dev/isci/scil/scic_sds_phy.h>
71 #include <dev/isci/scil/scic_sds_remote_device.h>
72 #include <dev/isci/scil/scic_sds_request.h>
73 #include <dev/isci/scil/scic_sds_port_registers.h>
74 #include <dev/isci/scil/scic_sds_logger.h>
75 #include <dev/isci/scil/scic_sds_phy_registers.h>
76
77 #include <dev/isci/scil/intel_sas.h>
78 #include <dev/isci/scil/scic_sds_remote_node_context.h>
79 #include <dev/isci/scil/sci_util.h>
80
81 #define SCIC_SDS_PORT_MIN_TIMER_COUNT (SCI_MAX_PORTS)
82 #define SCIC_SDS_PORT_MAX_TIMER_COUNT (SCI_MAX_PORTS)
83
84 #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000)
85 #define SCU_DUMMY_INDEX (0xFFFF)
86
87 /**
88 * This method will return a TRUE value if the specified phy can be assigned
89 * to this port
90 *
91 * The following is a list of phys for each port that are allowed:
92 * - Port 0 - 3 2 1 0
93 * - Port 1 - 1
94 * - Port 2 - 3 2
95 * - Port 3 - 3
96 *
97 * This method doesn't preclude all configurations. It merely ensures
98 * that a phy is part of the allowable set of phy identifiers for
99 * that port. For example, one could assign phy 3 to port 0 and no other
100 * phys. Please refer to scic_sds_port_is_phy_mask_valid() for
101 * information regarding whether the phy_mask for a port can be supported.
102 *
103 * @param[in] this_port This is the port object to which the phy is being
104 * assigned.
105 * @param[in] phy_index This is the phy index that is being assigned to the
106 * port.
107 *
108 * @return BOOL
109 * @retval TRUE if this is a valid phy assignment for the port
110 * @retval FALSE if this is not a valid phy assignment for the port
111 */
scic_sds_port_is_valid_phy_assignment(SCIC_SDS_PORT_T * this_port,U32 phy_index)112 BOOL scic_sds_port_is_valid_phy_assignment(
113 SCIC_SDS_PORT_T *this_port,
114 U32 phy_index
115 )
116 {
117 // Initialize to invalid value.
118 U32 existing_phy_index = SCI_MAX_PHYS;
119 U32 index;
120
121 if ((this_port->physical_port_index == 1) && (phy_index != 1))
122 {
123 return FALSE;
124 }
125
126 if (this_port->physical_port_index == 3 && phy_index != 3)
127 {
128 return FALSE;
129 }
130
131 if (
132 (this_port->physical_port_index == 2)
133 && ((phy_index == 0) || (phy_index == 1))
134 )
135 {
136 return FALSE;
137 }
138
139 for (index = 0; index < SCI_MAX_PHYS; index++)
140 {
141 if ( (this_port->phy_table[index] != NULL)
142 && (index != phy_index) )
143 {
144 existing_phy_index = index;
145 }
146 }
147
148 // Ensure that all of the phys in the port are capable of
149 // operating at the same maximum link rate.
150 if (
151 (existing_phy_index < SCI_MAX_PHYS)
152 && (this_port->owning_controller->user_parameters.sds1.phys[
153 phy_index].max_speed_generation !=
154 this_port->owning_controller->user_parameters.sds1.phys[
155 existing_phy_index].max_speed_generation)
156 )
157 return FALSE;
158
159 return TRUE;
160 }
161
162 /**
163 * @brief This method requests a list (mask) of the phys contained in the
164 * supplied SAS port.
165 *
166 * @param[in] this_port a handle corresponding to the SAS port for which
167 * to return the phy mask.
168 *
169 * @return Return a bit mask indicating which phys are a part of this port.
170 * Each bit corresponds to a phy identifier (e.g. bit 0 = phy id 0).
171 */
scic_sds_port_get_phys(SCIC_SDS_PORT_T * this_port)172 U32 scic_sds_port_get_phys(
173 SCIC_SDS_PORT_T * this_port
174 )
175 {
176 U32 index;
177 U32 mask;
178
179 SCIC_LOG_TRACE((
180 sci_base_object_get_logger(this_port),
181 SCIC_LOG_OBJECT_PORT,
182 "scic_sds_port_get_phys(0x%x) enter\n",
183 this_port
184 ));
185
186 mask = 0;
187
188 for (index = 0; index < SCI_MAX_PHYS; index++)
189 {
190 if (this_port->phy_table[index] != NULL)
191 {
192 mask |= (1 << index);
193 }
194 }
195
196 return mask;
197 }
198
199 /**
200 * This method will return a TRUE value if the port's phy mask can be
201 * supported by the SCU.
202 *
203 * The following is a list of valid PHY mask configurations for each
204 * port:
205 * - Port 0 - [[3 2] 1] 0
206 * - Port 1 - [1]
207 * - Port 2 - [[3] 2]
208 * - Port 3 - [3]
209 *
210 * @param[in] this_port This is the port object for which to determine
211 * if the phy mask can be supported.
212 *
213 * @return This method returns a boolean indication specifying if the
214 * phy mask can be supported.
215 * @retval TRUE if this is a valid phy assignment for the port
216 * @retval FALSE if this is not a valid phy assignment for the port
217 */
scic_sds_port_is_phy_mask_valid(SCIC_SDS_PORT_T * this_port,U32 phy_mask)218 BOOL scic_sds_port_is_phy_mask_valid(
219 SCIC_SDS_PORT_T *this_port,
220 U32 phy_mask
221 )
222 {
223 if (this_port->physical_port_index == 0)
224 {
225 if ( ((phy_mask & 0x0F) == 0x0F)
226 || ((phy_mask & 0x03) == 0x03)
227 || ((phy_mask & 0x01) == 0x01)
228 || (phy_mask == 0) )
229 return TRUE;
230 }
231 else if (this_port->physical_port_index == 1)
232 {
233 if ( ((phy_mask & 0x02) == 0x02)
234 || (phy_mask == 0) )
235 return TRUE;
236 }
237 else if (this_port->physical_port_index == 2)
238 {
239 if ( ((phy_mask & 0x0C) == 0x0C)
240 || ((phy_mask & 0x04) == 0x04)
241 || (phy_mask == 0) )
242 return TRUE;
243 }
244 else if (this_port->physical_port_index == 3)
245 {
246 if ( ((phy_mask & 0x08) == 0x08)
247 || (phy_mask == 0) )
248 return TRUE;
249 }
250
251 return FALSE;
252 }
253
254 /**
255 * This method retrieves a currently active (i.e. connected) phy
256 * contained in the port. Currently, the lowest order phy that is
257 * connected is returned.
258 *
259 * @param[in] this_port This parameter specifies the port from which
260 * to return a connected phy.
261 *
262 * @return This method returns a pointer to a SCIS_SDS_PHY object.
263 * @retval NULL This value is returned if there are no currently
264 * active (i.e. connected to a remote end point) phys
265 * contained in the port.
266 * @retval All other values specify a SCIC_SDS_PHY object that is
267 * active in the port.
268 */
scic_sds_port_get_a_connected_phy(SCIC_SDS_PORT_T * this_port)269 SCIC_SDS_PHY_T * scic_sds_port_get_a_connected_phy(
270 SCIC_SDS_PORT_T *this_port
271 )
272 {
273 U32 index;
274 SCIC_SDS_PHY_T *phy;
275
276 for (index = 0; index < SCI_MAX_PHYS; index++)
277 {
278 // Ensure that the phy is both part of the port and currently
279 // connected to the remote end-point.
280 phy = this_port->phy_table[index];
281 if (
282 (phy != NULL)
283 && scic_sds_port_active_phy(this_port, phy)
284 )
285 {
286 return phy;
287 }
288 }
289
290 return NULL;
291 }
292
293 /**
294 * This method attempts to make the assignment of the phy to the port.
295 * If successful the phy is assigned to the ports phy table.
296 *
297 * @param[in, out] port The port object to which the phy assignement
298 * is being made.
299 * @param[in, out] phy The phy which is being assigned to the port.
300 *
301 * @return BOOL
302 * @retval TRUE if the phy assignment can be made.
303 * @retval FALSE if the phy assignement can not be made.
304 *
305 * @note This is a functional test that only fails if the phy is currently
306 * assigned to a different port.
307 */
scic_sds_port_set_phy(SCIC_SDS_PORT_T * port,SCIC_SDS_PHY_T * phy)308 SCI_STATUS scic_sds_port_set_phy(
309 SCIC_SDS_PORT_T *port,
310 SCIC_SDS_PHY_T *phy
311 )
312 {
313 // Check to see if we can add this phy to a port
314 // that means that the phy is not part of a port and that the port does
315 // not already have a phy assigned to the phy index.
316 if (
317 (port->phy_table[phy->phy_index] == SCI_INVALID_HANDLE)
318 && (scic_sds_phy_get_port(phy) == SCI_INVALID_HANDLE)
319 && scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)
320 )
321 {
322 // Phy is being added in the stopped state so we are in MPC mode
323 // make logical port index = physical port index
324 port->logical_port_index = port->physical_port_index;
325 port->phy_table[phy->phy_index] = phy;
326 scic_sds_phy_set_port(phy, port);
327
328 return SCI_SUCCESS;
329 }
330
331 return SCI_FAILURE;
332 }
333
334 /**
335 * This method will clear the phy assigned to this port. This method fails
336 * if this phy is not currently assigned to this port.
337 *
338 * @param[in, out] port The port from which the phy is being cleared.
339 * @param[in, out] phy The phy being cleared from the port.
340 *
341 * @return BOOL
342 * @retval TRUE if the phy is removed from the port.
343 * @retval FALSE if this phy is not assined to this port.
344 */
scic_sds_port_clear_phy(SCIC_SDS_PORT_T * port,SCIC_SDS_PHY_T * phy)345 SCI_STATUS scic_sds_port_clear_phy(
346 SCIC_SDS_PORT_T *port,
347 SCIC_SDS_PHY_T *phy
348 )
349 {
350 // Make sure that this phy is part of this port
351 if (
352 (port->phy_table[phy->phy_index] == phy)
353 && (scic_sds_phy_get_port(phy) == port)
354 )
355 {
356 // Yep it is assigned to this port so remove it
357 scic_sds_phy_set_port(
358 phy,
359 &scic_sds_port_get_controller(port)->port_table[SCI_MAX_PORTS]
360 );
361
362 port->phy_table[phy->phy_index] = SCI_INVALID_HANDLE;
363
364 return SCI_SUCCESS;
365 }
366
367 return SCI_FAILURE;
368 }
369
370 /**
371 * This method will add a PHY to the selected port.
372 *
373 * @param[in] this_port This parameter specifies the port in which the phy will
374 * be added.
375 *
376 * @param[in] the_phy This parameter is the phy which is to be added to the
377 * port.
378 *
379 * @return This method returns an SCI_STATUS.
380 * @retval SCI_SUCCESS the phy has been added to the port.
381 * @retval Any other status is failre to add the phy to the port.
382 */
scic_sds_port_add_phy(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy)383 SCI_STATUS scic_sds_port_add_phy(
384 SCIC_SDS_PORT_T * this_port,
385 SCIC_SDS_PHY_T * the_phy
386 )
387 {
388 return this_port->state_handlers->parent.add_phy_handler(
389 &this_port->parent, &the_phy->parent);
390 }
391
392
393 /**
394 * This method will remove the PHY from the selected PORT.
395 *
396 * @param[in] this_port This parameter specifies the port in which the phy will
397 * be added.
398 *
399 * @param[in] the_phy This parameter is the phy which is to be added to the
400 * port.
401 *
402 * @return This method returns an SCI_STATUS.
403 * @retval SCI_SUCCESS the phy has been removed from the port.
404 * @retval Any other status is failre to add the phy to the port.
405 */
scic_sds_port_remove_phy(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy)406 SCI_STATUS scic_sds_port_remove_phy(
407 SCIC_SDS_PORT_T * this_port,
408 SCIC_SDS_PHY_T * the_phy
409 )
410 {
411 return this_port->state_handlers->parent.remove_phy_handler(
412 &this_port->parent, &the_phy->parent);
413 }
414
415 /**
416 * @brief This method requests the SAS address for the supplied SAS port
417 * from the SCI implementation.
418 *
419 * @param[in] this_port a handle corresponding to the SAS port for which
420 * to return the SAS address.
421 * @param[out] sas_address This parameter specifies a pointer to a SAS
422 * address structure into which the core will copy the SAS
423 * address for the port.
424 *
425 * @return none
426 */
scic_sds_port_get_sas_address(SCIC_SDS_PORT_T * this_port,SCI_SAS_ADDRESS_T * sas_address)427 void scic_sds_port_get_sas_address(
428 SCIC_SDS_PORT_T * this_port,
429 SCI_SAS_ADDRESS_T * sas_address
430 )
431 {
432 U32 index;
433
434 SCIC_LOG_TRACE((
435 sci_base_object_get_logger(this_port),
436 SCIC_LOG_OBJECT_PORT,
437 "scic_sds_port_get_sas_address(0x%x, 0x%x) enter\n",
438 this_port, sas_address
439 ));
440
441 sas_address->high = 0;
442 sas_address->low = 0;
443
444 for (index = 0; index < SCI_MAX_PHYS; index++)
445 {
446 if (this_port->phy_table[index] != NULL)
447 {
448 scic_sds_phy_get_sas_address(this_port->phy_table[index], sas_address);
449 }
450 }
451 }
452
453 /**
454 * @brief This method will indicate which protocols are supported by this
455 * port.
456 *
457 * @param[in] this_port a handle corresponding to the SAS port for which
458 * to return the supported protocols.
459 * @param[out] protocols This parameter specifies a pointer to an IAF
460 * protocol field structure into which the core will copy
461 * the protocol values for the port. The values are
462 * returned as part of a bit mask in order to allow for
463 * multi-protocol support.
464 *
465 * @return none
466 */
467 static
scic_sds_port_get_protocols(SCIC_SDS_PORT_T * this_port,SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols)468 void scic_sds_port_get_protocols(
469 SCIC_SDS_PORT_T * this_port,
470 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
471 )
472 {
473 U8 index;
474
475 SCIC_LOG_TRACE((
476 sci_base_object_get_logger(this_port),
477 SCIC_LOG_OBJECT_PORT,
478 "scic_sds_port_get_protocols(0x%x, 0x%x) enter\n",
479 this_port, protocols
480 ));
481
482 protocols->u.all = 0;
483
484 for (index = 0; index < SCI_MAX_PHYS; index++)
485 {
486 if (this_port->phy_table[index] != NULL)
487 {
488 scic_sds_phy_get_protocols(this_port->phy_table[index], protocols);
489 }
490 }
491 }
492
493 /**
494 * @brief This method requests the SAS address for the device directly
495 * attached to this SAS port.
496 *
497 * @param[in] this_port a handle corresponding to the SAS port for which
498 * to return the SAS address.
499 * @param[out] sas_address This parameter specifies a pointer to a SAS
500 * address structure into which the core will copy the SAS
501 * address for the device directly attached to the port.
502 *
503 * @return none
504 */
scic_sds_port_get_attached_sas_address(SCIC_SDS_PORT_T * this_port,SCI_SAS_ADDRESS_T * sas_address)505 void scic_sds_port_get_attached_sas_address(
506 SCIC_SDS_PORT_T * this_port,
507 SCI_SAS_ADDRESS_T * sas_address
508 )
509 {
510 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
511 SCIC_SDS_PHY_T *phy;
512
513 SCIC_LOG_TRACE((
514 sci_base_object_get_logger(this_port),
515 SCIC_LOG_OBJECT_PORT,
516 "scic_sds_port_get_attached_sas_address(0x%x, 0x%x) enter\n",
517 this_port, sas_address
518 ));
519
520 // Ensure that the phy is both part of the port and currently
521 // connected to the remote end-point.
522 phy = scic_sds_port_get_a_connected_phy(this_port);
523 if (phy != NULL)
524 {
525 scic_sds_phy_get_attached_phy_protocols(phy, &protocols);
526
527 if (!protocols.u.bits.stp_target)
528 {
529 scic_sds_phy_get_attached_sas_address(phy, sas_address);
530 }
531 else
532 {
533 scic_sds_phy_get_sas_address(phy, sas_address);
534 sas_address->low += phy->phy_index;
535
536 //Need to make up attached STP device's SAS address in
537 //the same order as recorded IAF from SSP device.
538 sas_address->high = SCIC_SWAP_DWORD(sas_address->high);
539 sas_address->low = SCIC_SWAP_DWORD(sas_address->low);
540 }
541 }
542 else
543 {
544 sas_address->high = 0;
545 sas_address->low = 0;
546 }
547 }
548
549 /**
550 * @brief This method will indicate which protocols are supported by this
551 * remote device.
552 *
553 * @param[in] this_port a handle corresponding to the SAS port for which
554 * to return the supported protocols.
555 * @param[out] protocols This parameter specifies a pointer to an IAF
556 * protocol field structure into which the core will copy
557 * the protocol values for the port. The values are
558 * returned as part of a bit mask in order to allow for
559 * multi-protocol support.
560 *
561 * @return none
562 */
scic_sds_port_get_attached_protocols(SCIC_SDS_PORT_T * this_port,SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols)563 void scic_sds_port_get_attached_protocols(
564 SCIC_SDS_PORT_T * this_port,
565 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T * protocols
566 )
567 {
568 SCIC_SDS_PHY_T *phy;
569
570 SCIC_LOG_TRACE((
571 sci_base_object_get_logger(this_port),
572 SCIC_LOG_OBJECT_PORT,
573 "scic_sds_port_get_attached_protocols(0x%x, 0x%x) enter\n",
574 this_port, protocols
575 ));
576
577 // Ensure that the phy is both part of the port and currently
578 // connected to the remote end-point.
579 phy = scic_sds_port_get_a_connected_phy(this_port);
580 if (phy != NULL)
581 scic_sds_phy_get_attached_phy_protocols(phy, protocols);
582 else
583 protocols->u.all = 0;
584 }
585
586 /**
587 * @brief This method returns the amount of memory required for a port
588 * object.
589 *
590 * @return U32
591 */
scic_sds_port_get_object_size(void)592 U32 scic_sds_port_get_object_size(void)
593 {
594 return sizeof(SCIC_SDS_PORT_T);
595 }
596
597 /**
598 * @brief This method returns the minimum number of timers required for all
599 * port objects.
600 *
601 * @return U32
602 */
scic_sds_port_get_min_timer_count(void)603 U32 scic_sds_port_get_min_timer_count(void)
604 {
605 return SCIC_SDS_PORT_MIN_TIMER_COUNT;
606 }
607
608 /**
609 * @brief This method returns the maximum number of timers required for all
610 * port objects.
611 *
612 * @return U32
613 */
scic_sds_port_get_max_timer_count(void)614 U32 scic_sds_port_get_max_timer_count(void)
615 {
616 return SCIC_SDS_PORT_MAX_TIMER_COUNT;
617 }
618
619 #ifdef SCI_LOGGING
scic_sds_port_initialize_state_logging(SCIC_SDS_PORT_T * this_port)620 void scic_sds_port_initialize_state_logging(
621 SCIC_SDS_PORT_T *this_port
622 )
623 {
624 sci_base_state_machine_logger_initialize(
625 &this_port->parent.state_machine_logger,
626 &this_port->parent.state_machine,
627 &this_port->parent.parent,
628 scic_cb_logger_log_states,
629 "SCIC_SDS_PORT_T", "base state machine",
630 SCIC_LOG_OBJECT_PORT
631 );
632
633 sci_base_state_machine_logger_initialize(
634 &this_port->ready_substate_machine_logger,
635 &this_port->ready_substate_machine,
636 &this_port->parent.parent,
637 scic_cb_logger_log_states,
638 "SCIC_SDS_PORT_T", "ready substate machine",
639 SCIC_LOG_OBJECT_PORT
640 );
641 }
642 #endif
643
644 /**
645 * This routine will construct a dummy remote node context data structure
646 * This structure will be posted to the hardware to work around a scheduler
647 * error in the hardware.
648 *
649 * @param[in] this_port The logical port on which we need to create the
650 * remote node context.
651 * @param[in] rni The remote node index for this remote node context.
652 *
653 * @return none
654 */
655 static
scic_sds_port_construct_dummy_rnc(SCIC_SDS_PORT_T * this_port,U16 rni)656 void scic_sds_port_construct_dummy_rnc(
657 SCIC_SDS_PORT_T *this_port,
658 U16 rni
659 )
660 {
661 SCU_REMOTE_NODE_CONTEXT_T * rnc;
662
663 rnc = &(this_port->owning_controller->remote_node_context_table[rni]);
664
665 memset(rnc, 0, sizeof(SCU_REMOTE_NODE_CONTEXT_T));
666
667 rnc->ssp.remote_sas_address_hi = 0;
668 rnc->ssp.remote_sas_address_lo = 0;
669
670 rnc->ssp.remote_node_index = rni;
671 rnc->ssp.remote_node_port_width = 1;
672 rnc->ssp.logical_port_index = this_port->physical_port_index;
673
674 rnc->ssp.nexus_loss_timer_enable = FALSE;
675 rnc->ssp.check_bit = FALSE;
676 rnc->ssp.is_valid = TRUE;
677 rnc->ssp.is_remote_node_context = TRUE;
678 rnc->ssp.function_number = 0;
679 rnc->ssp.arbitration_wait_time = 0;
680 }
681
682 /**
683 * This routine will construct a dummy task context data structure. This
684 * structure will be posted to the hardwre to work around a scheduler error
685 * in the hardware.
686 *
687 * @param[in] this_port The logical port on which we need to create the
688 * remote node context.
689 * context.
690 * @param[in] tci The remote node index for this remote node context.
691 *
692 */
693 static
scic_sds_port_construct_dummy_task(SCIC_SDS_PORT_T * this_port,U16 tci)694 void scic_sds_port_construct_dummy_task(
695 SCIC_SDS_PORT_T *this_port,
696 U16 tci
697 )
698 {
699 SCU_TASK_CONTEXT_T * task_context;
700
701 task_context = scic_sds_controller_get_task_context_buffer(this_port->owning_controller, tci);
702
703 memset(task_context, 0, sizeof(SCU_TASK_CONTEXT_T));
704
705 task_context->abort = 0;
706 task_context->priority = 0;
707 task_context->initiator_request = 1;
708 task_context->connection_rate = 1;
709 task_context->protocol_engine_index = 0;
710 task_context->logical_port_index = this_port->physical_port_index;
711 task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP;
712 task_context->task_index = scic_sds_io_tag_get_index(tci);
713 task_context->valid = SCU_TASK_CONTEXT_VALID;
714 task_context->context_type = SCU_TASK_CONTEXT_TYPE;
715
716 task_context->remote_node_index = this_port->reserved_rni;
717 task_context->command_code = 0;
718
719 task_context->link_layer_control = 0;
720 task_context->do_not_dma_ssp_good_response = 1;
721 task_context->strict_ordering = 0;
722 task_context->control_frame = 0;
723 task_context->timeout_enable = 0;
724 task_context->block_guard_enable = 0;
725
726 task_context->address_modifier = 0;
727
728 task_context->task_phase = 0x01;
729 }
730
731 /**
732 * This routine will free any allocated dummy resources for this port.
733 *
734 * @param[in, out] this_port The port on which the resources are being destroyed.
735 */
736 static
scic_sds_port_destroy_dummy_resources(SCIC_SDS_PORT_T * this_port)737 void scic_sds_port_destroy_dummy_resources(
738 SCIC_SDS_PORT_T * this_port
739 )
740 {
741 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
742 {
743 scic_controller_free_io_tag(
744 this_port->owning_controller, this_port->reserved_tci
745 );
746 }
747
748 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
749 {
750 scic_sds_remote_node_table_release_remote_node_index(
751 &this_port->owning_controller->available_remote_nodes, 1, this_port->reserved_rni
752 );
753 }
754
755 this_port->reserved_rni = SCU_DUMMY_INDEX;
756 this_port->reserved_tci = SCU_DUMMY_INDEX;
757 }
758
759 /**
760 * @brief
761 *
762 * @param[in] this_port
763 * @param[in] port_index
764 * @param[in] owning_controller
765 */
scic_sds_port_construct(SCIC_SDS_PORT_T * this_port,U8 port_index,SCIC_SDS_CONTROLLER_T * owning_controller)766 void scic_sds_port_construct(
767 SCIC_SDS_PORT_T *this_port,
768 U8 port_index,
769 SCIC_SDS_CONTROLLER_T *owning_controller
770 )
771 {
772 U32 index;
773
774 sci_base_port_construct(
775 &this_port->parent,
776 sci_base_object_get_logger(owning_controller),
777 scic_sds_port_state_table
778 );
779
780 sci_base_state_machine_construct(
781 scic_sds_port_get_ready_substate_machine(this_port),
782 &this_port->parent.parent,
783 scic_sds_port_ready_substate_table,
784 SCIC_SDS_PORT_READY_SUBSTATE_WAITING
785 );
786
787 scic_sds_port_initialize_state_logging(this_port);
788
789 this_port->logical_port_index = SCIC_SDS_DUMMY_PORT;
790 this_port->physical_port_index = port_index;
791 this_port->active_phy_mask = 0;
792 this_port->enabled_phy_mask = 0;
793 this_port->owning_controller = owning_controller;
794
795 this_port->started_request_count = 0;
796 this_port->assigned_device_count = 0;
797
798 this_port->reserved_rni = SCU_DUMMY_INDEX;
799 this_port->reserved_tci = SCU_DUMMY_INDEX;
800
801 this_port->timer_handle = SCI_INVALID_HANDLE;
802
803 this_port->port_task_scheduler_registers = NULL;
804
805 for (index = 0; index < SCI_MAX_PHYS; index++)
806 {
807 this_port->phy_table[index] = NULL;
808 }
809 }
810
811 /**
812 * @brief This method performs initialization of the supplied port.
813 * Initialization includes:
814 * - state machine initialization
815 * - member variable initialization
816 * - configuring the phy_mask
817 *
818 * @param[in] this_port
819 * @param[in] transport_layer_registers
820 * @param[in] port_task_scheduler_registers
821 * @param[in] port_configuration_regsiter
822 *
823 * @return SCI_STATUS
824 * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This value is
825 * returned if the phy being added to the port
826 */
scic_sds_port_initialize(SCIC_SDS_PORT_T * this_port,void * port_task_scheduler_registers,void * port_configuration_regsiter,void * viit_registers)827 SCI_STATUS scic_sds_port_initialize(
828 SCIC_SDS_PORT_T *this_port,
829 void *port_task_scheduler_registers,
830 void *port_configuration_regsiter,
831 void *viit_registers
832 )
833 {
834 this_port->port_task_scheduler_registers = port_task_scheduler_registers;
835 this_port->port_pe_configuration_register = port_configuration_regsiter;
836 this_port->viit_registers = viit_registers;
837
838 return SCI_SUCCESS;
839 }
840
841 /**
842 * This method is the a general link up handler for the SCIC_SDS_PORT object.
843 * This function will determine if this SCIC_SDS_PHY can
844 * be assigned to this SCIC_SDS_PORT object. If the SCIC_SDS_PHY object can
845 * is not a valid PHY for this port then the function will notify the SCIC_USER.
846 * A PHY can only be part of a port if it's attached SAS ADDRESS is the same as
847 * all other PHYs in the same port.
848 *
849 * @param[in] this_port This is the SCIC_SDS_PORT object for which has a phy
850 * that has gone link up.
851 * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
852 * @param[in] do_notify_user This parameter specifies whether to inform
853 * the user (via scic_cb_port_link_up()) as to the fact that
854 * a new phy as become ready.
855 * @param[in] do_resume_phy This parameter specifies whether to resume the phy.
856 * If this function is called from MPC mode, it will be always true.
857 * for APC, this will be false, so that phys could be resumed later
858 *
859 * @return none
860 */
scic_sds_port_general_link_up_handler(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy,BOOL do_notify_user,BOOL do_resume_phy)861 void scic_sds_port_general_link_up_handler(
862 SCIC_SDS_PORT_T * this_port,
863 SCIC_SDS_PHY_T * the_phy,
864 BOOL do_notify_user,
865 BOOL do_resume_phy
866 )
867 {
868 SCI_SAS_ADDRESS_T port_sas_address;
869 SCI_SAS_ADDRESS_T phy_sas_address;
870
871 scic_sds_port_get_attached_sas_address(this_port, &port_sas_address);
872 scic_sds_phy_get_attached_sas_address(the_phy, &phy_sas_address);
873
874 // If the SAS address of the new phy matches the SAS address of
875 // other phys in the port OR this is the first phy in the port,
876 // then activate the phy and allow it to be used for operations
877 // in this port.
878 if (
879 (
880 (phy_sas_address.high == port_sas_address.high)
881 && (phy_sas_address.low == port_sas_address.low )
882 )
883 || (this_port->active_phy_mask == 0)
884 )
885 {
886 scic_sds_port_activate_phy(this_port, the_phy, do_notify_user, do_resume_phy);
887
888 if (this_port->parent.state_machine.current_state_id
889 == SCI_BASE_PORT_STATE_RESETTING)
890 {
891 sci_base_state_machine_change_state(
892 &this_port->parent.state_machine, SCI_BASE_PORT_STATE_READY
893 );
894 }
895 }
896 else
897 {
898 scic_sds_port_invalid_link_up(this_port, the_phy);
899 }
900 }
901
902 // ---------------------------------------------------------------------------
903
scic_port_add_phy(SCI_PORT_HANDLE_T handle,SCI_PHY_HANDLE_T phy)904 SCI_STATUS scic_port_add_phy(
905 SCI_PORT_HANDLE_T handle,
906 SCI_PHY_HANDLE_T phy
907 )
908 {
909 #if defined (SCI_LOGGING)
910 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)handle;
911 #endif // defined (SCI_LOGGING)
912
913 SCIC_LOG_TRACE((
914 sci_base_object_get_logger(this_port),
915 SCIC_LOG_OBJECT_PORT,
916 "scic_port_add_phy(0x%x, 0x%x) enter\n",
917 handle, phy
918 ));
919
920 SCIC_LOG_ERROR((
921 sci_base_object_get_logger(this_port),
922 SCIC_LOG_OBJECT_PORT,
923 "Interface function scic_port_add_phy() has been deprecated. "
924 "PORT configuration is handled through the OEM parameters.\n"
925 ));
926
927 return SCI_FAILURE_ADDING_PHY_UNSUPPORTED;
928
929 }
930
931 // ---------------------------------------------------------------------------
932
scic_port_remove_phy(SCI_PORT_HANDLE_T handle,SCI_PHY_HANDLE_T phy)933 SCI_STATUS scic_port_remove_phy(
934 SCI_PORT_HANDLE_T handle,
935 SCI_PHY_HANDLE_T phy
936 )
937 {
938 #if defined (SCI_LOGGING)
939 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)handle;
940 #endif // defined (SCI_LOGGING)
941
942 SCIC_LOG_TRACE((
943 sci_base_object_get_logger(this_port),
944 SCIC_LOG_OBJECT_PORT,
945 "scic_port_remove_phy(0x%x, 0x%x) enter\n",
946 handle, phy
947 ));
948
949 SCIC_LOG_ERROR((
950 sci_base_object_get_logger(this_port),
951 SCIC_LOG_OBJECT_PORT,
952 "Interface function scic_port_remove_phy() has been deprecated. "
953 "PORT configuration is handled through the OEM parameters.\n"
954 ));
955
956 return SCI_FAILURE_ADDING_PHY_UNSUPPORTED;
957 }
958
959 // ---------------------------------------------------------------------------
960
scic_port_get_properties(SCI_PORT_HANDLE_T port,SCIC_PORT_PROPERTIES_T * properties)961 SCI_STATUS scic_port_get_properties(
962 SCI_PORT_HANDLE_T port,
963 SCIC_PORT_PROPERTIES_T * properties
964 )
965 {
966 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
967
968 SCIC_LOG_TRACE((
969 sci_base_object_get_logger(this_port),
970 SCIC_LOG_OBJECT_PORT,
971 "scic_port_get_properties(0x%x, 0x%x) enter\n",
972 port, properties
973 ));
974
975 if (
976 (port == SCI_INVALID_HANDLE)
977 || (this_port->logical_port_index == SCIC_SDS_DUMMY_PORT)
978 )
979 {
980 return SCI_FAILURE_INVALID_PORT;
981 }
982
983 properties->index = this_port->logical_port_index;
984 properties->phy_mask = scic_sds_port_get_phys(this_port);
985 scic_sds_port_get_sas_address(this_port, &properties->local.sas_address);
986 scic_sds_port_get_protocols(this_port, &properties->local.protocols);
987 scic_sds_port_get_attached_sas_address(this_port, &properties->remote.sas_address);
988 scic_sds_port_get_attached_protocols(this_port, &properties->remote.protocols);
989
990 return SCI_SUCCESS;
991 }
992
993 // ---------------------------------------------------------------------------
994
scic_port_hard_reset(SCI_PORT_HANDLE_T handle,U32 reset_timeout)995 SCI_STATUS scic_port_hard_reset(
996 SCI_PORT_HANDLE_T handle,
997 U32 reset_timeout
998 )
999 {
1000 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)handle;
1001
1002 SCIC_LOG_TRACE((
1003 sci_base_object_get_logger(this_port),
1004 SCIC_LOG_OBJECT_PORT,
1005 "scic_port_hard_reset(0x%x, 0x%x) enter\n",
1006 handle, reset_timeout
1007 ));
1008
1009 return this_port->state_handlers->parent.reset_handler(
1010 &this_port->parent,
1011 reset_timeout
1012 );
1013 }
1014
1015 /**
1016 * This method assigns the direct attached device ID for this port.
1017 *
1018 * @param[in] this_port The port for which the direct attached device id is to
1019 * be assigned.
1020 * @param[in] device_id The direct attached device ID to assign to the port.
1021 * This will be the RNi for the device
1022 */
scic_sds_port_setup_transports(SCIC_SDS_PORT_T * this_port,U32 device_id)1023 void scic_sds_port_setup_transports(
1024 SCIC_SDS_PORT_T * this_port,
1025 U32 device_id
1026 )
1027 {
1028 U8 index;
1029
1030 for (index = 0; index < SCI_MAX_PHYS; index++)
1031 {
1032 if (this_port->active_phy_mask & (1 << index))
1033 {
1034 scic_sds_phy_setup_transport(this_port->phy_table[index], device_id);
1035 }
1036 }
1037 }
1038
1039 /**
1040 * This method will resume the phy which is already added in the port.
1041 * Activation includes:
1042 * - enabling the Protocol Engine in the silicon.
1043 * - update the reay mask.
1044 *
1045 * @param[in] this_port This is the port on which the phy should be enabled.
1046 * @return none
1047 */
1048 static
scic_sds_port_resume_phy(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy)1049 void scic_sds_port_resume_phy(
1050 SCIC_SDS_PORT_T * this_port,
1051 SCIC_SDS_PHY_T * the_phy
1052 )
1053 {
1054 scic_sds_phy_resume (the_phy);
1055 this_port->enabled_phy_mask |= 1 << the_phy->phy_index;
1056 }
1057 /**
1058 * This method will activate the phy in the port.
1059 * Activation includes:
1060 * - adding the phy to the port
1061 * - enabling the Protocol Engine in the silicon.
1062 * - notifying the user that the link is up.
1063 *
1064 * @param[in] this_port This is the port on which the phy should be enabled.
1065 * @param[in] the_phy This is the specific phy which to enable.
1066 * @param[in] do_notify_user This parameter specifies whether to inform
1067 * the user (via scic_cb_port_link_up()) as to the fact that
1068 * a new phy as become ready.
1069 * @param[in] do_resume_phy This parameter specifies whether to resume the phy.
1070 * If this function is called from MPC mode, it will be always true.
1071 * for APC, this will be false, so that phys could be resumed later
1072 *
1073
1074 * @return none
1075 */
scic_sds_port_activate_phy(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy,BOOL do_notify_user,BOOL do_resume_phy)1076 void scic_sds_port_activate_phy(
1077 SCIC_SDS_PORT_T * this_port,
1078 SCIC_SDS_PHY_T * the_phy,
1079 BOOL do_notify_user,
1080 BOOL do_resume_phy
1081 )
1082 {
1083 SCIC_SDS_CONTROLLER_T * controller;
1084 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
1085
1086 SCIC_LOG_TRACE((
1087 sci_base_object_get_logger(this_port),
1088 SCIC_LOG_OBJECT_PORT,
1089 "scic_sds_port_activate_phy(0x%x,0x%x,0x%x) enter\n",
1090 this_port, the_phy, do_notify_user
1091 ));
1092
1093 controller = scic_sds_port_get_controller(this_port);
1094 scic_sds_phy_get_attached_phy_protocols(the_phy, &protocols);
1095
1096 // If this is sata port then the phy has already been resumed
1097 if (!protocols.u.bits.stp_target)
1098 {
1099 if (do_resume_phy == TRUE)
1100 {
1101 scic_sds_port_resume_phy(this_port, the_phy);
1102 }
1103 }
1104
1105 this_port->active_phy_mask |= 1 << the_phy->phy_index;
1106
1107 scic_sds_controller_clear_invalid_phy(controller, the_phy);
1108
1109 if (do_notify_user == TRUE)
1110 scic_cb_port_link_up(this_port->owning_controller, this_port, the_phy);
1111 }
1112
1113 /**
1114 * This method will deactivate the supplied phy in the port.
1115 *
1116 * @param[in] this_port This is the port on which the phy should be
1117 * deactivated.
1118 * @param[in] the_phy This is the specific phy that is no longer
1119 * active in the port.
1120 * @param[in] do_notify_user This parameter specifies whether to inform
1121 * the user (via scic_cb_port_link_down()) as to the fact that
1122 * a new phy as become ready.
1123 *
1124 * @return none
1125 */
scic_sds_port_deactivate_phy(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy,BOOL do_notify_user)1126 void scic_sds_port_deactivate_phy(
1127 SCIC_SDS_PORT_T * this_port,
1128 SCIC_SDS_PHY_T * the_phy,
1129 BOOL do_notify_user
1130 )
1131 {
1132 SCIC_LOG_TRACE((
1133 sci_base_object_get_logger(this_port),
1134 SCIC_LOG_OBJECT_PORT,
1135 "scic_sds_port_deactivate_phy(0x%x,0x%x,0x%x) enter\n",
1136 this_port, the_phy, do_notify_user
1137 ));
1138
1139 this_port->active_phy_mask &= ~(1 << the_phy->phy_index);
1140 this_port->enabled_phy_mask &= ~(1 << the_phy->phy_index);
1141
1142 the_phy->max_negotiated_speed = SCI_SAS_NO_LINK_RATE;
1143
1144 // Re-assign the phy back to the LP as if it were a narrow port for APC mode.
1145 // For MPC mode, the phy will remain in the port
1146 if (this_port->owning_controller->oem_parameters.sds1.controller.mode_type
1147 == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE)
1148 {
1149 SCU_PCSPExCR_WRITE(this_port, the_phy->phy_index, the_phy->phy_index);
1150 }
1151
1152 if (do_notify_user == TRUE)
1153 scic_cb_port_link_down(this_port->owning_controller, this_port, the_phy);
1154 }
1155
1156 /**
1157 * This method will disable the phy and report that the phy is not valid for this
1158 * port object.
1159 *
1160 * @param[in] this_port This is the port on which the phy should be disabled.
1161 * @param[in] the_phy This is the specific phy which to disabled.
1162 *
1163 * @return None
1164 */
scic_sds_port_invalid_link_up(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy)1165 void scic_sds_port_invalid_link_up(
1166 SCIC_SDS_PORT_T * this_port,
1167 SCIC_SDS_PHY_T * the_phy
1168 )
1169 {
1170 SCIC_SDS_CONTROLLER_T * controller = scic_sds_port_get_controller(this_port);
1171
1172 // Check to see if we have alreay reported this link as bad and if not go
1173 // ahead and tell the SCI_USER that we have discovered an invalid link.
1174 if ((controller->invalid_phy_mask & (1 << the_phy->phy_index)) == 0)
1175 {
1176 scic_sds_controller_set_invalid_phy(controller, the_phy);
1177
1178 scic_cb_port_invalid_link_up(controller, this_port, the_phy);
1179 }
1180 }
1181
1182 /**
1183 * @brief This method returns FALSE if the port only has a single phy object
1184 * assigned. If there are no phys or more than one phy then the
1185 * method will return TRUE.
1186 *
1187 * @param[in] this_port The port for which the wide port condition is to be
1188 * checked.
1189 *
1190 * @return BOOL
1191 * @retval TRUE Is returned if this is a wide ported port.
1192 * @retval FALSE Is returned if this is a narrow port.
1193 */
1194 static
scic_sds_port_is_wide(SCIC_SDS_PORT_T * this_port)1195 BOOL scic_sds_port_is_wide(
1196 SCIC_SDS_PORT_T *this_port
1197 )
1198 {
1199 U32 index;
1200 U32 phy_count = 0;
1201
1202 for (index = 0; index < SCI_MAX_PHYS; index++)
1203 {
1204 if (this_port->phy_table[index] != NULL)
1205 {
1206 phy_count++;
1207 }
1208 }
1209
1210 return (phy_count != 1);
1211 }
1212
1213 /**
1214 * @brief This method is called by the PHY object when the link is detected.
1215 * if the port wants the PHY to continue on to the link up state then
1216 * the port layer must return TRUE. If the port object returns FALSE
1217 * the phy object must halt its attempt to go link up.
1218 *
1219 * @param[in] this_port The port associated with the phy object.
1220 * @param[in] the_phy The phy object that is trying to go link up.
1221 *
1222 * @return TRUE if the phy object can continue to the link up condition.
1223 * @retval TRUE Is returned if this phy can continue to the ready state.
1224 * @retval FALSE Is returned if can not continue on to the ready state.
1225 *
1226 * @note This notification is in place for wide ports and direct attached
1227 * phys. Since there are no wide ported SATA devices this could
1228 * become an invalid port configuration.
1229 */
scic_sds_port_link_detected(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy)1230 BOOL scic_sds_port_link_detected(
1231 SCIC_SDS_PORT_T *this_port,
1232 SCIC_SDS_PHY_T *the_phy
1233 )
1234 {
1235 SCI_SAS_IDENTIFY_ADDRESS_FRAME_PROTOCOLS_T protocols;
1236
1237 scic_sds_phy_get_attached_phy_protocols(the_phy, &protocols);
1238
1239 if (
1240 (this_port->logical_port_index != SCIC_SDS_DUMMY_PORT)
1241 && (protocols.u.bits.stp_target)
1242 )
1243 {
1244 if (scic_sds_port_is_wide(this_port))
1245 {
1246 //direct attached Sata phy cannot be in wide port.
1247 scic_sds_port_invalid_link_up( this_port, the_phy);
1248 return FALSE;
1249 }
1250 else
1251 {
1252 SCIC_SDS_PORT_T *destination_port = &(this_port->owning_controller->port_table[the_phy->phy_index]);
1253
1254 //add the phy to the its logical port for direct attached SATA. The phy will be added
1255 //to port whose port_index will be the phy_index.
1256 SCU_PCSPExCR_WRITE( destination_port, the_phy->phy_index, the_phy->phy_index);
1257 }
1258 }
1259
1260 return TRUE;
1261 }
1262
1263 /**
1264 * @brief This method is the entry point for the phy to inform
1265 * the port that it is now in a ready state
1266 *
1267 * @param[in] this_port
1268 * @param[in] phy
1269 */
scic_sds_port_link_up(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy)1270 void scic_sds_port_link_up(
1271 SCIC_SDS_PORT_T *this_port,
1272 SCIC_SDS_PHY_T *the_phy
1273 )
1274 {
1275 the_phy->is_in_link_training = FALSE;
1276
1277 this_port->state_handlers->link_up_handler(this_port, the_phy);
1278 }
1279
1280 /**
1281 * @brief This method is the entry point for the phy to inform
1282 * the port that it is no longer in a ready state
1283 *
1284 * @param[in] this_port
1285 * @param[in] phy
1286 */
scic_sds_port_link_down(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy)1287 void scic_sds_port_link_down(
1288 SCIC_SDS_PORT_T *this_port,
1289 SCIC_SDS_PHY_T *the_phy
1290 )
1291 {
1292 this_port->state_handlers->link_down_handler(this_port, the_phy);
1293 }
1294
1295 /**
1296 * @brief This method is called to start an IO request on this port.
1297 *
1298 * @param[in] this_port
1299 * @param[in] the_device
1300 * @param[in] the_io_request
1301 *
1302 * @return SCI_STATUS
1303 */
scic_sds_port_start_io(SCIC_SDS_PORT_T * this_port,SCIC_SDS_REMOTE_DEVICE_T * the_device,SCIC_SDS_REQUEST_T * the_io_request)1304 SCI_STATUS scic_sds_port_start_io(
1305 SCIC_SDS_PORT_T *this_port,
1306 SCIC_SDS_REMOTE_DEVICE_T *the_device,
1307 SCIC_SDS_REQUEST_T *the_io_request
1308 )
1309 {
1310 return this_port->state_handlers->start_io_handler(
1311 this_port, the_device, the_io_request);
1312 }
1313
1314 /**
1315 * @brief This method is called to complete an IO request to the port.
1316 *
1317 * @param[in] this_port
1318 * @param[in] the_device
1319 * @param[in] the_io_request
1320 *
1321 * @return SCI_STATUS
1322 */
scic_sds_port_complete_io(SCIC_SDS_PORT_T * this_port,SCIC_SDS_REMOTE_DEVICE_T * the_device,SCIC_SDS_REQUEST_T * the_io_request)1323 SCI_STATUS scic_sds_port_complete_io(
1324 SCIC_SDS_PORT_T *this_port,
1325 SCIC_SDS_REMOTE_DEVICE_T *the_device,
1326 SCIC_SDS_REQUEST_T *the_io_request
1327 )
1328 {
1329 return this_port->state_handlers->complete_io_handler(
1330 this_port, the_device, the_io_request);
1331 }
1332
1333 /**
1334 * @brief This method is provided to timeout requests for port operations.
1335 * Mostly its for the port reset operation.
1336 *
1337 * @param[in] port This is the parameter or cookie value that is provided
1338 * to the timer construct operation.
1339 */
scic_sds_port_timeout_handler(void * port)1340 void scic_sds_port_timeout_handler(
1341 void *port
1342 )
1343 {
1344 U32 current_state;
1345 SCIC_SDS_PORT_T * this_port;
1346
1347 this_port = (SCIC_SDS_PORT_T *)port;
1348 current_state = sci_base_state_machine_get_state(
1349 &this_port->parent.state_machine);
1350
1351 if (current_state == SCI_BASE_PORT_STATE_RESETTING)
1352 {
1353 // if the port is still in the resetting state then the timeout fired
1354 // before the reset completed.
1355 sci_base_state_machine_change_state(
1356 &this_port->parent.state_machine,
1357 SCI_BASE_PORT_STATE_FAILED
1358 );
1359 }
1360 else if (current_state == SCI_BASE_PORT_STATE_STOPPED)
1361 {
1362 // if the port is stopped then the start request failed
1363 // In this case stay in the stopped state.
1364 SCIC_LOG_ERROR((
1365 sci_base_object_get_logger(this_port),
1366 SCIC_LOG_OBJECT_PORT,
1367 "SCIC Port 0x%x failed to stop before tiemout.\n",
1368 this_port
1369 ));
1370 }
1371 else if (current_state == SCI_BASE_PORT_STATE_STOPPING)
1372 {
1373 // if the port is still stopping then the stop has not completed
1374 scic_cb_port_stop_complete(
1375 scic_sds_port_get_controller(this_port),
1376 port,
1377 SCI_FAILURE_TIMEOUT
1378 );
1379 }
1380 else
1381 {
1382 // The port is in the ready state and we have a timer reporting a timeout
1383 // this should not happen.
1384 SCIC_LOG_ERROR((
1385 sci_base_object_get_logger(this_port),
1386 SCIC_LOG_OBJECT_PORT,
1387 "SCIC Port 0x%x is processing a timeout operation in state %d.\n",
1388 this_port, current_state
1389 ));
1390 }
1391 }
1392
1393 // ---------------------------------------------------------------------------
1394
1395 #ifdef SCIC_DEBUG_ENABLED
scic_sds_port_decrement_request_count(SCIC_SDS_PORT_T * this_port)1396 void scic_sds_port_decrement_request_count(
1397 SCIC_SDS_PORT_T *this_port
1398 )
1399 {
1400 if (this_port->started_request_count == 0)
1401 {
1402 SCIC_LOG_WARNING((
1403 sci_base_object_get_logger(this_port),
1404 SCIC_LOG_OBJECT_PORT,
1405 "SCIC Port object requested to decrement started io count past zero.\n"
1406 ));
1407 }
1408 else
1409 {
1410 this_port->started_request_count--;
1411 }
1412 }
1413 #endif
1414
1415 /**
1416 * @brief This function updates the hardwares VIIT entry for this port.
1417 *
1418 * @param[in] this_port
1419 */
scic_sds_port_update_viit_entry(SCIC_SDS_PORT_T * this_port)1420 void scic_sds_port_update_viit_entry(
1421 SCIC_SDS_PORT_T *this_port
1422 )
1423 {
1424 SCI_SAS_ADDRESS_T sas_address;
1425
1426 scic_sds_port_get_sas_address(this_port, &sas_address);
1427
1428 scu_port_viit_register_write(
1429 this_port, initiator_sas_address_hi, sas_address.high);
1430
1431 scu_port_viit_register_write(
1432 this_port, initiator_sas_address_lo, sas_address.low);
1433
1434 // This value get cleared just in case its not already cleared
1435 scu_port_viit_register_write(
1436 this_port, reserved, 0);
1437
1438
1439 // We are required to update the status register last
1440 scu_port_viit_register_write(
1441 this_port, status, (
1442 SCU_VIIT_ENTRY_ID_VIIT
1443 | SCU_VIIT_IPPT_INITIATOR
1444 | ((1UL << this_port->physical_port_index) << SCU_VIIT_ENTRY_LPVIE_SHIFT)
1445 | SCU_VIIT_STATUS_ALL_VALID
1446 )
1447 );
1448 }
1449
1450 /**
1451 * @brief This method returns the maximum allowed speed for data transfers
1452 * on this port. This maximum allowed speed evaluates to the maximum
1453 * speed of the slowest phy in the port.
1454 *
1455 * @param[in] this_port This parameter specifies the port for which to
1456 * retrieve the maximum allowed speed.
1457 *
1458 * @return This method returns the maximum negotiated speed of the slowest
1459 * phy in the port.
1460 */
scic_sds_port_get_max_allowed_speed(SCIC_SDS_PORT_T * this_port)1461 SCI_SAS_LINK_RATE scic_sds_port_get_max_allowed_speed(
1462 SCIC_SDS_PORT_T * this_port
1463 )
1464 {
1465 U16 index = 0;
1466 SCI_SAS_LINK_RATE max_allowed_speed = SCI_SAS_600_GB;
1467 SCIC_SDS_PHY_T * phy = NULL;
1468
1469 // Loop through all of the phys in this port and find the phy with the
1470 // lowest maximum link rate.
1471 for (index = 0; index < SCI_MAX_PHYS; index++)
1472 {
1473 phy = this_port->phy_table[index];
1474 if (
1475 (phy != NULL)
1476 && (scic_sds_port_active_phy(this_port, phy) == TRUE)
1477 && (phy->max_negotiated_speed < max_allowed_speed)
1478 )
1479 max_allowed_speed = phy->max_negotiated_speed;
1480 }
1481
1482 return max_allowed_speed;
1483 }
1484
1485
1486 /**
1487 * @brief This method passes the event to core user.
1488 * @param[in] this_port The port that a BCN happens.
1489 * @param[in] this_phy The phy that receives BCN.
1490 *
1491 * @return none
1492 */
scic_sds_port_broadcast_change_received(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * this_phy)1493 void scic_sds_port_broadcast_change_received(
1494 SCIC_SDS_PORT_T * this_port,
1495 SCIC_SDS_PHY_T * this_phy
1496 )
1497 {
1498 //notify the user.
1499 scic_cb_port_bc_change_primitive_recieved(
1500 this_port->owning_controller, this_port, this_phy
1501 );
1502 }
1503
1504
1505 /**
1506 * @brief This API methhod enables the broadcast change notification from
1507 * underneath hardware.
1508 * @param[in] this_port The port that a BCN had been disabled from.
1509 *
1510 * @return none
1511 */
scic_port_enable_broadcast_change_notification(SCI_PORT_HANDLE_T port)1512 void scic_port_enable_broadcast_change_notification(
1513 SCI_PORT_HANDLE_T port
1514 )
1515 {
1516 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
1517 SCIC_SDS_PHY_T * phy;
1518 U32 register_value;
1519 U8 index;
1520
1521 // Loop through all of the phys to enable BCN.
1522 for (index = 0; index < SCI_MAX_PHYS; index++)
1523 {
1524 phy = this_port->phy_table[index];
1525 if ( phy != NULL)
1526 {
1527 register_value = SCU_SAS_LLCTL_READ(phy);
1528
1529 // clear the bit by writing 1.
1530 SCU_SAS_LLCTL_WRITE(phy, register_value);
1531 }
1532 }
1533 }
1534
1535 /**
1536 * @brief This method release resources in for a scic port.
1537 *
1538 * @param[in] controller This parameter specifies the core controller, one of
1539 * its phy's resources are to be released.
1540 * @param[in] this_port This parameter specifies the port whose resource is to
1541 * be released.
1542 */
scic_sds_port_release_resource(SCIC_SDS_CONTROLLER_T * controller,SCIC_SDS_PORT_T * this_port)1543 void scic_sds_port_release_resource(
1544 SCIC_SDS_CONTROLLER_T * controller,
1545 SCIC_SDS_PORT_T *this_port
1546 )
1547 {
1548 SCIC_LOG_TRACE((
1549 sci_base_object_get_logger(this_port),
1550 SCIC_LOG_OBJECT_PORT,
1551 "scic_sds_port_release_resource(0x%x, 0x%x)\n",
1552 controller, this_port
1553 ));
1554
1555 //Currently, the only resource to be released is a timer.
1556 if (this_port->timer_handle != NULL)
1557 {
1558 scic_cb_timer_destroy(controller, this_port->timer_handle);
1559 this_port->timer_handle = NULL;
1560 }
1561 }
1562
1563
1564 //******************************************************************************
1565 //* PORT STATE MACHINE
1566 //******************************************************************************
1567
1568 //***************************************************************************
1569 //* DEFAULT HANDLERS
1570 //***************************************************************************
1571
1572 /**
1573 * This is the default method for port a start request. It will report a
1574 * warning and exit.
1575 *
1576 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1577 * SCIC_SDS_PORT object.
1578 *
1579 * @return SCI_STATUS
1580 * @retval SCI_FAILURE_INVALID_STATE
1581 */
scic_sds_port_default_start_handler(SCI_BASE_PORT_T * port)1582 SCI_STATUS scic_sds_port_default_start_handler(
1583 SCI_BASE_PORT_T *port
1584 )
1585 {
1586 SCIC_LOG_WARNING((
1587 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1588 SCIC_LOG_OBJECT_PORT,
1589 "SCIC Port 0x%08x requested to start while in invalid state %d\n",
1590 port,
1591 sci_base_state_machine_get_state(
1592 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1593 ));
1594
1595 return SCI_FAILURE_INVALID_STATE;
1596 }
1597
1598 /**
1599 * This is the default method for a port stop request. It will report a
1600 * warning and exit.
1601 *
1602 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1603 * SCIC_SDS_PORT object.
1604 *
1605 * @return SCI_STATUS
1606 * @retval SCI_FAILURE_INVALID_STATE
1607 */
scic_sds_port_default_stop_handler(SCI_BASE_PORT_T * port)1608 SCI_STATUS scic_sds_port_default_stop_handler(
1609 SCI_BASE_PORT_T *port
1610 )
1611 {
1612 SCIC_LOG_WARNING((
1613 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1614 SCIC_LOG_OBJECT_PORT,
1615 "SCIC Port 0x%08x requested to stop while in invalid state %d\n",
1616 port,
1617 sci_base_state_machine_get_state(
1618 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1619 ));
1620
1621 return SCI_FAILURE_INVALID_STATE;
1622 }
1623
1624 /**
1625 * This is the default method for a port destruct request. It will report a
1626 * warning and exit.
1627 *
1628 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1629 * SCIC_SDS_PORT object.
1630 *
1631 * @return SCI_STATUS
1632 * @retval SCI_FAILURE_INVALID_STATE
1633 */
scic_sds_port_default_destruct_handler(SCI_BASE_PORT_T * port)1634 SCI_STATUS scic_sds_port_default_destruct_handler(
1635 SCI_BASE_PORT_T *port
1636 )
1637 {
1638 SCIC_LOG_WARNING((
1639 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1640 SCIC_LOG_OBJECT_PORT,
1641 "SCIC Port 0x%08x requested to destruct while in invalid state %d\n",
1642 port,
1643 sci_base_state_machine_get_state(
1644 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1645 ));
1646
1647 return SCI_FAILURE_INVALID_STATE;
1648 }
1649
1650 /**
1651 * This is the default method for a port reset request. It will report a
1652 * warning and exit.
1653 *
1654 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1655 * SCIC_SDS_PORT object.
1656 * @param[in] timeout This is the timeout for the reset request to complete.
1657 *
1658 * @return SCI_STATUS
1659 * @retval SCI_FAILURE_INVALID_STATE
1660 */
scic_sds_port_default_reset_handler(SCI_BASE_PORT_T * port,U32 timeout)1661 SCI_STATUS scic_sds_port_default_reset_handler(
1662 SCI_BASE_PORT_T * port,
1663 U32 timeout
1664 )
1665 {
1666 SCIC_LOG_WARNING((
1667 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1668 SCIC_LOG_OBJECT_PORT,
1669 "SCIC Port 0x%08x requested to reset while in invalid state %d\n",
1670 port,
1671 sci_base_state_machine_get_state(
1672 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1673 ));
1674
1675 return SCI_FAILURE_INVALID_STATE;
1676 }
1677
1678 /**
1679 * This is the default method for a port add phy request. It will report a
1680 * warning and exit.
1681 *
1682 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1683 * SCIC_SDS_PORT object.
1684 *
1685 * @return SCI_STATUS
1686 * @retval SCI_FAILURE_INVALID_STATE
1687 */
scic_sds_port_default_add_phy_handler(SCI_BASE_PORT_T * port,SCI_BASE_PHY_T * phy)1688 SCI_STATUS scic_sds_port_default_add_phy_handler(
1689 SCI_BASE_PORT_T *port,
1690 SCI_BASE_PHY_T *phy
1691 )
1692 {
1693 SCIC_LOG_WARNING((
1694 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1695 SCIC_LOG_OBJECT_PORT,
1696 "SCIC Port 0x%08x requested to add phy 0x%08x while in invalid state %d\n",
1697 port, phy,
1698 sci_base_state_machine_get_state(
1699 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1700 ));
1701
1702 return SCI_FAILURE_INVALID_STATE;
1703 }
1704
1705 /**
1706 * This is the default method for a port remove phy request. It will report a
1707 * warning and exit.
1708 *
1709 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1710 * SCIC_SDS_PORT object.
1711 *
1712 * @return SCI_STATUS
1713 * @retval SCI_FAILURE_INVALID_STATE
1714 */
scic_sds_port_default_remove_phy_handler(SCI_BASE_PORT_T * port,SCI_BASE_PHY_T * phy)1715 SCI_STATUS scic_sds_port_default_remove_phy_handler(
1716 SCI_BASE_PORT_T *port,
1717 SCI_BASE_PHY_T *phy
1718 )
1719 {
1720 SCIC_LOG_WARNING((
1721 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1722 SCIC_LOG_OBJECT_PORT,
1723 "SCIC Port 0x%08x requested to remove phy 0x%08x while in invalid state %d\n",
1724 port, phy,
1725 sci_base_state_machine_get_state(
1726 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1727 ));
1728
1729 return SCI_FAILURE_INVALID_STATE;
1730 }
1731
1732 /**
1733 * This is the default method for a port unsolicited frame request. It will
1734 * report a warning and exit.
1735 *
1736 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1737 * SCIC_SDS_PORT object.
1738 *
1739 * @return SCI_STATUS
1740 * @retval SCI_FAILURE_INVALID_STATE
1741 *
1742 * @todo Is it even possible to receive an unsolicited frame directed to a
1743 * port object? It seems possible if we implementing virtual functions
1744 * but until then?
1745 */
scic_sds_port_default_frame_handler(SCIC_SDS_PORT_T * port,U32 frame_index)1746 SCI_STATUS scic_sds_port_default_frame_handler(
1747 SCIC_SDS_PORT_T * port,
1748 U32 frame_index
1749 )
1750 {
1751 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
1752
1753 SCIC_LOG_WARNING((
1754 sci_base_object_get_logger(this_port),
1755 SCIC_LOG_OBJECT_PORT,
1756 "SCIC Port 0x%08x requested to process frame %d while in invalid state %d\n",
1757 port, frame_index,
1758 sci_base_state_machine_get_state(
1759 scic_sds_port_get_base_state_machine(this_port))
1760 ));
1761
1762 scic_sds_controller_release_frame(
1763 scic_sds_port_get_controller(this_port), frame_index
1764 );
1765
1766 return SCI_FAILURE_INVALID_STATE;
1767 }
1768
1769 /**
1770 * This is the default method for a port event request. It will report a
1771 * warning and exit.
1772 *
1773 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1774 * SCIC_SDS_PORT object.
1775 *
1776 * @return SCI_STATUS
1777 * @retval SCI_FAILURE_INVALID_STATE
1778 */
scic_sds_port_default_event_handler(SCIC_SDS_PORT_T * port,U32 event_code)1779 SCI_STATUS scic_sds_port_default_event_handler(
1780 SCIC_SDS_PORT_T * port,
1781 U32 event_code
1782 )
1783 {
1784 SCIC_LOG_WARNING((
1785 sci_base_object_get_logger((SCIC_SDS_PORT_T *)port),
1786 SCIC_LOG_OBJECT_PORT,
1787 "SCIC Port 0x%08x requested to process event 0x%08x while in invalid state %d\n",
1788 port, event_code,
1789 sci_base_state_machine_get_state(
1790 scic_sds_port_get_base_state_machine((SCIC_SDS_PORT_T *)port))
1791 ));
1792
1793 return SCI_FAILURE_INVALID_STATE;
1794 }
1795
1796 /**
1797 * This is the default method for a port link up notification. It will report
1798 * a warning and exit.
1799 *
1800 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1801 * SCIC_SDS_PORT object.
1802 *
1803 * @return SCI_STATUS
1804 * @retval SCI_FAILURE_INVALID_STATE
1805 */
scic_sds_port_default_link_up_handler(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * phy)1806 void scic_sds_port_default_link_up_handler(
1807 SCIC_SDS_PORT_T *this_port,
1808 SCIC_SDS_PHY_T *phy
1809 )
1810 {
1811 SCIC_LOG_WARNING((
1812 sci_base_object_get_logger(this_port),
1813 SCIC_LOG_OBJECT_PORT,
1814 "SCIC Port 0x%08x received link_up notification from phy 0x%08x while in invalid state %d\n",
1815 this_port, phy,
1816 sci_base_state_machine_get_state(
1817 scic_sds_port_get_base_state_machine(this_port))
1818 ));
1819 }
1820
1821 /**
1822 * This is the default method for a port link down notification. It will
1823 * report a warning and exit.
1824 *
1825 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1826 * SCIC_SDS_PORT object.
1827 *
1828 * @return SCI_STATUS
1829 * @retval SCI_FAILURE_INVALID_STATE
1830 */
scic_sds_port_default_link_down_handler(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * phy)1831 void scic_sds_port_default_link_down_handler(
1832 SCIC_SDS_PORT_T *this_port,
1833 SCIC_SDS_PHY_T *phy
1834 )
1835 {
1836 SCIC_LOG_WARNING((
1837 sci_base_object_get_logger(this_port),
1838 SCIC_LOG_OBJECT_PORT,
1839 "SCIC Port 0x%08x received link down notification from phy 0x%08x while in invalid state %d\n",
1840 this_port, phy,
1841 sci_base_state_machine_get_state(
1842 scic_sds_port_get_base_state_machine(this_port))
1843 ));
1844 }
1845
1846 /**
1847 * This is the default method for a port start io request. It will report a
1848 * warning and exit.
1849 *
1850 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1851 * SCIC_SDS_PORT object.
1852 *
1853 * @return SCI_STATUS
1854 * @retval SCI_FAILURE_INVALID_STATE
1855 */
scic_sds_port_default_start_io_handler(SCIC_SDS_PORT_T * this_port,SCIC_SDS_REMOTE_DEVICE_T * device,SCIC_SDS_REQUEST_T * io_request)1856 SCI_STATUS scic_sds_port_default_start_io_handler(
1857 SCIC_SDS_PORT_T *this_port,
1858 SCIC_SDS_REMOTE_DEVICE_T *device,
1859 SCIC_SDS_REQUEST_T *io_request
1860 )
1861 {
1862 SCIC_LOG_WARNING((
1863 sci_base_object_get_logger(this_port),
1864 SCIC_LOG_OBJECT_PORT,
1865 "SCIC Port 0x%08x requested to start io request 0x%08x while in invalid state %d\n",
1866 this_port, io_request,
1867 sci_base_state_machine_get_state(
1868 scic_sds_port_get_base_state_machine(this_port))
1869 ));
1870
1871 return SCI_FAILURE_INVALID_STATE;
1872 }
1873
1874 /**
1875 * This is the default method for a port complete io request. It will report
1876 * a warning and exit.
1877 *
1878 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1879 * SCIC_SDS_PORT object.
1880 *
1881 * @return SCI_STATUS
1882 * @retval SCI_FAILURE_INVALID_STATE
1883 */
scic_sds_port_default_complete_io_handler(SCIC_SDS_PORT_T * this_port,SCIC_SDS_REMOTE_DEVICE_T * device,SCIC_SDS_REQUEST_T * io_request)1884 SCI_STATUS scic_sds_port_default_complete_io_handler(
1885 SCIC_SDS_PORT_T *this_port,
1886 SCIC_SDS_REMOTE_DEVICE_T *device,
1887 SCIC_SDS_REQUEST_T *io_request
1888 )
1889 {
1890 SCIC_LOG_WARNING((
1891 sci_base_object_get_logger(this_port),
1892 SCIC_LOG_OBJECT_PORT,
1893 "SCIC Port 0x%08x requested to complete io request 0x%08x while in invalid state %d\n",
1894 this_port, io_request,
1895 sci_base_state_machine_get_state(
1896 scic_sds_port_get_base_state_machine(this_port))
1897 ));
1898
1899 return SCI_FAILURE_INVALID_STATE;
1900 }
1901
1902 //****************************************************************************
1903 //* GENERAL STATE HANDLERS
1904 //****************************************************************************
1905
1906 /**
1907 * This is a general complete io request handler for the SCIC_SDS_PORT object.
1908 *
1909 * @param[in] port This is the SCIC_SDS_PORT object on which the io request
1910 * count will be decremented.
1911 * @param[in] device This is the SCIC_SDS_REMOTE_DEVICE object to which the io
1912 * request is being directed. This parameter is not required to
1913 * complete this operation.
1914 * @param[in] io_request This is the request that is being completed on this
1915 * port object. This parameter is not required to complete this
1916 * operation.
1917 *
1918 * @return SCI_STATUS
1919 * @retval SCI_SUCCESS
1920 */
1921 static
scic_sds_port_general_complete_io_handler(SCIC_SDS_PORT_T * port,SCIC_SDS_REMOTE_DEVICE_T * device,SCIC_SDS_REQUEST_T * io_request)1922 SCI_STATUS scic_sds_port_general_complete_io_handler(
1923 SCIC_SDS_PORT_T *port,
1924 SCIC_SDS_REMOTE_DEVICE_T *device,
1925 SCIC_SDS_REQUEST_T *io_request
1926 )
1927 {
1928 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
1929
1930 scic_sds_port_decrement_request_count(this_port);
1931
1932 return SCI_SUCCESS;
1933 }
1934
1935 //****************************************************************************
1936 //* STOPPED STATE HANDLERS
1937 //****************************************************************************
1938 static
scic_sds_port_requires_scheduler_workaround(SCIC_SDS_PORT_T * this_port)1939 BOOL scic_sds_port_requires_scheduler_workaround(
1940 SCIC_SDS_PORT_T * this_port
1941 )
1942 {
1943 if (
1944 (
1945 this_port->owning_controller->logical_port_entries
1946 < this_port->owning_controller->task_context_entries
1947 )
1948 && (
1949 this_port->owning_controller->logical_port_entries
1950 < this_port->owning_controller->remote_node_entries
1951 )
1952 )
1953 {
1954 return TRUE;
1955 }
1956
1957 return FALSE;
1958 }
1959
1960
1961 /**
1962 * This method takes the SCIC_SDS_PORT from a stopped state and attempts to
1963 * start it. To start a port it must have no assiged devices and it must have
1964 * at least one phy assigned to it. If those conditions are met then the port
1965 * can transition to the ready state.
1966 *
1967 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
1968 * SCIC_SDS_PORT object.
1969 *
1970 * @return SCI_STATUS
1971 * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION This SCIC_SDS_PORT
1972 * object could not be started because the port configuration is not
1973 * valid.
1974 * @retval SCI_SUCCESS the start request is successful and the SCIC_SDS_PORT
1975 * object has transitioned to the SCI_BASE_PORT_STATE_READY.
1976 */
1977 static
scic_sds_port_stopped_state_start_handler(SCI_BASE_PORT_T * port)1978 SCI_STATUS scic_sds_port_stopped_state_start_handler(
1979 SCI_BASE_PORT_T *port
1980 )
1981 {
1982 U32 phy_mask;
1983 SCI_STATUS status = SCI_SUCCESS;
1984 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
1985
1986 if (this_port->assigned_device_count > 0)
1987 {
1988 /// @todo This is a start failure operation because there are still
1989 /// devices assigned to this port. There must be no devices
1990 /// assigned to a port on a start operation.
1991 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
1992 }
1993
1994 this_port->timer_handle = scic_cb_timer_create(
1995 scic_sds_port_get_controller(this_port),
1996 scic_sds_port_timeout_handler,
1997 this_port
1998 );
1999
2000 if (this_port->timer_handle == SCI_INVALID_HANDLE)
2001 {
2002 return SCI_FAILURE_INSUFFICIENT_RESOURCES;
2003 }
2004
2005 if (scic_sds_port_requires_scheduler_workaround(this_port))
2006 {
2007 if (this_port->reserved_rni == SCU_DUMMY_INDEX)
2008 {
2009 this_port->reserved_rni =
2010 scic_sds_remote_node_table_allocate_remote_node(
2011 &this_port->owning_controller->available_remote_nodes, 1
2012 );
2013
2014 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
2015 {
2016 scic_sds_port_construct_dummy_rnc(
2017 this_port,
2018 this_port->reserved_rni
2019 );
2020 }
2021 else
2022 {
2023 status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
2024 }
2025 }
2026
2027 if (this_port->reserved_tci == SCU_DUMMY_INDEX)
2028 {
2029 // Allocate a TCI and remove the sequence nibble
2030 this_port->reserved_tci =
2031 scic_controller_allocate_io_tag(this_port->owning_controller);
2032
2033 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
2034 {
2035 scic_sds_port_construct_dummy_task(this_port, this_port->reserved_tci);
2036 }
2037 else
2038 {
2039 status = SCI_FAILURE_INSUFFICIENT_RESOURCES;
2040 }
2041 }
2042 }
2043
2044 if (status == SCI_SUCCESS)
2045 {
2046 phy_mask = scic_sds_port_get_phys(this_port);
2047
2048 // There are one or more phys assigned to this port. Make sure
2049 // the port's phy mask is in fact legal and supported by the
2050 // silicon.
2051 if (scic_sds_port_is_phy_mask_valid(this_port, phy_mask) == TRUE)
2052 {
2053 sci_base_state_machine_change_state(
2054 scic_sds_port_get_base_state_machine(this_port),
2055 SCI_BASE_PORT_STATE_READY
2056 );
2057 }
2058 else
2059 {
2060 status = SCI_FAILURE;
2061 }
2062 }
2063
2064 if (status != SCI_SUCCESS)
2065 {
2066 scic_sds_port_destroy_dummy_resources(this_port);
2067 }
2068
2069 return status;
2070 }
2071
2072 /**
2073 * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
2074 * a stop request. This function takes no action.
2075 *
2076 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2077 * SCIC_SDS_PORT object.
2078 *
2079 * @return SCI_STATUS
2080 * @retval SCI_SUCCESS the stop request is successful as the SCIC_SDS_PORT
2081 * object is already stopped.
2082 */
2083 static
scic_sds_port_stopped_state_stop_handler(SCI_BASE_PORT_T * port)2084 SCI_STATUS scic_sds_port_stopped_state_stop_handler(
2085 SCI_BASE_PORT_T *port
2086 )
2087 {
2088 // We are already stopped so there is nothing to do here
2089 return SCI_SUCCESS;
2090 }
2091
2092 /**
2093 * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
2094 * the destruct request. The stopped state is the only state in which the
2095 * SCIC_SDS_PORT can be destroyed. This function causes the port object to
2096 * transition to the SCI_BASE_PORT_STATE_FINAL.
2097 *
2098 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2099 * SCIC_SDS_PORT object.
2100 *
2101 * @return SCI_STATUS
2102 * @retval SCI_SUCCESS
2103 */
2104 static
scic_sds_port_stopped_state_destruct_handler(SCI_BASE_PORT_T * port)2105 SCI_STATUS scic_sds_port_stopped_state_destruct_handler(
2106 SCI_BASE_PORT_T *port
2107 )
2108 {
2109 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2110
2111 sci_base_state_machine_stop(&this_port->parent.state_machine);
2112
2113 return SCI_SUCCESS;
2114 }
2115
2116 /**
2117 * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
2118 * the add phy request. In MPC mode the only time a phy can be added to a
2119 * port is in the SCI_BASE_PORT_STATE_STOPPED.
2120 *
2121 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2122 * SCIC_SDS_PORT object.
2123 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
2124 * SCIC_SDS_PHY object.
2125 *
2126 * @return SCI_STATUS
2127 * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy
2128 * can not be added to the port.
2129 * @retval SCI_SUCCESS if the phy is added to the port.
2130 */
2131 static
scic_sds_port_stopped_state_add_phy_handler(SCI_BASE_PORT_T * port,SCI_BASE_PHY_T * phy)2132 SCI_STATUS scic_sds_port_stopped_state_add_phy_handler(
2133 SCI_BASE_PORT_T *port,
2134 SCI_BASE_PHY_T *phy
2135 )
2136 {
2137 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
2138 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
2139 SCI_SAS_ADDRESS_T port_sas_address;
2140
2141 // Read the port assigned SAS Address if there is one
2142 scic_sds_port_get_sas_address(this_port, &port_sas_address);
2143
2144 if (port_sas_address.high != 0 && port_sas_address.low != 0)
2145 {
2146 SCI_SAS_ADDRESS_T phy_sas_address;
2147
2148 // Make sure that the PHY SAS Address matches the SAS Address
2149 // for this port.
2150 scic_sds_phy_get_sas_address(this_phy, &phy_sas_address);
2151
2152 if (
2153 (port_sas_address.high != phy_sas_address.high)
2154 || (port_sas_address.low != phy_sas_address.low)
2155 )
2156 {
2157 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION;
2158 }
2159 }
2160
2161 return scic_sds_port_set_phy(this_port, this_phy);
2162 }
2163
2164
2165 /**
2166 * This method takes the SCIC_SDS_PORT that is in a stopped state and handles
2167 * the remove phy request. In MPC mode the only time a phy can be removed
2168 * from a port is in the SCI_BASE_PORT_STATE_STOPPED.
2169 *
2170 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2171 * SCIC_SDS_PORT object.
2172 * @param[in] phy This is the SCI_BASE_PHY object which is cast into a
2173 * SCIC_SDS_PHY object.
2174 *
2175 * @return SCI_STATUS
2176 * @retval SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION is returned when the phy
2177 * can not be added to the port.
2178 * @retval SCI_SUCCESS if the phy is added to the port.
2179 */
2180 static
scic_sds_port_stopped_state_remove_phy_handler(SCI_BASE_PORT_T * port,SCI_BASE_PHY_T * phy)2181 SCI_STATUS scic_sds_port_stopped_state_remove_phy_handler(
2182 SCI_BASE_PORT_T *port,
2183 SCI_BASE_PHY_T *phy
2184 )
2185 {
2186 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2187 SCIC_SDS_PHY_T *this_phy = (SCIC_SDS_PHY_T *)phy;
2188
2189 return scic_sds_port_clear_phy(this_port, this_phy);
2190 }
2191
2192 //****************************************************************************
2193 //* READY STATE HANDLERS
2194 //****************************************************************************
2195
2196 //****************************************************************************
2197 //* RESETTING STATE HANDLERS
2198 //****************************************************************************
2199
2200 //****************************************************************************
2201 //* STOPPING STATE HANDLERS
2202 //****************************************************************************
2203
2204 /**
2205 * This method takes the SCIC_SDS_PORT that is in a stopping state and handles
2206 * the complete io request. Should the request count reach 0 then the port
2207 * object will transition to the stopped state.
2208 *
2209 * @param[in] port This is the SCIC_SDS_PORT object on which the io request
2210 * count will be decremented.
2211 * @param[in] device This is the SCIC_SDS_REMOTE_DEVICE object to which the io
2212 * request is being directed. This parameter is not required to
2213 * complete this operation.
2214 * @param[in] io_request This is the request that is being completed on this
2215 * port object. This parameter is not required to complete this
2216 * operation.
2217 *
2218 * @return SCI_STATUS
2219 * @retval SCI_SUCCESS
2220 */
2221 static
scic_sds_port_stopping_state_complete_io_handler(SCIC_SDS_PORT_T * port,SCIC_SDS_REMOTE_DEVICE_T * device,SCIC_SDS_REQUEST_T * io_request)2222 SCI_STATUS scic_sds_port_stopping_state_complete_io_handler(
2223 SCIC_SDS_PORT_T *port,
2224 SCIC_SDS_REMOTE_DEVICE_T *device,
2225 SCIC_SDS_REQUEST_T *io_request
2226 )
2227 {
2228 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2229
2230 scic_sds_port_decrement_request_count(this_port);
2231
2232 if (this_port->started_request_count == 0)
2233 {
2234 sci_base_state_machine_change_state(
2235 scic_sds_port_get_base_state_machine(this_port),
2236 SCI_BASE_PORT_STATE_STOPPED
2237 );
2238 }
2239
2240 return SCI_SUCCESS;
2241 }
2242
2243 //****************************************************************************
2244 //* RESETTING STATE HANDLERS
2245 //****************************************************************************
2246
2247 /**
2248 * This method will stop a failed port. This causes a transition to the
2249 * stopping state.
2250 *
2251 * @param[in] port This is the port object which is being requested to stop.
2252 *
2253 * @return SCI_STATUS
2254 * @retval SCI_SUCCESS
2255 */
2256 static
scic_sds_port_reset_state_stop_handler(SCI_BASE_PORT_T * port)2257 SCI_STATUS scic_sds_port_reset_state_stop_handler(
2258 SCI_BASE_PORT_T *port
2259 )
2260 {
2261 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2262
2263 sci_base_state_machine_change_state(
2264 &this_port->parent.state_machine,
2265 SCI_BASE_PORT_STATE_STOPPING
2266 );
2267
2268 return SCI_SUCCESS;
2269 }
2270
2271 /**
2272 * This method will transition a failed port to its ready state. The port
2273 * failed because a hard reset request timed out but at some time later one or
2274 * more phys in the port became ready.
2275 *
2276 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2277 * SCIC_SDS_PORT object.
2278 *
2279 * @return SCI_STATUS
2280 * @retval SCI_SUCCESS
2281 */
2282 static
scic_sds_port_reset_state_link_up_handler(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * phy)2283 void scic_sds_port_reset_state_link_up_handler(
2284 SCIC_SDS_PORT_T *this_port,
2285 SCIC_SDS_PHY_T *phy
2286 )
2287 {
2288 /// @todo We should make sure that the phy that has gone link up is the same
2289 /// one on which we sent the reset. It is possible that the phy on
2290 /// which we sent the reset is not the one that has gone link up and we
2291 /// want to make sure that phy being reset comes back. Consider the
2292 /// case where a reset is sent but before the hardware processes the
2293 /// reset it get a link up on the port because of a hot plug event.
2294 /// because of the reset request this phy will go link down almost
2295 /// immediately.
2296
2297 // In the resetting state we don't notify the user regarding
2298 // link up and link down notifications.
2299 scic_sds_port_general_link_up_handler(this_port, phy, FALSE, TRUE);
2300 }
2301
2302 /**
2303 * This method process link down notifications that occur during a
2304 * port reset operation. Link downs can occur during the reset operation.
2305 *
2306 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2307 * SCIC_SDS_PORT object.
2308 *
2309 * @return SCI_STATUS
2310 * @retval SCI_SUCCESS
2311 */
2312 static
scic_sds_port_reset_state_link_down_handler(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * phy)2313 void scic_sds_port_reset_state_link_down_handler(
2314 SCIC_SDS_PORT_T *this_port,
2315 SCIC_SDS_PHY_T *phy
2316 )
2317 {
2318 // In the resetting state we don't notify the user regarding
2319 // link up and link down notifications.
2320 scic_sds_port_deactivate_phy(this_port, phy, FALSE);
2321 }
2322
2323 // ---------------------------------------------------------------------------
2324
2325 SCIC_SDS_PORT_STATE_HANDLER_T
2326 scic_sds_port_state_handler_table[SCI_BASE_PORT_MAX_STATES] =
2327 {
2328 // SCI_BASE_PORT_STATE_STOPPED
2329 {
2330 {
2331 scic_sds_port_stopped_state_start_handler,
2332 scic_sds_port_stopped_state_stop_handler,
2333 scic_sds_port_stopped_state_destruct_handler,
2334 scic_sds_port_default_reset_handler,
2335 scic_sds_port_stopped_state_add_phy_handler,
2336 scic_sds_port_stopped_state_remove_phy_handler
2337 },
2338 scic_sds_port_default_frame_handler,
2339 scic_sds_port_default_event_handler,
2340 scic_sds_port_default_link_up_handler,
2341 scic_sds_port_default_link_down_handler,
2342 scic_sds_port_default_start_io_handler,
2343 scic_sds_port_default_complete_io_handler
2344 },
2345 // SCI_BASE_PORT_STATE_STOPPING
2346 {
2347 {
2348 scic_sds_port_default_start_handler,
2349 scic_sds_port_default_stop_handler,
2350 scic_sds_port_default_destruct_handler,
2351 scic_sds_port_default_reset_handler,
2352 scic_sds_port_default_add_phy_handler,
2353 scic_sds_port_default_remove_phy_handler
2354 },
2355 scic_sds_port_default_frame_handler,
2356 scic_sds_port_default_event_handler,
2357 scic_sds_port_default_link_up_handler,
2358 scic_sds_port_default_link_down_handler,
2359 scic_sds_port_default_start_io_handler,
2360 scic_sds_port_stopping_state_complete_io_handler
2361 },
2362 // SCI_BASE_PORT_STATE_READY
2363 {
2364 {
2365 scic_sds_port_default_start_handler,
2366 scic_sds_port_default_stop_handler,
2367 scic_sds_port_default_destruct_handler,
2368 scic_sds_port_default_reset_handler,
2369 scic_sds_port_default_add_phy_handler,
2370 scic_sds_port_default_remove_phy_handler
2371 },
2372 scic_sds_port_default_frame_handler,
2373 scic_sds_port_default_event_handler,
2374 scic_sds_port_default_link_up_handler,
2375 scic_sds_port_default_link_down_handler,
2376 scic_sds_port_default_start_io_handler,
2377 scic_sds_port_general_complete_io_handler
2378 },
2379 // SCI_BASE_PORT_STATE_RESETTING
2380 {
2381 {
2382 scic_sds_port_default_start_handler,
2383 scic_sds_port_reset_state_stop_handler,
2384 scic_sds_port_default_destruct_handler,
2385 scic_sds_port_default_reset_handler,
2386 scic_sds_port_default_add_phy_handler,
2387 scic_sds_port_default_remove_phy_handler
2388 },
2389 scic_sds_port_default_frame_handler,
2390 scic_sds_port_default_event_handler,
2391 scic_sds_port_reset_state_link_up_handler,
2392 scic_sds_port_reset_state_link_down_handler,
2393 scic_sds_port_default_start_io_handler,
2394 scic_sds_port_general_complete_io_handler
2395 },
2396 // SCI_BASE_PORT_STATE_FAILED
2397 {
2398 {
2399 scic_sds_port_default_start_handler,
2400 scic_sds_port_default_stop_handler,
2401 scic_sds_port_default_destruct_handler,
2402 scic_sds_port_default_reset_handler,
2403 scic_sds_port_default_add_phy_handler,
2404 scic_sds_port_default_remove_phy_handler
2405 },
2406 scic_sds_port_default_frame_handler,
2407 scic_sds_port_default_event_handler,
2408 scic_sds_port_default_link_up_handler,
2409 scic_sds_port_default_link_down_handler,
2410 scic_sds_port_default_start_io_handler,
2411 scic_sds_port_general_complete_io_handler
2412 }
2413 };
2414
2415 //******************************************************************************
2416 //* PORT STATE PRIVATE METHODS
2417 //******************************************************************************
2418
2419 /**
2420 * This method will enable the SCU Port Task Scheduler for this port object
2421 * but will leave the port task scheduler in a suspended state.
2422 *
2423 * @param[in] this_port This is the port object which to suspend.
2424 *
2425 * @return none
2426 */
2427 static
scic_sds_port_enable_port_task_scheduler(SCIC_SDS_PORT_T * this_port)2428 void scic_sds_port_enable_port_task_scheduler(
2429 SCIC_SDS_PORT_T *this_port
2430 )
2431 {
2432 U32 pts_control_value;
2433
2434 pts_control_value = scu_port_task_scheduler_read(this_port, control);
2435
2436 pts_control_value |= SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND);
2437
2438 scu_port_task_scheduler_write(this_port, control, pts_control_value);
2439 }
2440
2441 /**
2442 * This method will disable the SCU port task scheduler for this port
2443 * object.
2444 *
2445 * @param[in] this_port This is the port object which to resume.
2446 *
2447 * @return none
2448 */
2449 static
scic_sds_port_disable_port_task_scheduler(SCIC_SDS_PORT_T * this_port)2450 void scic_sds_port_disable_port_task_scheduler(
2451 SCIC_SDS_PORT_T *this_port
2452 )
2453 {
2454 U32 pts_control_value;
2455
2456 pts_control_value = scu_port_task_scheduler_read(this_port, control);
2457
2458 pts_control_value &= ~( SCU_PTSxCR_GEN_BIT(ENABLE)
2459 | SCU_PTSxCR_GEN_BIT(SUSPEND) );
2460
2461 scu_port_task_scheduler_write(this_port, control, pts_control_value);
2462 }
2463
2464 /**
2465 *
2466 */
2467 static
scic_sds_port_post_dummy_remote_node(SCIC_SDS_PORT_T * this_port)2468 void scic_sds_port_post_dummy_remote_node(
2469 SCIC_SDS_PORT_T *this_port
2470 )
2471 {
2472 U32 command;
2473 SCU_REMOTE_NODE_CONTEXT_T * rnc;
2474
2475 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
2476 {
2477 rnc = &(this_port->owning_controller->remote_node_context_table[this_port->reserved_rni]);
2478
2479 rnc->ssp.is_valid = TRUE;
2480
2481 command = (
2482 (SCU_CONTEXT_COMMAND_POST_RNC_32)
2483 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
2484 | (this_port->reserved_rni)
2485 );
2486
2487 scic_sds_controller_post_request(this_port->owning_controller, command);
2488
2489 scic_cb_stall_execution(10);
2490
2491 command = (
2492 (SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX)
2493 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
2494 | (this_port->reserved_rni)
2495 );
2496
2497 scic_sds_controller_post_request(this_port->owning_controller, command);
2498 }
2499 }
2500
2501 /**
2502 *
2503 */
2504 static
scic_sds_port_invalidate_dummy_remote_node(SCIC_SDS_PORT_T * this_port)2505 void scic_sds_port_invalidate_dummy_remote_node(
2506 SCIC_SDS_PORT_T *this_port
2507 )
2508 {
2509 U32 command;
2510 SCU_REMOTE_NODE_CONTEXT_T * rnc;
2511
2512 if (this_port->reserved_rni != SCU_DUMMY_INDEX)
2513 {
2514 rnc = &(this_port->owning_controller->remote_node_context_table[this_port->reserved_rni]);
2515
2516 rnc->ssp.is_valid = FALSE;
2517
2518 scic_cb_stall_execution(10);
2519
2520 command = (
2521 (SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE)
2522 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
2523 | (this_port->reserved_rni)
2524 );
2525
2526 scic_sds_controller_post_request(this_port->owning_controller, command);
2527 }
2528 }
2529
2530 //******************************************************************************
2531 //* PORT STATE METHODS
2532 //******************************************************************************
2533
2534 /**
2535 * This method will perform the actions required by the SCIC_SDS_PORT on
2536 * entering the SCI_BASE_PORT_STATE_STOPPED. This function sets the stopped
2537 * state handlers for the SCIC_SDS_PORT object and disables the port task
2538 * scheduler in the hardware.
2539 *
2540 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2541 * SCIC_SDS_PORT object.
2542 *
2543 * @return none
2544 */
2545 static
scic_sds_port_stopped_state_enter(SCI_BASE_OBJECT_T * object)2546 void scic_sds_port_stopped_state_enter(
2547 SCI_BASE_OBJECT_T *object
2548 )
2549 {
2550 SCIC_SDS_PORT_T *this_port;
2551 this_port = (SCIC_SDS_PORT_T *)object;
2552
2553 scic_sds_port_set_base_state_handlers(
2554 this_port, SCI_BASE_PORT_STATE_STOPPED
2555 );
2556
2557 if (
2558 SCI_BASE_PORT_STATE_STOPPING
2559 == this_port->parent.state_machine.previous_state_id
2560 )
2561 {
2562 // If we enter this state becasuse of a request to stop
2563 // the port then we want to disable the hardwares port
2564 // task scheduler.
2565 scic_sds_port_disable_port_task_scheduler(this_port);
2566 }
2567 }
2568
2569 /**
2570 * This method will perform the actions required by the SCIC_SDS_PORT on
2571 * exiting the SCI_BASE_STATE_STOPPED. This function enables the SCU hardware
2572 * port task scheduler.
2573 *
2574 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2575 * SCIC_SDS_PORT object.
2576 *
2577 * @return none
2578 */
2579 static
scic_sds_port_stopped_state_exit(SCI_BASE_OBJECT_T * object)2580 void scic_sds_port_stopped_state_exit(
2581 SCI_BASE_OBJECT_T *object
2582 )
2583 {
2584 SCIC_SDS_PORT_T *this_port;
2585 this_port = (SCIC_SDS_PORT_T *)object;
2586
2587 // Enable and suspend the port task scheduler
2588 scic_sds_port_enable_port_task_scheduler(this_port);
2589 }
2590
2591 /**
2592 * This method will perform the actions required by the SCIC_SDS_PORT on
2593 * entering the SCI_BASE_PORT_STATE_READY. This function sets the ready state
2594 * handlers for the SCIC_SDS_PORT object, reports the port object as not ready
2595 * and starts the ready substate machine.
2596 *
2597 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2598 * SCIC_SDS_PORT object.
2599 *
2600 * @return none
2601 */
2602 static
scic_sds_port_ready_state_enter(SCI_BASE_OBJECT_T * object)2603 void scic_sds_port_ready_state_enter(
2604 SCI_BASE_OBJECT_T *object
2605 )
2606 {
2607 SCIC_SDS_PORT_T *this_port;
2608 this_port = (SCIC_SDS_PORT_T *)object;
2609
2610 // Put the ready state handlers in place though they will not be there long
2611 scic_sds_port_set_base_state_handlers(
2612 this_port, SCI_BASE_PORT_STATE_READY
2613 );
2614
2615 if (
2616 SCI_BASE_PORT_STATE_RESETTING
2617 == this_port->parent.state_machine.previous_state_id
2618 )
2619 {
2620 scic_cb_port_hard_reset_complete(
2621 scic_sds_port_get_controller(this_port),
2622 this_port,
2623 SCI_SUCCESS
2624 );
2625 }
2626 else
2627 {
2628 // Notify the caller that the port is not yet ready
2629 scic_cb_port_not_ready(
2630 scic_sds_port_get_controller(this_port),
2631 this_port,
2632 SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS
2633 );
2634 }
2635
2636 // Post and suspend the dummy remote node context for this
2637 // port.
2638 scic_sds_port_post_dummy_remote_node(this_port);
2639
2640 // Start the ready substate machine
2641 sci_base_state_machine_start(
2642 scic_sds_port_get_ready_substate_machine(this_port)
2643 );
2644 }
2645
2646 /**
2647 * This method will perform the actions required by the SCIC_SDS_PORT on
2648 * exiting the SCI_BASE_STATE_READY. This function does nothing.
2649 *
2650 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2651 * SCIC_SDS_PORT object.
2652 *
2653 * @return none
2654 */
2655 static
scic_sds_port_ready_state_exit(SCI_BASE_OBJECT_T * object)2656 void scic_sds_port_ready_state_exit(
2657 SCI_BASE_OBJECT_T *object
2658 )
2659 {
2660 SCIC_SDS_PORT_T *this_port;
2661 this_port = (SCIC_SDS_PORT_T *)object;
2662
2663 sci_base_state_machine_stop(&this_port->ready_substate_machine);
2664
2665 scic_cb_stall_execution(10);
2666 scic_sds_port_invalidate_dummy_remote_node(this_port);
2667 }
2668
2669 /**
2670 * This method will perform the actions required by the SCIC_SDS_PORT on
2671 * entering the SCI_BASE_PORT_STATE_RESETTING. This function sets the
2672 * resetting state handlers for the SCIC_SDS_PORT object.
2673 *
2674 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2675 * SCIC_SDS_PORT object.
2676 *
2677 * @return none
2678 */
2679 static
scic_sds_port_resetting_state_enter(SCI_BASE_OBJECT_T * object)2680 void scic_sds_port_resetting_state_enter(
2681 SCI_BASE_OBJECT_T *object
2682 )
2683 {
2684 SCIC_SDS_PORT_T *this_port;
2685 this_port = (SCIC_SDS_PORT_T *)object;
2686
2687 scic_sds_port_set_base_state_handlers(
2688 this_port, SCI_BASE_PORT_STATE_RESETTING
2689 );
2690 }
2691
2692 /**
2693 * This method will perform the actions required by the SCIC_SDS_PORT on
2694 * exiting the SCI_BASE_STATE_RESETTING. This function does nothing.
2695 *
2696 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2697 * SCIC_SDS_PORT object.
2698 *
2699 * @return none
2700 */
2701 static
scic_sds_port_resetting_state_exit(SCI_BASE_OBJECT_T * object)2702 void scic_sds_port_resetting_state_exit(
2703 SCI_BASE_OBJECT_T *object
2704 )
2705 {
2706 SCIC_SDS_PORT_T *this_port;
2707 this_port = (SCIC_SDS_PORT_T *)object;
2708
2709 scic_cb_timer_stop(
2710 scic_sds_port_get_controller(this_port),
2711 this_port->timer_handle
2712 );
2713 }
2714
2715 /**
2716 * This method will perform the actions required by the SCIC_SDS_PORT on
2717 * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping
2718 * state handlers for the SCIC_SDS_PORT object.
2719 *
2720 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2721 * SCIC_SDS_PORT object.
2722 *
2723 * @return none
2724 */
2725 static
scic_sds_port_stopping_state_enter(SCI_BASE_OBJECT_T * object)2726 void scic_sds_port_stopping_state_enter(
2727 SCI_BASE_OBJECT_T *object
2728 )
2729 {
2730 SCIC_SDS_PORT_T *this_port;
2731 this_port = (SCIC_SDS_PORT_T *)object;
2732
2733 scic_sds_port_set_base_state_handlers(
2734 this_port, SCI_BASE_PORT_STATE_STOPPING
2735 );
2736
2737 if (this_port->started_request_count == 0)
2738 {
2739 sci_base_state_machine_change_state(
2740 &this_port->parent.state_machine,
2741 SCI_BASE_PORT_STATE_STOPPED
2742 );
2743 }
2744 }
2745
2746 /**
2747 * This method will perform the actions required by the SCIC_SDS_PORT on
2748 * exiting the SCI_BASE_STATE_STOPPING. This function does nothing.
2749 *
2750 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2751 * SCIC_SDS_PORT object.
2752 *
2753 * @return none
2754 */
2755 static
scic_sds_port_stopping_state_exit(SCI_BASE_OBJECT_T * object)2756 void scic_sds_port_stopping_state_exit(
2757 SCI_BASE_OBJECT_T *object
2758 )
2759 {
2760 SCIC_SDS_PORT_T *this_port;
2761 this_port = (SCIC_SDS_PORT_T *)object;
2762
2763 scic_cb_timer_stop(
2764 scic_sds_port_get_controller(this_port),
2765 this_port->timer_handle
2766 );
2767
2768 scic_cb_timer_destroy(
2769 scic_sds_port_get_controller(this_port),
2770 this_port->timer_handle
2771 );
2772 this_port->timer_handle = NULL;
2773
2774 scic_sds_port_destroy_dummy_resources(this_port);
2775 }
2776
2777 /**
2778 * This method will perform the actions required by the SCIC_SDS_PORT on
2779 * entering the SCI_BASE_PORT_STATE_STOPPING. This function sets the stopping
2780 * state handlers for the SCIC_SDS_PORT object.
2781 *
2782 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
2783 * SCIC_SDS_PORT object.
2784 *
2785 * @return none
2786 */
2787 static
scic_sds_port_failed_state_enter(SCI_BASE_OBJECT_T * object)2788 void scic_sds_port_failed_state_enter(
2789 SCI_BASE_OBJECT_T *object
2790 )
2791 {
2792 SCIC_SDS_PORT_T *this_port;
2793 this_port = (SCIC_SDS_PORT_T *)object;
2794
2795 scic_sds_port_set_base_state_handlers(
2796 this_port,
2797 SCI_BASE_PORT_STATE_FAILED
2798 );
2799
2800 scic_cb_port_hard_reset_complete(
2801 scic_sds_port_get_controller(this_port),
2802 this_port,
2803 SCI_FAILURE_TIMEOUT
2804 );
2805 }
2806
2807 // ---------------------------------------------------------------------------
2808
2809 SCI_BASE_STATE_T scic_sds_port_state_table[SCI_BASE_PORT_MAX_STATES] =
2810 {
2811 {
2812 SCI_BASE_PORT_STATE_STOPPED,
2813 scic_sds_port_stopped_state_enter,
2814 scic_sds_port_stopped_state_exit
2815 },
2816 {
2817 SCI_BASE_PORT_STATE_STOPPING,
2818 scic_sds_port_stopping_state_enter,
2819 scic_sds_port_stopping_state_exit
2820 },
2821 {
2822 SCI_BASE_PORT_STATE_READY,
2823 scic_sds_port_ready_state_enter,
2824 scic_sds_port_ready_state_exit
2825 },
2826 {
2827 SCI_BASE_PORT_STATE_RESETTING,
2828 scic_sds_port_resetting_state_enter,
2829 scic_sds_port_resetting_state_exit
2830 },
2831 {
2832 SCI_BASE_PORT_STATE_FAILED,
2833 scic_sds_port_failed_state_enter,
2834 NULL
2835 }
2836 };
2837
2838 //******************************************************************************
2839 //* PORT READY SUB-STATE MACHINE
2840 //******************************************************************************
2841
2842 //****************************************************************************
2843 //* READY SUBSTATE HANDLERS
2844 //****************************************************************************
2845
2846 /**
2847 * This method is the general ready state stop handler for the SCIC_SDS_PORT
2848 * object. This function will transition the ready substate machine to its
2849 * final state.
2850 *
2851 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2852 * SCIC_SDS_PORT object.
2853 *
2854 * @return SCI_STATUS
2855 * @retval SCI_SUCCESS
2856 */
2857 static
scic_sds_port_ready_substate_stop_handler(SCI_BASE_PORT_T * port)2858 SCI_STATUS scic_sds_port_ready_substate_stop_handler(
2859 SCI_BASE_PORT_T *port
2860 )
2861 {
2862 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2863
2864 sci_base_state_machine_change_state(
2865 &this_port->parent.state_machine,
2866 SCI_BASE_PORT_STATE_STOPPING
2867 );
2868
2869 return SCI_SUCCESS;
2870 }
2871
2872 /**
2873 * This method is the general ready substate complete io handler for the
2874 * SCIC_SDS_PORT object. This function decrments the outstanding request
2875 * count for this port object.
2876 *
2877 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2878 * SCIC_SDS_PORT object.
2879 * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
2880 * used in this function.
2881 * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
2882 * in this function.
2883 *
2884 * @return SCI_STATUS
2885 * @retval SCI_SUCCESS
2886 */
2887 static
scic_sds_port_ready_substate_complete_io_handler(SCIC_SDS_PORT_T * port,struct SCIC_SDS_REMOTE_DEVICE * device,struct SCIC_SDS_REQUEST * io_request)2888 SCI_STATUS scic_sds_port_ready_substate_complete_io_handler(
2889 SCIC_SDS_PORT_T *port,
2890 struct SCIC_SDS_REMOTE_DEVICE *device,
2891 struct SCIC_SDS_REQUEST *io_request
2892 )
2893 {
2894 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
2895
2896 scic_sds_port_decrement_request_count(this_port);
2897
2898 return SCI_SUCCESS;
2899 }
2900
2901 static
scic_sds_port_ready_substate_add_phy_handler(SCI_BASE_PORT_T * port,SCI_BASE_PHY_T * phy)2902 SCI_STATUS scic_sds_port_ready_substate_add_phy_handler(
2903 SCI_BASE_PORT_T *port,
2904 SCI_BASE_PHY_T *phy
2905 )
2906 {
2907 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
2908 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
2909 SCI_STATUS status;
2910
2911 status = scic_sds_port_set_phy(this_port, this_phy);
2912
2913 if (status == SCI_SUCCESS)
2914 {
2915 scic_sds_port_general_link_up_handler(this_port, this_phy, TRUE, FALSE);
2916
2917 this_port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING;
2918
2919 sci_base_state_machine_change_state(
2920 &this_port->ready_substate_machine,
2921 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
2922 );
2923 }
2924
2925 return status;
2926 }
2927
2928 static
scic_sds_port_ready_substate_remove_phy_handler(SCI_BASE_PORT_T * port,SCI_BASE_PHY_T * phy)2929 SCI_STATUS scic_sds_port_ready_substate_remove_phy_handler(
2930 SCI_BASE_PORT_T *port,
2931 SCI_BASE_PHY_T *phy
2932 )
2933 {
2934 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
2935 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
2936 SCI_STATUS status;
2937
2938 status = scic_sds_port_clear_phy(this_port, this_phy);
2939
2940 if (status == SCI_SUCCESS)
2941 {
2942 scic_sds_port_deactivate_phy(this_port, this_phy, TRUE);
2943
2944 this_port->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING;
2945
2946 sci_base_state_machine_change_state(
2947 &this_port->ready_substate_machine,
2948 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
2949 );
2950 }
2951
2952 return status;
2953 }
2954
2955 //****************************************************************************
2956 //* READY SUBSTATE WAITING HANDLERS
2957 //****************************************************************************
2958
2959 /**
2960 * This method is the ready waiting substate link up handler for the
2961 * SCIC_SDS_PORT object. This methos will report the link up condition for
2962 * this port and will transition to the ready operational substate.
2963 *
2964 * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
2965 * that has gone link up.
2966 * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
2967 *
2968 * @return none
2969 */
2970 static
scic_sds_port_ready_waiting_substate_link_up_handler(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy)2971 void scic_sds_port_ready_waiting_substate_link_up_handler(
2972 SCIC_SDS_PORT_T *this_port,
2973 SCIC_SDS_PHY_T *the_phy
2974 )
2975 {
2976 // Since this is the first phy going link up for the port we can just enable
2977 // it and continue.
2978 scic_sds_port_activate_phy(this_port, the_phy, TRUE, TRUE);
2979
2980 sci_base_state_machine_change_state(
2981 &this_port->ready_substate_machine,
2982 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
2983 );
2984 }
2985
2986 /**
2987 * This method is the ready waiting substate start io handler for the
2988 * SCIC_SDS_PORT object. The port object can not accept new requests so the
2989 * request is failed.
2990 *
2991 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
2992 * SCIC_SDS_PORT object.
2993 * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
2994 * used in this request.
2995 * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
2996 * in this function.
2997 *
2998 * @return SCI_STATUS
2999 * @retval SCI_FAILURE_INVALID_STATE
3000 */
3001 static
scic_sds_port_ready_waiting_substate_start_io_handler(SCIC_SDS_PORT_T * port,SCIC_SDS_REMOTE_DEVICE_T * device,SCIC_SDS_REQUEST_T * io_request)3002 SCI_STATUS scic_sds_port_ready_waiting_substate_start_io_handler(
3003 SCIC_SDS_PORT_T *port,
3004 SCIC_SDS_REMOTE_DEVICE_T *device,
3005 SCIC_SDS_REQUEST_T *io_request
3006 )
3007 {
3008 return SCI_FAILURE_INVALID_STATE;
3009 }
3010
3011 //****************************************************************************
3012 //* READY SUBSTATE OPERATIONAL HANDLERS
3013 //****************************************************************************
3014
3015 /**
3016 * This method will cause the port to reset.
3017 *
3018 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
3019 * SCIC_SDS_PORT object.
3020 * @param[in] timeout This is the timeout for the reset request to complete.
3021 *
3022 * @return SCI_STATUS
3023 * @retval SCI_SUCCESS
3024 */
3025 static
scic_sds_port_ready_operational_substate_reset_handler(SCI_BASE_PORT_T * port,U32 timeout)3026 SCI_STATUS scic_sds_port_ready_operational_substate_reset_handler(
3027 SCI_BASE_PORT_T * port,
3028 U32 timeout
3029 )
3030 {
3031 SCI_STATUS status = SCI_FAILURE_INVALID_PHY;
3032 U32 phy_index;
3033 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
3034 SCIC_SDS_PHY_T * selected_phy = SCI_INVALID_HANDLE;
3035
3036
3037 // Select a phy on which we can send the hard reset request.
3038 for (
3039 phy_index = 0;
3040 (phy_index < SCI_MAX_PHYS)
3041 && (selected_phy == SCI_INVALID_HANDLE);
3042 phy_index++
3043 )
3044 {
3045 selected_phy = this_port->phy_table[phy_index];
3046
3047 if (
3048 (selected_phy != SCI_INVALID_HANDLE)
3049 && !scic_sds_port_active_phy(this_port, selected_phy)
3050 )
3051 {
3052 // We found a phy but it is not ready select different phy
3053 selected_phy = SCI_INVALID_HANDLE;
3054 }
3055 }
3056
3057 // If we have a phy then go ahead and start the reset procedure
3058 if (selected_phy != SCI_INVALID_HANDLE)
3059 {
3060 status = scic_sds_phy_reset(selected_phy);
3061
3062 if (status == SCI_SUCCESS)
3063 {
3064 scic_cb_timer_start(
3065 scic_sds_port_get_controller(this_port),
3066 this_port->timer_handle,
3067 timeout
3068 );
3069
3070 this_port->not_ready_reason = SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED;
3071
3072 sci_base_state_machine_change_state(
3073 &this_port->parent.state_machine,
3074 SCI_BASE_PORT_STATE_RESETTING
3075 );
3076 }
3077 }
3078
3079 return status;
3080 }
3081
3082 /**
3083 * This method is the ready operational substate link up handler for the
3084 * SCIC_SDS_PORT object. This function notifies the SCI User that the phy has
3085 * gone link up.
3086 *
3087 * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
3088 * that has gone link up.
3089 * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link up.
3090 *
3091 * @return none
3092 */
3093 static
scic_sds_port_ready_operational_substate_link_up_handler(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy)3094 void scic_sds_port_ready_operational_substate_link_up_handler(
3095 SCIC_SDS_PORT_T *this_port,
3096 SCIC_SDS_PHY_T *the_phy
3097 )
3098 {
3099 scic_sds_port_general_link_up_handler(this_port, the_phy, TRUE, TRUE);
3100 }
3101
3102 /**
3103 * This method is the ready operational substate link down handler for the
3104 * SCIC_SDS_PORT object. This function notifies the SCI User that the phy has
3105 * gone link down and if this is the last phy in the port the port will change
3106 * state to the ready waiting substate.
3107 *
3108 * @param[in] this_port This is the SCIC_SDS_PORT object that which has a phy
3109 * that has gone link down.
3110 * @param[in] the_phy This is the SCIC_SDS_PHY object that has gone link down.
3111 *
3112 * @return none
3113 */
3114 static
scic_sds_port_ready_operational_substate_link_down_handler(SCIC_SDS_PORT_T * this_port,SCIC_SDS_PHY_T * the_phy)3115 void scic_sds_port_ready_operational_substate_link_down_handler(
3116 SCIC_SDS_PORT_T *this_port,
3117 SCIC_SDS_PHY_T *the_phy
3118 )
3119 {
3120 scic_sds_port_deactivate_phy(this_port, the_phy, TRUE);
3121
3122 // If there are no active phys left in the port, then transition
3123 // the port to the WAITING state until such time as a phy goes
3124 // link up.
3125 if (this_port->active_phy_mask == 0)
3126 {
3127 sci_base_state_machine_change_state(
3128 scic_sds_port_get_ready_substate_machine(this_port),
3129 SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3130 );
3131 }
3132 }
3133
3134 /**
3135 * This method is the ready operational substate start io handler for the
3136 * SCIC_SDS_PORT object. This function incremetns the outstanding request
3137 * count for this port object.
3138 *
3139 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
3140 * SCIC_SDS_PORT object.
3141 * @param[in] device This is the SCI_BASE_REMOTE_DEVICE object which is not
3142 * used in this function.
3143 * @param[in] io_request This is the SCI_BASE_REQUEST object which is not used
3144 * in this function.
3145 *
3146 * @return SCI_STATUS
3147 * @retval SCI_SUCCESS
3148 */
3149 static
scic_sds_port_ready_operational_substate_start_io_handler(SCIC_SDS_PORT_T * port,SCIC_SDS_REMOTE_DEVICE_T * device,SCIC_SDS_REQUEST_T * io_request)3150 SCI_STATUS scic_sds_port_ready_operational_substate_start_io_handler(
3151 SCIC_SDS_PORT_T *port,
3152 SCIC_SDS_REMOTE_DEVICE_T *device,
3153 SCIC_SDS_REQUEST_T *io_request
3154 )
3155 {
3156 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)port;
3157
3158 scic_sds_port_increment_request_count(this_port);
3159
3160 return SCI_SUCCESS;
3161 }
3162
3163 //****************************************************************************
3164 //* READY SUBSTATE OPERATIONAL HANDLERS
3165 //****************************************************************************
3166
3167 /**
3168 * This is the default method for a port add phy request. It will report a
3169 * warning and exit.
3170 *
3171 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
3172 * SCIC_SDS_PORT object.
3173 *
3174 * @return SCI_STATUS
3175 * @retval SCI_FAILURE_INVALID_STATE
3176 */
3177 static
scic_sds_port_ready_configuring_substate_add_phy_handler(SCI_BASE_PORT_T * port,SCI_BASE_PHY_T * phy)3178 SCI_STATUS scic_sds_port_ready_configuring_substate_add_phy_handler(
3179 SCI_BASE_PORT_T *port,
3180 SCI_BASE_PHY_T *phy
3181 )
3182 {
3183 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
3184 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
3185 SCI_STATUS status;
3186
3187 status = scic_sds_port_set_phy(this_port, this_phy);
3188
3189 if (status == SCI_SUCCESS)
3190 {
3191 scic_sds_port_general_link_up_handler(this_port, this_phy, TRUE, FALSE);
3192
3193 // Re-enter the configuring state since this may be the last phy in
3194 // the port.
3195 sci_base_state_machine_change_state(
3196 &this_port->ready_substate_machine,
3197 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3198 );
3199 }
3200
3201 return status;
3202 }
3203
3204 /**
3205 * This is the default method for a port remove phy request. It will report a
3206 * warning and exit.
3207 *
3208 * @param[in] port This is the SCI_BASE_PORT object which is cast into a
3209 * SCIC_SDS_PORT object.
3210 *
3211 * @return SCI_STATUS
3212 * @retval SCI_FAILURE_INVALID_STATE
3213 */
3214 static
scic_sds_port_ready_configuring_substate_remove_phy_handler(SCI_BASE_PORT_T * port,SCI_BASE_PHY_T * phy)3215 SCI_STATUS scic_sds_port_ready_configuring_substate_remove_phy_handler(
3216 SCI_BASE_PORT_T *port,
3217 SCI_BASE_PHY_T *phy
3218 )
3219 {
3220 SCIC_SDS_PORT_T * this_port = (SCIC_SDS_PORT_T *)port;
3221 SCIC_SDS_PHY_T * this_phy = (SCIC_SDS_PHY_T *)phy;
3222 SCI_STATUS status;
3223
3224 status = scic_sds_port_clear_phy(this_port, this_phy);
3225
3226 if (status == SCI_SUCCESS)
3227 {
3228 scic_sds_port_deactivate_phy(this_port, this_phy, TRUE);
3229
3230 // Re-enter the configuring state since this may be the last phy in
3231 // the port.
3232 sci_base_state_machine_change_state(
3233 &this_port->ready_substate_machine,
3234 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3235 );
3236 }
3237
3238 return status;
3239 }
3240
3241 /**
3242 * This method will decrement the outstanding request count for this port.
3243 * If the request count goes to 0 then the port can be reprogrammed with
3244 * its new phy data.
3245 *
3246 * @param[in] port This is the port that is being requested to complete
3247 * the io request.
3248 * @param[in] device This is the device on which the io is completing.
3249 * @param[in] io_request This is the io request that is completing.
3250 */
3251 static
scic_sds_port_ready_configuring_substate_complete_io_handler(SCIC_SDS_PORT_T * port,SCIC_SDS_REMOTE_DEVICE_T * device,SCIC_SDS_REQUEST_T * io_request)3252 SCI_STATUS scic_sds_port_ready_configuring_substate_complete_io_handler(
3253 SCIC_SDS_PORT_T *port,
3254 SCIC_SDS_REMOTE_DEVICE_T *device,
3255 SCIC_SDS_REQUEST_T *io_request
3256 )
3257 {
3258 scic_sds_port_decrement_request_count(port);
3259
3260 if (port->started_request_count == 0)
3261 {
3262 sci_base_state_machine_change_state(
3263 &port->ready_substate_machine,
3264 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3265 );
3266 }
3267
3268 return SCI_SUCCESS;
3269 }
3270
3271 // ---------------------------------------------------------------------------
3272
3273 SCIC_SDS_PORT_STATE_HANDLER_T
3274 scic_sds_port_ready_substate_handler_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] =
3275 {
3276 // SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3277 {
3278 {
3279 scic_sds_port_default_start_handler,
3280 scic_sds_port_ready_substate_stop_handler,
3281 scic_sds_port_default_destruct_handler,
3282 scic_sds_port_default_reset_handler,
3283 scic_sds_port_ready_substate_add_phy_handler,
3284 scic_sds_port_default_remove_phy_handler
3285 },
3286 scic_sds_port_default_frame_handler,
3287 scic_sds_port_default_event_handler,
3288 scic_sds_port_ready_waiting_substate_link_up_handler,
3289 scic_sds_port_default_link_down_handler,
3290 scic_sds_port_ready_waiting_substate_start_io_handler,
3291 scic_sds_port_ready_substate_complete_io_handler,
3292 },
3293 // SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3294 {
3295 {
3296 scic_sds_port_default_start_handler,
3297 scic_sds_port_ready_substate_stop_handler,
3298 scic_sds_port_default_destruct_handler,
3299 scic_sds_port_ready_operational_substate_reset_handler,
3300 scic_sds_port_ready_substate_add_phy_handler,
3301 scic_sds_port_ready_substate_remove_phy_handler
3302 },
3303 scic_sds_port_default_frame_handler,
3304 scic_sds_port_default_event_handler,
3305 scic_sds_port_ready_operational_substate_link_up_handler,
3306 scic_sds_port_ready_operational_substate_link_down_handler,
3307 scic_sds_port_ready_operational_substate_start_io_handler,
3308 scic_sds_port_ready_substate_complete_io_handler
3309 },
3310 // SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3311 {
3312 {
3313 scic_sds_port_default_start_handler,
3314 scic_sds_port_ready_substate_stop_handler,
3315 scic_sds_port_default_destruct_handler,
3316 scic_sds_port_default_reset_handler,
3317 scic_sds_port_ready_configuring_substate_add_phy_handler,
3318 scic_sds_port_ready_configuring_substate_remove_phy_handler
3319 },
3320 scic_sds_port_default_frame_handler,
3321 scic_sds_port_default_event_handler,
3322 scic_sds_port_default_link_up_handler,
3323 scic_sds_port_default_link_down_handler,
3324 scic_sds_port_default_start_io_handler,
3325 scic_sds_port_ready_configuring_substate_complete_io_handler
3326 }
3327 };
3328
3329 /**
3330 * This macro sets the port ready substate handlers.
3331 */
3332 #define scic_sds_port_set_ready_state_handlers(port, state_id) \
3333 scic_sds_port_set_state_handlers( \
3334 port, &scic_sds_port_ready_substate_handler_table[(state_id)] \
3335 )
3336
3337 //******************************************************************************
3338 //* PORT STATE PRIVATE METHODS
3339 //******************************************************************************
3340
3341 /**
3342 * This method will susped the port task scheduler for this port object.
3343 *
3344 * @param[in] this_port This is the SCIC_SDS_PORT object to suspend.
3345 *
3346 * @return none
3347 */
scic_sds_port_suspend_port_task_scheduler(SCIC_SDS_PORT_T * this_port)3348 void scic_sds_port_suspend_port_task_scheduler(
3349 SCIC_SDS_PORT_T *this_port
3350 )
3351 {
3352 U32 pts_control_value;
3353
3354 pts_control_value = scu_port_task_scheduler_read(this_port, control);
3355 pts_control_value |= SCU_PTSxCR_GEN_BIT(SUSPEND);
3356 scu_port_task_scheduler_write(this_port, control, pts_control_value);
3357 }
3358
3359 /**
3360 * This method will resume the port task scheduler for this port object.
3361 *
3362 * @param[in] this_port This is the SCIC_SDS_PORT object to resume.
3363 *
3364 * @return none
3365 */
scic_sds_port_resume_port_task_scheduler(SCIC_SDS_PORT_T * this_port)3366 void scic_sds_port_resume_port_task_scheduler(
3367 SCIC_SDS_PORT_T *this_port
3368 )
3369 {
3370 U32 pts_control_value;
3371
3372 pts_control_value = scu_port_task_scheduler_read(this_port, control);
3373
3374 pts_control_value &= ~SCU_PTSxCR_GEN_BIT(SUSPEND);
3375
3376 scu_port_task_scheduler_write(this_port, control, pts_control_value);
3377 }
3378
3379 /**
3380 * This routine will post the dummy request. This will prevent the hardware
3381 * scheduler from posting new requests to the front of the scheduler queue
3382 * causing a starvation problem for currently ongoing requests.
3383 *
3384 * @parm[in] this_port The port on which the task must be posted.
3385 *
3386 * @return none
3387 */
3388 static
scic_sds_port_post_dummy_request(SCIC_SDS_PORT_T * this_port)3389 void scic_sds_port_post_dummy_request(
3390 SCIC_SDS_PORT_T *this_port
3391 )
3392 {
3393 U32 command;
3394 SCU_TASK_CONTEXT_T * task_context;
3395
3396 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
3397 {
3398 task_context = scic_sds_controller_get_task_context_buffer(
3399 this_port->owning_controller,
3400 this_port->reserved_tci
3401 );
3402
3403 task_context->abort = 0;
3404
3405 command = (
3406 (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC)
3407 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
3408 | (this_port->reserved_tci)
3409 );
3410
3411 scic_sds_controller_post_request(this_port->owning_controller, command);
3412 }
3413 }
3414
3415 /**
3416 * This routine will abort the dummy request. This will alow the hardware to
3417 * power down parts of the silicon to save power.
3418 *
3419 * @parm[in] this_port The port on which the task must be aborted.
3420 *
3421 * @return none
3422 */
3423 static
scic_sds_port_abort_dummy_request(SCIC_SDS_PORT_T * this_port)3424 void scic_sds_port_abort_dummy_request(
3425 SCIC_SDS_PORT_T *this_port
3426 )
3427 {
3428 U32 command;
3429 SCU_TASK_CONTEXT_T * task_context;
3430
3431 if (this_port->reserved_tci != SCU_DUMMY_INDEX)
3432 {
3433 task_context = scic_sds_controller_get_task_context_buffer(
3434 this_port->owning_controller,
3435 this_port->reserved_tci
3436 );
3437
3438 task_context->abort = 1;
3439
3440 command = (
3441 (SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT)
3442 | (this_port->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT)
3443 | (this_port->reserved_tci)
3444 );
3445
3446 scic_sds_controller_post_request(this_port->owning_controller, command);
3447 }
3448 }
3449
3450 //******************************************************************************
3451 //* PORT READY SUBSTATE METHODS
3452 //******************************************************************************
3453
3454 /**
3455 * This method will perform the actions required by the SCIC_SDS_PORT on
3456 * entering the SCIC_SDS_PORT_READY_SUBSTATE_WAITING. This function checks the
3457 * port for any ready phys. If there is at least one phy in a ready state
3458 * then the port transitions to the ready operational substate.
3459 *
3460 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3461 * SCIC_SDS_PORT object.
3462 *
3463 * @return none
3464 */
3465 static
scic_sds_port_ready_substate_waiting_enter(SCI_BASE_OBJECT_T * object)3466 void scic_sds_port_ready_substate_waiting_enter(
3467 SCI_BASE_OBJECT_T *object
3468 )
3469 {
3470 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3471
3472 scic_sds_port_set_ready_state_handlers(
3473 this_port, SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3474 );
3475
3476 scic_sds_port_suspend_port_task_scheduler(this_port);
3477
3478
3479 this_port->not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS;
3480
3481 if (this_port->active_phy_mask != 0)
3482 {
3483 // At least one of the phys on the port is ready
3484 sci_base_state_machine_change_state(
3485 &this_port->ready_substate_machine,
3486 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3487 );
3488 }
3489 }
3490
3491 /**
3492 * This method will perform the actions required by the SCIC_SDS_PORT on
3493 * exiting the SCIC_SDS_PORT_READY_SUBSTATE_WAITING. This function resume the
3494 * PTSG that was suspended at the entry of this state.
3495 *
3496 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3497 * SCIC_SDS_PORT object.
3498 *
3499 * @return none
3500 */
3501 static
scic_sds_port_ready_substate_waiting_exit(SCI_BASE_OBJECT_T * object)3502 void scic_sds_port_ready_substate_waiting_exit(
3503 SCI_BASE_OBJECT_T *object
3504 )
3505 {
3506 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3507 scic_sds_port_resume_port_task_scheduler(this_port);
3508 }
3509
3510 /**
3511 * This method will perform the actions required by the SCIC_SDS_PORT on
3512 * entering the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function sets
3513 * the state handlers for the port object, notifies the SCI User that the port
3514 * is ready, and resumes port operations.
3515 *
3516 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3517 * SCIC_SDS_PORT object.
3518 *
3519 * @return none
3520 */
3521 static
scic_sds_port_ready_substate_operational_enter(SCI_BASE_OBJECT_T * object)3522 void scic_sds_port_ready_substate_operational_enter(
3523 SCI_BASE_OBJECT_T *object
3524 )
3525 {
3526 U32 index;
3527 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3528
3529 scic_sds_port_set_ready_state_handlers(
3530 this_port, SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3531 );
3532
3533 scic_cb_port_ready(
3534 scic_sds_port_get_controller(this_port), this_port
3535 );
3536
3537 for (index = 0; index < SCI_MAX_PHYS; index++)
3538 {
3539 if (this_port->phy_table[index] != NULL)
3540 {
3541 scic_sds_port_write_phy_assignment(
3542 this_port, this_port->phy_table[index]
3543 );
3544
3545 //if the bit at the index location for active phy mask is set and
3546 //enabled_phy_mask is not set then resume the phy
3547 if ( ( (this_port->active_phy_mask ^ this_port->enabled_phy_mask) & (1 << index) ) != 0)
3548 {
3549 scic_sds_port_resume_phy (
3550 this_port,
3551 this_port->phy_table[index]
3552 );
3553 }
3554 }
3555 }
3556
3557 scic_sds_port_update_viit_entry(this_port);
3558
3559 // Post the dummy task for the port so the hardware can schedule
3560 // io correctly
3561 scic_sds_port_post_dummy_request(this_port);
3562 }
3563
3564 /**
3565 * This method will perform the actions required by the SCIC_SDS_PORT on
3566 * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports
3567 * the port not ready and suspends the port task scheduler.
3568 *
3569 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3570 * SCIC_SDS_PORT object.
3571 *
3572 * @return none
3573 */
3574 static
scic_sds_port_ready_substate_operational_exit(SCI_BASE_OBJECT_T * object)3575 void scic_sds_port_ready_substate_operational_exit(
3576 SCI_BASE_OBJECT_T *object
3577 )
3578 {
3579 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3580
3581 // Kill the dummy task for this port if it has not yet posted
3582 // the hardware will treat this as a NOP and just return abort
3583 // complete.
3584 scic_sds_port_abort_dummy_request(this_port);
3585
3586 scic_cb_port_not_ready(
3587 scic_sds_port_get_controller(this_port),
3588 this_port,
3589 this_port->not_ready_reason
3590 );
3591 }
3592
3593 //******************************************************************************
3594 //* PORT READY CONFIGURING METHODS
3595 //******************************************************************************
3596
3597 /**
3598 * This method will perform the actions required by the SCIC_SDS_PORT on
3599 * exiting the SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL. This function reports
3600 * the port not ready and suspends the port task scheduler.
3601 *
3602 * @param[in] object This is the SCI_BASE_OBJECT which is cast to a
3603 * SCIC_SDS_PORT object.
3604 *
3605 * @return none
3606 */
3607 static
scic_sds_port_ready_substate_configuring_enter(SCI_BASE_OBJECT_T * object)3608 void scic_sds_port_ready_substate_configuring_enter(
3609 SCI_BASE_OBJECT_T *object
3610 )
3611 {
3612 SCIC_SDS_PORT_T *this_port = (SCIC_SDS_PORT_T *)object;
3613
3614 scic_sds_port_set_ready_state_handlers(
3615 this_port, SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING
3616 );
3617
3618 if (this_port->active_phy_mask == 0)
3619 {
3620 scic_cb_port_not_ready(
3621 scic_sds_port_get_controller(this_port),
3622 this_port,
3623 SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS
3624 );
3625
3626 sci_base_state_machine_change_state(
3627 &this_port->ready_substate_machine,
3628 SCIC_SDS_PORT_READY_SUBSTATE_WAITING
3629 );
3630 }
3631 //do not wait for IO to go to 0 in this state.
3632 else
3633 {
3634 sci_base_state_machine_change_state(
3635 &this_port->ready_substate_machine,
3636 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL
3637 );
3638 }
3639 }
3640
3641 // ---------------------------------------------------------------------------
3642
3643 SCI_BASE_STATE_T
3644 scic_sds_port_ready_substate_table[SCIC_SDS_PORT_READY_MAX_SUBSTATES] =
3645 {
3646 {
3647 SCIC_SDS_PORT_READY_SUBSTATE_WAITING,
3648 scic_sds_port_ready_substate_waiting_enter,
3649 scic_sds_port_ready_substate_waiting_exit
3650 },
3651 {
3652 SCIC_SDS_PORT_READY_SUBSTATE_OPERATIONAL,
3653 scic_sds_port_ready_substate_operational_enter,
3654 scic_sds_port_ready_substate_operational_exit
3655 },
3656 {
3657 SCIC_SDS_PORT_READY_SUBSTATE_CONFIGURING,
3658 scic_sds_port_ready_substate_configuring_enter,
3659 NULL
3660 }
3661 };
3662
3663