scif_sas_smp_phy.c revision 231136
1218887Sdim/*- 2218887Sdim * This file is provided under a dual BSD/GPLv2 license. When using or 3353358Sdim * redistributing this file, you may do so under either license. 4353358Sdim * 5353358Sdim * GPL LICENSE SUMMARY 6218887Sdim * 7218887Sdim * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 8218887Sdim * 9309124Sdim * This program is free software; you can redistribute it and/or modify 10218887Sdim * it under the terms of version 2 of the GNU General Public License as 11218887Sdim * published by the Free Software Foundation. 12218887Sdim * 13218887Sdim * This program is distributed in the hope that it will be useful, but 14280031Sdim * WITHOUT ANY WARRANTY; without even the implied warranty of 15280031Sdim * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16218887Sdim * General Public License for more details. 17249423Sdim * 18218887Sdim * You should have received a copy of the GNU General Public License 19218887Sdim * along with this program; if not, write to the Free Software 20218887Sdim * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 21218887Sdim * The full GNU General Public License is included in this distribution 22218887Sdim * in the file called LICENSE.GPL. 23218887Sdim * 24218887Sdim * BSD LICENSE 25218887Sdim * 26218887Sdim * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 27218887Sdim * All rights reserved. 28218887Sdim * 29218887Sdim * Redistribution and use in source and binary forms, with or without 30218887Sdim * modification, are permitted provided that the following conditions 31218887Sdim * are met: 32218887Sdim * 33218887Sdim * * Redistributions of source code must retain the above copyright 34218887Sdim * notice, this list of conditions and the following disclaimer. 35218887Sdim * * Redistributions in binary form must reproduce the above copyright 36218887Sdim * notice, this list of conditions and the following disclaimer in 37218887Sdim * the documentation and/or other materials provided with the 38218887Sdim * distribution. 39341825Sdim * 40218887Sdim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 41314564Sdim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 42360784Sdim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 43261991Sdim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 44218887Sdim * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45360784Sdim * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46218887Sdim * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47360784Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48360784Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49218887Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 50218887Sdim * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51360784Sdim */ 52218887Sdim 53218887Sdim#include <sys/cdefs.h> 54218887Sdim__FBSDID("$FreeBSD: head/sys/dev/isci/scil/scif_sas_smp_phy.c 231136 2012-02-07 17:43:58Z jimharris $"); 55218887Sdim 56218887Sdim/** 57218887Sdim * @file 58218887Sdim * 59218887Sdim * @brief This file contains the implementation of the SCIF_SAS_SMP_PHY 60218887Sdim * object. 61218887Sdim */ 62218887Sdim 63218887Sdim#include <dev/isci/scil/scif_sas_controller.h> 64261991Sdim#include <dev/isci/scil/scif_sas_smp_phy.h> 65218887Sdim#include <dev/isci/scil/scif_sas_smp_remote_device.h> 66218887Sdim 67218887Sdim//****************************************************************************** 68218887Sdim//* 69218887Sdim//* P U B L I C M E T H O D S 70261991Sdim//* 71261991Sdim//****************************************************************************** 72218887Sdim 73218887Sdim/** 74218887Sdim * @brief This routine constructs a smp phy object for an expander phy and insert 75218887Sdim * to owning expander device's smp_phy_list. 76218887Sdim * @param[in] this_smp_phy The memory space to store a phy 77218887Sdim * @param[in] owning_device The smp remote device that owns this smp phy. 78218887Sdim * @param[in] expander_phy_id The expander phy id for this_smp_phy. 79218887Sdim * @return None 80261991Sdim */ 81341825Sdimvoid scif_sas_smp_phy_construct( 82218887Sdim SCIF_SAS_SMP_PHY_T * this_smp_phy, 83341825Sdim SCIF_SAS_REMOTE_DEVICE_T * owning_device, 84224145Sdim U8 expander_phy_id 85224145Sdim) 86224145Sdim{ 87224145Sdim memset(this_smp_phy, 0, sizeof(SCIF_SAS_SMP_PHY_T)); 88224145Sdim 89224145Sdim this_smp_phy->phy_identifier = expander_phy_id; 90341825Sdim this_smp_phy->owning_device = owning_device; 91218887Sdim 92218887Sdim sci_fast_list_element_init((this_smp_phy), (&this_smp_phy->list_element)); 93218887Sdim 94276479Sdim //insert to owning device's smp phy list. 95261991Sdim sci_fast_list_insert_tail( 96261991Sdim (&owning_device->protocol_device.smp_device.smp_phy_list), 97261991Sdim (&this_smp_phy->list_element) 98218887Sdim ); 99218887Sdim} 100218887Sdim 101218887Sdim/** 102218887Sdim * @brief This routine destructs a smp phy object for an expander phy and free the smp 103218887Sdim * phy to controller's smp phy memory. 104218887Sdim * @param[in] this_smp_phy The smp phy to be destructed. 105218887Sdim * 106218887Sdim * @return None 107218887Sdim */ 108218887Sdimvoid scif_sas_smp_phy_destruct( 109218887Sdim SCIF_SAS_SMP_PHY_T * this_smp_phy 110218887Sdim) 111218887Sdim{ 112341825Sdim SCIF_SAS_REMOTE_DEVICE_T * owning_device = this_smp_phy->owning_device; 113219077Sdim SCIF_SAS_CONTROLLER_T * fw_controller = owning_device->domain->controller; 114219077Sdim 115219077Sdim if ( ( this_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE 116219077Sdim || this_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE) 117219077Sdim && this_smp_phy->u.attached_phy != NULL ) 118341825Sdim { 119219077Sdim //update the counterpart phy from the other smp phy list. 120219077Sdim this_smp_phy->u.attached_phy->attached_device_type = SMP_NO_DEVICE_ATTACHED; 121219077Sdim this_smp_phy->u.attached_phy->u.attached_phy = NULL; 122219077Sdim } 123219077Sdim 124219077Sdim //remove curr_smp_phy 125218887Sdim sci_fast_list_remove_element(&this_smp_phy->list_element); 126218887Sdim scif_sas_controller_free_smp_phy(fw_controller, this_smp_phy); 127261991Sdim} 128218887Sdim 129218887Sdim 130261991Sdim/** 131218887Sdim * @brief This routine save a smp phy information based on discover response. 132341825Sdim * 133224145Sdim * @param[in] this_smp_phy The memory space to store a phy 134224145Sdim * @param[in] attached_device A possible direct attached device to this phy. 135341825Sdim * 136224145Sdim * @param[in] discover_response The smp DISCOVER response for this_smp_phy. 137224145Sdim * @return None 138224145Sdim */ 139218887Sdimvoid scif_sas_smp_phy_save_information( 140218887Sdim SCIF_SAS_SMP_PHY_T * this_smp_phy, 141218887Sdim SCIF_SAS_REMOTE_DEVICE_T * attached_device, 142218887Sdim SMP_RESPONSE_DISCOVER_T * discover_response 143218887Sdim) 144218887Sdim{ 145218887Sdim ASSERT (this_smp_phy->owning_device != NULL); 146218887Sdim ASSERT (this_smp_phy->phy_identifier == discover_response->phy_identifier); 147218887Sdim 148218887Sdim 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 */ 176SCI_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 */ 211SCI_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 */ 250SCIF_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 */ 284SCIF_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 */ 319SCIF_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