1 /* 2 * This file is provided under a dual BSD/GPLv2 license. When using or 3 * redistributing this file, you may do so under either license. 4 * 5 * GPL LICENSE SUMMARY 6 * 7 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of version 2 of the GNU General Public License as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 21 * The full GNU General Public License is included in this distribution 22 * in the file called LICENSE.GPL. 23 * 24 * BSD LICENSE 25 * 26 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 27 * All rights reserved. 28 * 29 * Redistribution and use in source and binary forms, with or without 30 * modification, are permitted provided that the following conditions 31 * are met: 32 * 33 * * Redistributions of source code must retain the above copyright 34 * notice, this list of conditions and the following disclaimer. 35 * * Redistributions in binary form must reproduce the above copyright 36 * notice, this list of conditions and the following disclaimer in 37 * the documentation and/or other materials provided with the 38 * distribution. 39 * * Neither the name of Intel Corporation nor the names of its 40 * contributors may be used to endorse or promote products derived 41 * from this software without specific prior written permission. 42 * 43 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 44 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 45 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 46 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 47 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 48 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 49 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 53 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 */ 55 56 #include "host.h" 57 58 #define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10) 59 #define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10) 60 #define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (100) 61 62 enum SCIC_SDS_APC_ACTIVITY { 63 SCIC_SDS_APC_SKIP_PHY, 64 SCIC_SDS_APC_ADD_PHY, 65 SCIC_SDS_APC_START_TIMER, 66 67 SCIC_SDS_APC_ACTIVITY_MAX 68 }; 69 70 /* 71 * ****************************************************************************** 72 * General port configuration agent routines 73 * ****************************************************************************** */ 74 75 /** 76 * 77 * @address_one: A SAS Address to be compared. 78 * @address_two: A SAS Address to be compared. 79 * 80 * Compare the two SAS Address and if SAS Address One is greater than SAS 81 * Address Two then return > 0 else if SAS Address One is less than SAS Address 82 * Two return < 0 Otherwise they are the same return 0 A signed value of x > 0 83 * > y where x is returned for Address One > Address Two y is returned for 84 * Address One < Address Two 0 is returned ofr Address One = Address Two 85 */ 86 static s32 sci_sas_address_compare( 87 struct sci_sas_address address_one, 88 struct sci_sas_address address_two) 89 { 90 if (address_one.high > address_two.high) { 91 return 1; 92 } else if (address_one.high < address_two.high) { 93 return -1; 94 } else if (address_one.low > address_two.low) { 95 return 1; 96 } else if (address_one.low < address_two.low) { 97 return -1; 98 } 99 100 /* The two SAS Address must be identical */ 101 return 0; 102 } 103 104 /** 105 * 106 * @controller: The controller object used for the port search. 107 * @phy: The phy object to match. 108 * 109 * This routine will find a matching port for the phy. This means that the 110 * port and phy both have the same broadcast sas address and same received sas 111 * address. The port address or the NULL if there is no matching 112 * port. port address if the port can be found to match the phy. 113 * NULL if there is no matching port for the phy. 114 */ 115 static struct scic_sds_port *scic_sds_port_configuration_agent_find_port( 116 struct scic_sds_controller *scic, 117 struct scic_sds_phy *phy) 118 { 119 u8 i; 120 struct sci_sas_address port_sas_address; 121 struct sci_sas_address port_attached_device_address; 122 struct sci_sas_address phy_sas_address; 123 struct sci_sas_address phy_attached_device_address; 124 125 /* 126 * Since this phy can be a member of a wide port check to see if one or 127 * more phys match the sent and received SAS address as this phy in which 128 * case it should participate in the same port. 129 */ 130 scic_sds_phy_get_sas_address(phy, &phy_sas_address); 131 scic_sds_phy_get_attached_sas_address(phy, &phy_attached_device_address); 132 133 for (i = 0; i < scic->logical_port_entries; i++) { 134 struct isci_host *ihost = scic_to_ihost(scic); 135 struct scic_sds_port *sci_port = &ihost->ports[i].sci; 136 137 scic_sds_port_get_sas_address(sci_port, &port_sas_address); 138 scic_sds_port_get_attached_sas_address(sci_port, &port_attached_device_address); 139 140 if (sci_sas_address_compare(port_sas_address, phy_sas_address) == 0 && 141 sci_sas_address_compare(port_attached_device_address, phy_attached_device_address) == 0) 142 return sci_port; 143 } 144 145 return NULL; 146 } 147 148 /** 149 * 150 * @controller: This is the controller object that contains the port agent 151 * @port_agent: This is the port configruation agent for the controller. 152 * 153 * This routine will validate the port configuration is correct for the SCU 154 * hardware. The SCU hardware allows for port configurations as follows. LP0 155 * -> (PE0), (PE0, PE1), (PE0, PE1, PE2, PE3) LP1 -> (PE1) LP2 -> (PE2), (PE2, 156 * PE3) LP3 -> (PE3) enum sci_status SCI_SUCCESS the port configuration is valid for 157 * this port configuration agent. SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION 158 * the port configuration is not valid for this port configuration agent. 159 */ 160 static enum sci_status scic_sds_port_configuration_agent_validate_ports( 161 struct scic_sds_controller *controller, 162 struct scic_sds_port_configuration_agent *port_agent) 163 { 164 struct isci_host *ihost = scic_to_ihost(controller); 165 struct sci_sas_address first_address; 166 struct sci_sas_address second_address; 167 168 /* 169 * Sanity check the max ranges for all the phys the max index 170 * is always equal to the port range index */ 171 if (port_agent->phy_valid_port_range[0].max_index != 0 || 172 port_agent->phy_valid_port_range[1].max_index != 1 || 173 port_agent->phy_valid_port_range[2].max_index != 2 || 174 port_agent->phy_valid_port_range[3].max_index != 3) 175 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 176 177 /* 178 * This is a request to configure a single x4 port or at least attempt 179 * to make all the phys into a single port */ 180 if (port_agent->phy_valid_port_range[0].min_index == 0 && 181 port_agent->phy_valid_port_range[1].min_index == 0 && 182 port_agent->phy_valid_port_range[2].min_index == 0 && 183 port_agent->phy_valid_port_range[3].min_index == 0) 184 return SCI_SUCCESS; 185 186 /* 187 * This is a degenerate case where phy 1 and phy 2 are assigned 188 * to the same port this is explicitly disallowed by the hardware 189 * unless they are part of the same x4 port and this condition was 190 * already checked above. */ 191 if (port_agent->phy_valid_port_range[2].min_index == 1) { 192 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 193 } 194 195 /* 196 * PE0 and PE3 can never have the same SAS Address unless they 197 * are part of the same x4 wide port and we have already checked 198 * for this condition. */ 199 scic_sds_phy_get_sas_address(&ihost->phys[0].sci, &first_address); 200 scic_sds_phy_get_sas_address(&ihost->phys[3].sci, &second_address); 201 202 if (sci_sas_address_compare(first_address, second_address) == 0) { 203 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 204 } 205 206 /* 207 * PE0 and PE1 are configured into a 2x1 ports make sure that the 208 * SAS Address for PE0 and PE2 are different since they can not be 209 * part of the same port. */ 210 if (port_agent->phy_valid_port_range[0].min_index == 0 && 211 port_agent->phy_valid_port_range[1].min_index == 1) { 212 scic_sds_phy_get_sas_address(&ihost->phys[0].sci, &first_address); 213 scic_sds_phy_get_sas_address(&ihost->phys[2].sci, &second_address); 214 215 if (sci_sas_address_compare(first_address, second_address) == 0) { 216 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 217 } 218 } 219 220 /* 221 * PE2 and PE3 are configured into a 2x1 ports make sure that the 222 * SAS Address for PE1 and PE3 are different since they can not be 223 * part of the same port. */ 224 if (port_agent->phy_valid_port_range[2].min_index == 2 && 225 port_agent->phy_valid_port_range[3].min_index == 3) { 226 scic_sds_phy_get_sas_address(&ihost->phys[1].sci, &first_address); 227 scic_sds_phy_get_sas_address(&ihost->phys[3].sci, &second_address); 228 229 if (sci_sas_address_compare(first_address, second_address) == 0) { 230 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 231 } 232 } 233 234 return SCI_SUCCESS; 235 } 236 237 /* 238 * ****************************************************************************** 239 * Manual port configuration agent routines 240 * ****************************************************************************** */ 241 242 /** 243 * 244 * 245 * This routine will verify that all of the phys in the same port are using the 246 * same SAS address. 247 */ 248 static enum sci_status scic_sds_mpc_agent_validate_phy_configuration( 249 struct scic_sds_controller *controller, 250 struct scic_sds_port_configuration_agent *port_agent) 251 { 252 struct isci_host *ihost = scic_to_ihost(controller); 253 u32 phy_mask; 254 u32 assigned_phy_mask; 255 struct sci_sas_address sas_address; 256 struct sci_sas_address phy_assigned_address; 257 u8 port_index; 258 u8 phy_index; 259 260 assigned_phy_mask = 0; 261 sas_address.high = 0; 262 sas_address.low = 0; 263 264 for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) { 265 phy_mask = controller->oem_parameters.sds1.ports[port_index].phy_mask; 266 267 if (!phy_mask) 268 continue; 269 /* 270 * Make sure that one or more of the phys were not already assinged to 271 * a different port. */ 272 if ((phy_mask & ~assigned_phy_mask) == 0) { 273 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 274 } 275 276 /* Find the starting phy index for this round through the loop */ 277 for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) { 278 if ((phy_mask & (1 << phy_index)) == 0) 279 continue; 280 scic_sds_phy_get_sas_address(&ihost->phys[phy_index].sci, 281 &sas_address); 282 283 /* 284 * The phy_index can be used as the starting point for the 285 * port range since the hardware starts all logical ports 286 * the same as the PE index. */ 287 port_agent->phy_valid_port_range[phy_index].min_index = port_index; 288 port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 289 290 if (phy_index != port_index) { 291 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 292 } 293 294 break; 295 } 296 297 /* 298 * See how many additional phys are being added to this logical port. 299 * Note: We have not moved the current phy_index so we will actually 300 * compare the startting phy with itself. 301 * This is expected and required to add the phy to the port. */ 302 while (phy_index < SCI_MAX_PHYS) { 303 if ((phy_mask & (1 << phy_index)) == 0) 304 continue; 305 scic_sds_phy_get_sas_address(&ihost->phys[phy_index].sci, 306 &phy_assigned_address); 307 308 if (sci_sas_address_compare(sas_address, phy_assigned_address) != 0) { 309 /* 310 * The phy mask specified that this phy is part of the same port 311 * as the starting phy and it is not so fail this configuration */ 312 return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; 313 } 314 315 port_agent->phy_valid_port_range[phy_index].min_index = port_index; 316 port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 317 318 scic_sds_port_add_phy(&ihost->ports[port_index].sci, 319 &ihost->phys[phy_index].sci); 320 321 assigned_phy_mask |= (1 << phy_index); 322 } 323 324 phy_index++; 325 } 326 327 return scic_sds_port_configuration_agent_validate_ports(controller, port_agent); 328 } 329 330 static void mpc_agent_timeout(unsigned long data) 331 { 332 u8 index; 333 struct sci_timer *tmr = (struct sci_timer *)data; 334 struct scic_sds_port_configuration_agent *port_agent; 335 struct scic_sds_controller *scic; 336 struct isci_host *ihost; 337 unsigned long flags; 338 u16 configure_phy_mask; 339 340 port_agent = container_of(tmr, typeof(*port_agent), timer); 341 scic = container_of(port_agent, typeof(*scic), port_agent); 342 ihost = scic_to_ihost(scic); 343 344 spin_lock_irqsave(&ihost->scic_lock, flags); 345 346 if (tmr->cancel) 347 goto done; 348 349 port_agent->timer_pending = false; 350 351 /* Find the mask of phys that are reported read but as yet unconfigured into a port */ 352 configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask; 353 354 for (index = 0; index < SCI_MAX_PHYS; index++) { 355 struct scic_sds_phy *sci_phy = &ihost->phys[index].sci; 356 357 if (configure_phy_mask & (1 << index)) { 358 port_agent->link_up_handler(scic, port_agent, 359 phy_get_non_dummy_port(sci_phy), 360 sci_phy); 361 } 362 } 363 364 done: 365 spin_unlock_irqrestore(&ihost->scic_lock, flags); 366 } 367 368 /** 369 * 370 * @controller: This is the controller object that receives the link up 371 * notification. 372 * @port: This is the port object associated with the phy. If the is no 373 * associated port this is an NULL. 374 * @phy: This is the phy object which has gone ready. 375 * 376 * This method handles the manual port configuration link up notifications. 377 * Since all ports and phys are associate at initialization time we just turn 378 * around and notifiy the port object that there is a link up. If this PHY is 379 * not associated with a port there is no action taken. Is it possible to get a 380 * link up notification from a phy that has no assocoated port? 381 */ 382 static void scic_sds_mpc_agent_link_up( 383 struct scic_sds_controller *controller, 384 struct scic_sds_port_configuration_agent *port_agent, 385 struct scic_sds_port *port, 386 struct scic_sds_phy *phy) 387 { 388 /* 389 * If the port has an invalid handle then the phy was not assigned to 390 * a port. This is because the phy was not given the same SAS Address 391 * as the other PHYs in the port. */ 392 if (port != NULL) { 393 port_agent->phy_ready_mask |= (1 << scic_sds_phy_get_index(phy)); 394 395 scic_sds_port_link_up(port, phy); 396 397 if ((port->active_phy_mask & (1 << scic_sds_phy_get_index(phy))) != 0) { 398 port_agent->phy_configured_mask |= (1 << scic_sds_phy_get_index(phy)); 399 } 400 } 401 } 402 403 /** 404 * 405 * @controller: This is the controller object that receives the link down 406 * notification. 407 * @port: This is the port object associated with the phy. If the is no 408 * associated port this is an NULL. The port is an invalid 409 * handle only if the phy was never port of this port. This happens when 410 * the phy is not broadcasting the same SAS address as the other phys in the 411 * assigned port. 412 * @phy: This is the phy object which has gone link down. 413 * 414 * This function handles the manual port configuration link down notifications. 415 * Since all ports and phys are associated at initialization time we just turn 416 * around and notifiy the port object of the link down event. If this PHY is 417 * not associated with a port there is no action taken. Is it possible to get a 418 * link down notification from a phy that has no assocoated port? 419 */ 420 static void scic_sds_mpc_agent_link_down( 421 struct scic_sds_controller *scic, 422 struct scic_sds_port_configuration_agent *port_agent, 423 struct scic_sds_port *sci_port, 424 struct scic_sds_phy *sci_phy) 425 { 426 if (sci_port != NULL) { 427 /* 428 * If we can form a new port from the remainder of the phys 429 * then we want to start the timer to allow the SCI User to 430 * cleanup old devices and rediscover the port before 431 * rebuilding the port with the phys that remain in the ready 432 * state. 433 */ 434 port_agent->phy_ready_mask &= 435 ~(1 << scic_sds_phy_get_index(sci_phy)); 436 port_agent->phy_configured_mask &= 437 ~(1 << scic_sds_phy_get_index(sci_phy)); 438 439 /* 440 * Check to see if there are more phys waiting to be 441 * configured into a port. If there are allow the SCI User 442 * to tear down this port, if necessary, and then reconstruct 443 * the port after the timeout. 444 */ 445 if ((port_agent->phy_configured_mask == 0x0000) && 446 (port_agent->phy_ready_mask != 0x0000) && 447 !port_agent->timer_pending) { 448 port_agent->timer_pending = true; 449 450 sci_mod_timer(&port_agent->timer, 451 SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT); 452 } 453 454 scic_sds_port_link_down(sci_port, sci_phy); 455 } 456 } 457 458 /* 459 * ****************************************************************************** 460 * Automatic port configuration agent routines 461 * ****************************************************************************** */ 462 463 /** 464 * 465 * 466 * This routine will verify that the phys are assigned a valid SAS address for 467 * automatic port configuration mode. 468 */ 469 static enum sci_status scic_sds_apc_agent_validate_phy_configuration( 470 struct scic_sds_controller *controller, 471 struct scic_sds_port_configuration_agent *port_agent) 472 { 473 u8 phy_index; 474 u8 port_index; 475 struct sci_sas_address sas_address; 476 struct sci_sas_address phy_assigned_address; 477 struct isci_host *ihost = scic_to_ihost(controller); 478 479 phy_index = 0; 480 481 while (phy_index < SCI_MAX_PHYS) { 482 port_index = phy_index; 483 484 /* Get the assigned SAS Address for the first PHY on the controller. */ 485 scic_sds_phy_get_sas_address(&ihost->phys[phy_index].sci, 486 &sas_address); 487 488 while (++phy_index < SCI_MAX_PHYS) { 489 scic_sds_phy_get_sas_address(&ihost->phys[phy_index].sci, 490 &phy_assigned_address); 491 492 /* Verify each of the SAS address are all the same for every PHY */ 493 if (sci_sas_address_compare(sas_address, phy_assigned_address) == 0) { 494 port_agent->phy_valid_port_range[phy_index].min_index = port_index; 495 port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 496 } else { 497 port_agent->phy_valid_port_range[phy_index].min_index = phy_index; 498 port_agent->phy_valid_port_range[phy_index].max_index = phy_index; 499 break; 500 } 501 } 502 } 503 504 return scic_sds_port_configuration_agent_validate_ports(controller, port_agent); 505 } 506 507 /** 508 * 509 * @controller: This is the controller object that receives the link up 510 * notification. 511 * @phy: This is the phy object which has gone link up. 512 * 513 * This method handles the automatic port configuration for link up 514 * notifications. 515 */ 516 static void scic_sds_apc_agent_configure_ports( 517 struct scic_sds_controller *controller, 518 struct scic_sds_port_configuration_agent *port_agent, 519 struct scic_sds_phy *phy, 520 bool start_timer) 521 { 522 u8 port_index; 523 enum sci_status status; 524 struct scic_sds_port *port; 525 enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY; 526 struct isci_host *ihost = scic_to_ihost(controller); 527 528 port = scic_sds_port_configuration_agent_find_port(controller, phy); 529 530 if (port != NULL) { 531 if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)) 532 apc_activity = SCIC_SDS_APC_ADD_PHY; 533 else 534 apc_activity = SCIC_SDS_APC_SKIP_PHY; 535 } else { 536 /* 537 * There is no matching Port for this PHY so lets search through the 538 * Ports and see if we can add the PHY to its own port or maybe start 539 * the timer and wait to see if a wider port can be made. 540 * 541 * Note the break when we reach the condition of the port id == phy id */ 542 for ( 543 port_index = port_agent->phy_valid_port_range[phy->phy_index].min_index; 544 port_index <= port_agent->phy_valid_port_range[phy->phy_index].max_index; 545 port_index++ 546 ) { 547 548 port = &ihost->ports[port_index].sci; 549 550 /* First we must make sure that this PHY can be added to this Port. */ 551 if (scic_sds_port_is_valid_phy_assignment(port, phy->phy_index)) { 552 /* 553 * Port contains a PHY with a greater PHY ID than the current 554 * PHY that has gone link up. This phy can not be part of any 555 * port so skip it and move on. */ 556 if (port->active_phy_mask > (1 << phy->phy_index)) { 557 apc_activity = SCIC_SDS_APC_SKIP_PHY; 558 break; 559 } 560 561 /* 562 * We have reached the end of our Port list and have not found 563 * any reason why we should not either add the PHY to the port 564 * or wait for more phys to become active. */ 565 if (port->physical_port_index == phy->phy_index) { 566 /* 567 * The Port either has no active PHYs. 568 * Consider that if the port had any active PHYs we would have 569 * or active PHYs with 570 * a lower PHY Id than this PHY. */ 571 if (apc_activity != SCIC_SDS_APC_START_TIMER) { 572 apc_activity = SCIC_SDS_APC_ADD_PHY; 573 } 574 575 break; 576 } 577 578 /* 579 * The current Port has no active PHYs and this PHY could be part 580 * of this Port. Since we dont know as yet setup to start the 581 * timer and see if there is a better configuration. */ 582 if (port->active_phy_mask == 0) { 583 apc_activity = SCIC_SDS_APC_START_TIMER; 584 } 585 } else if (port->active_phy_mask != 0) { 586 /* 587 * The Port has an active phy and the current Phy can not 588 * participate in this port so skip the PHY and see if 589 * there is a better configuration. */ 590 apc_activity = SCIC_SDS_APC_SKIP_PHY; 591 } 592 } 593 } 594 595 /* 596 * Check to see if the start timer operations should instead map to an 597 * add phy operation. This is caused because we have been waiting to 598 * add a phy to a port but could not becuase the automatic port 599 * configuration engine had a choice of possible ports for the phy. 600 * Since we have gone through a timeout we are going to restrict the 601 * choice to the smallest possible port. */ 602 if ( 603 (start_timer == false) 604 && (apc_activity == SCIC_SDS_APC_START_TIMER) 605 ) { 606 apc_activity = SCIC_SDS_APC_ADD_PHY; 607 } 608 609 switch (apc_activity) { 610 case SCIC_SDS_APC_ADD_PHY: 611 status = scic_sds_port_add_phy(port, phy); 612 613 if (status == SCI_SUCCESS) { 614 port_agent->phy_configured_mask |= (1 << phy->phy_index); 615 } 616 break; 617 618 case SCIC_SDS_APC_START_TIMER: 619 /* 620 * This can occur for either a link down event, or a link 621 * up event where we cannot yet tell the port to which a 622 * phy belongs. 623 */ 624 if (port_agent->timer_pending) 625 sci_del_timer(&port_agent->timer); 626 627 port_agent->timer_pending = true; 628 sci_mod_timer(&port_agent->timer, 629 SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); 630 break; 631 632 case SCIC_SDS_APC_SKIP_PHY: 633 default: 634 /* do nothing the PHY can not be made part of a port at this time. */ 635 break; 636 } 637 } 638 639 /** 640 * scic_sds_apc_agent_link_up - handle apc link up events 641 * @scic: This is the controller object that receives the link up 642 * notification. 643 * @sci_port: This is the port object associated with the phy. If the is no 644 * associated port this is an NULL. 645 * @sci_phy: This is the phy object which has gone link up. 646 * 647 * This method handles the automatic port configuration for link up 648 * notifications. Is it possible to get a link down notification from a phy 649 * that has no assocoated port? 650 */ 651 static void scic_sds_apc_agent_link_up(struct scic_sds_controller *scic, 652 struct scic_sds_port_configuration_agent *port_agent, 653 struct scic_sds_port *sci_port, 654 struct scic_sds_phy *sci_phy) 655 { 656 u8 phy_index = sci_phy->phy_index; 657 658 if (!sci_port) { 659 /* the phy is not the part of this port */ 660 port_agent->phy_ready_mask |= 1 << phy_index; 661 scic_sds_apc_agent_configure_ports(scic, port_agent, sci_phy, true); 662 } else { 663 /* the phy is already the part of the port */ 664 u32 port_state = sci_port->sm.current_state_id; 665 666 /* if the PORT'S state is resetting then the link up is from 667 * port hard reset in this case, we need to tell the port 668 * that link up is recieved 669 */ 670 BUG_ON(port_state != SCI_PORT_RESETTING); 671 port_agent->phy_ready_mask |= 1 << phy_index; 672 scic_sds_port_link_up(sci_port, sci_phy); 673 } 674 } 675 676 /** 677 * 678 * @controller: This is the controller object that receives the link down 679 * notification. 680 * @port: This is the port object associated with the phy. If the is no 681 * associated port this is an NULL. 682 * @phy: This is the phy object which has gone link down. 683 * 684 * This method handles the automatic port configuration link down 685 * notifications. not associated with a port there is no action taken. Is it 686 * possible to get a link down notification from a phy that has no assocoated 687 * port? 688 */ 689 static void scic_sds_apc_agent_link_down( 690 struct scic_sds_controller *controller, 691 struct scic_sds_port_configuration_agent *port_agent, 692 struct scic_sds_port *port, 693 struct scic_sds_phy *phy) 694 { 695 port_agent->phy_ready_mask &= ~(1 << scic_sds_phy_get_index(phy)); 696 697 if (port != NULL) { 698 if (port_agent->phy_configured_mask & (1 << phy->phy_index)) { 699 enum sci_status status; 700 701 status = scic_sds_port_remove_phy(port, phy); 702 703 if (status == SCI_SUCCESS) { 704 port_agent->phy_configured_mask &= ~(1 << phy->phy_index); 705 } 706 } 707 } 708 } 709 710 /* configure the phys into ports when the timer fires */ 711 static void apc_agent_timeout(unsigned long data) 712 { 713 u32 index; 714 struct sci_timer *tmr = (struct sci_timer *)data; 715 struct scic_sds_port_configuration_agent *port_agent; 716 struct scic_sds_controller *scic; 717 struct isci_host *ihost; 718 unsigned long flags; 719 u16 configure_phy_mask; 720 721 port_agent = container_of(tmr, typeof(*port_agent), timer); 722 scic = container_of(port_agent, typeof(*scic), port_agent); 723 ihost = scic_to_ihost(scic); 724 725 spin_lock_irqsave(&ihost->scic_lock, flags); 726 727 if (tmr->cancel) 728 goto done; 729 730 port_agent->timer_pending = false; 731 732 configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask; 733 734 if (!configure_phy_mask) 735 return; 736 737 for (index = 0; index < SCI_MAX_PHYS; index++) { 738 if ((configure_phy_mask & (1 << index)) == 0) 739 continue; 740 741 scic_sds_apc_agent_configure_ports(scic, port_agent, 742 &ihost->phys[index].sci, false); 743 } 744 745 done: 746 spin_unlock_irqrestore(&ihost->scic_lock, flags); 747 } 748 749 /* 750 * ****************************************************************************** 751 * Public port configuration agent routines 752 * ****************************************************************************** */ 753 754 /** 755 * 756 * 757 * This method will construct the port configuration agent for operation. This 758 * call is universal for both manual port configuration and automatic port 759 * configuration modes. 760 */ 761 void scic_sds_port_configuration_agent_construct( 762 struct scic_sds_port_configuration_agent *port_agent) 763 { 764 u32 index; 765 766 port_agent->phy_configured_mask = 0x00; 767 port_agent->phy_ready_mask = 0x00; 768 769 port_agent->link_up_handler = NULL; 770 port_agent->link_down_handler = NULL; 771 772 port_agent->timer_pending = false; 773 774 for (index = 0; index < SCI_MAX_PORTS; index++) { 775 port_agent->phy_valid_port_range[index].min_index = 0; 776 port_agent->phy_valid_port_range[index].max_index = 0; 777 } 778 } 779 780 enum sci_status scic_sds_port_configuration_agent_initialize( 781 struct scic_sds_controller *scic, 782 struct scic_sds_port_configuration_agent *port_agent) 783 { 784 enum sci_status status; 785 enum scic_port_configuration_mode mode; 786 787 mode = scic->oem_parameters.sds1.controller.mode_type; 788 789 if (mode == SCIC_PORT_MANUAL_CONFIGURATION_MODE) { 790 status = scic_sds_mpc_agent_validate_phy_configuration( 791 scic, port_agent); 792 793 port_agent->link_up_handler = scic_sds_mpc_agent_link_up; 794 port_agent->link_down_handler = scic_sds_mpc_agent_link_down; 795 796 sci_init_timer(&port_agent->timer, mpc_agent_timeout); 797 } else { 798 status = scic_sds_apc_agent_validate_phy_configuration( 799 scic, port_agent); 800 801 port_agent->link_up_handler = scic_sds_apc_agent_link_up; 802 port_agent->link_down_handler = scic_sds_apc_agent_link_down; 803 804 sci_init_timer(&port_agent->timer, apc_agent_timeout); 805 } 806 807 return status; 808 } 809