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