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 of the SCIF_SAS_SMP_PHY 62 * object. 63 */ 64 65 #include <dev/isci/scil/scif_sas_controller.h> 66 #include <dev/isci/scil/scif_sas_smp_phy.h> 67 #include <dev/isci/scil/scif_sas_smp_remote_device.h> 68 69 //****************************************************************************** 70 //* 71 //* P U B L I C M E T H O D S 72 //* 73 //****************************************************************************** 74 75 /** 76 * @brief This routine constructs a smp phy object for an expander phy and insert 77 * to owning expander device's smp_phy_list. 78 * @param[in] this_smp_phy The memory space to store a phy 79 * @param[in] owning_device The smp remote device that owns this smp phy. 80 * @param[in] expander_phy_id The expander phy id for this_smp_phy. 81 * @return None 82 */ 83 void scif_sas_smp_phy_construct( 84 SCIF_SAS_SMP_PHY_T * this_smp_phy, 85 SCIF_SAS_REMOTE_DEVICE_T * owning_device, 86 U8 expander_phy_id 87 ) 88 { 89 memset(this_smp_phy, 0, sizeof(SCIF_SAS_SMP_PHY_T)); 90 91 this_smp_phy->phy_identifier = expander_phy_id; 92 this_smp_phy->owning_device = owning_device; 93 94 sci_fast_list_element_init((this_smp_phy), (&this_smp_phy->list_element)); 95 96 //insert to owning device's smp phy list. 97 sci_fast_list_insert_tail( 98 (&owning_device->protocol_device.smp_device.smp_phy_list), 99 (&this_smp_phy->list_element) 100 ); 101 } 102 103 /** 104 * @brief This routine destructs a smp phy object for an expander phy and free the smp 105 * phy to controller's smp phy memory. 106 * @param[in] this_smp_phy The smp phy to be destructed. 107 * 108 * @return None 109 */ 110 void scif_sas_smp_phy_destruct( 111 SCIF_SAS_SMP_PHY_T * this_smp_phy 112 ) 113 { 114 SCIF_SAS_REMOTE_DEVICE_T * owning_device = this_smp_phy->owning_device; 115 SCIF_SAS_CONTROLLER_T * fw_controller = owning_device->domain->controller; 116 117 if ( ( this_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE 118 || this_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE) 119 && this_smp_phy->u.attached_phy != NULL ) 120 { 121 //update the counterpart phy from the other smp phy list. 122 this_smp_phy->u.attached_phy->attached_device_type = SMP_NO_DEVICE_ATTACHED; 123 this_smp_phy->u.attached_phy->u.attached_phy = NULL; 124 } 125 126 //remove curr_smp_phy 127 sci_fast_list_remove_element(&this_smp_phy->list_element); 128 scif_sas_controller_free_smp_phy(fw_controller, this_smp_phy); 129 } 130 131 132 /** 133 * @brief This routine save a smp phy information based on discover response. 134 * 135 * @param[in] this_smp_phy The memory space to store a phy 136 * @param[in] attached_device A possible direct attached device to this phy. 137 * 138 * @param[in] discover_response The smp DISCOVER response for this_smp_phy. 139 * @return None 140 */ 141 void scif_sas_smp_phy_save_information( 142 SCIF_SAS_SMP_PHY_T * this_smp_phy, 143 SCIF_SAS_REMOTE_DEVICE_T * attached_device, 144 SMP_RESPONSE_DISCOVER_T * discover_response 145 ) 146 { 147 ASSERT (this_smp_phy->owning_device != NULL); 148 ASSERT (this_smp_phy->phy_identifier == discover_response->phy_identifier); 149 150 this_smp_phy->attached_device_type = (U8)discover_response->u2.sas1_1.attached_device_type; 151 this_smp_phy->routing_attribute = (U8)discover_response->routing_attribute; 152 this_smp_phy->attached_sas_address = discover_response->attached_sas_address; 153 this_smp_phy->config_route_table_index_anchor = 0; 154 155 if (this_smp_phy->attached_device_type != SMP_EDGE_EXPANDER_DEVICE 156 && this_smp_phy->attached_device_type != SMP_FANOUT_EXPANDER_DEVICE) 157 { 158 //note, end_device field could be an end device, or a NULL value, but can't be expander device. 159 this_smp_phy->u.end_device = attached_device; 160 } 161 else 162 { 163 //if attached device type is expander, we will set u.attached_phy later when the 164 //the attached expander finish its discover on attached_phy. 165 ; 166 } 167 } 168 169 /** 170 * @brief This routine constructs a smp phy object for an expander phy. 171 * @param[in] this_smp_phy The memory space to store a phy 172 * @param[in] owning_device The smp remote device that owns this smp phy. 173 * @param[in] discover_response The smp DISCOVER response for this_smp_phy. 174 * 175 * @return Whether a smp phy has an attached phy and the pair of phy are set 176 * set to each other as attached phy successfully. 177 */ 178 SCI_STATUS scif_sas_smp_phy_set_attached_phy( 179 SCIF_SAS_SMP_PHY_T * this_smp_phy, 180 U8 attached_phy_identifier, 181 SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device 182 ) 183 { 184 //find the attached phy from its owning device by attached_phy_id. 185 SCIF_SAS_SMP_PHY_T * attached_smp_phy = 186 (SCIF_SAS_SMP_PHY_T *)scif_sas_smp_remote_device_find_smp_phy_by_id( 187 attached_phy_identifier, 188 &attached_remote_device->protocol_device.smp_device); 189 190 if (attached_smp_phy != NULL) 191 { 192 this_smp_phy->u.attached_phy = attached_smp_phy; 193 attached_smp_phy->u.attached_phy = this_smp_phy; 194 195 return SCI_SUCCESS; 196 } 197 198 return SCI_FAILURE; 199 } 200 201 202 /** 203 * @brief This method verify the routing attributes of a phy connection per 204 * specification. 205 * 206 * @param[in] this_smp_phy One smp phy belongs to a smp phy connection. 207 * @param[in] attached_smp_phy One smp phy belongs to a smp phy connection. 208 * 209 * @return Whether routing attributes of a phy connection is legal. 210 * @retval SCI_SUCCESS indicates a good phy connection. 211 * SCI_FAILURE indicates a illegal phy connection. 212 */ 213 SCI_STATUS scif_sas_smp_phy_verify_routing_attribute( 214 SCIF_SAS_SMP_PHY_T * this_smp_phy, 215 SCIF_SAS_SMP_PHY_T * attached_smp_phy 216 ) 217 { 218 SCI_STATUS status = SCI_SUCCESS; 219 220 //expander phy with direct routing attribute can only connect to 221 //phy with direct routing attribute. 222 if ( this_smp_phy->routing_attribute == DIRECT_ROUTING_ATTRIBUTE 223 || attached_smp_phy->routing_attribute == DIRECT_ROUTING_ATTRIBUTE ) 224 { 225 if ( (this_smp_phy->routing_attribute | attached_smp_phy->routing_attribute) 226 != DIRECT_ROUTING_ATTRIBUTE ) 227 status = SCI_FAILURE; 228 } 229 230 if (this_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE 231 && attached_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE) 232 { 233 if ( ! this_smp_phy->owning_device->protocol_device.smp_device.is_table_to_table_supported 234 || !attached_smp_phy->owning_device->protocol_device.smp_device.is_table_to_table_supported ) 235 status = SCI_FAILURE; 236 } 237 238 return status; 239 } 240 241 242 /** 243 * @brief This method find The next smp phy that is in the smp phy list and 244 * resides in the same wide port as this_smp_phy. 245 * 246 * @param[in] this_smp_phy The smp phy whose neighbor phy that is in the same 247 * same wide port is to be find. 248 * 249 * @return The next smp phy that is in the smp phy list and resides in the same 250 * wide port as this_smp_phy. 251 */ 252 SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_next_phy_in_wide_port( 253 SCIF_SAS_SMP_PHY_T * this_smp_phy 254 ) 255 { 256 SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next( 257 &(this_smp_phy->list_element) ); 258 259 SCIF_SAS_SMP_PHY_T * next_phy; 260 261 while (next_phy_element != NULL) 262 { 263 next_phy = (SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element); 264 265 next_phy_element = sci_fast_list_get_next( &(next_phy->list_element)); 266 267 if (next_phy->attached_sas_address.high == this_smp_phy->attached_sas_address.high 268 &&next_phy->attached_sas_address.low == this_smp_phy->attached_sas_address.low) 269 return next_phy; 270 } 271 272 return NULL; 273 } 274 275 276 /** 277 * @brief This method find the smp phy that resides in the middle of the same 278 * wide port as this_smp_phy. 279 * 280 * @param[in] this_smp_phy The smp phy who is the lowest order phy in a wide 281 * port . 282 * 283 * @return The next smp phy that is in the smp phy list and resides in the same 284 * wide port as this_smp_phy. 285 */ 286 SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_middle_phy_in_wide_port( 287 SCIF_SAS_SMP_PHY_T * this_smp_phy 288 ) 289 { 290 SCIF_SAS_SMP_PHY_T * next_phy = 291 scif_sas_smp_phy_find_next_phy_in_wide_port(this_smp_phy); 292 SCIF_SAS_SMP_PHY_T * middle_phy = this_smp_phy; 293 294 //currently we assume a wide port could not be wider than X4. so the 295 //second phy is always the correct answer for x2, x3 or x4 wide port. 296 //For a narrow port, phy0 is the middle phy. 297 if (next_phy != NULL) 298 { 299 middle_phy = next_phy; 300 next_phy = 301 scif_sas_smp_phy_find_next_phy_in_wide_port(next_phy); 302 } 303 304 if (next_phy != NULL) 305 middle_phy = next_phy; 306 307 return middle_phy; 308 } 309 310 311 /** 312 * @brief This method find the smp phy that is the hishest order phy 313 * in the same wide port as this_smp_phy. 314 * 315 * @param[in] this_smp_phy The smp phy who is the lowest order phy in a wide 316 * port. 317 * 318 * @return The next smp phy that is in the smp phy list and resides in the same 319 * wide port as this_smp_phy. 320 */ 321 SCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_highest_phy_in_wide_port( 322 SCIF_SAS_SMP_PHY_T * this_smp_phy 323 ) 324 { 325 SCIF_SAS_SMP_PHY_T * next_phy = 326 scif_sas_smp_phy_find_next_phy_in_wide_port(this_smp_phy); 327 SCIF_SAS_SMP_PHY_T * highest_phy = this_smp_phy; 328 329 while(next_phy != NULL ) 330 { 331 highest_phy = next_phy; 332 next_phy = 333 scif_sas_smp_phy_find_next_phy_in_wide_port(next_phy); 334 } 335 336 return highest_phy; 337 } 338