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 <linux/workqueue.h> 57 #include "isci.h" 58 #include "scic_phy.h" 59 #include "scic_sds_phy.h" 60 #include "scic_port.h" 61 #include "port.h" 62 #include "request.h" 63 64 static void isci_port_change_state(struct isci_port *iport, enum isci_status status) 65 { 66 unsigned long flags; 67 68 dev_dbg(&iport->isci_host->pdev->dev, 69 "%s: iport = %p, state = 0x%x\n", 70 __func__, iport, status); 71 72 /* XXX pointless lock */ 73 spin_lock_irqsave(&iport->state_lock, flags); 74 iport->status = status; 75 spin_unlock_irqrestore(&iport->state_lock, flags); 76 } 77 78 void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index) 79 { 80 INIT_LIST_HEAD(&iport->remote_dev_list); 81 INIT_LIST_HEAD(&iport->domain_dev_list); 82 spin_lock_init(&iport->state_lock); 83 init_completion(&iport->start_complete); 84 iport->isci_host = ihost; 85 isci_port_change_state(iport, isci_freed); 86 } 87 88 /** 89 * isci_port_get_state() - This function gets the status of the port object. 90 * @isci_port: This parameter points to the isci_port object 91 * 92 * status of the object as a isci_status enum. 93 */ 94 enum isci_status isci_port_get_state( 95 struct isci_port *isci_port) 96 { 97 return isci_port->status; 98 } 99 100 void isci_port_bc_change_received(struct isci_host *ihost, 101 struct scic_sds_port *sci_port, 102 struct scic_sds_phy *sci_phy) 103 { 104 struct isci_phy *iphy = sci_phy_to_iphy(sci_phy); 105 106 dev_dbg(&ihost->pdev->dev, "%s: iphy = %p, sas_phy = %p\n", 107 __func__, iphy, &iphy->sas_phy); 108 109 ihost->sas_ha.notify_port_event(&iphy->sas_phy, PORTE_BROADCAST_RCVD); 110 scic_port_enable_broadcast_change_notification(sci_port); 111 } 112 113 void isci_port_link_up(struct isci_host *isci_host, 114 struct scic_sds_port *port, 115 struct scic_sds_phy *phy) 116 { 117 unsigned long flags; 118 struct scic_port_properties properties; 119 struct isci_phy *isci_phy = sci_phy_to_iphy(phy); 120 struct isci_port *isci_port = sci_port_to_iport(port); 121 unsigned long success = true; 122 123 BUG_ON(isci_phy->isci_port != NULL); 124 125 isci_phy->isci_port = isci_port; 126 127 dev_dbg(&isci_host->pdev->dev, 128 "%s: isci_port = %p\n", 129 __func__, isci_port); 130 131 spin_lock_irqsave(&isci_phy->sas_phy.frame_rcvd_lock, flags); 132 133 isci_port_change_state(isci_phy->isci_port, isci_starting); 134 135 scic_port_get_properties(port, &properties); 136 137 if (phy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) { 138 u64 attached_sas_address; 139 140 isci_phy->sas_phy.oob_mode = SATA_OOB_MODE; 141 isci_phy->sas_phy.frame_rcvd_size = sizeof(struct dev_to_host_fis); 142 143 /* 144 * For direct-attached SATA devices, the SCI core will 145 * automagically assign a SAS address to the end device 146 * for the purpose of creating a port. This SAS address 147 * will not be the same as assigned to the PHY and needs 148 * to be obtained from struct scic_port_properties properties. 149 */ 150 attached_sas_address = properties.remote.sas_address.high; 151 attached_sas_address <<= 32; 152 attached_sas_address |= properties.remote.sas_address.low; 153 swab64s(&attached_sas_address); 154 155 memcpy(&isci_phy->sas_phy.attached_sas_addr, 156 &attached_sas_address, sizeof(attached_sas_address)); 157 } else if (phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { 158 isci_phy->sas_phy.oob_mode = SAS_OOB_MODE; 159 isci_phy->sas_phy.frame_rcvd_size = sizeof(struct sas_identify_frame); 160 161 /* Copy the attached SAS address from the IAF */ 162 memcpy(isci_phy->sas_phy.attached_sas_addr, 163 isci_phy->frame_rcvd.iaf.sas_addr, SAS_ADDR_SIZE); 164 } else { 165 dev_err(&isci_host->pdev->dev, "%s: unkown target\n", __func__); 166 success = false; 167 } 168 169 isci_phy->sas_phy.phy->negotiated_linkrate = sci_phy_linkrate(phy); 170 171 spin_unlock_irqrestore(&isci_phy->sas_phy.frame_rcvd_lock, flags); 172 173 /* Notify libsas that we have an address frame, if indeed 174 * we've found an SSP, SMP, or STP target */ 175 if (success) 176 isci_host->sas_ha.notify_port_event(&isci_phy->sas_phy, 177 PORTE_BYTES_DMAED); 178 } 179 180 181 /** 182 * isci_port_link_down() - This function is called by the sci core when a link 183 * becomes inactive. 184 * @isci_host: This parameter specifies the isci host object. 185 * @phy: This parameter specifies the isci phy with the active link. 186 * @port: This parameter specifies the isci port with the active link. 187 * 188 */ 189 void isci_port_link_down(struct isci_host *isci_host, struct isci_phy *isci_phy, 190 struct isci_port *isci_port) 191 { 192 struct isci_remote_device *isci_device; 193 194 dev_dbg(&isci_host->pdev->dev, 195 "%s: isci_port = %p\n", __func__, isci_port); 196 197 if (isci_port) { 198 199 /* check to see if this is the last phy on this port. */ 200 if (isci_phy->sas_phy.port 201 && isci_phy->sas_phy.port->num_phys == 1) { 202 203 /* change the state for all devices on this port. 204 * The next task sent to this device will be returned 205 * as SAS_TASK_UNDELIVERED, and the scsi mid layer 206 * will remove the target 207 */ 208 list_for_each_entry(isci_device, 209 &isci_port->remote_dev_list, 210 node) { 211 dev_dbg(&isci_host->pdev->dev, 212 "%s: isci_device = %p\n", 213 __func__, isci_device); 214 isci_remote_device_change_state(isci_device, 215 isci_stopping); 216 } 217 } 218 isci_port_change_state(isci_port, isci_stopping); 219 } 220 221 /* Notify libsas of the borken link, this will trigger calls to our 222 * isci_port_deformed and isci_dev_gone functions. 223 */ 224 sas_phy_disconnected(&isci_phy->sas_phy); 225 isci_host->sas_ha.notify_phy_event(&isci_phy->sas_phy, 226 PHYE_LOSS_OF_SIGNAL); 227 228 isci_phy->isci_port = NULL; 229 230 dev_dbg(&isci_host->pdev->dev, 231 "%s: isci_port = %p - Done\n", __func__, isci_port); 232 } 233 234 235 /** 236 * isci_port_deformed() - This function is called by libsas when a port becomes 237 * inactive. 238 * @phy: This parameter specifies the libsas phy with the inactive port. 239 * 240 */ 241 void isci_port_deformed( 242 struct asd_sas_phy *phy) 243 { 244 pr_debug("%s: sas_phy = %p\n", __func__, phy); 245 } 246 247 /** 248 * isci_port_formed() - This function is called by libsas when a port becomes 249 * active. 250 * @phy: This parameter specifies the libsas phy with the active port. 251 * 252 */ 253 void isci_port_formed( 254 struct asd_sas_phy *phy) 255 { 256 pr_debug("%s: sas_phy = %p, sas_port = %p\n", __func__, phy, phy->port); 257 } 258 259 /** 260 * isci_port_ready() - This function is called by the sci core when a link 261 * becomes ready. 262 * @isci_host: This parameter specifies the isci host object. 263 * @port: This parameter specifies the sci port with the active link. 264 * 265 */ 266 void isci_port_ready(struct isci_host *isci_host, struct isci_port *isci_port) 267 { 268 dev_dbg(&isci_host->pdev->dev, 269 "%s: isci_port = %p\n", __func__, isci_port); 270 271 complete_all(&isci_port->start_complete); 272 isci_port_change_state(isci_port, isci_ready); 273 return; 274 } 275 276 /** 277 * isci_port_not_ready() - This function is called by the sci core when a link 278 * is not ready. All remote devices on this link will be removed if they are 279 * in the stopping state. 280 * @isci_host: This parameter specifies the isci host object. 281 * @port: This parameter specifies the sci port with the active link. 282 * 283 */ 284 void isci_port_not_ready(struct isci_host *isci_host, struct isci_port *isci_port) 285 { 286 dev_dbg(&isci_host->pdev->dev, 287 "%s: isci_port = %p\n", __func__, isci_port); 288 } 289 290 /** 291 * isci_port_hard_reset_complete() - This function is called by the sci core 292 * when the hard reset complete notification has been received. 293 * @port: This parameter specifies the sci port with the active link. 294 * @completion_status: This parameter specifies the core status for the reset 295 * process. 296 * 297 */ 298 void isci_port_hard_reset_complete(struct isci_port *isci_port, 299 enum sci_status completion_status) 300 { 301 dev_dbg(&isci_port->isci_host->pdev->dev, 302 "%s: isci_port = %p, completion_status=%x\n", 303 __func__, isci_port, completion_status); 304 305 /* Save the status of the hard reset from the port. */ 306 isci_port->hard_reset_status = completion_status; 307 308 complete_all(&isci_port->hard_reset_complete); 309 } 310 311 int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, 312 struct isci_phy *iphy) 313 { 314 unsigned long flags; 315 enum sci_status status; 316 int ret = TMF_RESP_FUNC_COMPLETE; 317 318 dev_dbg(&ihost->pdev->dev, "%s: iport = %p\n", 319 __func__, iport); 320 321 init_completion(&iport->hard_reset_complete); 322 323 spin_lock_irqsave(&ihost->scic_lock, flags); 324 325 #define ISCI_PORT_RESET_TIMEOUT SCIC_SDS_SIGNATURE_FIS_TIMEOUT 326 status = scic_port_hard_reset(&iport->sci, ISCI_PORT_RESET_TIMEOUT); 327 328 spin_unlock_irqrestore(&ihost->scic_lock, flags); 329 330 if (status == SCI_SUCCESS) { 331 wait_for_completion(&iport->hard_reset_complete); 332 333 dev_dbg(&ihost->pdev->dev, 334 "%s: iport = %p; hard reset completion\n", 335 __func__, iport); 336 337 if (iport->hard_reset_status != SCI_SUCCESS) 338 ret = TMF_RESP_FUNC_FAILED; 339 } else { 340 ret = TMF_RESP_FUNC_FAILED; 341 342 dev_err(&ihost->pdev->dev, 343 "%s: iport = %p; scic_port_hard_reset call" 344 " failed 0x%x\n", 345 __func__, iport, status); 346 347 } 348 349 /* If the hard reset for the port has failed, consider this 350 * the same as link failures on all phys in the port. 351 */ 352 if (ret != TMF_RESP_FUNC_COMPLETE) { 353 dev_err(&ihost->pdev->dev, 354 "%s: iport = %p; hard reset failed " 355 "(0x%x) - sending link down to libsas for phy %p\n", 356 __func__, iport, iport->hard_reset_status, iphy); 357 358 isci_port_link_down(ihost, iphy, iport); 359 } 360 361 return ret; 362 } 363 364 void isci_port_stop_complete(struct scic_sds_controller *scic, 365 struct scic_sds_port *sci_port, 366 enum sci_status completion_status) 367 { 368 dev_dbg(&scic_to_ihost(scic)->pdev->dev, "Port stop complete\n"); 369 } 370