1230557Sjimharris/*- 2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license. When using or 3230557Sjimharris * redistributing this file, you may do so under either license. 4230557Sjimharris * 5230557Sjimharris * GPL LICENSE SUMMARY 6230557Sjimharris * 7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 8230557Sjimharris * 9230557Sjimharris * This program is free software; you can redistribute it and/or modify 10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as 11230557Sjimharris * published by the Free Software Foundation. 12230557Sjimharris * 13230557Sjimharris * This program is distributed in the hope that it will be useful, but 14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of 15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16230557Sjimharris * General Public License for more details. 17230557Sjimharris * 18230557Sjimharris * You should have received a copy of the GNU General Public License 19230557Sjimharris * along with this program; if not, write to the Free Software 20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 21230557Sjimharris * The full GNU General Public License is included in this distribution 22230557Sjimharris * in the file called LICENSE.GPL. 23230557Sjimharris * 24230557Sjimharris * BSD LICENSE 25230557Sjimharris * 26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. 27230557Sjimharris * All rights reserved. 28230557Sjimharris * 29230557Sjimharris * Redistribution and use in source and binary forms, with or without 30230557Sjimharris * modification, are permitted provided that the following conditions 31230557Sjimharris * are met: 32230557Sjimharris * 33230557Sjimharris * * Redistributions of source code must retain the above copyright 34230557Sjimharris * notice, this list of conditions and the following disclaimer. 35230557Sjimharris * * Redistributions in binary form must reproduce the above copyright 36230557Sjimharris * notice, this list of conditions and the following disclaimer in 37230557Sjimharris * the documentation and/or other materials provided with the 38230557Sjimharris * distribution. 39230557Sjimharris * 40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51230557Sjimharris */ 52230557Sjimharris 53230557Sjimharris#include <sys/cdefs.h> 54230557Sjimharris__FBSDID("$FreeBSD$"); 55230557Sjimharris 56230557Sjimharris/** 57230557Sjimharris * @file 58230557Sjimharris * 59230557Sjimharris * @brief This file contains the implementation of the SCIF_SAS_SMP_PHY 60230557Sjimharris * object. 61230557Sjimharris */ 62230557Sjimharris 63230557Sjimharris#include <dev/isci/scil/scif_sas_controller.h> 64230557Sjimharris#include <dev/isci/scil/scif_sas_smp_phy.h> 65230557Sjimharris#include <dev/isci/scil/scif_sas_smp_remote_device.h> 66230557Sjimharris 67230557Sjimharris//****************************************************************************** 68230557Sjimharris//* 69230557Sjimharris//* P U B L I C M E T H O D S 70230557Sjimharris//* 71230557Sjimharris//****************************************************************************** 72230557Sjimharris 73230557Sjimharris/** 74230557Sjimharris * @brief This routine constructs a smp phy object for an expander phy and insert 75230557Sjimharris * to owning expander device's smp_phy_list. 76230557Sjimharris * @param[in] this_smp_phy The memory space to store a phy 77230557Sjimharris * @param[in] owning_device The smp remote device that owns this smp phy. 78230557Sjimharris * @param[in] expander_phy_id The expander phy id for this_smp_phy. 79230557Sjimharris * @return None 80230557Sjimharris */ 81230557Sjimharrisvoid scif_sas_smp_phy_construct( 82230557Sjimharris SCIF_SAS_SMP_PHY_T * this_smp_phy, 83230557Sjimharris SCIF_SAS_REMOTE_DEVICE_T * owning_device, 84230557Sjimharris U8 expander_phy_id 85230557Sjimharris) 86230557Sjimharris{ 87230557Sjimharris memset(this_smp_phy, 0, sizeof(SCIF_SAS_SMP_PHY_T)); 88230557Sjimharris 89230557Sjimharris this_smp_phy->phy_identifier = expander_phy_id; 90230557Sjimharris this_smp_phy->owning_device = owning_device; 91230557Sjimharris 92230557Sjimharris sci_fast_list_element_init((this_smp_phy), (&this_smp_phy->list_element)); 93230557Sjimharris 94230557Sjimharris //insert to owning device's smp phy list. 95230557Sjimharris sci_fast_list_insert_tail( 96230557Sjimharris (&owning_device->protocol_device.smp_device.smp_phy_list), 97230557Sjimharris (&this_smp_phy->list_element) 98230557Sjimharris ); 99230557Sjimharris} 100230557Sjimharris 101230557Sjimharris/** 102230557Sjimharris * @brief This routine destructs a smp phy object for an expander phy and free the smp 103230557Sjimharris * phy to controller's smp phy memory. 104230557Sjimharris * @param[in] this_smp_phy The smp phy to be destructed. 105230557Sjimharris * 106230557Sjimharris * @return None 107230557Sjimharris */ 108230557Sjimharrisvoid scif_sas_smp_phy_destruct( 109230557Sjimharris SCIF_SAS_SMP_PHY_T * this_smp_phy 110230557Sjimharris) 111230557Sjimharris{ 112230557Sjimharris SCIF_SAS_REMOTE_DEVICE_T * owning_device = this_smp_phy->owning_device; 113230557Sjimharris SCIF_SAS_CONTROLLER_T * fw_controller = owning_device->domain->controller; 114230557Sjimharris 115230557Sjimharris if ( ( this_smp_phy->attached_device_type == SMP_EDGE_EXPANDER_DEVICE 116230557Sjimharris || this_smp_phy->attached_device_type == SMP_FANOUT_EXPANDER_DEVICE) 117230557Sjimharris && this_smp_phy->u.attached_phy != NULL ) 118230557Sjimharris { 119230557Sjimharris //update the counterpart phy from the other smp phy list. 120230557Sjimharris this_smp_phy->u.attached_phy->attached_device_type = SMP_NO_DEVICE_ATTACHED; 121230557Sjimharris this_smp_phy->u.attached_phy->u.attached_phy = NULL; 122230557Sjimharris } 123230557Sjimharris 124230557Sjimharris //remove curr_smp_phy 125230557Sjimharris sci_fast_list_remove_element(&this_smp_phy->list_element); 126230557Sjimharris scif_sas_controller_free_smp_phy(fw_controller, this_smp_phy); 127230557Sjimharris} 128230557Sjimharris 129230557Sjimharris 130230557Sjimharris/** 131230557Sjimharris * @brief This routine save a smp phy information based on discover response. 132230557Sjimharris * 133230557Sjimharris * @param[in] this_smp_phy The memory space to store a phy 134230557Sjimharris * @param[in] attached_device A possible direct attached device to this phy. 135230557Sjimharris * 136230557Sjimharris * @param[in] discover_response The smp DISCOVER response for this_smp_phy. 137230557Sjimharris * @return None 138230557Sjimharris */ 139230557Sjimharrisvoid scif_sas_smp_phy_save_information( 140230557Sjimharris SCIF_SAS_SMP_PHY_T * this_smp_phy, 141230557Sjimharris SCIF_SAS_REMOTE_DEVICE_T * attached_device, 142230557Sjimharris SMP_RESPONSE_DISCOVER_T * discover_response 143230557Sjimharris) 144230557Sjimharris{ 145230557Sjimharris ASSERT (this_smp_phy->owning_device != NULL); 146230557Sjimharris ASSERT (this_smp_phy->phy_identifier == discover_response->phy_identifier); 147230557Sjimharris 148230557Sjimharris this_smp_phy->attached_device_type = (U8)discover_response->u2.sas1_1.attached_device_type; 149230557Sjimharris this_smp_phy->routing_attribute = (U8)discover_response->routing_attribute; 150230557Sjimharris this_smp_phy->attached_sas_address = discover_response->attached_sas_address; 151230557Sjimharris this_smp_phy->config_route_table_index_anchor = 0; 152230557Sjimharris 153230557Sjimharris if (this_smp_phy->attached_device_type != SMP_EDGE_EXPANDER_DEVICE 154230557Sjimharris && this_smp_phy->attached_device_type != SMP_FANOUT_EXPANDER_DEVICE) 155230557Sjimharris { 156230557Sjimharris //note, end_device field could be an end device, or a NULL value, but can't be expander device. 157230557Sjimharris this_smp_phy->u.end_device = attached_device; 158230557Sjimharris } 159230557Sjimharris else 160230557Sjimharris { 161230557Sjimharris //if attached device type is expander, we will set u.attached_phy later when the 162230557Sjimharris //the attached expander finish its discover on attached_phy. 163230557Sjimharris ; 164230557Sjimharris } 165230557Sjimharris} 166230557Sjimharris 167230557Sjimharris/** 168230557Sjimharris * @brief This routine constructs a smp phy object for an expander phy. 169230557Sjimharris * @param[in] this_smp_phy The memory space to store a phy 170230557Sjimharris * @param[in] owning_device The smp remote device that owns this smp phy. 171230557Sjimharris * @param[in] discover_response The smp DISCOVER response for this_smp_phy. 172230557Sjimharris * 173230557Sjimharris * @return Whether a smp phy has an attached phy and the pair of phy are set 174230557Sjimharris * set to each other as attached phy successfully. 175230557Sjimharris */ 176230557SjimharrisSCI_STATUS scif_sas_smp_phy_set_attached_phy( 177230557Sjimharris SCIF_SAS_SMP_PHY_T * this_smp_phy, 178230557Sjimharris U8 attached_phy_identifier, 179230557Sjimharris SCIF_SAS_REMOTE_DEVICE_T * attached_remote_device 180230557Sjimharris) 181230557Sjimharris{ 182230557Sjimharris //find the attached phy from its owning device by attached_phy_id. 183230557Sjimharris SCIF_SAS_SMP_PHY_T * attached_smp_phy = 184230557Sjimharris (SCIF_SAS_SMP_PHY_T *)scif_sas_smp_remote_device_find_smp_phy_by_id( 185230557Sjimharris attached_phy_identifier, 186230557Sjimharris &attached_remote_device->protocol_device.smp_device); 187230557Sjimharris 188230557Sjimharris if (attached_smp_phy != NULL) 189230557Sjimharris { 190230557Sjimharris this_smp_phy->u.attached_phy = attached_smp_phy; 191230557Sjimharris attached_smp_phy->u.attached_phy = this_smp_phy; 192230557Sjimharris 193230557Sjimharris return SCI_SUCCESS; 194230557Sjimharris } 195230557Sjimharris 196230557Sjimharris return SCI_FAILURE; 197230557Sjimharris} 198230557Sjimharris 199230557Sjimharris 200230557Sjimharris/** 201230557Sjimharris * @brief This method verify the routing attributes of a phy connection per 202230557Sjimharris * specification. 203230557Sjimharris * 204230557Sjimharris * @param[in] this_smp_phy One smp phy belongs to a smp phy connection. 205230557Sjimharris * @param[in] attached_smp_phy One smp phy belongs to a smp phy connection. 206230557Sjimharris * 207230557Sjimharris * @return Whether routing attributes of a phy connection is legal. 208230557Sjimharris * @retval SCI_SUCCESS indicates a good phy connection. 209230557Sjimharris * SCI_FAILURE indicates a illegal phy connection. 210230557Sjimharris */ 211230557SjimharrisSCI_STATUS scif_sas_smp_phy_verify_routing_attribute( 212230557Sjimharris SCIF_SAS_SMP_PHY_T * this_smp_phy, 213230557Sjimharris SCIF_SAS_SMP_PHY_T * attached_smp_phy 214230557Sjimharris) 215230557Sjimharris{ 216230557Sjimharris SCI_STATUS status = SCI_SUCCESS; 217230557Sjimharris 218230557Sjimharris //expander phy with direct routing attribute can only connect to 219230557Sjimharris //phy with direct routing attribute. 220230557Sjimharris if ( this_smp_phy->routing_attribute == DIRECT_ROUTING_ATTRIBUTE 221230557Sjimharris || attached_smp_phy->routing_attribute == DIRECT_ROUTING_ATTRIBUTE ) 222230557Sjimharris { 223230557Sjimharris if ( (this_smp_phy->routing_attribute | attached_smp_phy->routing_attribute) 224230557Sjimharris != DIRECT_ROUTING_ATTRIBUTE ) 225230557Sjimharris status = SCI_FAILURE; 226230557Sjimharris } 227230557Sjimharris 228230557Sjimharris if (this_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE 229230557Sjimharris && attached_smp_phy->routing_attribute == TABLE_ROUTING_ATTRIBUTE) 230230557Sjimharris { 231230557Sjimharris if ( ! this_smp_phy->owning_device->protocol_device.smp_device.is_table_to_table_supported 232230557Sjimharris || !attached_smp_phy->owning_device->protocol_device.smp_device.is_table_to_table_supported ) 233230557Sjimharris status = SCI_FAILURE; 234230557Sjimharris } 235230557Sjimharris 236230557Sjimharris return status; 237230557Sjimharris} 238230557Sjimharris 239230557Sjimharris 240230557Sjimharris/** 241230557Sjimharris * @brief This method find The next smp phy that is in the smp phy list and 242230557Sjimharris * resides in the same wide port as this_smp_phy. 243230557Sjimharris * 244230557Sjimharris * @param[in] this_smp_phy The smp phy whose neighbor phy that is in the same 245230557Sjimharris * same wide port is to be find. 246230557Sjimharris * 247230557Sjimharris * @return The next smp phy that is in the smp phy list and resides in the same 248230557Sjimharris * wide port as this_smp_phy. 249230557Sjimharris */ 250230557SjimharrisSCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_next_phy_in_wide_port( 251230557Sjimharris SCIF_SAS_SMP_PHY_T * this_smp_phy 252230557Sjimharris) 253230557Sjimharris{ 254230557Sjimharris SCI_FAST_LIST_ELEMENT_T * next_phy_element = sci_fast_list_get_next( 255230557Sjimharris &(this_smp_phy->list_element) ); 256230557Sjimharris 257230557Sjimharris SCIF_SAS_SMP_PHY_T * next_phy; 258230557Sjimharris 259230557Sjimharris while (next_phy_element != NULL) 260230557Sjimharris { 261230557Sjimharris next_phy = (SCIF_SAS_SMP_PHY_T *)sci_fast_list_get_object(next_phy_element); 262230557Sjimharris 263230557Sjimharris next_phy_element = sci_fast_list_get_next( &(next_phy->list_element)); 264230557Sjimharris 265230557Sjimharris if (next_phy->attached_sas_address.high == this_smp_phy->attached_sas_address.high 266230557Sjimharris &&next_phy->attached_sas_address.low == this_smp_phy->attached_sas_address.low) 267230557Sjimharris return next_phy; 268230557Sjimharris } 269230557Sjimharris 270230557Sjimharris return NULL; 271230557Sjimharris} 272230557Sjimharris 273230557Sjimharris 274230557Sjimharris/** 275230557Sjimharris * @brief This method find the smp phy that resides in the middle of the same 276230557Sjimharris * wide port as this_smp_phy. 277230557Sjimharris * 278230557Sjimharris * @param[in] this_smp_phy The smp phy who is the lowest order phy in a wide 279230557Sjimharris * port . 280230557Sjimharris * 281230557Sjimharris * @return The next smp phy that is in the smp phy list and resides in the same 282230557Sjimharris * wide port as this_smp_phy. 283230557Sjimharris */ 284230557SjimharrisSCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_middle_phy_in_wide_port( 285230557Sjimharris SCIF_SAS_SMP_PHY_T * this_smp_phy 286230557Sjimharris) 287230557Sjimharris{ 288230557Sjimharris SCIF_SAS_SMP_PHY_T * next_phy = 289230557Sjimharris scif_sas_smp_phy_find_next_phy_in_wide_port(this_smp_phy); 290230557Sjimharris SCIF_SAS_SMP_PHY_T * middle_phy = this_smp_phy; 291230557Sjimharris 292230557Sjimharris //currently we assume a wide port could not be wider than X4. so the 293230557Sjimharris //second phy is always the correct answer for x2, x3 or x4 wide port. 294230557Sjimharris //For a narrow port, phy0 is the middle phy. 295230557Sjimharris if (next_phy != NULL) 296230557Sjimharris { 297230557Sjimharris middle_phy = next_phy; 298230557Sjimharris next_phy = 299230557Sjimharris scif_sas_smp_phy_find_next_phy_in_wide_port(next_phy); 300230557Sjimharris } 301230557Sjimharris 302230557Sjimharris if (next_phy != NULL) 303230557Sjimharris middle_phy = next_phy; 304230557Sjimharris 305230557Sjimharris return middle_phy; 306230557Sjimharris} 307230557Sjimharris 308230557Sjimharris 309230557Sjimharris/** 310230557Sjimharris * @brief This method find the smp phy that is the hishest order phy 311230557Sjimharris * in the same wide port as this_smp_phy. 312230557Sjimharris * 313230557Sjimharris * @param[in] this_smp_phy The smp phy who is the lowest order phy in a wide 314230557Sjimharris * port. 315230557Sjimharris * 316230557Sjimharris * @return The next smp phy that is in the smp phy list and resides in the same 317230557Sjimharris * wide port as this_smp_phy. 318230557Sjimharris */ 319230557SjimharrisSCIF_SAS_SMP_PHY_T * scif_sas_smp_phy_find_highest_phy_in_wide_port( 320230557Sjimharris SCIF_SAS_SMP_PHY_T * this_smp_phy 321230557Sjimharris) 322230557Sjimharris{ 323230557Sjimharris SCIF_SAS_SMP_PHY_T * next_phy = 324230557Sjimharris scif_sas_smp_phy_find_next_phy_in_wide_port(this_smp_phy); 325230557Sjimharris SCIF_SAS_SMP_PHY_T * highest_phy = this_smp_phy; 326230557Sjimharris 327230557Sjimharris while(next_phy != NULL ) 328230557Sjimharris { 329230557Sjimharris highest_phy = next_phy; 330230557Sjimharris next_phy = 331230557Sjimharris scif_sas_smp_phy_find_next_phy_in_wide_port(next_phy); 332230557Sjimharris } 333230557Sjimharris 334230557Sjimharris return highest_phy; 335230557Sjimharris} 336