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