| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * This file is provided under a dual BSD/GPLv2 license.  When using or | 
					
						
							|  |  |  |  * redistributing this file, you may do so under either license. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * GPL LICENSE SUMMARY | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of version 2 of the GNU General Public License as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, but | 
					
						
							|  |  |  |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  * General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 
					
						
							|  |  |  |  * The full GNU General Public License is included in this distribution | 
					
						
							|  |  |  |  * in the file called LICENSE.GPL. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * BSD LICENSE | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions | 
					
						
							|  |  |  |  * are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *   * Redistributions of source code must retain the above copyright | 
					
						
							|  |  |  |  *     notice, this list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  *   * Redistributions in binary form must reproduce the above copyright | 
					
						
							|  |  |  |  *     notice, this list of conditions and the following disclaimer in | 
					
						
							|  |  |  |  *     the documentation and/or other materials provided with the | 
					
						
							|  |  |  |  *     distribution. | 
					
						
							|  |  |  |  *   * Neither the name of Intel Corporation nor the names of its | 
					
						
							|  |  |  |  *     contributors may be used to endorse or promote products derived | 
					
						
							|  |  |  |  *     from this software without specific prior written permission. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
					
						
							|  |  |  |  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
					
						
							|  |  |  |  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
					
						
							|  |  |  |  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
					
						
							|  |  |  |  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
					
						
							|  |  |  |  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
					
						
							|  |  |  |  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
					
						
							|  |  |  |  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
					
						
							|  |  |  |  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
					
						
							|  |  |  |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "isci.h"
 | 
					
						
							|  |  |  | #include "port.h"
 | 
					
						
							|  |  |  | #include "request.h"
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define SCIC_SDS_PORT_HARD_RESET_TIMEOUT  (1000)
 | 
					
						
							|  |  |  | #define SCU_DUMMY_INDEX    (0xFFFF)
 | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-07 10:11:43 -07:00
										 |  |  | static void isci_port_change_state(struct isci_port *iport, enum isci_status status) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-07 10:11:43 -07:00
										 |  |  | 	dev_dbg(&iport->isci_host->pdev->dev, | 
					
						
							|  |  |  | 		"%s: iport = %p, state = 0x%x\n", | 
					
						
							|  |  |  | 		__func__, iport, status); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-07 10:11:43 -07:00
										 |  |  | 	/* XXX pointless lock */ | 
					
						
							|  |  |  | 	spin_lock_irqsave(&iport->state_lock, flags); | 
					
						
							|  |  |  | 	iport->status = status; | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&iport->state_lock, flags); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_get_protocols(struct isci_port *iport, struct sci_phy_proto *proto) | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	u8 index; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	proto->all = 0; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	for (index = 0; index < SCI_MAX_PHYS; index++) { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		struct isci_phy *iphy = iport->phy_table[index]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!iphy) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		sci_phy_get_protocols(iphy, proto); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static u32 sci_port_get_phys(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	u32 index; | 
					
						
							|  |  |  | 	u32 mask; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mask = 0; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	for (index = 0; index < SCI_MAX_PHYS; index++) | 
					
						
							|  |  |  | 		if (iport->phy_table[index]) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 			mask |= (1 << index); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return mask; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  |  * sci_port_get_properties() - This method simply returns the properties | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  *    regarding the port, such as: physical index, protocols, sas address, etc. | 
					
						
							|  |  |  |  * @port: this parameter specifies the port for which to retrieve the physical | 
					
						
							|  |  |  |  *    index. | 
					
						
							|  |  |  |  * @properties: This parameter specifies the properties structure into which to | 
					
						
							|  |  |  |  *    copy the requested information. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Indicate if the user specified a valid port. SCI_SUCCESS This value is | 
					
						
							|  |  |  |  * returned if the specified port was valid. SCI_FAILURE_INVALID_PORT This | 
					
						
							|  |  |  |  * value is returned if the specified port is not valid.  When this value is | 
					
						
							|  |  |  |  * returned, no data is copied to the properties output parameter. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static enum sci_status sci_port_get_properties(struct isci_port *iport, | 
					
						
							|  |  |  | 						struct sci_port_properties *prop) | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (!iport || iport->logical_port_index == SCIC_SDS_DUMMY_PORT) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		return SCI_FAILURE_INVALID_PORT; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	prop->index = iport->logical_port_index; | 
					
						
							|  |  |  | 	prop->phy_mask = sci_port_get_phys(iport); | 
					
						
							|  |  |  | 	sci_port_get_sas_address(iport, &prop->local.sas_address); | 
					
						
							|  |  |  | 	sci_port_get_protocols(iport, &prop->local.protocols); | 
					
						
							|  |  |  | 	sci_port_get_attached_sas_address(iport, &prop->remote.sas_address); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	return SCI_SUCCESS; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_bcn_enable(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-06-21 12:16:33 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	struct isci_phy *iphy; | 
					
						
							| 
									
										
										
										
											2011-06-21 12:16:33 -07:00
										 |  |  | 	u32 val; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	for (i = 0; i < ARRAY_SIZE(iport->phy_table); i++) { | 
					
						
							|  |  |  | 		iphy = iport->phy_table[i]; | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 		if (!iphy) | 
					
						
							| 
									
										
										
										
											2011-06-21 12:16:33 -07:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 		val = readl(&iphy->link_layer_registers->link_layer_control); | 
					
						
							| 
									
										
										
										
											2011-06-21 12:16:33 -07:00
										 |  |  | 		/* clear the bit by writing 1. */ | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 		writel(val, &iphy->link_layer_registers->link_layer_control); | 
					
						
							| 
									
										
										
										
											2011-06-21 12:16:33 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | static void isci_port_bc_change_received(struct isci_host *ihost, | 
					
						
							|  |  |  | 					 struct isci_port *iport, | 
					
						
							|  |  |  | 					 struct isci_phy *iphy) | 
					
						
							| 
									
										
										
										
											2011-06-21 12:16:33 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-27 15:05:37 -07:00
										 |  |  | 	dev_dbg(&ihost->pdev->dev, | 
					
						
							|  |  |  | 		"%s: isci_phy = %p, sas_phy = %p\n", | 
					
						
							|  |  |  | 		__func__, iphy, &iphy->sas_phy); | 
					
						
							| 
									
										
										
										
											2011-06-21 12:16:33 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-27 15:05:37 -07:00
										 |  |  | 	ihost->sas_ha.notify_port_event(&iphy->sas_phy, PORTE_BROADCAST_RCVD); | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_bcn_enable(iport); | 
					
						
							| 
									
										
										
										
											2011-06-21 12:16:33 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | static void isci_port_link_up(struct isci_host *isci_host, | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 			      struct isci_port *iport, | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 			      struct isci_phy *iphy) | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	struct sci_port_properties properties; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 	unsigned long success = true; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	BUG_ON(iphy->isci_port != NULL); | 
					
						
							| 
									
										
										
										
											2011-04-12 17:28:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	iphy->isci_port = iport; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(&isci_host->pdev->dev, | 
					
						
							|  |  |  | 		"%s: isci_port = %p\n", | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		__func__, iport); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	isci_port_change_state(iphy->isci_port, isci_starting); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_get_properties(iport, &properties); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) { | 
					
						
							| 
									
										
										
										
											2011-02-25 10:25:21 -08:00
										 |  |  | 		u64 attached_sas_address; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 		iphy->sas_phy.oob_mode = SATA_OOB_MODE; | 
					
						
							|  |  |  | 		iphy->sas_phy.frame_rcvd_size = sizeof(struct dev_to_host_fis); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * For direct-attached SATA devices, the SCI core will | 
					
						
							|  |  |  | 		 * automagically assign a SAS address to the end device | 
					
						
							|  |  |  | 		 * for the purpose of creating a port. This SAS address | 
					
						
							|  |  |  | 		 * will not be the same as assigned to the PHY and needs | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		 * to be obtained from struct sci_port_properties properties. | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-02-25 10:25:21 -08:00
										 |  |  | 		attached_sas_address = properties.remote.sas_address.high; | 
					
						
							|  |  |  | 		attached_sas_address <<= 32; | 
					
						
							|  |  |  | 		attached_sas_address |= properties.remote.sas_address.low; | 
					
						
							|  |  |  | 		swab64s(&attached_sas_address); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 		memcpy(&iphy->sas_phy.attached_sas_addr, | 
					
						
							| 
									
										
										
										
											2011-02-25 10:25:21 -08:00
										 |  |  | 		       &attached_sas_address, sizeof(attached_sas_address)); | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	} else if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { | 
					
						
							|  |  |  | 		iphy->sas_phy.oob_mode = SAS_OOB_MODE; | 
					
						
							|  |  |  | 		iphy->sas_phy.frame_rcvd_size = sizeof(struct sas_identify_frame); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Copy the attached SAS address from the IAF */ | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 		memcpy(iphy->sas_phy.attached_sas_addr, | 
					
						
							|  |  |  | 		       iphy->frame_rcvd.iaf.sas_addr, SAS_ADDR_SIZE); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		dev_err(&isci_host->pdev->dev, "%s: unkown target\n", __func__); | 
					
						
							|  |  |  | 		success = false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	iphy->sas_phy.phy->negotiated_linkrate = sci_phy_linkrate(iphy); | 
					
						
							| 
									
										
										
										
											2011-02-18 09:25:13 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	spin_unlock_irqrestore(&iphy->sas_phy.frame_rcvd_lock, flags); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Notify libsas that we have an address frame, if indeed
 | 
					
						
							|  |  |  | 	 * we've found an SSP, SMP, or STP target */ | 
					
						
							|  |  |  | 	if (success) | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 		isci_host->sas_ha.notify_port_event(&iphy->sas_phy, | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 						    PORTE_BYTES_DMAED); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * isci_port_link_down() - This function is called by the sci core when a link | 
					
						
							|  |  |  |  *    becomes inactive. | 
					
						
							|  |  |  |  * @isci_host: This parameter specifies the isci host object. | 
					
						
							|  |  |  |  * @phy: This parameter specifies the isci phy with the active link. | 
					
						
							|  |  |  |  * @port: This parameter specifies the isci port with the active link. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | static void isci_port_link_down(struct isci_host *isci_host, | 
					
						
							|  |  |  | 				struct isci_phy *isci_phy, | 
					
						
							|  |  |  | 				struct isci_port *isci_port) | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct isci_remote_device *isci_device; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(&isci_host->pdev->dev, | 
					
						
							|  |  |  | 		"%s: isci_port = %p\n", __func__, isci_port); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (isci_port) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* check to see if this is the last phy on this port. */ | 
					
						
							| 
									
										
										
										
											2011-06-21 12:16:33 -07:00
										 |  |  | 		if (isci_phy->sas_phy.port && | 
					
						
							|  |  |  | 		    isci_phy->sas_phy.port->num_phys == 1) { | 
					
						
							|  |  |  | 			/* change the state for all devices on this port.  The
 | 
					
						
							|  |  |  | 			 * next task sent to this device will be returned as | 
					
						
							|  |  |  | 			 * SAS_TASK_UNDELIVERED, and the scsi mid layer will | 
					
						
							|  |  |  | 			 * remove the target | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 			 */ | 
					
						
							|  |  |  | 			list_for_each_entry(isci_device, | 
					
						
							|  |  |  | 					    &isci_port->remote_dev_list, | 
					
						
							|  |  |  | 					    node) { | 
					
						
							|  |  |  | 				dev_dbg(&isci_host->pdev->dev, | 
					
						
							|  |  |  | 					"%s: isci_device = %p\n", | 
					
						
							|  |  |  | 					__func__, isci_device); | 
					
						
							| 
									
										
										
										
											2011-06-13 17:39:44 -07:00
										 |  |  | 				set_bit(IDEV_GONE, &isci_device->flags); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2011-09-28 18:47:56 -07:00
										 |  |  | 			isci_port_change_state(isci_port, isci_stopping); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Notify libsas of the borken link, this will trigger calls to our
 | 
					
						
							|  |  |  | 	 * isci_port_deformed and isci_dev_gone functions. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	sas_phy_disconnected(&isci_phy->sas_phy); | 
					
						
							|  |  |  | 	isci_host->sas_ha.notify_phy_event(&isci_phy->sas_phy, | 
					
						
							|  |  |  | 					   PHYE_LOSS_OF_SIGNAL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	isci_phy->isci_port = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(&isci_host->pdev->dev, | 
					
						
							|  |  |  | 		"%s: isci_port = %p - Done\n", __func__, isci_port); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * isci_port_ready() - This function is called by the sci core when a link | 
					
						
							|  |  |  |  *    becomes ready. | 
					
						
							|  |  |  |  * @isci_host: This parameter specifies the isci host object. | 
					
						
							|  |  |  |  * @port: This parameter specifies the sci port with the active link. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | static void isci_port_ready(struct isci_host *isci_host, struct isci_port *isci_port) | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	dev_dbg(&isci_host->pdev->dev, | 
					
						
							|  |  |  | 		"%s: isci_port = %p\n", __func__, isci_port); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	complete_all(&isci_port->start_complete); | 
					
						
							|  |  |  | 	isci_port_change_state(isci_port, isci_ready); | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * isci_port_not_ready() - This function is called by the sci core when a link | 
					
						
							|  |  |  |  *    is not ready. All remote devices on this link will be removed if they are | 
					
						
							|  |  |  |  *    in the stopping state. | 
					
						
							|  |  |  |  * @isci_host: This parameter specifies the isci host object. | 
					
						
							|  |  |  |  * @port: This parameter specifies the sci port with the active link. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | static void isci_port_not_ready(struct isci_host *isci_host, struct isci_port *isci_port) | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	dev_dbg(&isci_host->pdev->dev, | 
					
						
							|  |  |  | 		"%s: isci_port = %p\n", __func__, isci_port); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | static void isci_port_stop_complete(struct isci_host *ihost, | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 				    struct isci_port *iport, | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 				    enum sci_status completion_status) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	dev_dbg(&ihost->pdev->dev, "Port stop complete\n"); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-27 15:05:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | static bool is_port_ready_state(enum sci_port_states state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	switch (state) { | 
					
						
							|  |  |  | 	case SCI_PORT_READY: | 
					
						
							|  |  |  | 	case SCI_PORT_SUB_WAITING: | 
					
						
							|  |  |  | 	case SCI_PORT_SUB_OPERATIONAL: | 
					
						
							|  |  |  | 	case SCI_PORT_SUB_CONFIGURING: | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* flag dummy rnc hanling when exiting a ready state */ | 
					
						
							|  |  |  | static void port_state_machine_change(struct isci_port *iport, | 
					
						
							|  |  |  | 				      enum sci_port_states state) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sci_base_state_machine *sm = &iport->sm; | 
					
						
							|  |  |  | 	enum sci_port_states old_state = sm->current_state_id; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (is_port_ready_state(old_state) && !is_port_ready_state(state)) | 
					
						
							|  |  |  | 		iport->ready_exit = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sci_change_state(sm, state); | 
					
						
							|  |  |  | 	iport->ready_exit = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * isci_port_hard_reset_complete() - This function is called by the sci core | 
					
						
							|  |  |  |  *    when the hard reset complete notification has been received. | 
					
						
							|  |  |  |  * @port: This parameter specifies the sci port with the active link. | 
					
						
							|  |  |  |  * @completion_status: This parameter specifies the core status for the reset | 
					
						
							|  |  |  |  *    process. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | static void isci_port_hard_reset_complete(struct isci_port *isci_port, | 
					
						
							|  |  |  | 					  enum sci_status completion_status) | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	dev_dbg(&isci_port->isci_host->pdev->dev, | 
					
						
							|  |  |  | 		"%s: isci_port = %p, completion_status=%x\n", | 
					
						
							|  |  |  | 		     __func__, isci_port, completion_status); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Save the status of the hard reset from the port. */ | 
					
						
							|  |  |  | 	isci_port->hard_reset_status = completion_status; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-27 15:05:32 -07:00
										 |  |  | 	if (completion_status != SCI_SUCCESS) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* The reset failed.  The port state is now SCI_PORT_FAILED. */ | 
					
						
							|  |  |  | 		if (isci_port->active_phy_mask == 0) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* Generate the link down now to the host, since it
 | 
					
						
							|  |  |  | 			 * was intercepted by the hard reset state machine when | 
					
						
							|  |  |  | 			 * it really happened. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			isci_port_link_down(isci_port->isci_host, | 
					
						
							|  |  |  | 					    &isci_port->isci_host->phys[ | 
					
						
							|  |  |  | 						   isci_port->last_active_phy], | 
					
						
							|  |  |  | 					    isci_port); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		/* Advance the port state so that link state changes will be
 | 
					
						
							|  |  |  | 		* noticed. | 
					
						
							|  |  |  | 		*/ | 
					
						
							|  |  |  | 		port_state_machine_change(isci_port, SCI_PORT_SUB_WAITING); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 	complete_all(&isci_port->hard_reset_complete); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-03-31 13:10:44 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | /* This method will return a true value if the specified phy can be assigned to
 | 
					
						
							|  |  |  |  * this port The following is a list of phys for each port that are allowed: - | 
					
						
							|  |  |  |  * Port 0 - 3 2 1 0 - Port 1 -     1 - Port 2 - 3 2 - Port 3 - 3 This method | 
					
						
							|  |  |  |  * doesn't preclude all configurations.  It merely ensures that a phy is part | 
					
						
							|  |  |  |  * of the allowable set of phy identifiers for that port.  For example, one | 
					
						
							|  |  |  |  * could assign phy 3 to port 0 and no other phys.  Please refer to | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  |  * sci_port_is_phy_mask_valid() for information regarding whether the | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  * phy_mask for a port can be supported. bool true if this is a valid phy | 
					
						
							|  |  |  |  * assignment for the port false if this is not a valid phy assignment for the | 
					
						
							|  |  |  |  * port | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | bool sci_port_is_valid_phy_assignment(struct isci_port *iport, u32 phy_index) | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							|  |  |  | 	struct sci_user_parameters *user = &ihost->user_parameters; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	/* Initialize to invalid value. */ | 
					
						
							|  |  |  | 	u32 existing_phy_index = SCI_MAX_PHYS; | 
					
						
							|  |  |  | 	u32 index; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	if ((iport->physical_port_index == 1) && (phy_index != 1)) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	if (iport->physical_port_index == 3 && phy_index != 3) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	if (iport->physical_port_index == 2 && | 
					
						
							|  |  |  | 	    (phy_index == 0 || phy_index == 1)) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	for (index = 0; index < SCI_MAX_PHYS; index++) | 
					
						
							|  |  |  | 		if (iport->phy_table[index] && index != phy_index) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 			existing_phy_index = index; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	/* Ensure that all of the phys in the port are capable of
 | 
					
						
							|  |  |  | 	 * operating at the same maximum link rate. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (existing_phy_index < SCI_MAX_PHYS && | 
					
						
							|  |  |  | 	    user->phys[phy_index].max_speed_generation != | 
					
						
							|  |  |  | 	    user->phys[existing_phy_index].max_speed_generation) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		return false; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @sci_port: This is the port object for which to determine if the phy mask | 
					
						
							|  |  |  |  *    can be supported. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This method will return a true value if the port's phy mask can be supported | 
					
						
							|  |  |  |  * by the SCU. The following is a list of valid PHY mask configurations for | 
					
						
							|  |  |  |  * each port: - Port 0 - [[3  2] 1] 0 - Port 1 -        [1] - Port 2 - [[3] 2] | 
					
						
							|  |  |  |  * - Port 3 -  [3] This method returns a boolean indication specifying if the | 
					
						
							|  |  |  |  * phy mask can be supported. true if this is a valid phy assignment for the | 
					
						
							|  |  |  |  * port false if this is not a valid phy assignment for the port | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static bool sci_port_is_phy_mask_valid( | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport, | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	u32 phy_mask) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->physical_port_index == 0) { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		if (((phy_mask & 0x0F) == 0x0F) | 
					
						
							|  |  |  | 		    || ((phy_mask & 0x03) == 0x03) | 
					
						
							|  |  |  | 		    || ((phy_mask & 0x01) == 0x01) | 
					
						
							|  |  |  | 		    || (phy_mask == 0)) | 
					
						
							|  |  |  | 			return true; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	} else if (iport->physical_port_index == 1) { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		if (((phy_mask & 0x02) == 0x02) | 
					
						
							|  |  |  | 		    || (phy_mask == 0)) | 
					
						
							|  |  |  | 			return true; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	} else if (iport->physical_port_index == 2) { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		if (((phy_mask & 0x0C) == 0x0C) | 
					
						
							|  |  |  | 		    || ((phy_mask & 0x04) == 0x04) | 
					
						
							|  |  |  | 		    || (phy_mask == 0)) | 
					
						
							|  |  |  | 			return true; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	} else if (iport->physical_port_index == 3) { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		if (((phy_mask & 0x08) == 0x08) | 
					
						
							|  |  |  | 		    || (phy_mask == 0)) | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  * This method retrieves a currently active (i.e. connected) phy contained in | 
					
						
							|  |  |  |  * the port.  Currently, the lowest order phy that is connected is returned. | 
					
						
							|  |  |  |  * This method returns a pointer to a SCIS_SDS_PHY object. NULL This value is | 
					
						
							|  |  |  |  * returned if there are no currently active (i.e. connected to a remote end | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  |  * point) phys contained in the port. All other values specify a struct sci_phy | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  * object that is active in the port. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static struct isci_phy *sci_port_get_a_connected_phy(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	u32 index; | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	struct isci_phy *iphy; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	for (index = 0; index < SCI_MAX_PHYS; index++) { | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 		/* Ensure that the phy is both part of the port and currently
 | 
					
						
							|  |  |  | 		 * connected to the remote end-point. | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		iphy = iport->phy_table[index]; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		if (iphy && sci_port_active_phy(iport, iphy)) | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 			return iphy; | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static enum sci_status sci_port_set_phy(struct isci_port *iport, struct isci_phy *iphy) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	/* Check to see if we can add this phy to a port
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	 * that means that the phy is not part of a port and that the port does | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	 * not already have a phy assinged to the phy index. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (!iport->phy_table[iphy->phy_index] && | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	    !phy_get_non_dummy_port(iphy) && | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	    sci_port_is_valid_phy_assignment(iport, iphy->phy_index)) { | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 		/* Phy is being added in the stopped state so we are in MPC mode
 | 
					
						
							|  |  |  | 		 * make logical port index = physical port index | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		iport->logical_port_index = iport->physical_port_index; | 
					
						
							|  |  |  | 		iport->phy_table[iphy->phy_index] = iphy; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_phy_set_port(iphy, iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return SCI_SUCCESS; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return SCI_FAILURE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static enum sci_status sci_port_clear_phy(struct isci_port *iport, struct isci_phy *iphy) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	/* Make sure that this phy is part of this port */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->phy_table[iphy->phy_index] == iphy && | 
					
						
							|  |  |  | 	    phy_get_non_dummy_port(iphy) == iport) { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 		struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Yep it is assigned to this port so remove it */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_phy_set_port(iphy, &ihost->ports[SCI_MAX_PORTS]); | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		iport->phy_table[iphy->phy_index] = NULL; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return SCI_FAILURE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | void sci_port_get_sas_address(struct isci_port *iport, struct sci_sas_address *sas) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 index; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sas->high = 0; | 
					
						
							|  |  |  | 	sas->low  = 0; | 
					
						
							|  |  |  | 	for (index = 0; index < SCI_MAX_PHYS; index++) | 
					
						
							|  |  |  | 		if (iport->phy_table[index]) | 
					
						
							|  |  |  | 			sci_phy_get_sas_address(iport->phy_table[index], sas); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | void sci_port_get_attached_sas_address(struct isci_port *iport, struct sci_sas_address *sas) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	struct isci_phy *iphy; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Ensure that the phy is both part of the port and currently | 
					
						
							|  |  |  | 	 * connected to the remote end-point. | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	iphy = sci_port_get_a_connected_phy(iport); | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	if (iphy) { | 
					
						
							|  |  |  | 		if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 			sci_phy_get_attached_sas_address(iphy, sas); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 			sci_phy_get_sas_address(iphy, sas); | 
					
						
							|  |  |  | 			sas->low += iphy->phy_index; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sas->high = 0; | 
					
						
							|  |  |  | 		sas->low  = 0; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-03-31 13:10:44 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  |  * sci_port_construct_dummy_rnc() - create dummy rnc for si workaround | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * @sci_port: logical port on which we need to create the remote node context | 
					
						
							|  |  |  |  * @rni: remote node index for this remote node context. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This routine will construct a dummy remote node context data structure | 
					
						
							|  |  |  |  * This structure will be posted to the hardware to work around a scheduler | 
					
						
							|  |  |  |  * error in the hardware. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_construct_dummy_rnc(struct isci_port *iport, u16 rni) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	union scu_remote_node_context *rnc; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	rnc = &iport->owning_controller->remote_node_context_table[rni]; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	memset(rnc, 0, sizeof(union scu_remote_node_context)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rnc->ssp.remote_sas_address_hi = 0; | 
					
						
							|  |  |  | 	rnc->ssp.remote_sas_address_lo = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rnc->ssp.remote_node_index = rni; | 
					
						
							|  |  |  | 	rnc->ssp.remote_node_port_width = 1; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	rnc->ssp.logical_port_index = iport->physical_port_index; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	rnc->ssp.nexus_loss_timer_enable = false; | 
					
						
							|  |  |  | 	rnc->ssp.check_bit = false; | 
					
						
							|  |  |  | 	rnc->ssp.is_valid = true; | 
					
						
							|  |  |  | 	rnc->ssp.is_remote_node_context = true; | 
					
						
							|  |  |  | 	rnc->ssp.function_number = 0; | 
					
						
							|  |  |  | 	rnc->ssp.arbitration_wait_time = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-09 11:06:58 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * construct a dummy task context data structure.  This | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  * structure will be posted to the hardwre to work around a scheduler error | 
					
						
							|  |  |  |  * in the hardware. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_construct_dummy_task(struct isci_port *iport, u16 tag) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	struct scu_task_context *task_context; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	task_context = &ihost->task_context_table[ISCI_TAG_TCI(tag)]; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	memset(task_context, 0, sizeof(struct scu_task_context)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	task_context->initiator_request = 1; | 
					
						
							|  |  |  | 	task_context->connection_rate = 1; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	task_context->logical_port_index = iport->physical_port_index; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP; | 
					
						
							| 
									
										
										
										
											2011-06-09 11:06:58 -07:00
										 |  |  | 	task_context->task_index = ISCI_TAG_TCI(tag); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	task_context->valid = SCU_TASK_CONTEXT_VALID; | 
					
						
							|  |  |  | 	task_context->context_type = SCU_TASK_CONTEXT_TYPE; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	task_context->remote_node_index = iport->reserved_rni; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	task_context->do_not_dma_ssp_good_response = 1; | 
					
						
							|  |  |  | 	task_context->task_phase = 0x01; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_destroy_dummy_resources(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->reserved_tag != SCI_CONTROLLER_INVALID_IO_TAG) | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 		isci_free_tag(ihost, iport->reserved_tag); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->reserved_rni != SCU_DUMMY_INDEX) | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_remote_node_table_release_remote_node_index(&ihost->available_remote_nodes, | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 								     1, iport->reserved_rni); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	iport->reserved_rni = SCU_DUMMY_INDEX; | 
					
						
							|  |  |  | 	iport->reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | void sci_port_setup_transports(struct isci_port *iport, u32 device_id) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	u8 index; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (index = 0; index < SCI_MAX_PHYS; index++) { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		if (iport->active_phy_mask & (1 << index)) | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 			sci_phy_setup_transport(iport->phy_table[index], device_id); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_activate_phy(struct isci_port *iport, struct isci_phy *iphy, | 
					
						
							|  |  |  | 				  bool do_notify_user) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_phy_resume(iphy); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	iport->active_phy_mask |= 1 << iphy->phy_index; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_controller_clear_invalid_phy(ihost, iphy); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (do_notify_user == true) | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		isci_port_link_up(ihost, iport, iphy); | 
					
						
							| 
									
										
										
										
											2011-07-02 22:56:22 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-03-26 16:11:51 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | void sci_port_deactivate_phy(struct isci_port *iport, struct isci_phy *iphy, | 
					
						
							|  |  |  | 			     bool do_notify_user) | 
					
						
							| 
									
										
										
										
											2011-03-26 16:11:51 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-07-01 02:25:15 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	iport->active_phy_mask &= ~(1 << iphy->phy_index); | 
					
						
							| 
									
										
										
										
											2011-10-27 15:05:32 -07:00
										 |  |  | 	if (!iport->active_phy_mask) | 
					
						
							|  |  |  | 		iport->last_active_phy = iphy->phy_index; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Re-assign the phy back to the LP as if it were a narrow port */ | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	writel(iphy->phy_index, | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		&iport->port_pe_configuration_register[iphy->phy_index]); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (do_notify_user == true) | 
					
						
							|  |  |  | 		isci_port_link_down(ihost, iphy, iport); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_invalid_link_up(struct isci_port *iport, struct isci_phy *iphy) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Check to see if we have alreay reported this link as bad and if | 
					
						
							|  |  |  | 	 * not go ahead and tell the SCI_USER that we have discovered an | 
					
						
							|  |  |  | 	 * invalid link. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	if ((ihost->invalid_phy_mask & (1 << iphy->phy_index)) == 0) { | 
					
						
							| 
									
										
										
										
											2011-07-01 02:25:15 -07:00
										 |  |  | 		ihost->invalid_phy_mask |= 1 << iphy->phy_index; | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 		dev_warn(&ihost->pdev->dev, "Invalid link up!\n"); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  |  * sci_port_general_link_up_handler - phy can be assigned to port? | 
					
						
							|  |  |  |  * @sci_port: sci_port object for which has a phy that has gone link up. | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  |  * @sci_phy: This is the struct isci_phy object that has gone link up. | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  * @do_notify_user: This parameter specifies whether to inform the user (via | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  |  *    sci_port_link_up()) as to the fact that a new phy as become ready. | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Determine if this phy can be assigned to this | 
					
						
							|  |  |  |  * port . If the phy is not a valid PHY for | 
					
						
							|  |  |  |  * this port then the function will notify the user. A PHY can only be | 
					
						
							|  |  |  |  * part of a port if it's attached SAS ADDRESS is the same as all other PHYs in | 
					
						
							|  |  |  |  * the same port. none | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_general_link_up_handler(struct isci_port *iport, | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 						  struct isci_phy *iphy, | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 						  bool do_notify_user) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sci_sas_address port_sas_address; | 
					
						
							|  |  |  | 	struct sci_sas_address phy_sas_address; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_get_attached_sas_address(iport, &port_sas_address); | 
					
						
							|  |  |  | 	sci_phy_get_attached_sas_address(iphy, &phy_sas_address); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* If the SAS address of the new phy matches the SAS address of
 | 
					
						
							|  |  |  | 	 * other phys in the port OR this is the first phy in the port, | 
					
						
							|  |  |  | 	 * then activate the phy and allow it to be used for operations | 
					
						
							|  |  |  | 	 * in this port. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if ((phy_sas_address.high == port_sas_address.high && | 
					
						
							|  |  |  | 	     phy_sas_address.low  == port_sas_address.low) || | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	    iport->active_phy_mask == 0) { | 
					
						
							|  |  |  | 		struct sci_base_state_machine *sm = &iport->sm; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_activate_phy(iport, iphy, do_notify_user); | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 		if (sm->current_state_id == SCI_PORT_RESETTING) | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 			port_state_machine_change(iport, SCI_PORT_READY); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} else | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_invalid_link_up(iport, iphy); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * This method returns false if the port only has a single phy object assigned. | 
					
						
							|  |  |  |  *     If there are no phys or more than one phy then the method will return | 
					
						
							|  |  |  |  *    true. | 
					
						
							|  |  |  |  * @sci_port: The port for which the wide port condition is to be checked. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * bool true Is returned if this is a wide ported port. false Is returned if | 
					
						
							|  |  |  |  * this is a narrow port. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static bool sci_port_is_wide(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 index; | 
					
						
							|  |  |  | 	u32 phy_count = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (index = 0; index < SCI_MAX_PHYS; index++) { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		if (iport->phy_table[index] != NULL) { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 			phy_count++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return phy_count != 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * This method is called by the PHY object when the link is detected. if the | 
					
						
							|  |  |  |  *    port wants the PHY to continue on to the link up state then the port | 
					
						
							|  |  |  |  *    layer must return true.  If the port object returns false the phy object | 
					
						
							|  |  |  |  *    must halt its attempt to go link up. | 
					
						
							|  |  |  |  * @sci_port: The port associated with the phy object. | 
					
						
							|  |  |  |  * @sci_phy: The phy object that is trying to go link up. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * true if the phy object can continue to the link up condition. true Is | 
					
						
							|  |  |  |  * returned if this phy can continue to the ready state. false Is returned if | 
					
						
							|  |  |  |  * can not continue on to the ready state. This notification is in place for | 
					
						
							|  |  |  |  * wide ports and direct attached phys.  Since there are no wide ported SATA | 
					
						
							|  |  |  |  * devices this could become an invalid port configuration. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | bool sci_port_link_detected( | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport, | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	struct isci_phy *iphy) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if ((iport->logical_port_index != SCIC_SDS_DUMMY_PORT) && | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	    (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) && | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	    sci_port_is_wide(iport)) { | 
					
						
							|  |  |  | 		sci_port_invalid_link_up(iport, iphy); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-19 11:59:10 +00:00
										 |  |  | static void port_timeout(unsigned long data) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-05-19 11:59:10 +00:00
										 |  |  | 	struct sci_timer *tmr = (struct sci_timer *)data; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(tmr, typeof(*iport), timer); | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-19 11:59:10 +00:00
										 |  |  | 	unsigned long flags; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	u32 current_state; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-19 11:59:10 +00:00
										 |  |  | 	spin_lock_irqsave(&ihost->scic_lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (tmr->cancel) | 
					
						
							|  |  |  | 		goto done; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	current_state = iport->sm.current_state_id; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	if (current_state == SCI_PORT_RESETTING) { | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 		/* if the port is still in the resetting state then the timeout
 | 
					
						
							|  |  |  | 		 * fired before the reset completed. | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		port_state_machine_change(iport, SCI_PORT_FAILED); | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	} else if (current_state == SCI_PORT_STOPPED) { | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 		/* if the port is stopped then the start request failed In this
 | 
					
						
							|  |  |  | 		 * case stay in the stopped state. | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		dev_err(sciport_to_dev(iport), | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 			"%s: SCIC Port 0x%p failed to stop before tiemout.\n", | 
					
						
							|  |  |  | 			__func__, | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 			iport); | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	} else if (current_state == SCI_PORT_STOPPING) { | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 		/* if the port is still stopping then the stop has not completed */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		isci_port_stop_complete(iport->owning_controller, | 
					
						
							|  |  |  | 					iport, | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 					SCI_FAILURE_TIMEOUT); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 		/* The port is in the ready state and we have a timer
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		 * reporting a timeout this should not happen. | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		dev_err(sciport_to_dev(iport), | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 			"%s: SCIC Port 0x%p is processing a timeout operation " | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 			"in state %d.\n", __func__, iport, current_state); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-05-19 11:59:10 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | done: | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&ihost->scic_lock, flags); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * This function updates the hardwares VIIT entry for this port. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_update_viit_entry(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct sci_sas_address sas_address; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_get_sas_address(iport, &sas_address); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	writel(sas_address.high, | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		&iport->viit_registers->initiator_sas_address_hi); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	writel(sas_address.low, | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		&iport->viit_registers->initiator_sas_address_lo); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* This value get cleared just in case its not already cleared */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	writel(0, &iport->viit_registers->reserved); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* We are required to update the status register last */ | 
					
						
							|  |  |  | 	writel(SCU_VIIT_ENTRY_ID_VIIT | | 
					
						
							|  |  |  | 	       SCU_VIIT_IPPT_INITIATOR | | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	       ((1 << iport->physical_port_index) << SCU_VIIT_ENTRY_LPVIE_SHIFT) | | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	       SCU_VIIT_STATUS_ALL_VALID, | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	       &iport->viit_registers->status); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | enum sas_linkrate sci_port_get_max_allowed_speed(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	u16 index; | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	struct isci_phy *iphy; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	enum sas_linkrate max_allowed_speed = SAS_LINK_RATE_6_0_GBPS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Loop through all of the phys in this port and find the phy with the | 
					
						
							|  |  |  | 	 * lowest maximum link rate. */ | 
					
						
							|  |  |  | 	for (index = 0; index < SCI_MAX_PHYS; index++) { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		iphy = iport->phy_table[index]; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		if (iphy && sci_port_active_phy(iport, iphy) && | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 		    iphy->max_negotiated_speed < max_allowed_speed) | 
					
						
							|  |  |  | 			max_allowed_speed = iphy->max_negotiated_speed; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return max_allowed_speed; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_suspend_port_task_scheduler(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 pts_control_value; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	pts_control_value = readl(&iport->port_task_scheduler_registers->control); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	pts_control_value |= SCU_PTSxCR_GEN_BIT(SUSPEND); | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	writel(pts_control_value, &iport->port_task_scheduler_registers->control); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  |  * sci_port_post_dummy_request() - post dummy/workaround request | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  * @sci_port: port to post task | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Prevent the hardware scheduler from posting new requests to the front | 
					
						
							|  |  |  |  * of the scheduler queue causing a starvation problem for currently | 
					
						
							|  |  |  |  * ongoing requests. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_post_dummy_request(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	u16 tag = iport->reserved_tag; | 
					
						
							| 
									
										
										
										
											2011-06-28 13:47:09 -07:00
										 |  |  | 	struct scu_task_context *tc; | 
					
						
							|  |  |  | 	u32 command; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	tc = &ihost->task_context_table[ISCI_TAG_TCI(tag)]; | 
					
						
							| 
									
										
										
										
											2011-06-28 13:47:09 -07:00
										 |  |  | 	tc->abort = 0; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	command = SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		  iport->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | | 
					
						
							| 
									
										
										
										
											2011-06-28 13:47:09 -07:00
										 |  |  | 		  ISCI_TAG_TCI(tag); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_controller_post_request(ihost, command); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * This routine will abort the dummy request.  This will alow the hardware to | 
					
						
							|  |  |  |  * power down parts of the silicon to save power. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @sci_port: The port on which the task must be aborted. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_abort_dummy_request(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	u16 tag = iport->reserved_tag; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	struct scu_task_context *tc; | 
					
						
							|  |  |  | 	u32 command; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	tc = &ihost->task_context_table[ISCI_TAG_TCI(tag)]; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	tc->abort = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	command = SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT | | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		  iport->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | | 
					
						
							| 
									
										
										
										
											2011-06-28 13:47:09 -07:00
										 |  |  | 		  ISCI_TAG_TCI(tag); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_controller_post_request(ihost, command); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  |  * @sci_port: This is the struct isci_port object to resume. | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  * | 
					
						
							|  |  |  |  * This method will resume the port task scheduler for this port object. none | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | sci_port_resume_port_task_scheduler(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 pts_control_value; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	pts_control_value = readl(&iport->port_task_scheduler_registers->control); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	pts_control_value &= ~SCU_PTSxCR_GEN_BIT(SUSPEND); | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	writel(pts_control_value, &iport->port_task_scheduler_registers->control); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_ready_substate_waiting_enter(struct sci_base_state_machine *sm) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(sm, typeof(*iport), sm); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_suspend_port_task_scheduler(iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	iport->not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->active_phy_mask != 0) { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		/* At least one of the phys on the port is ready */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 					  SCI_PORT_SUB_OPERATIONAL); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_ready_substate_operational_enter(struct sci_base_state_machine *sm) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 index; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(sm, typeof(*iport), sm); | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	isci_port_ready(ihost, iport); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (index = 0; index < SCI_MAX_PHYS; index++) { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		if (iport->phy_table[index]) { | 
					
						
							|  |  |  | 			writel(iport->physical_port_index, | 
					
						
							|  |  |  | 				&iport->port_pe_configuration_register[ | 
					
						
							|  |  |  | 					iport->phy_table[index]->phy_index]); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_update_viit_entry(iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_resume_port_task_scheduler(iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Post the dummy task for the port so the hardware can schedule | 
					
						
							|  |  |  | 	 * io correctly | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_post_dummy_request(iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_invalidate_dummy_remote_node(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	u8 phys_index = iport->physical_port_index; | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 	union scu_remote_node_context *rnc; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	u16 rni = iport->reserved_rni; | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 	u32 command; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	rnc = &ihost->remote_node_context_table[rni]; | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	rnc->ssp.is_valid = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* ensure the preceding tc abort request has reached the
 | 
					
						
							|  |  |  | 	 * controller and give it ample time to act before posting the rnc | 
					
						
							|  |  |  | 	 * invalidate | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	readl(&ihost->smu_registers->interrupt_status); /* flush */ | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 	udelay(10); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	command = SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE | | 
					
						
							|  |  |  | 		  phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_controller_post_request(ihost, command); | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  |  * @object: This is the object which is cast to a struct isci_port object. | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  |  * This method will perform the actions required by the struct isci_port on | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  |  * exiting the SCI_PORT_SUB_OPERATIONAL. This function reports | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  |  * the port not ready and suspends the port task scheduler. none | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_ready_substate_operational_exit(struct sci_base_state_machine *sm) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(sm, typeof(*iport), sm); | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Kill the dummy task for this port if it has not yet posted | 
					
						
							|  |  |  | 	 * the hardware will treat this as a NOP and just return abort | 
					
						
							|  |  |  | 	 * complete. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_abort_dummy_request(iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	isci_port_not_ready(ihost, iport); | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->ready_exit) | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_invalidate_dummy_remote_node(iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_ready_substate_configuring_enter(struct sci_base_state_machine *sm) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(sm, typeof(*iport), sm); | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->active_phy_mask == 0) { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		isci_port_not_ready(ihost, iport); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 					  SCI_PORT_SUB_WAITING); | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	} else if (iport->started_request_count == 0) | 
					
						
							|  |  |  | 		port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 					  SCI_PORT_SUB_OPERATIONAL); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_ready_substate_configuring_exit(struct sci_base_state_machine *sm) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(sm, typeof(*iport), sm); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_suspend_port_task_scheduler(iport); | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->ready_exit) | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_invalidate_dummy_remote_node(iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | enum sci_status sci_port_start(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 	enum sci_status status = SCI_SUCCESS; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	enum sci_port_states state; | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 	u32 phy_mask; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	state = iport->sm.current_state_id; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	if (state != SCI_PORT_STOPPED) { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		dev_warn(sciport_to_dev(iport), | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 			 "%s: in wrong state: %d\n", __func__, state); | 
					
						
							|  |  |  | 		return SCI_FAILURE_INVALID_STATE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->assigned_device_count > 0) { | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 		/* TODO This is a start failure operation because
 | 
					
						
							|  |  |  | 		 * there are still devices assigned to this port. | 
					
						
							|  |  |  | 		 * There must be no devices assigned to a port on a | 
					
						
							|  |  |  | 		 * start operation. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->reserved_rni == SCU_DUMMY_INDEX) { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		u16 rni = sci_remote_node_table_allocate_remote_node( | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 				&ihost->available_remote_nodes, 1); | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (rni != SCU_DUMMY_INDEX) | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 			sci_port_construct_dummy_rnc(iport, rni); | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 		else | 
					
						
							|  |  |  | 			status = SCI_FAILURE_INSUFFICIENT_RESOURCES; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		iport->reserved_rni = rni; | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->reserved_tag == SCI_CONTROLLER_INVALID_IO_TAG) { | 
					
						
							| 
									
										
										
										
											2011-06-28 13:47:09 -07:00
										 |  |  | 		u16 tag; | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-28 13:47:09 -07:00
										 |  |  | 		tag = isci_alloc_tag(ihost); | 
					
						
							|  |  |  | 		if (tag == SCI_CONTROLLER_INVALID_IO_TAG) | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 			status = SCI_FAILURE_INSUFFICIENT_RESOURCES; | 
					
						
							| 
									
										
										
										
											2011-06-28 13:47:09 -07:00
										 |  |  | 		else | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 			sci_port_construct_dummy_task(iport, tag); | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		iport->reserved_tag = tag; | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (status == SCI_SUCCESS) { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		phy_mask = sci_port_get_phys(iport); | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * There are one or more phys assigned to this port.  Make sure | 
					
						
							|  |  |  | 		 * the port's phy mask is in fact legal and supported by the | 
					
						
							|  |  |  | 		 * silicon. | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		if (sci_port_is_phy_mask_valid(iport, phy_mask) == true) { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 			port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 						  SCI_PORT_READY); | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			return SCI_SUCCESS; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		status = SCI_FAILURE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (status != SCI_SUCCESS) | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_destroy_dummy_resources(iport); | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return status; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | enum sci_status sci_port_stop(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:31 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	enum sci_port_states state; | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	state = iport->sm.current_state_id; | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:31 +00:00
										 |  |  | 	switch (state) { | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_STOPPED: | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:31 +00:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_SUB_WAITING: | 
					
						
							|  |  |  | 	case SCI_PORT_SUB_OPERATIONAL: | 
					
						
							|  |  |  | 	case SCI_PORT_SUB_CONFIGURING: | 
					
						
							|  |  |  | 	case SCI_PORT_RESETTING: | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 					  SCI_PORT_STOPPING); | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:31 +00:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		dev_warn(sciport_to_dev(iport), | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:31 +00:00
										 |  |  | 			 "%s: in wrong state: %d\n", __func__, state); | 
					
						
							|  |  |  | 		return SCI_FAILURE_INVALID_STATE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static enum sci_status sci_port_hard_reset(struct isci_port *iport, u32 timeout) | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	enum sci_status status = SCI_FAILURE_INVALID_PHY; | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	struct isci_phy *iphy = NULL; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	enum sci_port_states state; | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 	u32 phy_index; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	state = iport->sm.current_state_id; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	if (state != SCI_PORT_SUB_OPERATIONAL) { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		dev_warn(sciport_to_dev(iport), | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 			 "%s: in wrong state: %d\n", __func__, state); | 
					
						
							|  |  |  | 		return SCI_FAILURE_INVALID_STATE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Select a phy on which we can send the hard reset request. */ | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	for (phy_index = 0; phy_index < SCI_MAX_PHYS && !iphy; phy_index++) { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		iphy = iport->phy_table[phy_index]; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		if (iphy && !sci_port_active_phy(iport, iphy)) { | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * We found a phy but it is not ready select | 
					
						
							|  |  |  | 			 * different phy | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 			iphy = NULL; | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If we have a phy then go ahead and start the reset procedure */ | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 	if (!iphy) | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 		return status; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	status = sci_phy_reset(iphy); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (status != SCI_SUCCESS) | 
					
						
							|  |  |  | 		return status; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	sci_mod_timer(&iport->timer, timeout); | 
					
						
							|  |  |  | 	iport->not_ready_reason = SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED; | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	port_state_machine_change(iport, SCI_PORT_RESETTING); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 	return SCI_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  |  * sci_port_add_phy() - | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  |  * @sci_port: This parameter specifies the port in which the phy will be added. | 
					
						
							|  |  |  |  * @sci_phy: This parameter is the phy which is to be added to the port. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This method will add a PHY to the selected port. This method returns an | 
					
						
							|  |  |  |  * enum sci_status. SCI_SUCCESS the phy has been added to the port. Any other | 
					
						
							|  |  |  |  * status is a failure to add the phy to the port. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | enum sci_status sci_port_add_phy(struct isci_port *iport, | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 				      struct isci_phy *iphy) | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	enum sci_status status; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	enum sci_port_states state; | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	state = iport->sm.current_state_id; | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 	switch (state) { | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_STOPPED: { | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 		struct sci_sas_address port_sas_address; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Read the port assigned SAS Address if there is one */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_get_sas_address(iport, &port_sas_address); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (port_sas_address.high != 0 && port_sas_address.low != 0) { | 
					
						
							|  |  |  | 			struct sci_sas_address phy_sas_address; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/* Make sure that the PHY SAS Address matches the SAS Address
 | 
					
						
							|  |  |  | 			 * for this port | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 			sci_phy_get_sas_address(iphy, &phy_sas_address); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (port_sas_address.high != phy_sas_address.high || | 
					
						
							|  |  |  | 			    port_sas_address.low  != phy_sas_address.low) | 
					
						
							|  |  |  | 				return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		return sci_port_set_phy(iport, iphy); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_SUB_WAITING: | 
					
						
							|  |  |  | 	case SCI_PORT_SUB_OPERATIONAL: | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		status = sci_port_set_phy(iport, iphy); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (status != SCI_SUCCESS) | 
					
						
							|  |  |  | 			return status; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_general_link_up_handler(iport, iphy, true); | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		iport->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING; | 
					
						
							|  |  |  | 		port_state_machine_change(iport, SCI_PORT_SUB_CONFIGURING); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return status; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_SUB_CONFIGURING: | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		status = sci_port_set_phy(iport, iphy); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (status != SCI_SUCCESS) | 
					
						
							|  |  |  | 			return status; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_general_link_up_handler(iport, iphy, true); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Re-enter the configuring state since this may be the last phy in
 | 
					
						
							|  |  |  | 		 * the port. | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 					  SCI_PORT_SUB_CONFIGURING); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		dev_warn(sciport_to_dev(iport), | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 			 "%s: in wrong state: %d\n", __func__, state); | 
					
						
							|  |  |  | 		return SCI_FAILURE_INVALID_STATE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  |  * sci_port_remove_phy() - | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  |  * @sci_port: This parameter specifies the port in which the phy will be added. | 
					
						
							|  |  |  |  * @sci_phy: This parameter is the phy which is to be added to the port. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This method will remove the PHY from the selected PORT. This method returns | 
					
						
							|  |  |  |  * an enum sci_status. SCI_SUCCESS the phy has been removed from the port. Any | 
					
						
							|  |  |  |  * other status is a failure to add the phy to the port. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | enum sci_status sci_port_remove_phy(struct isci_port *iport, | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 					 struct isci_phy *iphy) | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	enum sci_status status; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	enum sci_port_states state; | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	state = iport->sm.current_state_id; | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch (state) { | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_STOPPED: | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		return sci_port_clear_phy(iport, iphy); | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_SUB_OPERATIONAL: | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		status = sci_port_clear_phy(iport, iphy); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 		if (status != SCI_SUCCESS) | 
					
						
							|  |  |  | 			return status; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_deactivate_phy(iport, iphy, true); | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		iport->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING; | 
					
						
							|  |  |  | 		port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 					  SCI_PORT_SUB_CONFIGURING); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_SUB_CONFIGURING: | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		status = sci_port_clear_phy(iport, iphy); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (status != SCI_SUCCESS) | 
					
						
							|  |  |  | 			return status; | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_deactivate_phy(iport, iphy, true); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* Re-enter the configuring state since this may be the last phy in
 | 
					
						
							|  |  |  | 		 * the port | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 					  SCI_PORT_SUB_CONFIGURING); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		dev_warn(sciport_to_dev(iport), | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 			 "%s: in wrong state: %d\n", __func__, state); | 
					
						
							|  |  |  | 		return SCI_FAILURE_INVALID_STATE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | enum sci_status sci_port_link_up(struct isci_port *iport, | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 				      struct isci_phy *iphy) | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	enum sci_port_states state; | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	state = iport->sm.current_state_id; | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 	switch (state) { | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_SUB_WAITING: | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 		/* Since this is the first phy going link up for the port we
 | 
					
						
							|  |  |  | 		 * can just enable it and continue | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_activate_phy(iport, iphy, true); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 					  SCI_PORT_SUB_OPERATIONAL); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_SUB_OPERATIONAL: | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_general_link_up_handler(iport, iphy, true); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_RESETTING: | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 		/* TODO We should  make  sure  that  the phy  that  has gone
 | 
					
						
							|  |  |  | 		 * link up is the same one on which we sent the reset.  It is | 
					
						
							|  |  |  | 		 * possible that the phy on which we sent  the reset is not the | 
					
						
							|  |  |  | 		 * one that has  gone  link up  and we  want to make sure that | 
					
						
							|  |  |  | 		 * phy being reset  comes  back.  Consider the case where a | 
					
						
							|  |  |  | 		 * reset is sent but before the hardware processes the reset it | 
					
						
							|  |  |  | 		 * get a link up on  the  port because of a hot plug event. | 
					
						
							|  |  |  | 		 * because  of  the reset request this phy will go link down | 
					
						
							|  |  |  | 		 * almost immediately. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* In the resetting state we don't notify the user regarding
 | 
					
						
							|  |  |  | 		 * link up and link down notifications. | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_general_link_up_handler(iport, iphy, false); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		dev_warn(sciport_to_dev(iport), | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 			 "%s: in wrong state: %d\n", __func__, state); | 
					
						
							|  |  |  | 		return SCI_FAILURE_INVALID_STATE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | enum sci_status sci_port_link_down(struct isci_port *iport, | 
					
						
							| 
									
										
										
										
											2011-06-28 15:05:53 -07:00
										 |  |  | 					struct isci_phy *iphy) | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	enum sci_port_states state; | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	state = iport->sm.current_state_id; | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 	switch (state) { | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_SUB_OPERATIONAL: | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_deactivate_phy(iport, iphy, true); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* If there are no active phys left in the port, then
 | 
					
						
							|  |  |  | 		 * transition the port to the WAITING state until such time | 
					
						
							|  |  |  | 		 * as a phy goes link up | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		if (iport->active_phy_mask == 0) | 
					
						
							|  |  |  | 			port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 						  SCI_PORT_SUB_WAITING); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_RESETTING: | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:14 +00:00
										 |  |  | 		/* In the resetting state we don't notify the user regarding
 | 
					
						
							|  |  |  | 		 * link up and link down notifications. */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_deactivate_phy(iport, iphy, false); | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		dev_warn(sciport_to_dev(iport), | 
					
						
							| 
									
										
										
										
											2011-05-12 19:10:03 +00:00
										 |  |  | 			 "%s: in wrong state: %d\n", __func__, state); | 
					
						
							|  |  |  | 		return SCI_FAILURE_INVALID_STATE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | enum sci_status sci_port_start_io(struct isci_port *iport, | 
					
						
							|  |  |  | 				  struct isci_remote_device *idev, | 
					
						
							|  |  |  | 				  struct isci_request *ireq) | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	enum sci_port_states state; | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	state = iport->sm.current_state_id; | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 	switch (state) { | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_SUB_WAITING: | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 		return SCI_FAILURE_INVALID_STATE; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_SUB_OPERATIONAL: | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		iport->started_request_count++; | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 		return SCI_SUCCESS; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		dev_warn(sciport_to_dev(iport), | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 			 "%s: in wrong state: %d\n", __func__, state); | 
					
						
							|  |  |  | 		return SCI_FAILURE_INVALID_STATE; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | enum sci_status sci_port_complete_io(struct isci_port *iport, | 
					
						
							|  |  |  | 				     struct isci_remote_device *idev, | 
					
						
							|  |  |  | 				     struct isci_request *ireq) | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	enum sci_port_states state; | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	state = iport->sm.current_state_id; | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 	switch (state) { | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_STOPPED: | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		dev_warn(sciport_to_dev(iport), | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 			 "%s: in wrong state: %d\n", __func__, state); | 
					
						
							|  |  |  | 		return SCI_FAILURE_INVALID_STATE; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_STOPPING: | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_decrement_request_count(iport); | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		if (iport->started_request_count == 0) | 
					
						
							|  |  |  | 			port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 						  SCI_PORT_STOPPED); | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_READY: | 
					
						
							|  |  |  | 	case SCI_PORT_RESETTING: | 
					
						
							|  |  |  | 	case SCI_PORT_FAILED: | 
					
						
							|  |  |  | 	case SCI_PORT_SUB_WAITING: | 
					
						
							|  |  |  | 	case SCI_PORT_SUB_OPERATIONAL: | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_decrement_request_count(iport); | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	case SCI_PORT_SUB_CONFIGURING: | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_decrement_request_count(iport); | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		if (iport->started_request_count == 0) { | 
					
						
							|  |  |  | 			port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 						  SCI_PORT_SUB_OPERATIONAL); | 
					
						
							| 
									
										
										
										
											2011-05-12 07:16:06 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return SCI_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_enable_port_task_scheduler(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 pts_control_value; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	 /* enable the port task scheduler in a suspended state */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	pts_control_value = readl(&iport->port_task_scheduler_registers->control); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	pts_control_value |= SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND); | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	writel(pts_control_value, &iport->port_task_scheduler_registers->control); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_disable_port_task_scheduler(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	u32 pts_control_value; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	pts_control_value = readl(&iport->port_task_scheduler_registers->control); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	pts_control_value &= | 
					
						
							|  |  |  | 		~(SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND)); | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	writel(pts_control_value, &iport->port_task_scheduler_registers->control); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_post_dummy_remote_node(struct isci_port *iport) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	u8 phys_index = iport->physical_port_index; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	union scu_remote_node_context *rnc; | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	u16 rni = iport->reserved_rni; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	u32 command; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	rnc = &ihost->remote_node_context_table[rni]; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	rnc->ssp.is_valid = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	command = SCU_CONTEXT_COMMAND_POST_RNC_32 | | 
					
						
							|  |  |  | 		  phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_controller_post_request(ihost, command); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* ensure hardware has seen the post rnc command and give it
 | 
					
						
							|  |  |  | 	 * ample time to act before sending the suspend | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	readl(&ihost->smu_registers->interrupt_status); /* flush */ | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	udelay(10); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	command = SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX | | 
					
						
							|  |  |  | 		  phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_controller_post_request(ihost, command); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_stopped_state_enter(struct sci_base_state_machine *sm) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(sm, typeof(*iport), sm); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	if (iport->sm.previous_state_id == SCI_PORT_STOPPING) { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		/*
 | 
					
						
							|  |  |  | 		 * If we enter this state becasuse of a request to stop | 
					
						
							|  |  |  | 		 * the port then we want to disable the hardwares port | 
					
						
							|  |  |  | 		 * task scheduler. */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		sci_port_disable_port_task_scheduler(iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_stopped_state_exit(struct sci_base_state_machine *sm) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(sm, typeof(*iport), sm); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Enable and suspend the port task scheduler */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_enable_port_task_scheduler(iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_ready_state_enter(struct sci_base_state_machine *sm) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(sm, typeof(*iport), sm); | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	u32 prev_state; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	prev_state = iport->sm.previous_state_id; | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	if (prev_state  == SCI_PORT_RESETTING) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		isci_port_hard_reset_complete(iport, SCI_SUCCESS); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		isci_port_not_ready(ihost, iport); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Post and suspend the dummy remote node context for this port. */ | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_post_dummy_remote_node(iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Start the ready substate machine */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	port_state_machine_change(iport, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 				  SCI_PORT_SUB_WAITING); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_resetting_state_exit(struct sci_base_state_machine *sm) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(sm, typeof(*iport), sm); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	sci_del_timer(&iport->timer); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_stopping_state_exit(struct sci_base_state_machine *sm) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(sm, typeof(*iport), sm); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	sci_del_timer(&iport->timer); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_port_destroy_dummy_resources(iport); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static void sci_port_failed_state_enter(struct sci_base_state_machine *sm) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	struct isci_port *iport = container_of(sm, typeof(*iport), sm); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	isci_port_hard_reset_complete(iport, SCI_FAILURE_TIMEOUT); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --------------------------------------------------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | static const struct sci_base_state sci_port_state_table[] = { | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	[SCI_PORT_STOPPED] = { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		.enter_state = sci_port_stopped_state_enter, | 
					
						
							|  |  |  | 		.exit_state  = sci_port_stopped_state_exit | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	[SCI_PORT_STOPPING] = { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		.exit_state  = sci_port_stopping_state_exit | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	[SCI_PORT_READY] = { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		.enter_state = sci_port_ready_state_enter, | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	[SCI_PORT_SUB_WAITING] = { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		.enter_state = sci_port_ready_substate_waiting_enter, | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	[SCI_PORT_SUB_OPERATIONAL] = { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		.enter_state = sci_port_ready_substate_operational_enter, | 
					
						
							|  |  |  | 		.exit_state  = sci_port_ready_substate_operational_exit | 
					
						
							| 
									
										
										
										
											2011-05-11 23:52:21 +00:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	[SCI_PORT_SUB_CONFIGURING] = { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		.enter_state = sci_port_ready_substate_configuring_enter, | 
					
						
							|  |  |  | 		.exit_state  = sci_port_ready_substate_configuring_exit | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	[SCI_PORT_RESETTING] = { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		.exit_state  = sci_port_resetting_state_exit | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2011-06-02 00:10:43 +00:00
										 |  |  | 	[SCI_PORT_FAILED] = { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 		.enter_state = sci_port_failed_state_enter, | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | void sci_port_construct(struct isci_port *iport, u8 index, | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 			     struct isci_host *ihost) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	sci_init_sm(&iport->sm, sci_port_state_table, SCI_PORT_STOPPED); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	iport->logical_port_index  = SCIC_SDS_DUMMY_PORT; | 
					
						
							|  |  |  | 	iport->physical_port_index = index; | 
					
						
							|  |  |  | 	iport->active_phy_mask     = 0; | 
					
						
							| 
									
										
										
										
											2011-10-27 15:05:32 -07:00
										 |  |  | 	iport->last_active_phy     = 0; | 
					
						
							|  |  |  | 	iport->ready_exit	   = false; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	iport->owning_controller = ihost; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	iport->started_request_count = 0; | 
					
						
							|  |  |  | 	iport->assigned_device_count = 0; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	iport->reserved_rni = SCU_DUMMY_INDEX; | 
					
						
							|  |  |  | 	iport->reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	sci_init_timer(&iport->timer, port_timeout); | 
					
						
							| 
									
										
										
										
											2011-05-19 11:59:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	iport->port_task_scheduler_registers = NULL; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (index = 0; index < SCI_MAX_PHYS; index++) | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 		iport->phy_table[index] = NULL; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	INIT_LIST_HEAD(&iport->remote_dev_list); | 
					
						
							|  |  |  | 	INIT_LIST_HEAD(&iport->domain_dev_list); | 
					
						
							|  |  |  | 	spin_lock_init(&iport->state_lock); | 
					
						
							|  |  |  | 	init_completion(&iport->start_complete); | 
					
						
							|  |  |  | 	iport->isci_host = ihost; | 
					
						
							|  |  |  | 	isci_port_change_state(iport, isci_freed); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * isci_port_get_state() - This function gets the status of the port object. | 
					
						
							|  |  |  |  * @isci_port: This parameter points to the isci_port object | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * status of the object as a isci_status enum. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | enum isci_status isci_port_get_state( | 
					
						
							|  |  |  | 	struct isci_port *isci_port) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return isci_port->status; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy *iphy) | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-06-30 17:38:32 -07:00
										 |  |  | 	struct isci_host *ihost = iport->owning_controller; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* notify the user. */ | 
					
						
							| 
									
										
										
										
											2011-06-29 13:09:25 -07:00
										 |  |  | 	isci_port_bc_change_received(ihost, iport, iphy); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, | 
					
						
							|  |  |  | 				 struct isci_phy *iphy) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	enum sci_status status; | 
					
						
							| 
									
										
										
										
											2011-10-27 15:05:32 -07:00
										 |  |  | 	int ret = TMF_RESP_FUNC_COMPLETE; | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(&ihost->pdev->dev, "%s: iport = %p\n", | 
					
						
							|  |  |  | 		__func__, iport); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	init_completion(&iport->hard_reset_complete); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&ihost->scic_lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#define ISCI_PORT_RESET_TIMEOUT SCIC_SDS_SIGNATURE_FIS_TIMEOUT
 | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 	status = sci_port_hard_reset(iport, ISCI_PORT_RESET_TIMEOUT); | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&ihost->scic_lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (status == SCI_SUCCESS) { | 
					
						
							|  |  |  | 		wait_for_completion(&iport->hard_reset_complete); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dev_dbg(&ihost->pdev->dev, | 
					
						
							|  |  |  | 			"%s: iport = %p; hard reset completion\n", | 
					
						
							|  |  |  | 			__func__, iport); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-27 15:05:32 -07:00
										 |  |  | 		if (iport->hard_reset_status != SCI_SUCCESS) { | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 			ret = TMF_RESP_FUNC_FAILED; | 
					
						
							| 
									
										
										
										
											2011-10-27 15:05:32 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			dev_err(&ihost->pdev->dev, | 
					
						
							|  |  |  | 				"%s: iport = %p; hard reset failed (0x%x)\n", | 
					
						
							|  |  |  | 				__func__, iport, iport->hard_reset_status); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		ret = TMF_RESP_FUNC_FAILED; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dev_err(&ihost->pdev->dev, | 
					
						
							| 
									
										
										
										
											2011-06-30 19:14:33 -07:00
										 |  |  | 			"%s: iport = %p; sci_port_hard_reset call" | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 			" failed 0x%x\n", | 
					
						
							|  |  |  | 			__func__, iport, status); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If the hard reset for the port has failed, consider this
 | 
					
						
							|  |  |  | 	 * the same as link failures on all phys in the port. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	if (ret != TMF_RESP_FUNC_COMPLETE) { | 
					
						
							| 
									
										
										
										
											2011-06-20 14:09:26 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 		dev_err(&ihost->pdev->dev, | 
					
						
							|  |  |  | 			"%s: iport = %p; hard reset failed " | 
					
						
							| 
									
										
										
										
											2011-06-20 14:09:26 -07:00
										 |  |  | 			"(0x%x) - driving explicit link fail for all phys\n", | 
					
						
							|  |  |  | 			__func__, iport, iport->hard_reset_status); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-05-10 02:28:46 -07:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * isci_port_deformed() - This function is called by libsas when a port becomes | 
					
						
							|  |  |  |  *    inactive. | 
					
						
							|  |  |  |  * @phy: This parameter specifies the libsas phy with the inactive port. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void isci_port_deformed(struct asd_sas_phy *phy) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	pr_debug("%s: sas_phy = %p\n", __func__, phy); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * isci_port_formed() - This function is called by libsas when a port becomes | 
					
						
							|  |  |  |  *    active. | 
					
						
							|  |  |  |  * @phy: This parameter specifies the libsas phy with the active port. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void isci_port_formed(struct asd_sas_phy *phy) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	pr_debug("%s: sas_phy = %p, sas_port = %p\n", __func__, phy, phy->port); | 
					
						
							| 
									
										
										
										
											2011-03-26 16:11:51 -07:00
										 |  |  | } |