brintos

brintos / linux-shallow public Read only

0
0
Text · 63.5 KiB · d84413b Raw
2194 lines · c
1/*2 * SAS Transport Layer for MPT (Message Passing Technology) based controllers3 *4 * This code is based on drivers/scsi/mpt3sas/mpt3sas_transport.c5 * Copyright (C) 2012-2014  LSI Corporation6 * Copyright (C) 2013-2014 Avago Technologies7 *  (mailto: MPT-FusionLinux.pdl@avagotech.com)8 *9 * This program is free software; you can redistribute it and/or10 * modify it under the terms of the GNU General Public License11 * as published by the Free Software Foundation; either version 212 * of the License, or (at your option) any later version.13 *14 * This program is distributed in the hope that it will be useful,15 * but WITHOUT ANY WARRANTY; without even the implied warranty of16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the17 * GNU General Public License for more details.18 *19 * NO WARRANTY20 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR21 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT22 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,23 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is24 * solely responsible for determining the appropriateness of using and25 * distributing the Program and assumes all risks associated with its26 * exercise of rights under this Agreement, including but not limited to27 * the risks and costs of program errors, damage to or loss of data,28 * programs or equipment, and unavailability or interruption of operations.29 30 * DISCLAIMER OF LIABILITY31 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL33 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND34 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR35 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE36 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED37 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES38 39 * You should have received a copy of the GNU General Public License40 * along with this program; if not, write to the Free Software41 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,42 * USA.43 */44 45#include <linux/module.h>46#include <linux/kernel.h>47#include <linux/init.h>48#include <linux/errno.h>49#include <linux/sched.h>50#include <linux/workqueue.h>51#include <linux/delay.h>52#include <linux/pci.h>53 54#include <scsi/scsi.h>55#include <scsi/scsi_cmnd.h>56#include <scsi/scsi_device.h>57#include <scsi/scsi_host.h>58#include <scsi/scsi_transport_sas.h>59#include <scsi/scsi_dbg.h>60 61#include "mpt3sas_base.h"62 63/**64 * _transport_get_port_id_by_sas_phy - get zone's port id that Phy belong to65 * @phy: sas_phy object66 *67 * Return Port number68 */69static inline u870_transport_get_port_id_by_sas_phy(struct sas_phy *phy)71{72	u8 port_id = 0xFF;73	struct hba_port *port = phy->hostdata;74 75	if (port)76		port_id = port->port_id;77 78	return port_id;79}80 81/**82 * _transport_sas_node_find_by_sas_address - sas node search83 * @ioc: per adapter object84 * @sas_address: sas address of expander or sas host85 * @port: hba port entry86 * Context: Calling function should acquire ioc->sas_node_lock.87 *88 * Search for either hba phys or expander device based on handle, then returns89 * the sas_node object.90 */91static struct _sas_node *92_transport_sas_node_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc,93	u64 sas_address, struct hba_port *port)94{95	if (ioc->sas_hba.sas_address == sas_address)96		return &ioc->sas_hba;97	else98		return mpt3sas_scsih_expander_find_by_sas_address(ioc,99		    sas_address, port);100}101 102/**103 * _transport_get_port_id_by_rphy - Get Port number from rphy object104 * @ioc: per adapter object105 * @rphy: sas_rphy object106 *107 * Returns Port number.108 */109static u8110_transport_get_port_id_by_rphy(struct MPT3SAS_ADAPTER *ioc,111	struct sas_rphy *rphy)112{113	struct _sas_node *sas_expander;114	struct _sas_device *sas_device;115	unsigned long flags;116	u8 port_id = 0xFF;117 118	if (!rphy)119		return port_id;120 121	if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||122	    rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) {123		spin_lock_irqsave(&ioc->sas_node_lock, flags);124		list_for_each_entry(sas_expander,125		    &ioc->sas_expander_list, list) {126			if (sas_expander->rphy == rphy) {127				port_id = sas_expander->port->port_id;128				break;129			}130		}131		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);132	} else if (rphy->identify.device_type == SAS_END_DEVICE) {133		spin_lock_irqsave(&ioc->sas_device_lock, flags);134		sas_device = __mpt3sas_get_sdev_by_rphy(ioc, rphy);135		if (sas_device) {136			port_id = sas_device->port->port_id;137			sas_device_put(sas_device);138		}139		spin_unlock_irqrestore(&ioc->sas_device_lock, flags);140	}141 142	return port_id;143}144 145/**146 * _transport_convert_phy_link_rate -147 * @link_rate: link rate returned from mpt firmware148 *149 * Convert link_rate from mpi fusion into sas_transport form.150 */151static enum sas_linkrate152_transport_convert_phy_link_rate(u8 link_rate)153{154	enum sas_linkrate rc;155 156	switch (link_rate) {157	case MPI2_SAS_NEG_LINK_RATE_1_5:158		rc = SAS_LINK_RATE_1_5_GBPS;159		break;160	case MPI2_SAS_NEG_LINK_RATE_3_0:161		rc = SAS_LINK_RATE_3_0_GBPS;162		break;163	case MPI2_SAS_NEG_LINK_RATE_6_0:164		rc = SAS_LINK_RATE_6_0_GBPS;165		break;166	case MPI25_SAS_NEG_LINK_RATE_12_0:167		rc = SAS_LINK_RATE_12_0_GBPS;168		break;169	case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED:170		rc = SAS_PHY_DISABLED;171		break;172	case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:173		rc = SAS_LINK_RATE_FAILED;174		break;175	case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR:176		rc = SAS_SATA_PORT_SELECTOR;177		break;178	case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:179		rc = SAS_PHY_RESET_IN_PROGRESS;180		break;181 182	default:183	case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:184	case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:185		rc = SAS_LINK_RATE_UNKNOWN;186		break;187	}188	return rc;189}190 191/**192 * _transport_set_identify - set identify for phys and end devices193 * @ioc: per adapter object194 * @handle: device handle195 * @identify: sas identify info196 *197 * Populates sas identify info.198 *199 * Return: 0 for success, non-zero for failure.200 */201static int202_transport_set_identify(struct MPT3SAS_ADAPTER *ioc, u16 handle,203	struct sas_identify *identify)204{205	Mpi2SasDevicePage0_t sas_device_pg0;206	Mpi2ConfigReply_t mpi_reply;207	u32 device_info;208	u32 ioc_status;209 210	if (ioc->shost_recovery || ioc->pci_error_recovery) {211		ioc_info(ioc, "%s: host reset in progress!\n", __func__);212		return -EFAULT;213	}214 215	if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,216	    MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {217		ioc_err(ioc, "failure at %s:%d/%s()!\n",218			__FILE__, __LINE__, __func__);219		return -ENXIO;220	}221 222	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &223	    MPI2_IOCSTATUS_MASK;224	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {225		ioc_err(ioc, "handle(0x%04x), ioc_status(0x%04x) failure at %s:%d/%s()!\n",226			handle, ioc_status, __FILE__, __LINE__, __func__);227		return -EIO;228	}229 230	memset(identify, 0, sizeof(struct sas_identify));231	device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);232 233	/* sas_address */234	identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress);235 236	/* phy number of the parent device this device is linked to */237	identify->phy_identifier = sas_device_pg0.PhyNum;238 239	/* device_type */240	switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {241	case MPI2_SAS_DEVICE_INFO_NO_DEVICE:242		identify->device_type = SAS_PHY_UNUSED;243		break;244	case MPI2_SAS_DEVICE_INFO_END_DEVICE:245		identify->device_type = SAS_END_DEVICE;246		break;247	case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER:248		identify->device_type = SAS_EDGE_EXPANDER_DEVICE;249		break;250	case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER:251		identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;252		break;253	}254 255	/* initiator_port_protocols */256	if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR)257		identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;258	if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR)259		identify->initiator_port_protocols |= SAS_PROTOCOL_STP;260	if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR)261		identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;262	if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST)263		identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;264 265	/* target_port_protocols */266	if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)267		identify->target_port_protocols |= SAS_PROTOCOL_SSP;268	if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)269		identify->target_port_protocols |= SAS_PROTOCOL_STP;270	if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET)271		identify->target_port_protocols |= SAS_PROTOCOL_SMP;272	if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)273		identify->target_port_protocols |= SAS_PROTOCOL_SATA;274 275	return 0;276}277 278/**279 * mpt3sas_transport_done -  internal transport layer callback handler.280 * @ioc: per adapter object281 * @smid: system request message index282 * @msix_index: MSIX table index supplied by the OS283 * @reply: reply message frame(lower 32bit addr)284 *285 * Callback handler when sending internal generated transport cmds.286 * The callback index passed is `ioc->transport_cb_idx`287 *288 * Return: 1 meaning mf should be freed from _base_interrupt289 *         0 means the mf is freed from this function.290 */291u8292mpt3sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,293	u32 reply)294{295	MPI2DefaultReply_t *mpi_reply;296 297	mpi_reply =  mpt3sas_base_get_reply_virt_addr(ioc, reply);298	if (ioc->transport_cmds.status == MPT3_CMD_NOT_USED)299		return 1;300	if (ioc->transport_cmds.smid != smid)301		return 1;302	ioc->transport_cmds.status |= MPT3_CMD_COMPLETE;303	if (mpi_reply) {304		memcpy(ioc->transport_cmds.reply, mpi_reply,305		    mpi_reply->MsgLength*4);306		ioc->transport_cmds.status |= MPT3_CMD_REPLY_VALID;307	}308	ioc->transport_cmds.status &= ~MPT3_CMD_PENDING;309	complete(&ioc->transport_cmds.done);310	return 1;311}312 313/* report manufacture request structure */314struct rep_manu_request {315	u8 smp_frame_type;316	u8 function;317	u8 reserved;318	u8 request_length;319};320 321/* report manufacture reply structure */322struct rep_manu_reply {323	u8 smp_frame_type; /* 0x41 */324	u8 function; /* 0x01 */325	u8 function_result;326	u8 response_length;327	u16 expander_change_count;328	u8 reserved0[2];329	u8 sas_format;330	u8 reserved2[3];331	u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];332	u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];333	u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];334	u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];335	u16 component_id;336	u8 component_revision_id;337	u8 reserved3;338	u8 vendor_specific[8];339};340 341/**342 * _transport_expander_report_manufacture - obtain SMP report_manufacture343 * @ioc: per adapter object344 * @sas_address: expander sas address345 * @edev: the sas_expander_device object346 * @port_id: Port ID number347 *348 * Fills in the sas_expander_device object when SMP port is created.349 *350 * Return: 0 for success, non-zero for failure.351 */352static int353_transport_expander_report_manufacture(struct MPT3SAS_ADAPTER *ioc,354	u64 sas_address, struct sas_expander_device *edev, u8 port_id)355{356	Mpi2SmpPassthroughRequest_t *mpi_request;357	Mpi2SmpPassthroughReply_t *mpi_reply;358	struct rep_manu_reply *manufacture_reply;359	struct rep_manu_request *manufacture_request;360	int rc;361	u16 smid;362	void *psge;363	u8 issue_reset = 0;364	void *data_out = NULL;365	dma_addr_t data_out_dma;366	dma_addr_t data_in_dma;367	size_t data_in_sz;368	size_t data_out_sz;369 370	if (ioc->shost_recovery || ioc->pci_error_recovery) {371		ioc_info(ioc, "%s: host reset in progress!\n", __func__);372		return -EFAULT;373	}374 375	mutex_lock(&ioc->transport_cmds.mutex);376 377	if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {378		ioc_err(ioc, "%s: transport_cmds in use\n", __func__);379		rc = -EAGAIN;380		goto out;381	}382	ioc->transport_cmds.status = MPT3_CMD_PENDING;383 384	rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT);385	if (rc)386		goto out;387 388	smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);389	if (!smid) {390		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);391		rc = -EAGAIN;392		goto out;393	}394 395	rc = 0;396	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);397	ioc->transport_cmds.smid = smid;398 399	data_out_sz = sizeof(struct rep_manu_request);400	data_in_sz = sizeof(struct rep_manu_reply);401	data_out = dma_alloc_coherent(&ioc->pdev->dev, data_out_sz + data_in_sz,402			&data_out_dma, GFP_KERNEL);403	if (!data_out) {404		pr_err("failure at %s:%d/%s()!\n", __FILE__,405		    __LINE__, __func__);406		rc = -ENOMEM;407		mpt3sas_base_free_smid(ioc, smid);408		goto out;409	}410 411	data_in_dma = data_out_dma + sizeof(struct rep_manu_request);412 413	manufacture_request = data_out;414	manufacture_request->smp_frame_type = 0x40;415	manufacture_request->function = 1;416	manufacture_request->reserved = 0;417	manufacture_request->request_length = 0;418 419	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));420	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;421	mpi_request->PhysicalPort = port_id;422	mpi_request->SASAddress = cpu_to_le64(sas_address);423	mpi_request->RequestDataLength = cpu_to_le16(data_out_sz);424	psge = &mpi_request->SGL;425 426	ioc->build_sg(ioc, psge, data_out_dma, data_out_sz, data_in_dma,427	    data_in_sz);428 429	dtransportprintk(ioc,430			 ioc_info(ioc, "report_manufacture - send to sas_addr(0x%016llx)\n",431				  (u64)sas_address));432	init_completion(&ioc->transport_cmds.done);433	ioc->put_smid_default(ioc, smid);434	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);435 436	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {437		ioc_err(ioc, "%s: timeout\n", __func__);438		_debug_dump_mf(mpi_request,439		    sizeof(Mpi2SmpPassthroughRequest_t)/4);440		if (!(ioc->transport_cmds.status & MPT3_CMD_RESET))441			issue_reset = 1;442		goto issue_host_reset;443	}444 445	dtransportprintk(ioc, ioc_info(ioc, "report_manufacture - complete\n"));446 447	if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) {448		u8 *tmp;449 450		mpi_reply = ioc->transport_cmds.reply;451 452		dtransportprintk(ioc,453				 ioc_info(ioc, "report_manufacture - reply data transfer size(%d)\n",454					  le16_to_cpu(mpi_reply->ResponseDataLength)));455 456		if (le16_to_cpu(mpi_reply->ResponseDataLength) !=457		    sizeof(struct rep_manu_reply))458			goto out;459 460		manufacture_reply = data_out + sizeof(struct rep_manu_request);461		memtostr(edev->vendor_id, manufacture_reply->vendor_id);462		memtostr(edev->product_id, manufacture_reply->product_id);463		memtostr(edev->product_rev, manufacture_reply->product_rev);464		edev->level = manufacture_reply->sas_format & 1;465		if (edev->level) {466			memtostr(edev->component_vendor_id,467				 manufacture_reply->component_vendor_id);468			tmp = (u8 *)&manufacture_reply->component_id;469			edev->component_id = tmp[0] << 8 | tmp[1];470			edev->component_revision_id =471			    manufacture_reply->component_revision_id;472		}473	} else474		dtransportprintk(ioc,475				 ioc_info(ioc, "report_manufacture - no reply\n"));476 477 issue_host_reset:478	if (issue_reset)479		mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);480 out:481	ioc->transport_cmds.status = MPT3_CMD_NOT_USED;482	if (data_out)483		dma_free_coherent(&ioc->pdev->dev, data_out_sz + data_in_sz,484		    data_out, data_out_dma);485 486	mutex_unlock(&ioc->transport_cmds.mutex);487	return rc;488}489 490 491/**492 * _transport_delete_port - helper function to removing a port493 * @ioc: per adapter object494 * @mpt3sas_port: mpt3sas per port object495 */496static void497_transport_delete_port(struct MPT3SAS_ADAPTER *ioc,498	struct _sas_port *mpt3sas_port)499{500	u64 sas_address = mpt3sas_port->remote_identify.sas_address;501	struct hba_port *port = mpt3sas_port->hba_port;502	enum sas_device_type device_type =503	    mpt3sas_port->remote_identify.device_type;504 505	dev_printk(KERN_INFO, &mpt3sas_port->port->dev,506	    "remove: sas_addr(0x%016llx)\n",507	    (unsigned long long) sas_address);508 509	ioc->logging_level |= MPT_DEBUG_TRANSPORT;510	if (device_type == SAS_END_DEVICE)511		mpt3sas_device_remove_by_sas_address(ioc,512		    sas_address, port);513	else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||514	    device_type == SAS_FANOUT_EXPANDER_DEVICE)515		mpt3sas_expander_remove(ioc, sas_address, port);516	ioc->logging_level &= ~MPT_DEBUG_TRANSPORT;517}518 519/**520 * _transport_delete_phy - helper function to removing single phy from port521 * @ioc: per adapter object522 * @mpt3sas_port: mpt3sas per port object523 * @mpt3sas_phy: mpt3sas per phy object524 */525static void526_transport_delete_phy(struct MPT3SAS_ADAPTER *ioc,527	struct _sas_port *mpt3sas_port, struct _sas_phy *mpt3sas_phy)528{529	u64 sas_address = mpt3sas_port->remote_identify.sas_address;530 531	dev_printk(KERN_INFO, &mpt3sas_phy->phy->dev,532	    "remove: sas_addr(0x%016llx), phy(%d)\n",533	    (unsigned long long) sas_address, mpt3sas_phy->phy_id);534 535	list_del(&mpt3sas_phy->port_siblings);536	mpt3sas_port->num_phys--;537	sas_port_delete_phy(mpt3sas_port->port, mpt3sas_phy->phy);538	mpt3sas_phy->phy_belongs_to_port = 0;539}540 541/**542 * _transport_add_phy - helper function to adding single phy to port543 * @ioc: per adapter object544 * @mpt3sas_port: mpt3sas per port object545 * @mpt3sas_phy: mpt3sas per phy object546 */547static void548_transport_add_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_port *mpt3sas_port,549	struct _sas_phy *mpt3sas_phy)550{551	u64 sas_address = mpt3sas_port->remote_identify.sas_address;552 553	dev_printk(KERN_INFO, &mpt3sas_phy->phy->dev,554	    "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long)555	    sas_address, mpt3sas_phy->phy_id);556 557	list_add_tail(&mpt3sas_phy->port_siblings, &mpt3sas_port->phy_list);558	mpt3sas_port->num_phys++;559	sas_port_add_phy(mpt3sas_port->port, mpt3sas_phy->phy);560	mpt3sas_phy->phy_belongs_to_port = 1;561}562 563/**564 * mpt3sas_transport_add_phy_to_an_existing_port - adding new phy to existing port565 * @ioc: per adapter object566 * @sas_node: sas node object (either expander or sas host)567 * @mpt3sas_phy: mpt3sas per phy object568 * @sas_address: sas address of device/expander were phy needs to be added to569 * @port: hba port entry570 */571void572mpt3sas_transport_add_phy_to_an_existing_port(struct MPT3SAS_ADAPTER *ioc,573	struct _sas_node *sas_node, struct _sas_phy *mpt3sas_phy,574	u64 sas_address, struct hba_port *port)575{576	struct _sas_port *mpt3sas_port;577	struct _sas_phy *phy_srch;578 579	if (mpt3sas_phy->phy_belongs_to_port == 1)580		return;581 582	if (!port)583		return;584 585	list_for_each_entry(mpt3sas_port, &sas_node->sas_port_list,586	    port_list) {587		if (mpt3sas_port->remote_identify.sas_address !=588		    sas_address)589			continue;590		if (mpt3sas_port->hba_port != port)591			continue;592		list_for_each_entry(phy_srch, &mpt3sas_port->phy_list,593		    port_siblings) {594			if (phy_srch == mpt3sas_phy)595				return;596		}597		_transport_add_phy(ioc, mpt3sas_port, mpt3sas_phy);598		return;599	}600 601}602 603/**604 * mpt3sas_transport_del_phy_from_an_existing_port - delete phy from existing port605 * @ioc: per adapter object606 * @sas_node: sas node object (either expander or sas host)607 * @mpt3sas_phy: mpt3sas per phy object608 */609void610mpt3sas_transport_del_phy_from_an_existing_port(struct MPT3SAS_ADAPTER *ioc,611	struct _sas_node *sas_node, struct _sas_phy *mpt3sas_phy)612{613	struct _sas_port *mpt3sas_port, *next;614	struct _sas_phy *phy_srch;615 616	if (mpt3sas_phy->phy_belongs_to_port == 0)617		return;618 619	list_for_each_entry_safe(mpt3sas_port, next, &sas_node->sas_port_list,620	    port_list) {621		list_for_each_entry(phy_srch, &mpt3sas_port->phy_list,622		    port_siblings) {623			if (phy_srch != mpt3sas_phy)624				continue;625 626			/*627			 * Don't delete port during host reset,628			 * just delete phy.629			 */630			if (mpt3sas_port->num_phys == 1 && !ioc->shost_recovery)631				_transport_delete_port(ioc, mpt3sas_port);632			else633				_transport_delete_phy(ioc, mpt3sas_port,634				    mpt3sas_phy);635			return;636		}637	}638}639 640/**641 * _transport_sanity_check - sanity check when adding a new port642 * @ioc: per adapter object643 * @sas_node: sas node object (either expander or sas host)644 * @sas_address: sas address of device being added645 * @port: hba port entry646 *647 * See the explanation above from _transport_delete_duplicate_port648 */649static void650_transport_sanity_check(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_node,651	u64 sas_address, struct hba_port *port)652{653	int i;654 655	for (i = 0; i < sas_node->num_phys; i++) {656		if (sas_node->phy[i].remote_identify.sas_address != sas_address)657			continue;658		if (sas_node->phy[i].port != port)659			continue;660		if (sas_node->phy[i].phy_belongs_to_port == 1)661			mpt3sas_transport_del_phy_from_an_existing_port(ioc,662			    sas_node, &sas_node->phy[i]);663	}664}665 666/**667 * mpt3sas_transport_port_add - insert port to the list668 * @ioc: per adapter object669 * @handle: handle of attached device670 * @sas_address: sas address of parent expander or sas host671 * @hba_port: hba port entry672 * Context: This function will acquire ioc->sas_node_lock.673 *674 * Adding new port object to the sas_node->sas_port_list.675 *676 * Return: mpt3sas_port.677 */678struct _sas_port *679mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,680	u64 sas_address, struct hba_port *hba_port)681{682	struct _sas_phy *mpt3sas_phy, *next;683	struct _sas_port *mpt3sas_port;684	unsigned long flags;685	struct _sas_node *sas_node;686	struct sas_rphy *rphy;687	struct _sas_device *sas_device = NULL;688	int i;689	struct sas_port *port;690	struct virtual_phy *vphy = NULL;691 692	if (!hba_port) {693		ioc_err(ioc, "failure at %s:%d/%s()!\n",694		    __FILE__, __LINE__, __func__);695		return NULL;696	}697 698	mpt3sas_port = kzalloc(sizeof(struct _sas_port),699	    GFP_KERNEL);700	if (!mpt3sas_port) {701		ioc_err(ioc, "failure at %s:%d/%s()!\n",702			__FILE__, __LINE__, __func__);703		return NULL;704	}705 706	INIT_LIST_HEAD(&mpt3sas_port->port_list);707	INIT_LIST_HEAD(&mpt3sas_port->phy_list);708	spin_lock_irqsave(&ioc->sas_node_lock, flags);709	sas_node = _transport_sas_node_find_by_sas_address(ioc,710	    sas_address, hba_port);711	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);712 713	if (!sas_node) {714		ioc_err(ioc, "%s: Could not find parent sas_address(0x%016llx)!\n",715			__func__, (u64)sas_address);716		goto out_fail;717	}718 719	if ((_transport_set_identify(ioc, handle,720	    &mpt3sas_port->remote_identify))) {721		ioc_err(ioc, "failure at %s:%d/%s()!\n",722			__FILE__, __LINE__, __func__);723		goto out_fail;724	}725 726	if (mpt3sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {727		ioc_err(ioc, "failure at %s:%d/%s()!\n",728			__FILE__, __LINE__, __func__);729		goto out_fail;730	}731 732	mpt3sas_port->hba_port = hba_port;733	_transport_sanity_check(ioc, sas_node,734	    mpt3sas_port->remote_identify.sas_address, hba_port);735 736	for (i = 0; i < sas_node->num_phys; i++) {737		if (sas_node->phy[i].remote_identify.sas_address !=738		    mpt3sas_port->remote_identify.sas_address)739			continue;740		if (sas_node->phy[i].port != hba_port)741			continue;742		list_add_tail(&sas_node->phy[i].port_siblings,743		    &mpt3sas_port->phy_list);744		mpt3sas_port->num_phys++;745		if (sas_node->handle <= ioc->sas_hba.num_phys) {746			if (!sas_node->phy[i].hba_vphy) {747				hba_port->phy_mask |= (1 << i);748				continue;749			}750 751			vphy = mpt3sas_get_vphy_by_phy(ioc, hba_port, i);752			if (!vphy) {753				ioc_err(ioc, "failure at %s:%d/%s()!\n",754				    __FILE__, __LINE__, __func__);755				goto out_fail;756			}757		}758	}759 760	if (!mpt3sas_port->num_phys) {761		ioc_err(ioc, "failure at %s:%d/%s()!\n",762			__FILE__, __LINE__, __func__);763		goto out_fail;764	}765 766	if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {767		sas_device = mpt3sas_get_sdev_by_addr(ioc,768		    mpt3sas_port->remote_identify.sas_address,769		    mpt3sas_port->hba_port);770		if (!sas_device) {771			ioc_err(ioc, "failure at %s:%d/%s()!\n",772			    __FILE__, __LINE__, __func__);773			goto out_fail;774		}775		sas_device->pend_sas_rphy_add = 1;776	}777 778	if (!sas_node->parent_dev) {779		ioc_err(ioc, "failure at %s:%d/%s()!\n",780			__FILE__, __LINE__, __func__);781		goto out_fail;782	}783	port = sas_port_alloc_num(sas_node->parent_dev);784	if (!port || (sas_port_add(port))) {785		ioc_err(ioc, "failure at %s:%d/%s()!\n",786			__FILE__, __LINE__, __func__);787		goto out_fail;788	}789 790	list_for_each_entry(mpt3sas_phy, &mpt3sas_port->phy_list,791	    port_siblings) {792		if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))793			dev_printk(KERN_INFO, &port->dev,794				"add: handle(0x%04x), sas_addr(0x%016llx), phy(%d)\n",795				handle, (unsigned long long)796			    mpt3sas_port->remote_identify.sas_address,797			    mpt3sas_phy->phy_id);798		sas_port_add_phy(port, mpt3sas_phy->phy);799		mpt3sas_phy->phy_belongs_to_port = 1;800		mpt3sas_phy->port = hba_port;801	}802 803	mpt3sas_port->port = port;804	if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {805		rphy = sas_end_device_alloc(port);806		sas_device->rphy = rphy;807		if (sas_node->handle <= ioc->sas_hba.num_phys) {808			if (!vphy)809				hba_port->sas_address =810				    sas_device->sas_address;811			else812				vphy->sas_address =813				    sas_device->sas_address;814		}815	} else {816		rphy = sas_expander_alloc(port,817		    mpt3sas_port->remote_identify.device_type);818		if (sas_node->handle <= ioc->sas_hba.num_phys)819			hba_port->sas_address =820			    mpt3sas_port->remote_identify.sas_address;821	}822 823	if (!rphy) {824		ioc_err(ioc, "failure at %s:%d/%s()!\n",825			__FILE__, __LINE__, __func__);826		goto out_delete_port;827	}828 829	rphy->identify = mpt3sas_port->remote_identify;830 831	if ((sas_rphy_add(rphy))) {832		ioc_err(ioc, "failure at %s:%d/%s()!\n",833			__FILE__, __LINE__, __func__);834		sas_rphy_free(rphy);835		rphy = NULL;836		goto out_delete_port;837	}838 839	if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {840		sas_device->pend_sas_rphy_add = 0;841		sas_device_put(sas_device);842	}843 844	dev_info(&rphy->dev,845	    "add: handle(0x%04x), sas_addr(0x%016llx)\n", handle,846	    (unsigned long long)mpt3sas_port->remote_identify.sas_address);847 848	mpt3sas_port->rphy = rphy;849	spin_lock_irqsave(&ioc->sas_node_lock, flags);850	list_add_tail(&mpt3sas_port->port_list, &sas_node->sas_port_list);851	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);852 853	/* fill in report manufacture */854	if (mpt3sas_port->remote_identify.device_type ==855	    MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||856	    mpt3sas_port->remote_identify.device_type ==857	    MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)858		_transport_expander_report_manufacture(ioc,859		    mpt3sas_port->remote_identify.sas_address,860		    rphy_to_expander_device(rphy), hba_port->port_id);861	return mpt3sas_port;862 863out_delete_port:864	sas_port_delete(port);865 866out_fail:867	list_for_each_entry_safe(mpt3sas_phy, next, &mpt3sas_port->phy_list,868	    port_siblings)869		list_del(&mpt3sas_phy->port_siblings);870	kfree(mpt3sas_port);871	return NULL;872}873 874/**875 * mpt3sas_transport_port_remove - remove port from the list876 * @ioc: per adapter object877 * @sas_address: sas address of attached device878 * @sas_address_parent: sas address of parent expander or sas host879 * @port: hba port entry880 * Context: This function will acquire ioc->sas_node_lock.881 *882 * Removing object and freeing associated memory from the883 * ioc->sas_port_list.884 */885void886mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address,887	u64 sas_address_parent, struct hba_port *port)888{889	int i;890	unsigned long flags;891	struct _sas_port *mpt3sas_port, *next;892	struct _sas_node *sas_node;893	u8 found = 0;894	struct _sas_phy *mpt3sas_phy, *next_phy;895	struct hba_port *hba_port_next, *hba_port = NULL;896	struct virtual_phy *vphy, *vphy_next = NULL;897 898	if (!port)899		return;900 901	spin_lock_irqsave(&ioc->sas_node_lock, flags);902	sas_node = _transport_sas_node_find_by_sas_address(ioc,903	    sas_address_parent, port);904	if (!sas_node) {905		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);906		return;907	}908	list_for_each_entry_safe(mpt3sas_port, next, &sas_node->sas_port_list,909	    port_list) {910		if (mpt3sas_port->remote_identify.sas_address != sas_address)911			continue;912		if (mpt3sas_port->hba_port != port)913			continue;914		found = 1;915		list_del(&mpt3sas_port->port_list);916		goto out;917	}918 out:919	if (!found) {920		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);921		return;922	}923 924	if (sas_node->handle <= ioc->sas_hba.num_phys &&925	    (ioc->multipath_on_hba)) {926		if (port->vphys_mask) {927			list_for_each_entry_safe(vphy, vphy_next,928			    &port->vphys_list, list) {929				if (vphy->sas_address != sas_address)930					continue;931				ioc_info(ioc,932				    "remove vphy entry: %p of port:%p,from %d port's vphys list\n",933				    vphy, port, port->port_id);934				port->vphys_mask &= ~vphy->phy_mask;935				list_del(&vphy->list);936				kfree(vphy);937			}938		}939 940		list_for_each_entry_safe(hba_port, hba_port_next,941		    &ioc->port_table_list, list) {942			if (hba_port != port)943				continue;944			/*945			 * Delete hba_port object if946			 *  - hba_port object's sas address matches with current947			 *    removed device's sas address and no vphy's948			 *    associated with it.949			 *  - Current removed device is a vSES device and950			 *    none of the other direct attached device have951			 *    this vSES device's port number (hence hba_port952			 *    object sas_address field will be zero).953			 */954			if ((hba_port->sas_address == sas_address ||955			    !hba_port->sas_address) && !hba_port->vphys_mask) {956				ioc_info(ioc,957				    "remove hba_port entry: %p port: %d from hba_port list\n",958				    hba_port, hba_port->port_id);959				list_del(&hba_port->list);960				kfree(hba_port);961			} else if (hba_port->sas_address == sas_address &&962			    hba_port->vphys_mask) {963				/*964				 * Current removed device is a non vSES device965				 * and a vSES device has the same port number966				 * as of current device's port number. Hence967				 * only clear the sas_address filed, don't968				 * delete the hba_port object.969				 */970				ioc_info(ioc,971				    "clearing sas_address from hba_port entry: %p port: %d from hba_port list\n",972				    hba_port, hba_port->port_id);973				port->sas_address = 0;974			}975			break;976		}977	}978 979	for (i = 0; i < sas_node->num_phys; i++) {980		if (sas_node->phy[i].remote_identify.sas_address == sas_address)981			memset(&sas_node->phy[i].remote_identify, 0 ,982			    sizeof(struct sas_identify));983	}984 985	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);986 987	list_for_each_entry_safe(mpt3sas_phy, next_phy,988	    &mpt3sas_port->phy_list, port_siblings) {989		if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))990			dev_printk(KERN_INFO, &mpt3sas_port->port->dev,991			    "remove: sas_addr(0x%016llx), phy(%d)\n",992			    (unsigned long long)993			    mpt3sas_port->remote_identify.sas_address,994			    mpt3sas_phy->phy_id);995		mpt3sas_phy->phy_belongs_to_port = 0;996		if (!ioc->remove_host)997			sas_port_delete_phy(mpt3sas_port->port,998						mpt3sas_phy->phy);999		list_del(&mpt3sas_phy->port_siblings);1000	}1001	if (!ioc->remove_host)1002		sas_port_delete(mpt3sas_port->port);1003	ioc_info(ioc, "%s: removed: sas_addr(0x%016llx)\n",1004	    __func__, (unsigned long long)sas_address);1005	kfree(mpt3sas_port);1006}1007 1008/**1009 * mpt3sas_transport_add_host_phy - report sas_host phy to transport1010 * @ioc: per adapter object1011 * @mpt3sas_phy: mpt3sas per phy object1012 * @phy_pg0: sas phy page 01013 * @parent_dev: parent device class object1014 *1015 * Return: 0 for success, non-zero for failure.1016 */1017int1018mpt3sas_transport_add_host_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy1019	*mpt3sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev)1020{1021	struct sas_phy *phy;1022	int phy_index = mpt3sas_phy->phy_id;1023 1024 1025	INIT_LIST_HEAD(&mpt3sas_phy->port_siblings);1026	phy = sas_phy_alloc(parent_dev, phy_index);1027	if (!phy) {1028		ioc_err(ioc, "failure at %s:%d/%s()!\n",1029			__FILE__, __LINE__, __func__);1030		return -1;1031	}1032	if ((_transport_set_identify(ioc, mpt3sas_phy->handle,1033	    &mpt3sas_phy->identify))) {1034		ioc_err(ioc, "failure at %s:%d/%s()!\n",1035			__FILE__, __LINE__, __func__);1036		sas_phy_free(phy);1037		return -1;1038	}1039	phy->identify = mpt3sas_phy->identify;1040	mpt3sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle);1041	if (mpt3sas_phy->attached_handle)1042		_transport_set_identify(ioc, mpt3sas_phy->attached_handle,1043		    &mpt3sas_phy->remote_identify);1044	phy->identify.phy_identifier = mpt3sas_phy->phy_id;1045	phy->negotiated_linkrate = _transport_convert_phy_link_rate(1046	    phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);1047	phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(1048	    phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);1049	phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(1050	    phy_pg0.HwLinkRate >> 4);1051	phy->minimum_linkrate = _transport_convert_phy_link_rate(1052	    phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);1053	phy->maximum_linkrate = _transport_convert_phy_link_rate(1054	    phy_pg0.ProgrammedLinkRate >> 4);1055	phy->hostdata = mpt3sas_phy->port;1056 1057	if ((sas_phy_add(phy))) {1058		ioc_err(ioc, "failure at %s:%d/%s()!\n",1059			__FILE__, __LINE__, __func__);1060		sas_phy_free(phy);1061		return -1;1062	}1063	if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))1064		dev_printk(KERN_INFO, &phy->dev,1065		    "add: handle(0x%04x), sas_addr(0x%016llx)\n"1066		    "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",1067		    mpt3sas_phy->handle, (unsigned long long)1068		    mpt3sas_phy->identify.sas_address,1069		    mpt3sas_phy->attached_handle,1070		    (unsigned long long)1071		    mpt3sas_phy->remote_identify.sas_address);1072	mpt3sas_phy->phy = phy;1073	return 0;1074}1075 1076 1077/**1078 * mpt3sas_transport_add_expander_phy - report expander phy to transport1079 * @ioc: per adapter object1080 * @mpt3sas_phy: mpt3sas per phy object1081 * @expander_pg1: expander page 11082 * @parent_dev: parent device class object1083 *1084 * Return: 0 for success, non-zero for failure.1085 */1086int1087mpt3sas_transport_add_expander_phy(struct MPT3SAS_ADAPTER *ioc, struct _sas_phy1088	*mpt3sas_phy, Mpi2ExpanderPage1_t expander_pg1,1089	struct device *parent_dev)1090{1091	struct sas_phy *phy;1092	int phy_index = mpt3sas_phy->phy_id;1093 1094	INIT_LIST_HEAD(&mpt3sas_phy->port_siblings);1095	phy = sas_phy_alloc(parent_dev, phy_index);1096	if (!phy) {1097		ioc_err(ioc, "failure at %s:%d/%s()!\n",1098			__FILE__, __LINE__, __func__);1099		return -1;1100	}1101	if ((_transport_set_identify(ioc, mpt3sas_phy->handle,1102	    &mpt3sas_phy->identify))) {1103		ioc_err(ioc, "failure at %s:%d/%s()!\n",1104			__FILE__, __LINE__, __func__);1105		sas_phy_free(phy);1106		return -1;1107	}1108	phy->identify = mpt3sas_phy->identify;1109	mpt3sas_phy->attached_handle =1110	    le16_to_cpu(expander_pg1.AttachedDevHandle);1111	if (mpt3sas_phy->attached_handle)1112		_transport_set_identify(ioc, mpt3sas_phy->attached_handle,1113		    &mpt3sas_phy->remote_identify);1114	phy->identify.phy_identifier = mpt3sas_phy->phy_id;1115	phy->negotiated_linkrate = _transport_convert_phy_link_rate(1116	    expander_pg1.NegotiatedLinkRate &1117	    MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);1118	phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(1119	    expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);1120	phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(1121	    expander_pg1.HwLinkRate >> 4);1122	phy->minimum_linkrate = _transport_convert_phy_link_rate(1123	    expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);1124	phy->maximum_linkrate = _transport_convert_phy_link_rate(1125	    expander_pg1.ProgrammedLinkRate >> 4);1126	phy->hostdata = mpt3sas_phy->port;1127 1128	if ((sas_phy_add(phy))) {1129		ioc_err(ioc, "failure at %s:%d/%s()!\n",1130			__FILE__, __LINE__, __func__);1131		sas_phy_free(phy);1132		return -1;1133	}1134	if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))1135		dev_printk(KERN_INFO, &phy->dev,1136		    "add: handle(0x%04x), sas_addr(0x%016llx)\n"1137		    "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",1138		    mpt3sas_phy->handle, (unsigned long long)1139		    mpt3sas_phy->identify.sas_address,1140		    mpt3sas_phy->attached_handle,1141		    (unsigned long long)1142		    mpt3sas_phy->remote_identify.sas_address);1143	mpt3sas_phy->phy = phy;1144	return 0;1145}1146 1147/**1148 * mpt3sas_transport_update_links - refreshing phy link changes1149 * @ioc: per adapter object1150 * @sas_address: sas address of parent expander or sas host1151 * @handle: attached device handle1152 * @phy_number: phy number1153 * @link_rate: new link rate1154 * @port: hba port entry1155 *1156 * Return nothing.1157 */1158void1159mpt3sas_transport_update_links(struct MPT3SAS_ADAPTER *ioc,1160	u64 sas_address, u16 handle, u8 phy_number, u8 link_rate,1161	struct hba_port *port)1162{1163	unsigned long flags;1164	struct _sas_node *sas_node;1165	struct _sas_phy *mpt3sas_phy;1166	struct hba_port *hba_port = NULL;1167 1168	if (ioc->shost_recovery || ioc->pci_error_recovery)1169		return;1170 1171	spin_lock_irqsave(&ioc->sas_node_lock, flags);1172	sas_node = _transport_sas_node_find_by_sas_address(ioc,1173	    sas_address, port);1174	if (!sas_node) {1175		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1176		return;1177	}1178 1179	mpt3sas_phy = &sas_node->phy[phy_number];1180	mpt3sas_phy->attached_handle = handle;1181	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1182	if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {1183		_transport_set_identify(ioc, handle,1184		    &mpt3sas_phy->remote_identify);1185		if ((sas_node->handle <= ioc->sas_hba.num_phys) &&1186		    (ioc->multipath_on_hba)) {1187			list_for_each_entry(hba_port,1188			    &ioc->port_table_list, list) {1189				if (hba_port->sas_address == sas_address &&1190				    hba_port == port)1191					hba_port->phy_mask |=1192					    (1 << mpt3sas_phy->phy_id);1193			}1194		}1195		mpt3sas_transport_add_phy_to_an_existing_port(ioc, sas_node,1196		    mpt3sas_phy, mpt3sas_phy->remote_identify.sas_address,1197		    port);1198	} else1199		memset(&mpt3sas_phy->remote_identify, 0 , sizeof(struct1200		    sas_identify));1201 1202	if (mpt3sas_phy->phy)1203		mpt3sas_phy->phy->negotiated_linkrate =1204		    _transport_convert_phy_link_rate(link_rate);1205 1206	if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))1207		dev_printk(KERN_INFO, &mpt3sas_phy->phy->dev,1208		    "refresh: parent sas_addr(0x%016llx),\n"1209		    "\tlink_rate(0x%02x), phy(%d)\n"1210		    "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",1211		    (unsigned long long)sas_address,1212		    link_rate, phy_number, handle, (unsigned long long)1213		    mpt3sas_phy->remote_identify.sas_address);1214}1215 1216static inline void *1217phy_to_ioc(struct sas_phy *phy)1218{1219	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);1220	return shost_priv(shost);1221}1222 1223static inline void *1224rphy_to_ioc(struct sas_rphy *rphy)1225{1226	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);1227	return shost_priv(shost);1228}1229 1230/* report phy error log structure */1231struct phy_error_log_request {1232	u8 smp_frame_type; /* 0x40 */1233	u8 function; /* 0x11 */1234	u8 allocated_response_length;1235	u8 request_length; /* 02 */1236	u8 reserved_1[5];1237	u8 phy_identifier;1238	u8 reserved_2[2];1239};1240 1241/* report phy error log reply structure */1242struct phy_error_log_reply {1243	u8 smp_frame_type; /* 0x41 */1244	u8 function; /* 0x11 */1245	u8 function_result;1246	u8 response_length;1247	__be16 expander_change_count;1248	u8 reserved_1[3];1249	u8 phy_identifier;1250	u8 reserved_2[2];1251	__be32 invalid_dword;1252	__be32 running_disparity_error;1253	__be32 loss_of_dword_sync;1254	__be32 phy_reset_problem;1255};1256 1257/**1258 * _transport_get_expander_phy_error_log - return expander counters1259 * @ioc: per adapter object1260 * @phy: The sas phy object1261 *1262 * Return: 0 for success, non-zero for failure.1263 *1264 */1265static int1266_transport_get_expander_phy_error_log(struct MPT3SAS_ADAPTER *ioc,1267	struct sas_phy *phy)1268{1269	Mpi2SmpPassthroughRequest_t *mpi_request;1270	Mpi2SmpPassthroughReply_t *mpi_reply;1271	struct phy_error_log_request *phy_error_log_request;1272	struct phy_error_log_reply *phy_error_log_reply;1273	int rc;1274	u16 smid;1275	void *psge;1276	u8 issue_reset = 0;1277	void *data_out = NULL;1278	dma_addr_t data_out_dma;1279	u32 sz;1280 1281	if (ioc->shost_recovery || ioc->pci_error_recovery) {1282		ioc_info(ioc, "%s: host reset in progress!\n", __func__);1283		return -EFAULT;1284	}1285 1286	mutex_lock(&ioc->transport_cmds.mutex);1287 1288	if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {1289		ioc_err(ioc, "%s: transport_cmds in use\n", __func__);1290		rc = -EAGAIN;1291		goto out;1292	}1293	ioc->transport_cmds.status = MPT3_CMD_PENDING;1294 1295	rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT);1296	if (rc)1297		goto out;1298 1299	smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);1300	if (!smid) {1301		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);1302		rc = -EAGAIN;1303		goto out;1304	}1305 1306	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);1307	ioc->transport_cmds.smid = smid;1308 1309	sz = sizeof(struct phy_error_log_request) +1310	    sizeof(struct phy_error_log_reply);1311	data_out = dma_alloc_coherent(&ioc->pdev->dev, sz, &data_out_dma,1312			GFP_KERNEL);1313	if (!data_out) {1314		pr_err("failure at %s:%d/%s()!\n", __FILE__,1315		    __LINE__, __func__);1316		rc = -ENOMEM;1317		mpt3sas_base_free_smid(ioc, smid);1318		goto out;1319	}1320 1321	rc = -EINVAL;1322	memset(data_out, 0, sz);1323	phy_error_log_request = data_out;1324	phy_error_log_request->smp_frame_type = 0x40;1325	phy_error_log_request->function = 0x11;1326	phy_error_log_request->request_length = 2;1327	phy_error_log_request->allocated_response_length = 0;1328	phy_error_log_request->phy_identifier = phy->number;1329 1330	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));1331	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;1332	mpi_request->PhysicalPort = _transport_get_port_id_by_sas_phy(phy);1333	mpi_request->VF_ID = 0; /* TODO */1334	mpi_request->VP_ID = 0;1335	mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);1336	mpi_request->RequestDataLength =1337	    cpu_to_le16(sizeof(struct phy_error_log_request));1338	psge = &mpi_request->SGL;1339 1340	ioc->build_sg(ioc, psge, data_out_dma,1341		sizeof(struct phy_error_log_request),1342	    data_out_dma + sizeof(struct phy_error_log_request),1343	    sizeof(struct phy_error_log_reply));1344 1345	dtransportprintk(ioc,1346			 ioc_info(ioc, "phy_error_log - send to sas_addr(0x%016llx), phy(%d)\n",1347				  (u64)phy->identify.sas_address,1348				  phy->number));1349	init_completion(&ioc->transport_cmds.done);1350	ioc->put_smid_default(ioc, smid);1351	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);1352 1353	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {1354		ioc_err(ioc, "%s: timeout\n", __func__);1355		_debug_dump_mf(mpi_request,1356		    sizeof(Mpi2SmpPassthroughRequest_t)/4);1357		if (!(ioc->transport_cmds.status & MPT3_CMD_RESET))1358			issue_reset = 1;1359		goto issue_host_reset;1360	}1361 1362	dtransportprintk(ioc, ioc_info(ioc, "phy_error_log - complete\n"));1363 1364	if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) {1365 1366		mpi_reply = ioc->transport_cmds.reply;1367 1368		dtransportprintk(ioc,1369				 ioc_info(ioc, "phy_error_log - reply data transfer size(%d)\n",1370					  le16_to_cpu(mpi_reply->ResponseDataLength)));1371 1372		if (le16_to_cpu(mpi_reply->ResponseDataLength) !=1373		    sizeof(struct phy_error_log_reply))1374			goto out;1375 1376		phy_error_log_reply = data_out +1377		    sizeof(struct phy_error_log_request);1378 1379		dtransportprintk(ioc,1380				 ioc_info(ioc, "phy_error_log - function_result(%d)\n",1381					  phy_error_log_reply->function_result));1382 1383		phy->invalid_dword_count =1384		    be32_to_cpu(phy_error_log_reply->invalid_dword);1385		phy->running_disparity_error_count =1386		    be32_to_cpu(phy_error_log_reply->running_disparity_error);1387		phy->loss_of_dword_sync_count =1388		    be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);1389		phy->phy_reset_problem_count =1390		    be32_to_cpu(phy_error_log_reply->phy_reset_problem);1391		rc = 0;1392	} else1393		dtransportprintk(ioc,1394				 ioc_info(ioc, "phy_error_log - no reply\n"));1395 1396 issue_host_reset:1397	if (issue_reset)1398		mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);1399 out:1400	ioc->transport_cmds.status = MPT3_CMD_NOT_USED;1401	if (data_out)1402		dma_free_coherent(&ioc->pdev->dev, sz, data_out, data_out_dma);1403 1404	mutex_unlock(&ioc->transport_cmds.mutex);1405	return rc;1406}1407 1408/**1409 * _transport_get_linkerrors - return phy counters for both hba and expanders1410 * @phy: The sas phy object1411 *1412 * Return: 0 for success, non-zero for failure.1413 *1414 */1415static int1416_transport_get_linkerrors(struct sas_phy *phy)1417{1418	struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy);1419	unsigned long flags;1420	Mpi2ConfigReply_t mpi_reply;1421	Mpi2SasPhyPage1_t phy_pg1;1422	struct hba_port *port = phy->hostdata;1423	int port_id = port->port_id;1424 1425	spin_lock_irqsave(&ioc->sas_node_lock, flags);1426	if (_transport_sas_node_find_by_sas_address(ioc,1427	    phy->identify.sas_address,1428	    mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) {1429		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1430		return -EINVAL;1431	}1432	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1433 1434	if (phy->identify.sas_address != ioc->sas_hba.sas_address)1435		return _transport_get_expander_phy_error_log(ioc, phy);1436 1437	/* get hba phy error logs */1438	if ((mpt3sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,1439		    phy->number))) {1440		ioc_err(ioc, "failure at %s:%d/%s()!\n",1441			__FILE__, __LINE__, __func__);1442		return -ENXIO;1443	}1444 1445	if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)1446		ioc_info(ioc, "phy(%d), ioc_status (0x%04x), loginfo(0x%08x)\n",1447			 phy->number,1448			 le16_to_cpu(mpi_reply.IOCStatus),1449			 le32_to_cpu(mpi_reply.IOCLogInfo));1450 1451	phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);1452	phy->running_disparity_error_count =1453	    le32_to_cpu(phy_pg1.RunningDisparityErrorCount);1454	phy->loss_of_dword_sync_count =1455	    le32_to_cpu(phy_pg1.LossDwordSynchCount);1456	phy->phy_reset_problem_count =1457	    le32_to_cpu(phy_pg1.PhyResetProblemCount);1458	return 0;1459}1460 1461/**1462 * _transport_get_enclosure_identifier -1463 * @rphy: The sas phy object1464 * @identifier: ?1465 *1466 * Obtain the enclosure logical id for an expander.1467 * Return: 0 for success, non-zero for failure.1468 */1469static int1470_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)1471{1472	struct MPT3SAS_ADAPTER *ioc = rphy_to_ioc(rphy);1473	struct _sas_device *sas_device;1474	unsigned long flags;1475	int rc;1476 1477	spin_lock_irqsave(&ioc->sas_device_lock, flags);1478	sas_device = __mpt3sas_get_sdev_by_rphy(ioc, rphy);1479	if (sas_device) {1480		*identifier = sas_device->enclosure_logical_id;1481		rc = 0;1482		sas_device_put(sas_device);1483	} else {1484		*identifier = 0;1485		rc = -ENXIO;1486	}1487 1488	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);1489	return rc;1490}1491 1492/**1493 * _transport_get_bay_identifier -1494 * @rphy: The sas phy object1495 *1496 * Return: the slot id for a device that resides inside an enclosure.1497 */1498static int1499_transport_get_bay_identifier(struct sas_rphy *rphy)1500{1501	struct MPT3SAS_ADAPTER *ioc = rphy_to_ioc(rphy);1502	struct _sas_device *sas_device;1503	unsigned long flags;1504	int rc;1505 1506	spin_lock_irqsave(&ioc->sas_device_lock, flags);1507	sas_device = __mpt3sas_get_sdev_by_rphy(ioc, rphy);1508	if (sas_device) {1509		rc = sas_device->slot;1510		sas_device_put(sas_device);1511	} else {1512		rc = -ENXIO;1513	}1514	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);1515	return rc;1516}1517 1518/* phy control request structure */1519struct phy_control_request {1520	u8 smp_frame_type; /* 0x40 */1521	u8 function; /* 0x91 */1522	u8 allocated_response_length;1523	u8 request_length; /* 0x09 */1524	u16 expander_change_count;1525	u8 reserved_1[3];1526	u8 phy_identifier;1527	u8 phy_operation;1528	u8 reserved_2[13];1529	u64 attached_device_name;1530	u8 programmed_min_physical_link_rate;1531	u8 programmed_max_physical_link_rate;1532	u8 reserved_3[6];1533};1534 1535/* phy control reply structure */1536struct phy_control_reply {1537	u8 smp_frame_type; /* 0x41 */1538	u8 function; /* 0x11 */1539	u8 function_result;1540	u8 response_length;1541};1542 1543#define SMP_PHY_CONTROL_LINK_RESET	(0x01)1544#define SMP_PHY_CONTROL_HARD_RESET	(0x02)1545#define SMP_PHY_CONTROL_DISABLE		(0x03)1546 1547/**1548 * _transport_expander_phy_control - expander phy control1549 * @ioc: per adapter object1550 * @phy: The sas phy object1551 * @phy_operation: ?1552 *1553 * Return: 0 for success, non-zero for failure.1554 *1555 */1556static int1557_transport_expander_phy_control(struct MPT3SAS_ADAPTER *ioc,1558	struct sas_phy *phy, u8 phy_operation)1559{1560	Mpi2SmpPassthroughRequest_t *mpi_request;1561	Mpi2SmpPassthroughReply_t *mpi_reply;1562	struct phy_control_request *phy_control_request;1563	struct phy_control_reply *phy_control_reply;1564	int rc;1565	u16 smid;1566	void *psge;1567	u8 issue_reset = 0;1568	void *data_out = NULL;1569	dma_addr_t data_out_dma;1570	u32 sz;1571 1572	if (ioc->shost_recovery || ioc->pci_error_recovery) {1573		ioc_info(ioc, "%s: host reset in progress!\n", __func__);1574		return -EFAULT;1575	}1576 1577	mutex_lock(&ioc->transport_cmds.mutex);1578 1579	if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {1580		ioc_err(ioc, "%s: transport_cmds in use\n", __func__);1581		rc = -EAGAIN;1582		goto out;1583	}1584	ioc->transport_cmds.status = MPT3_CMD_PENDING;1585 1586	rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT);1587	if (rc)1588		goto out;1589 1590	smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);1591	if (!smid) {1592		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);1593		rc = -EAGAIN;1594		goto out;1595	}1596 1597	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);1598	ioc->transport_cmds.smid = smid;1599 1600	sz = sizeof(struct phy_control_request) +1601	    sizeof(struct phy_control_reply);1602	data_out = dma_alloc_coherent(&ioc->pdev->dev, sz, &data_out_dma,1603			GFP_KERNEL);1604	if (!data_out) {1605		pr_err("failure at %s:%d/%s()!\n", __FILE__,1606		    __LINE__, __func__);1607		rc = -ENOMEM;1608		mpt3sas_base_free_smid(ioc, smid);1609		goto out;1610	}1611 1612	rc = -EINVAL;1613	memset(data_out, 0, sz);1614	phy_control_request = data_out;1615	phy_control_request->smp_frame_type = 0x40;1616	phy_control_request->function = 0x91;1617	phy_control_request->request_length = 9;1618	phy_control_request->allocated_response_length = 0;1619	phy_control_request->phy_identifier = phy->number;1620	phy_control_request->phy_operation = phy_operation;1621	phy_control_request->programmed_min_physical_link_rate =1622	    phy->minimum_linkrate << 4;1623	phy_control_request->programmed_max_physical_link_rate =1624	    phy->maximum_linkrate << 4;1625 1626	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));1627	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;1628	mpi_request->PhysicalPort = _transport_get_port_id_by_sas_phy(phy);1629	mpi_request->VF_ID = 0; /* TODO */1630	mpi_request->VP_ID = 0;1631	mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);1632	mpi_request->RequestDataLength =1633	    cpu_to_le16(sizeof(struct phy_error_log_request));1634	psge = &mpi_request->SGL;1635 1636	ioc->build_sg(ioc, psge, data_out_dma,1637			    sizeof(struct phy_control_request),1638	    data_out_dma + sizeof(struct phy_control_request),1639	    sizeof(struct phy_control_reply));1640 1641	dtransportprintk(ioc,1642			 ioc_info(ioc, "phy_control - send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n",1643				  (u64)phy->identify.sas_address,1644				  phy->number, phy_operation));1645	init_completion(&ioc->transport_cmds.done);1646	ioc->put_smid_default(ioc, smid);1647	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);1648 1649	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {1650		ioc_err(ioc, "%s: timeout\n", __func__);1651		_debug_dump_mf(mpi_request,1652		    sizeof(Mpi2SmpPassthroughRequest_t)/4);1653		if (!(ioc->transport_cmds.status & MPT3_CMD_RESET))1654			issue_reset = 1;1655		goto issue_host_reset;1656	}1657 1658	dtransportprintk(ioc, ioc_info(ioc, "phy_control - complete\n"));1659 1660	if (ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID) {1661 1662		mpi_reply = ioc->transport_cmds.reply;1663 1664		dtransportprintk(ioc,1665				 ioc_info(ioc, "phy_control - reply data transfer size(%d)\n",1666					  le16_to_cpu(mpi_reply->ResponseDataLength)));1667 1668		if (le16_to_cpu(mpi_reply->ResponseDataLength) !=1669		    sizeof(struct phy_control_reply))1670			goto out;1671 1672		phy_control_reply = data_out +1673		    sizeof(struct phy_control_request);1674 1675		dtransportprintk(ioc,1676				 ioc_info(ioc, "phy_control - function_result(%d)\n",1677					  phy_control_reply->function_result));1678 1679		rc = 0;1680	} else1681		dtransportprintk(ioc,1682				 ioc_info(ioc, "phy_control - no reply\n"));1683 1684 issue_host_reset:1685	if (issue_reset)1686		mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);1687 out:1688	ioc->transport_cmds.status = MPT3_CMD_NOT_USED;1689	if (data_out)1690		dma_free_coherent(&ioc->pdev->dev, sz, data_out,1691				data_out_dma);1692 1693	mutex_unlock(&ioc->transport_cmds.mutex);1694	return rc;1695}1696 1697/**1698 * _transport_phy_reset -1699 * @phy: The sas phy object1700 * @hard_reset:1701 *1702 * Return: 0 for success, non-zero for failure.1703 */1704static int1705_transport_phy_reset(struct sas_phy *phy, int hard_reset)1706{1707	struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy);1708	Mpi2SasIoUnitControlReply_t mpi_reply;1709	Mpi2SasIoUnitControlRequest_t mpi_request;1710	struct hba_port *port = phy->hostdata;1711	int port_id = port->port_id;1712	unsigned long flags;1713 1714	spin_lock_irqsave(&ioc->sas_node_lock, flags);1715	if (_transport_sas_node_find_by_sas_address(ioc,1716	    phy->identify.sas_address,1717	    mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) {1718		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1719		return -EINVAL;1720	}1721	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1722 1723	/* handle expander phys */1724	if (phy->identify.sas_address != ioc->sas_hba.sas_address)1725		return _transport_expander_phy_control(ioc, phy,1726		    (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :1727		    SMP_PHY_CONTROL_LINK_RESET);1728 1729	/* handle hba phys */1730	memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));1731	mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;1732	mpi_request.Operation = hard_reset ?1733	    MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;1734	mpi_request.PhyNum = phy->number;1735 1736	if ((mpt3sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {1737		ioc_err(ioc, "failure at %s:%d/%s()!\n",1738			__FILE__, __LINE__, __func__);1739		return -ENXIO;1740	}1741 1742	if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)1743		ioc_info(ioc, "phy(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",1744			 phy->number, le16_to_cpu(mpi_reply.IOCStatus),1745			 le32_to_cpu(mpi_reply.IOCLogInfo));1746 1747	return 0;1748}1749 1750/**1751 * _transport_phy_enable - enable/disable phys1752 * @phy: The sas phy object1753 * @enable: enable phy when true1754 *1755 * Only support sas_host direct attached phys.1756 * Return: 0 for success, non-zero for failure.1757 */1758static int1759_transport_phy_enable(struct sas_phy *phy, int enable)1760{1761	struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy);1762	Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;1763	Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;1764	Mpi2ConfigReply_t mpi_reply;1765	u16 ioc_status;1766	u16 sz;1767	int rc = 0;1768	unsigned long flags;1769	int i, discovery_active;1770	struct hba_port *port = phy->hostdata;1771	int port_id = port->port_id;1772 1773	spin_lock_irqsave(&ioc->sas_node_lock, flags);1774	if (_transport_sas_node_find_by_sas_address(ioc,1775	    phy->identify.sas_address,1776	    mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) {1777		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1778		return -EINVAL;1779	}1780	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1781 1782	/* handle expander phys */1783	if (phy->identify.sas_address != ioc->sas_hba.sas_address)1784		return _transport_expander_phy_control(ioc, phy,1785		    (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :1786		    SMP_PHY_CONTROL_DISABLE);1787 1788	/* handle hba phys */1789 1790	/* read sas_iounit page 0 */1791	sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys);1792	sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);1793	if (!sas_iounit_pg0) {1794		ioc_err(ioc, "failure at %s:%d/%s()!\n",1795			__FILE__, __LINE__, __func__);1796		rc = -ENOMEM;1797		goto out;1798	}1799	if ((mpt3sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,1800	    sas_iounit_pg0, sz))) {1801		ioc_err(ioc, "failure at %s:%d/%s()!\n",1802			__FILE__, __LINE__, __func__);1803		rc = -ENXIO;1804		goto out;1805	}1806	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &1807	    MPI2_IOCSTATUS_MASK;1808	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {1809		ioc_err(ioc, "failure at %s:%d/%s()!\n",1810			__FILE__, __LINE__, __func__);1811		rc = -EIO;1812		goto out;1813	}1814 1815	/* unable to enable/disable phys when when discovery is active */1816	for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) {1817		if (sas_iounit_pg0->PhyData[i].PortFlags &1818		    MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {1819			ioc_err(ioc, "discovery is active on port = %d, phy = %d: unable to enable/disable phys, try again later!\n",1820				sas_iounit_pg0->PhyData[i].Port, i);1821			discovery_active = 1;1822		}1823	}1824 1825	if (discovery_active) {1826		rc = -EAGAIN;1827		goto out;1828	}1829 1830	/* read sas_iounit page 1 */1831	sz = struct_size(sas_iounit_pg1, PhyData, ioc->sas_hba.num_phys);1832	sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);1833	if (!sas_iounit_pg1) {1834		ioc_err(ioc, "failure at %s:%d/%s()!\n",1835			__FILE__, __LINE__, __func__);1836		rc = -ENOMEM;1837		goto out;1838	}1839	if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,1840	    sas_iounit_pg1, sz))) {1841		ioc_err(ioc, "failure at %s:%d/%s()!\n",1842			__FILE__, __LINE__, __func__);1843		rc = -ENXIO;1844		goto out;1845	}1846	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &1847	    MPI2_IOCSTATUS_MASK;1848	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {1849		ioc_err(ioc, "failure at %s:%d/%s()!\n",1850			__FILE__, __LINE__, __func__);1851		rc = -EIO;1852		goto out;1853	}1854 1855	/* copy Port/PortFlags/PhyFlags from page 0 */1856	for (i = 0; i < ioc->sas_hba.num_phys ; i++) {1857		sas_iounit_pg1->PhyData[i].Port =1858		    sas_iounit_pg0->PhyData[i].Port;1859		sas_iounit_pg1->PhyData[i].PortFlags =1860		    (sas_iounit_pg0->PhyData[i].PortFlags &1861		    MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG);1862		sas_iounit_pg1->PhyData[i].PhyFlags =1863		    (sas_iounit_pg0->PhyData[i].PhyFlags &1864		    (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED +1865		    MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED));1866	}1867 1868	if (enable)1869		sas_iounit_pg1->PhyData[phy->number].PhyFlags1870		    &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;1871	else1872		sas_iounit_pg1->PhyData[phy->number].PhyFlags1873		    |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;1874 1875	mpt3sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);1876 1877	/* link reset */1878	if (enable)1879		_transport_phy_reset(phy, 0);1880 1881 out:1882	kfree(sas_iounit_pg1);1883	kfree(sas_iounit_pg0);1884	return rc;1885}1886 1887/**1888 * _transport_phy_speed - set phy min/max link rates1889 * @phy: The sas phy object1890 * @rates: rates defined in sas_phy_linkrates1891 *1892 * Only support sas_host direct attached phys.1893 *1894 * Return: 0 for success, non-zero for failure.1895 */1896static int1897_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)1898{1899	struct MPT3SAS_ADAPTER *ioc = phy_to_ioc(phy);1900	Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;1901	Mpi2SasPhyPage0_t phy_pg0;1902	Mpi2ConfigReply_t mpi_reply;1903	u16 ioc_status;1904	u16 sz;1905	int i;1906	int rc = 0;1907	unsigned long flags;1908	struct hba_port *port = phy->hostdata;1909	int port_id = port->port_id;1910 1911	spin_lock_irqsave(&ioc->sas_node_lock, flags);1912	if (_transport_sas_node_find_by_sas_address(ioc,1913	    phy->identify.sas_address,1914	    mpt3sas_get_port_by_id(ioc, port_id, 0)) == NULL) {1915		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1916		return -EINVAL;1917	}1918	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);1919 1920	if (!rates->minimum_linkrate)1921		rates->minimum_linkrate = phy->minimum_linkrate;1922	else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)1923		rates->minimum_linkrate = phy->minimum_linkrate_hw;1924 1925	if (!rates->maximum_linkrate)1926		rates->maximum_linkrate = phy->maximum_linkrate;1927	else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)1928		rates->maximum_linkrate = phy->maximum_linkrate_hw;1929 1930	/* handle expander phys */1931	if (phy->identify.sas_address != ioc->sas_hba.sas_address) {1932		phy->minimum_linkrate = rates->minimum_linkrate;1933		phy->maximum_linkrate = rates->maximum_linkrate;1934		return _transport_expander_phy_control(ioc, phy,1935		    SMP_PHY_CONTROL_LINK_RESET);1936	}1937 1938	/* handle hba phys */1939 1940	/* sas_iounit page 1 */1941	sz = struct_size(sas_iounit_pg1, PhyData, ioc->sas_hba.num_phys);1942	sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);1943	if (!sas_iounit_pg1) {1944		ioc_err(ioc, "failure at %s:%d/%s()!\n",1945			__FILE__, __LINE__, __func__);1946		rc = -ENOMEM;1947		goto out;1948	}1949	if ((mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,1950	    sas_iounit_pg1, sz))) {1951		ioc_err(ioc, "failure at %s:%d/%s()!\n",1952			__FILE__, __LINE__, __func__);1953		rc = -ENXIO;1954		goto out;1955	}1956	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &1957	    MPI2_IOCSTATUS_MASK;1958	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {1959		ioc_err(ioc, "failure at %s:%d/%s()!\n",1960			__FILE__, __LINE__, __func__);1961		rc = -EIO;1962		goto out;1963	}1964 1965	for (i = 0; i < ioc->sas_hba.num_phys; i++) {1966		if (phy->number != i) {1967			sas_iounit_pg1->PhyData[i].MaxMinLinkRate =1968			    (ioc->sas_hba.phy[i].phy->minimum_linkrate +1969			    (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));1970		} else {1971			sas_iounit_pg1->PhyData[i].MaxMinLinkRate =1972			    (rates->minimum_linkrate +1973			    (rates->maximum_linkrate << 4));1974		}1975	}1976 1977	if (mpt3sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,1978	    sz)) {1979		ioc_err(ioc, "failure at %s:%d/%s()!\n",1980			__FILE__, __LINE__, __func__);1981		rc = -ENXIO;1982		goto out;1983	}1984 1985	/* link reset */1986	_transport_phy_reset(phy, 0);1987 1988	/* read phy page 0, then update the rates in the sas transport phy */1989	if (!mpt3sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,1990	    phy->number)) {1991		phy->minimum_linkrate = _transport_convert_phy_link_rate(1992		    phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);1993		phy->maximum_linkrate = _transport_convert_phy_link_rate(1994		    phy_pg0.ProgrammedLinkRate >> 4);1995		phy->negotiated_linkrate = _transport_convert_phy_link_rate(1996		    phy_pg0.NegotiatedLinkRate &1997		    MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);1998	}1999 2000 out:2001	kfree(sas_iounit_pg1);2002	return rc;2003}2004 2005static int2006_transport_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,2007		dma_addr_t *dma_addr, size_t *dma_len, void **p)2008{2009	/* Check if the request is split across multiple segments */2010	if (buf->sg_cnt > 1) {2011		*p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,2012				GFP_KERNEL);2013		if (!*p)2014			return -ENOMEM;2015		*dma_len = buf->payload_len;2016	} else {2017		if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))2018			return -ENOMEM;2019		*dma_addr = sg_dma_address(buf->sg_list);2020		*dma_len = sg_dma_len(buf->sg_list);2021		*p = NULL;2022	}2023 2024	return 0;2025}2026 2027static void2028_transport_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,2029		dma_addr_t dma_addr, void *p)2030{2031	if (p)2032		dma_free_coherent(dev, buf->payload_len, p, dma_addr);2033	else2034		dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);2035}2036 2037/**2038 * _transport_smp_handler - transport portal for smp passthru2039 * @job: ?2040 * @shost: shost object2041 * @rphy: sas transport rphy object2042 *2043 * This used primarily for smp_utils.2044 * Example:2045 *           smp_rep_general /sys/class/bsg/expander-5:02046 */2047static void2048_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,2049		struct sas_rphy *rphy)2050{2051	struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);2052	Mpi2SmpPassthroughRequest_t *mpi_request;2053	Mpi2SmpPassthroughReply_t *mpi_reply;2054	int rc;2055	u16 smid;2056	void *psge;2057	dma_addr_t dma_addr_in;2058	dma_addr_t dma_addr_out;2059	void *addr_in = NULL;2060	void *addr_out = NULL;2061	size_t dma_len_in;2062	size_t dma_len_out;2063	unsigned int reslen = 0;2064 2065	if (ioc->shost_recovery || ioc->pci_error_recovery) {2066		ioc_info(ioc, "%s: host reset in progress!\n", __func__);2067		rc = -EFAULT;2068		goto job_done;2069	}2070 2071	rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);2072	if (rc)2073		goto job_done;2074 2075	if (ioc->transport_cmds.status != MPT3_CMD_NOT_USED) {2076		ioc_err(ioc, "%s: transport_cmds in use\n",2077			__func__);2078		rc = -EAGAIN;2079		goto out;2080	}2081	ioc->transport_cmds.status = MPT3_CMD_PENDING;2082 2083	rc = _transport_map_smp_buffer(&ioc->pdev->dev, &job->request_payload,2084			&dma_addr_out, &dma_len_out, &addr_out);2085	if (rc)2086		goto out;2087	if (addr_out) {2088		sg_copy_to_buffer(job->request_payload.sg_list,2089				job->request_payload.sg_cnt, addr_out,2090				job->request_payload.payload_len);2091	}2092 2093	rc = _transport_map_smp_buffer(&ioc->pdev->dev, &job->reply_payload,2094			&dma_addr_in, &dma_len_in, &addr_in);2095	if (rc)2096		goto unmap_out;2097 2098	rc = mpt3sas_wait_for_ioc(ioc, IOC_OPERATIONAL_WAIT_COUNT);2099	if (rc)2100		goto unmap_in;2101 2102	smid = mpt3sas_base_get_smid(ioc, ioc->transport_cb_idx);2103	if (!smid) {2104		ioc_err(ioc, "%s: failed obtaining a smid\n", __func__);2105		rc = -EAGAIN;2106		goto unmap_in;2107	}2108 2109	rc = 0;2110	mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);2111	ioc->transport_cmds.smid = smid;2112 2113	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));2114	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;2115	mpi_request->PhysicalPort = _transport_get_port_id_by_rphy(ioc, rphy);2116	mpi_request->SASAddress = (rphy) ?2117	    cpu_to_le64(rphy->identify.sas_address) :2118	    cpu_to_le64(ioc->sas_hba.sas_address);2119	mpi_request->RequestDataLength = cpu_to_le16(dma_len_out - 4);2120	psge = &mpi_request->SGL;2121 2122	ioc->build_sg(ioc, psge, dma_addr_out, dma_len_out - 4, dma_addr_in,2123			dma_len_in - 4);2124 2125	dtransportprintk(ioc,2126			 ioc_info(ioc, "%s: sending smp request\n", __func__));2127 2128	init_completion(&ioc->transport_cmds.done);2129	ioc->put_smid_default(ioc, smid);2130	wait_for_completion_timeout(&ioc->transport_cmds.done, 10*HZ);2131 2132	if (!(ioc->transport_cmds.status & MPT3_CMD_COMPLETE)) {2133		ioc_err(ioc, "%s: timeout\n", __func__);2134		_debug_dump_mf(mpi_request,2135		    sizeof(Mpi2SmpPassthroughRequest_t)/4);2136		if (!(ioc->transport_cmds.status & MPT3_CMD_RESET)) {2137			mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);2138			rc = -ETIMEDOUT;2139			goto unmap_in;2140		}2141	}2142 2143	dtransportprintk(ioc, ioc_info(ioc, "%s - complete\n", __func__));2144 2145	if (!(ioc->transport_cmds.status & MPT3_CMD_REPLY_VALID)) {2146		dtransportprintk(ioc,2147				 ioc_info(ioc, "%s: no reply\n", __func__));2148		rc = -ENXIO;2149		goto unmap_in;2150	}2151 2152	mpi_reply = ioc->transport_cmds.reply;2153 2154	dtransportprintk(ioc,2155			 ioc_info(ioc, "%s: reply data transfer size(%d)\n",2156				  __func__,2157				  le16_to_cpu(mpi_reply->ResponseDataLength)));2158 2159	memcpy(job->reply, mpi_reply, sizeof(*mpi_reply));2160	job->reply_len = sizeof(*mpi_reply);2161	reslen = le16_to_cpu(mpi_reply->ResponseDataLength);2162 2163	if (addr_in) {2164		sg_copy_to_buffer(job->reply_payload.sg_list,2165				job->reply_payload.sg_cnt, addr_in,2166				job->reply_payload.payload_len);2167	}2168 2169	rc = 0;2170 unmap_in:2171	_transport_unmap_smp_buffer(&ioc->pdev->dev, &job->reply_payload,2172			dma_addr_in, addr_in);2173 unmap_out:2174	_transport_unmap_smp_buffer(&ioc->pdev->dev, &job->request_payload,2175			dma_addr_out, addr_out);2176 out:2177	ioc->transport_cmds.status = MPT3_CMD_NOT_USED;2178	mutex_unlock(&ioc->transport_cmds.mutex);2179job_done:2180	bsg_job_done(job, rc, reslen);2181}2182 2183struct sas_function_template mpt3sas_transport_functions = {2184	.get_linkerrors		= _transport_get_linkerrors,2185	.get_enclosure_identifier = _transport_get_enclosure_identifier,2186	.get_bay_identifier	= _transport_get_bay_identifier,2187	.phy_reset		= _transport_phy_reset,2188	.phy_enable		= _transport_phy_enable,2189	.set_phy_speed		= _transport_phy_speed,2190	.smp_handler		= _transport_smp_handler,2191};2192 2193struct scsi_transport_template *mpt3sas_transport_template;2194