1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0 3 * 4 * This file is provided under a dual BSD/GPLv2 license. When using or 5 * redistributing this file, you may do so under either license. 6 * 7 * GPL LICENSE SUMMARY 8 * 9 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of version 2 of the GNU General Public License as 13 * published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 23 * The full GNU General Public License is included in this distribution 24 * in the file called LICENSE.GPL. 25 * 26 * BSD LICENSE 27 * 28 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 29 * All rights reserved. 30 * 31 * Redistribution and use in source and binary forms, with or without 32 * modification, are permitted provided that the following conditions 33 * are met: 34 * 35 * * Redistributions of source code must retain the above copyright 36 * notice, this list of conditions and the following disclaimer. 37 * * Redistributions in binary form must reproduce the above copyright 38 * notice, this list of conditions and the following disclaimer in 39 * the documentation and/or other materials provided with the 40 * distribution. 41 * 42 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 43 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 44 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 45 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 46 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 47 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 48 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 49 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 50 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 51 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 52 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 53 */ 54 55 #include <sys/cdefs.h> 56 /** 57 * @file 58 * 59 * @brief This file contains the implementation of the SCIF_SAS_SMP_PHY 60 * object. 61 */ 62 63 #include <dev/isci/scil/scif_sas_controller.h> 64 #include <dev/isci/scil/scif_sas_smp_phy.h> 65 #include <dev/isci/scil/scif_sas_smp_remote_device.h> 66 67 //****************************************************************************** 68 //* 69 //* P U B L I C M E T H O D S 70 //* 71 //****************************************************************************** 72 73 /** 74 * @brief This routine constructs a smp phy object for an expander phy and insert 75 * to owning expander device's smp_phy_list. 76 * @param[in] this_smp_phy The memory space to store a phy 77 * @param[in] owning_device The smp remote device that owns this smp phy. 78 * @param[in] expander_phy_id The expander phy id for this_smp_phy. 79 * @return None 80 */ 81 void scif_sas_smp_phy_construct( 82 SCIF_SAS_SMP_PHY_T * this_smp_phy, 83 SCIF_SAS_REMOTE_DEVICE_T * owning_device, 84 U8 expander_phy_id 85 ) 86 { 87 memset(this_smp_phy, 0, sizeof(SCIF_SAS_SMP_PHY_T)); 88 89 this_smp_phy->phy_identifier = expander_phy_id; 90 this_smp_phy->owning_device = owning_device; 91 92 sci_fast_list_element_init((this_smp_phy), (&this_smp_phy->list_element)); 93 94 //insert to owning device's smp phy list. 95 sci_fast_list_insert_tail( 96 (&owning_device->protocol_device.smp_device.smp_phy_list), 97 (&this_smp_phy->list_element) 98 ); 99 } 100 101 /** 102 * @brief This routine destructs a smp phy object for an expander phy and free the smp 103 * phy to controller's smp phy memory. 104 * @param[in] this_smp_phy The smp phy to be destructed. 105 * 106 * @return None 107 */ 108 void scif_sas_smp_phy_destruct( 109 SCIF_SAS_SMP_PHY_T * this_smp_phy 110 ) 111 { 112 SCIF_SAS_REMOTE_DEVICE_T * owning_device = this_smp_phy->owning_device; 113 SCIF_SAS_CONTROLLER_T * fw_controller = owning_device->domain->controller; 114 115 if ( ( this_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE 116 || this_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE) 117 && this_smp_phy->u.attached_phy != NULL ) 118 { 119 //update the counterpart phy from the other smp phy list. 120 this_smp_phy->u.attached_phy->attached_device_type = SMP_NO_DEVICE_ATTACHED; 121 this_smp_phy->u.attached_phy->u.attached_phy = NULL; 122 } 123 124 //remove curr_smp_phy 125 sci_fast_list_remove_element(&this_smp_phy->list_element); 126 scif_sas_controller_free_smp_phy(fw_controller, this_smp_phy); 127 } 128 129 130 /** 131 * @brief This routine save a smp phy information based on discover response. 132 * 133 * @param[in] this_smp_phy The memory space to store a phy 134 * @param[in] attached_device A possible direct attached device to this phy. 135 * 136 * @param[in] discover_response The smp DISCOVER response for this_smp_phy. 137 * @return None 138 */ 139 void scif_sas_smp_phy_save_information( 140 SCIF_SAS_SMP_PHY_T * this_smp_phy, 141 SCIF_SAS_REMOTE_DEVICE_T * attached_device, 142 SMP_RESPONSE_DISCOVER_T * discover_response 143 ) 144 { 145 ASSERT (this_smp_phy->owning_device != NULL); 146 ASSERT (this_smp_phy->phy_identifier == discover_response->phy_identifier); 147 148 this_smp_phy->attached_device_type = (U8)discover_response->u2.sas1_1.attached_device_type; 149 this_smp_phy->routing_attribute = (U8)discover_response->routing_attribute; 150 this_smp_phy->attached_sas_address = discover_response->attached_sas_address; 151 this_smp_phy->config_route_table_index_anchor = 0; 152 153 if (this_smp_phy->attached_device_type != SMP_EDGE_EXPANDER_DEVICE 154 && this_smp_phy->attached_device_type != SMP_FANOUT_EXPANDER_DEVICE) 155 { 156 //note, end_device field could be an end device, or a NULL value, but can't be expander device. 157 this_smp_phy->u.end_device = attached_device; 158 } 159 else 160 { 161 //if attached device type is expander, we will set u.attached_phy later when the 162 //the attached expander finish its discover on attached_phy. 163 ; 164 } 165 } 166 167 /** 168 * @brief This routine constructs a smp phy object for an expander phy. 169 * @param[in] this_smp_phy The memory space to store a phy 170 * @param[in] owning_device The smp remote device that owns this smp phy. 171 * @param[in] discover_response The smp DISCOVER response for this_smp_phy. 172 * 173 * @return Whether a smp phy has an attached phy and the pair of phy are set 174 * set to each other as attached phy successfully. 175 */ 176 SCI_STATUS scif_sas_smp_phy_set_attached_phy( 177 SCIF_SAS_SMP_PHY_T * this_smp_phy, 178 U8 attached_phy_identifier, 179 SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device 180 ) 181 { 182 //find the attached phy from its owning device by attached_phy_id. 183 SCIF_SAS_SMP_PHY_T * attached_smp_phy = 184 (SCIF_SAS_SMP_PHY_T *)scif_sas_smp_remote_device_find_smp_phy_by_id( 185 attached_phy_identifier, 186 &attached_remote_device->protocol_device.smp_device); 187 188 if (attached_smp_phy != NULL) 189 { 190 this_smp_phy->u.attached_phy = attached_smp_phy; 191 attached_smp_phy->u.attached_phy = this_smp_phy; 192 193 return SCI_SUCCESS; 194 } 195 196 return SCI_FAILURE; 197 } 198 199 200 /** 201 * @brief This method verify the routing attributes of a phy connection per 202 * specification. 203 * 204 * @param[in] this_smp_phy One smp phy belongs to a smp phy connection. 205 * @param[in] attached_smp_phy One smp phy belongs to a smp phy connection. 206 * 207 * @return Whether routing attributes of a phy connection is legal. 208 * @retval SCI_SUCCESS indicates a good phy connection. 209 * SCI_FAILURE indicates a illegal phy connection. 210 */ 211 SCI_STATUS scif_sas_smp_phy_verify_routing_attribute( 212 SCIF_SAS_SMP_PHY_T * this_smp_phy, 213 SCIF_SAS_SMP_PHY_T * attached_smp_phy 214 ) 215 { 216 SCI_STATUS status = SCI_SUCCESS; 217 218 //expander phy with direct routing attribute can only connect to 219 //phy with direct routing attribute. 220 if ( this_smp_phy->routing_attribute == DIRECT_ROUTING_ATTRIBUTE 221 || attached_smp_phy->routing_attribute == DIRECT_ROUTING_ATTRIBUTE ) 222 { 223 if ( (this_smp_phy->routing_attribute | attached_smp_phy->routing_attribute) 224 != DIRECT_ROUTING_ATTRIBUTE ) 225 status = SCI_FAILURE; 226 } 227 228 if (this_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE 229 && attached_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE) 230 { 231 if ( ! this_smp_phy->owning_device->protocol_device.smp_device.is_table_to_table_supported 232 || !attached_smp_phy->owning_device->protocol_device.smp_device.is_table_to_table_supported ) 233 status = SCI_FAILURE; 234 } 235 236 return status; 237 } 238 239 240 /** 241 * @brief This method find The next smp phy that is in the smp phy list and 242 * resides in the same wide port as this_smp_phy. 243 * 244 * @param[in] this_smp_phy The smp phy whose neighbor phy that is in the same 245 * same wide port is to be find. 246 * 247 * @return The next smp phy that is in the smp phy list and resides in the same 248 * wide port as this_smp_phy. 249 */ 250 SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_next_phy_in_wide_port( 251 SCIF_SAS_SMP_PHY_T * this_smp_phy 252 ) 253 { 254 SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next( 255 &(this_smp_phy->list_element) ); 256 257 SCIF_SAS_SMP_PHY_T * next_phy; 258 259 while (next_phy_element != NULL) 260 { 261 next_phy = (SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element); 262 263 next_phy_element = sci_fast_list_get_next( &(next_phy->list_element)); 264 265 if (next_phy->attached_sas_address.high == this_smp_phy->attached_sas_address.high 266 &&next_phy->attached_sas_address.low == this_smp_phy->attached_sas_address.low) 267 return next_phy; 268 } 269 270 return NULL; 271 } 272 273 274 /** 275 * @brief This method find the smp phy that resides in the middle of the same 276 * wide port as this_smp_phy. 277 * 278 * @param[in] this_smp_phy The smp phy who is the lowest order phy in a wide 279 * port . 280 * 281 * @return The next smp phy that is in the smp phy list and resides in the same 282 * wide port as this_smp_phy. 283 */ 284 SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_middle_phy_in_wide_port( 285 SCIF_SAS_SMP_PHY_T * this_smp_phy 286 ) 287 { 288 SCIF_SAS_SMP_PHY_T * next_phy = 289 scif_sas_smp_phy_find_next_phy_in_wide_port(this_smp_phy); 290 SCIF_SAS_SMP_PHY_T * middle_phy = this_smp_phy; 291 292 //currently we assume a wide port could not be wider than X4. so the 293 //second phy is always the correct answer for x2, x3 or x4 wide port. 294 //For a narrow port, phy0 is the middle phy. 295 if (next_phy != NULL) 296 { 297 middle_phy = next_phy; 298 next_phy = 299 scif_sas_smp_phy_find_next_phy_in_wide_port(next_phy); 300 } 301 302 if (next_phy != NULL) 303 middle_phy = next_phy; 304 305 return middle_phy; 306 } 307 308 309 /** 310 * @brief This method find the smp phy that is the hishest order phy 311 * in the same wide port as this_smp_phy. 312 * 313 * @param[in] this_smp_phy The smp phy who is the lowest order phy in a wide 314 * port. 315 * 316 * @return The next smp phy that is in the smp phy list and resides in the same 317 * wide port as this_smp_phy. 318 */ 319 SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_highest_phy_in_wide_port( 320 SCIF_SAS_SMP_PHY_T * this_smp_phy 321 ) 322 { 323 SCIF_SAS_SMP_PHY_T * next_phy = 324 scif_sas_smp_phy_find_next_phy_in_wide_port(this_smp_phy); 325 SCIF_SAS_SMP_PHY_T * highest_phy = this_smp_phy; 326 327 while(next_phy != NULL ) 328 { 329 highest_phy = next_phy; 330 next_phy = 331 scif_sas_smp_phy_find_next_phy_in_wide_port(next_phy); 332 } 333 334 return highest_phy; 335 } 336