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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 */ 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 */ 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 */ 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 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 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 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 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 */ 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 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 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 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 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 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 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 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 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