Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
Note: File does not exist in v6.8.
   1/*
   2 * SAS Transport Layer for MPT (Message Passing Technology) based controllers
   3 *
   4 * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
   5 * Copyright (C) 2007-2010  LSI Corporation
   6 *  (mailto:DL-MPTFusionLinux@lsi.com)
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License
  10 * as published by the Free Software Foundation; either version 2
  11 * of the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * NO WARRANTY
  19 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
  20 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
  21 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
  22 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
  23 * solely responsible for determining the appropriateness of using and
  24 * distributing the Program and assumes all risks associated with its
  25 * exercise of rights under this Agreement, including but not limited to
  26 * the risks and costs of program errors, damage to or loss of data,
  27 * programs or equipment, and unavailability or interruption of operations.
  28
  29 * DISCLAIMER OF LIABILITY
  30 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
  31 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  32 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
  33 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
  34 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  35 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
  36 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
  37
  38 * You should have received a copy of the GNU General Public License
  39 * along with this program; if not, write to the Free Software
  40 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
  41 * USA.
  42 */
  43
  44#include <linux/module.h>
  45#include <linux/kernel.h>
  46#include <linux/init.h>
  47#include <linux/errno.h>
  48#include <linux/sched.h>
  49#include <linux/workqueue.h>
  50#include <linux/delay.h>
  51#include <linux/pci.h>
  52#include <linux/slab.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 "mpt2sas_base.h"
  62/**
  63 * _transport_sas_node_find_by_sas_address - sas node search
  64 * @ioc: per adapter object
  65 * @sas_address: sas address of expander or sas host
  66 * Context: Calling function should acquire ioc->sas_node_lock.
  67 *
  68 * Search for either hba phys or expander device based on handle, then returns
  69 * the sas_node object.
  70 */
  71static struct _sas_node *
  72_transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
  73    u64 sas_address)
  74{
  75	if (ioc->sas_hba.sas_address == sas_address)
  76		return &ioc->sas_hba;
  77	else
  78		return mpt2sas_scsih_expander_find_by_sas_address(ioc,
  79		    sas_address);
  80}
  81
  82/**
  83 * _transport_convert_phy_link_rate -
  84 * @link_rate: link rate returned from mpt firmware
  85 *
  86 * Convert link_rate from mpi fusion into sas_transport form.
  87 */
  88static enum sas_linkrate
  89_transport_convert_phy_link_rate(u8 link_rate)
  90{
  91	enum sas_linkrate rc;
  92
  93	switch (link_rate) {
  94	case MPI2_SAS_NEG_LINK_RATE_1_5:
  95		rc = SAS_LINK_RATE_1_5_GBPS;
  96		break;
  97	case MPI2_SAS_NEG_LINK_RATE_3_0:
  98		rc = SAS_LINK_RATE_3_0_GBPS;
  99		break;
 100	case MPI2_SAS_NEG_LINK_RATE_6_0:
 101		rc = SAS_LINK_RATE_6_0_GBPS;
 102		break;
 103	case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED:
 104		rc = SAS_PHY_DISABLED;
 105		break;
 106	case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
 107		rc = SAS_LINK_RATE_FAILED;
 108		break;
 109	case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR:
 110		rc = SAS_SATA_PORT_SELECTOR;
 111		break;
 112	case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
 113		rc = SAS_PHY_RESET_IN_PROGRESS;
 114		break;
 115	default:
 116	case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
 117	case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
 118		rc = SAS_LINK_RATE_UNKNOWN;
 119		break;
 120	}
 121	return rc;
 122}
 123
 124/**
 125 * _transport_set_identify - set identify for phys and end devices
 126 * @ioc: per adapter object
 127 * @handle: device handle
 128 * @identify: sas identify info
 129 *
 130 * Populates sas identify info.
 131 *
 132 * Returns 0 for success, non-zero for failure.
 133 */
 134static int
 135_transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
 136    struct sas_identify *identify)
 137{
 138	Mpi2SasDevicePage0_t sas_device_pg0;
 139	Mpi2ConfigReply_t mpi_reply;
 140	u32 device_info;
 141	u32 ioc_status;
 142
 143	if (ioc->shost_recovery || ioc->pci_error_recovery) {
 144		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
 145		    __func__, ioc->name);
 146		return -EFAULT;
 147	}
 148
 149	if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
 150	    MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
 151		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 152
 153		    ioc->name, __FILE__, __LINE__, __func__);
 154		return -ENXIO;
 155	}
 156
 157	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
 158	    MPI2_IOCSTATUS_MASK;
 159	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
 160		printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
 161		    "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
 162		     __FILE__, __LINE__, __func__);
 163		return -EIO;
 164	}
 165
 166	memset(identify, 0, sizeof(identify));
 167	device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
 168
 169	/* sas_address */
 170	identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
 171
 172	/* device_type */
 173	switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
 174	case MPI2_SAS_DEVICE_INFO_NO_DEVICE:
 175		identify->device_type = SAS_PHY_UNUSED;
 176		break;
 177	case MPI2_SAS_DEVICE_INFO_END_DEVICE:
 178		identify->device_type = SAS_END_DEVICE;
 179		break;
 180	case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER:
 181		identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
 182		break;
 183	case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER:
 184		identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
 185		break;
 186	}
 187
 188	/* initiator_port_protocols */
 189	if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR)
 190		identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
 191	if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR)
 192		identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
 193	if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR)
 194		identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
 195	if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST)
 196		identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
 197
 198	/* target_port_protocols */
 199	if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)
 200		identify->target_port_protocols |= SAS_PROTOCOL_SSP;
 201	if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
 202		identify->target_port_protocols |= SAS_PROTOCOL_STP;
 203	if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET)
 204		identify->target_port_protocols |= SAS_PROTOCOL_SMP;
 205	if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
 206		identify->target_port_protocols |= SAS_PROTOCOL_SATA;
 207
 208	return 0;
 209}
 210
 211/**
 212 * mpt2sas_transport_done -  internal transport layer callback handler.
 213 * @ioc: per adapter object
 214 * @smid: system request message index
 215 * @msix_index: MSIX table index supplied by the OS
 216 * @reply: reply message frame(lower 32bit addr)
 217 *
 218 * Callback handler when sending internal generated transport cmds.
 219 * The callback index passed is `ioc->transport_cb_idx`
 220 *
 221 * Return 1 meaning mf should be freed from _base_interrupt
 222 *        0 means the mf is freed from this function.
 223 */
 224u8
 225mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
 226    u32 reply)
 227{
 228	MPI2DefaultReply_t *mpi_reply;
 229
 230	mpi_reply =  mpt2sas_base_get_reply_virt_addr(ioc, reply);
 231	if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED)
 232		return 1;
 233	if (ioc->transport_cmds.smid != smid)
 234		return 1;
 235	ioc->transport_cmds.status |= MPT2_CMD_COMPLETE;
 236	if (mpi_reply) {
 237		memcpy(ioc->transport_cmds.reply, mpi_reply,
 238		    mpi_reply->MsgLength*4);
 239		ioc->transport_cmds.status |= MPT2_CMD_REPLY_VALID;
 240	}
 241	ioc->transport_cmds.status &= ~MPT2_CMD_PENDING;
 242	complete(&ioc->transport_cmds.done);
 243	return 1;
 244}
 245
 246/* report manufacture request structure */
 247struct rep_manu_request{
 248	u8 smp_frame_type;
 249	u8 function;
 250	u8 reserved;
 251	u8 request_length;
 252};
 253
 254/* report manufacture reply structure */
 255struct rep_manu_reply{
 256	u8 smp_frame_type; /* 0x41 */
 257	u8 function; /* 0x01 */
 258	u8 function_result;
 259	u8 response_length;
 260	u16 expander_change_count;
 261	u8 reserved0[2];
 262	u8 sas_format;
 263	u8 reserved2[3];
 264	u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
 265	u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
 266	u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
 267	u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
 268	u16 component_id;
 269	u8 component_revision_id;
 270	u8 reserved3;
 271	u8 vendor_specific[8];
 272};
 273
 274/**
 275 * _transport_expander_report_manufacture - obtain SMP report_manufacture
 276 * @ioc: per adapter object
 277 * @sas_address: expander sas address
 278 * @edev: the sas_expander_device object
 279 *
 280 * Fills in the sas_expander_device object when SMP port is created.
 281 *
 282 * Returns 0 for success, non-zero for failure.
 283 */
 284static int
 285_transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
 286    u64 sas_address, struct sas_expander_device *edev)
 287{
 288	Mpi2SmpPassthroughRequest_t *mpi_request;
 289	Mpi2SmpPassthroughReply_t *mpi_reply;
 290	struct rep_manu_reply *manufacture_reply;
 291	struct rep_manu_request *manufacture_request;
 292	int rc;
 293	u16 smid;
 294	u32 ioc_state;
 295	unsigned long timeleft;
 296	void *psge;
 297	u32 sgl_flags;
 298	u8 issue_reset = 0;
 299	void *data_out = NULL;
 300	dma_addr_t data_out_dma;
 301	u32 sz;
 302	u16 wait_state_count;
 303
 304	if (ioc->shost_recovery || ioc->pci_error_recovery) {
 305		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
 306		    __func__, ioc->name);
 307		return -EFAULT;
 308	}
 309
 310	mutex_lock(&ioc->transport_cmds.mutex);
 311
 312	if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
 313		printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
 314		    ioc->name, __func__);
 315		rc = -EAGAIN;
 316		goto out;
 317	}
 318	ioc->transport_cmds.status = MPT2_CMD_PENDING;
 319
 320	wait_state_count = 0;
 321	ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
 322	while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
 323		if (wait_state_count++ == 10) {
 324			printk(MPT2SAS_ERR_FMT
 325			    "%s: failed due to ioc not operational\n",
 326			    ioc->name, __func__);
 327			rc = -EFAULT;
 328			goto out;
 329		}
 330		ssleep(1);
 331		ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
 332		printk(MPT2SAS_INFO_FMT "%s: waiting for "
 333		    "operational state(count=%d)\n", ioc->name,
 334		    __func__, wait_state_count);
 335	}
 336	if (wait_state_count)
 337		printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
 338		    ioc->name, __func__);
 339
 340	smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
 341	if (!smid) {
 342		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
 343		    ioc->name, __func__);
 344		rc = -EAGAIN;
 345		goto out;
 346	}
 347
 348	rc = 0;
 349	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
 350	ioc->transport_cmds.smid = smid;
 351
 352	sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
 353	data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
 354
 355	if (!data_out) {
 356		printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
 357		    __LINE__, __func__);
 358		rc = -ENOMEM;
 359		mpt2sas_base_free_smid(ioc, smid);
 360		goto out;
 361	}
 362
 363	manufacture_request = data_out;
 364	manufacture_request->smp_frame_type = 0x40;
 365	manufacture_request->function = 1;
 366	manufacture_request->reserved = 0;
 367	manufacture_request->request_length = 0;
 368
 369	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
 370	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
 371	mpi_request->PhysicalPort = 0xFF;
 372	mpi_request->VF_ID = 0; /* TODO */
 373	mpi_request->VP_ID = 0;
 374	mpi_request->SASAddress = cpu_to_le64(sas_address);
 375	mpi_request->RequestDataLength =
 376	    cpu_to_le16(sizeof(struct rep_manu_request));
 377	psge = &mpi_request->SGL;
 378
 379	/* WRITE sgel first */
 380	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
 381	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
 382	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
 383	ioc->base_add_sg_single(psge, sgl_flags |
 384	    sizeof(struct rep_manu_request), data_out_dma);
 385
 386	/* incr sgel */
 387	psge += ioc->sge_size;
 388
 389	/* READ sgel last */
 390	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
 391	    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
 392	    MPI2_SGE_FLAGS_END_OF_LIST);
 393	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
 394	ioc->base_add_sg_single(psge, sgl_flags |
 395	    sizeof(struct rep_manu_reply), data_out_dma +
 396	    sizeof(struct rep_manu_request));
 397
 398	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
 399	    "send to sas_addr(0x%016llx)\n", ioc->name,
 400	    (unsigned long long)sas_address));
 401	mpt2sas_base_put_smid_default(ioc, smid);
 402	init_completion(&ioc->transport_cmds.done);
 403	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
 404	    10*HZ);
 405
 406	if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
 407		printk(MPT2SAS_ERR_FMT "%s: timeout\n",
 408		    ioc->name, __func__);
 409		_debug_dump_mf(mpi_request,
 410		    sizeof(Mpi2SmpPassthroughRequest_t)/4);
 411		if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
 412			issue_reset = 1;
 413		goto issue_host_reset;
 414	}
 415
 416	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
 417	    "complete\n", ioc->name));
 418
 419	if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
 420		u8 *tmp;
 421
 422		mpi_reply = ioc->transport_cmds.reply;
 423
 424		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
 425		    "report_manufacture - reply data transfer size(%d)\n",
 426		    ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
 427
 428		if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
 429		    sizeof(struct rep_manu_reply))
 430			goto out;
 431
 432		manufacture_reply = data_out + sizeof(struct rep_manu_request);
 433		strncpy(edev->vendor_id, manufacture_reply->vendor_id,
 434		     SAS_EXPANDER_VENDOR_ID_LEN);
 435		strncpy(edev->product_id, manufacture_reply->product_id,
 436		     SAS_EXPANDER_PRODUCT_ID_LEN);
 437		strncpy(edev->product_rev, manufacture_reply->product_rev,
 438		     SAS_EXPANDER_PRODUCT_REV_LEN);
 439		edev->level = manufacture_reply->sas_format & 1;
 440		if (edev->level) {
 441			strncpy(edev->component_vendor_id,
 442			    manufacture_reply->component_vendor_id,
 443			     SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
 444			tmp = (u8 *)&manufacture_reply->component_id;
 445			edev->component_id = tmp[0] << 8 | tmp[1];
 446			edev->component_revision_id =
 447			    manufacture_reply->component_revision_id;
 448		}
 449	} else
 450		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
 451		    "report_manufacture - no reply\n", ioc->name));
 452
 453 issue_host_reset:
 454	if (issue_reset)
 455		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
 456		    FORCE_BIG_HAMMER);
 457 out:
 458	ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
 459	if (data_out)
 460		pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
 461
 462	mutex_unlock(&ioc->transport_cmds.mutex);
 463	return rc;
 464}
 465
 466/**
 467 * _transport_delete_port - helper function to removing a port
 468 * @ioc: per adapter object
 469 * @mpt2sas_port: mpt2sas per port object
 470 *
 471 * Returns nothing.
 472 */
 473static void
 474_transport_delete_port(struct MPT2SAS_ADAPTER *ioc,
 475	struct _sas_port *mpt2sas_port)
 476{
 477	u64 sas_address = mpt2sas_port->remote_identify.sas_address;
 478	enum sas_device_type device_type =
 479	    mpt2sas_port->remote_identify.device_type;
 480
 481	dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
 482	    "remove: sas_addr(0x%016llx)\n",
 483	    (unsigned long long) sas_address);
 484
 485	ioc->logging_level |= MPT_DEBUG_TRANSPORT;
 486	if (device_type == SAS_END_DEVICE)
 487		mpt2sas_device_remove(ioc, sas_address);
 488	else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
 489	    device_type == SAS_FANOUT_EXPANDER_DEVICE)
 490		mpt2sas_expander_remove(ioc, sas_address);
 491	ioc->logging_level &= ~MPT_DEBUG_TRANSPORT;
 492}
 493
 494/**
 495 * _transport_delete_phy - helper function to removing single phy from port
 496 * @ioc: per adapter object
 497 * @mpt2sas_port: mpt2sas per port object
 498 * @mpt2sas_phy: mpt2sas per phy object
 499 *
 500 * Returns nothing.
 501 */
 502static void
 503_transport_delete_phy(struct MPT2SAS_ADAPTER *ioc,
 504	struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy)
 505{
 506	u64 sas_address = mpt2sas_port->remote_identify.sas_address;
 507
 508	dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
 509	    "remove: sas_addr(0x%016llx), phy(%d)\n",
 510	    (unsigned long long) sas_address, mpt2sas_phy->phy_id);
 511
 512	list_del(&mpt2sas_phy->port_siblings);
 513	mpt2sas_port->num_phys--;
 514	sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
 515	mpt2sas_phy->phy_belongs_to_port = 0;
 516}
 517
 518/**
 519 * _transport_add_phy - helper function to adding single phy to port
 520 * @ioc: per adapter object
 521 * @mpt2sas_port: mpt2sas per port object
 522 * @mpt2sas_phy: mpt2sas per phy object
 523 *
 524 * Returns nothing.
 525 */
 526static void
 527_transport_add_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port,
 528	struct _sas_phy *mpt2sas_phy)
 529{
 530	u64 sas_address = mpt2sas_port->remote_identify.sas_address;
 531
 532	dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
 533	    "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long)
 534	    sas_address, mpt2sas_phy->phy_id);
 535
 536	list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list);
 537	mpt2sas_port->num_phys++;
 538	sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy);
 539	mpt2sas_phy->phy_belongs_to_port = 1;
 540}
 541
 542/**
 543 * _transport_add_phy_to_an_existing_port - adding new phy to existing port
 544 * @ioc: per adapter object
 545 * @sas_node: sas node object (either expander or sas host)
 546 * @mpt2sas_phy: mpt2sas per phy object
 547 * @sas_address: sas address of device/expander were phy needs to be added to
 548 *
 549 * Returns nothing.
 550 */
 551static void
 552_transport_add_phy_to_an_existing_port(struct MPT2SAS_ADAPTER *ioc,
 553struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, u64 sas_address)
 554{
 555	struct _sas_port *mpt2sas_port;
 556	struct _sas_phy *phy_srch;
 557
 558	if (mpt2sas_phy->phy_belongs_to_port == 1)
 559		return;
 560
 561	list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list,
 562	    port_list) {
 563		if (mpt2sas_port->remote_identify.sas_address !=
 564		    sas_address)
 565			continue;
 566		list_for_each_entry(phy_srch, &mpt2sas_port->phy_list,
 567		    port_siblings) {
 568			if (phy_srch == mpt2sas_phy)
 569				return;
 570		}
 571		_transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy);
 572			return;
 573	}
 574
 575}
 576
 577/**
 578 * _transport_del_phy_from_an_existing_port - delete phy from existing port
 579 * @ioc: per adapter object
 580 * @sas_node: sas node object (either expander or sas host)
 581 * @mpt2sas_phy: mpt2sas per phy object
 582 *
 583 * Returns nothing.
 584 */
 585static void
 586_transport_del_phy_from_an_existing_port(struct MPT2SAS_ADAPTER *ioc,
 587	struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy)
 588{
 589	struct _sas_port *mpt2sas_port, *next;
 590	struct _sas_phy *phy_srch;
 591
 592	if (mpt2sas_phy->phy_belongs_to_port == 0)
 593		return;
 594
 595	list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
 596	    port_list) {
 597		list_for_each_entry(phy_srch, &mpt2sas_port->phy_list,
 598		    port_siblings) {
 599			if (phy_srch != mpt2sas_phy)
 600				continue;
 601			if (mpt2sas_port->num_phys == 1)
 602				_transport_delete_port(ioc, mpt2sas_port);
 603			else
 604				_transport_delete_phy(ioc, mpt2sas_port,
 605				    mpt2sas_phy);
 606			return;
 607		}
 608	}
 609}
 610
 611/**
 612 * _transport_sanity_check - sanity check when adding a new port
 613 * @ioc: per adapter object
 614 * @sas_node: sas node object (either expander or sas host)
 615 * @sas_address: sas address of device being added
 616 *
 617 * See the explanation above from _transport_delete_duplicate_port
 618 */
 619static void
 620_transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node,
 621     u64 sas_address)
 622{
 623	int i;
 624
 625	for (i = 0; i < sas_node->num_phys; i++) {
 626		if (sas_node->phy[i].remote_identify.sas_address != sas_address)
 627			continue;
 628		if (sas_node->phy[i].phy_belongs_to_port == 1)
 629			_transport_del_phy_from_an_existing_port(ioc, sas_node,
 630			    &sas_node->phy[i]);
 631	}
 632}
 633
 634/**
 635 * mpt2sas_transport_port_add - insert port to the list
 636 * @ioc: per adapter object
 637 * @handle: handle of attached device
 638 * @sas_address: sas address of parent expander or sas host
 639 * Context: This function will acquire ioc->sas_node_lock.
 640 *
 641 * Adding new port object to the sas_node->sas_port_list.
 642 *
 643 * Returns mpt2sas_port.
 644 */
 645struct _sas_port *
 646mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
 647    u64 sas_address)
 648{
 649	struct _sas_phy *mpt2sas_phy, *next;
 650	struct _sas_port *mpt2sas_port;
 651	unsigned long flags;
 652	struct _sas_node *sas_node;
 653	struct sas_rphy *rphy;
 654	int i;
 655	struct sas_port *port;
 656
 657	mpt2sas_port = kzalloc(sizeof(struct _sas_port),
 658	    GFP_KERNEL);
 659	if (!mpt2sas_port) {
 660		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 661		    ioc->name, __FILE__, __LINE__, __func__);
 662		return NULL;
 663	}
 664
 665	INIT_LIST_HEAD(&mpt2sas_port->port_list);
 666	INIT_LIST_HEAD(&mpt2sas_port->phy_list);
 667	spin_lock_irqsave(&ioc->sas_node_lock, flags);
 668	sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
 669	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 670
 671	if (!sas_node) {
 672		printk(MPT2SAS_ERR_FMT "%s: Could not find "
 673		    "parent sas_address(0x%016llx)!\n", ioc->name,
 674		    __func__, (unsigned long long)sas_address);
 675		goto out_fail;
 676	}
 677
 678	if ((_transport_set_identify(ioc, handle,
 679	    &mpt2sas_port->remote_identify))) {
 680		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 681		    ioc->name, __FILE__, __LINE__, __func__);
 682		goto out_fail;
 683	}
 684
 685	if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
 686		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 687		    ioc->name, __FILE__, __LINE__, __func__);
 688		goto out_fail;
 689	}
 690
 691	_transport_sanity_check(ioc, sas_node,
 692	    mpt2sas_port->remote_identify.sas_address);
 693
 694	for (i = 0; i < sas_node->num_phys; i++) {
 695		if (sas_node->phy[i].remote_identify.sas_address !=
 696		    mpt2sas_port->remote_identify.sas_address)
 697			continue;
 698		list_add_tail(&sas_node->phy[i].port_siblings,
 699		    &mpt2sas_port->phy_list);
 700		mpt2sas_port->num_phys++;
 701	}
 702
 703	if (!mpt2sas_port->num_phys) {
 704		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 705		    ioc->name, __FILE__, __LINE__, __func__);
 706		goto out_fail;
 707	}
 708
 709	port = sas_port_alloc_num(sas_node->parent_dev);
 710	if ((sas_port_add(port))) {
 711		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 712		    ioc->name, __FILE__, __LINE__, __func__);
 713		goto out_fail;
 714	}
 715
 716	list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list,
 717	    port_siblings) {
 718		if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
 719			dev_printk(KERN_INFO, &port->dev, "add: handle(0x%04x)"
 720			    ", sas_addr(0x%016llx), phy(%d)\n", handle,
 721			    (unsigned long long)
 722			    mpt2sas_port->remote_identify.sas_address,
 723			    mpt2sas_phy->phy_id);
 724		sas_port_add_phy(port, mpt2sas_phy->phy);
 725		mpt2sas_phy->phy_belongs_to_port = 1;
 726	}
 727
 728	mpt2sas_port->port = port;
 729	if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE)
 730		rphy = sas_end_device_alloc(port);
 731	else
 732		rphy = sas_expander_alloc(port,
 733		    mpt2sas_port->remote_identify.device_type);
 734
 735	rphy->identify = mpt2sas_port->remote_identify;
 736	if ((sas_rphy_add(rphy))) {
 737		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 738		    ioc->name, __FILE__, __LINE__, __func__);
 739	}
 740	if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
 741		dev_printk(KERN_INFO, &rphy->dev, "add: handle(0x%04x), "
 742		    "sas_addr(0x%016llx)\n", handle,
 743		    (unsigned long long)
 744		    mpt2sas_port->remote_identify.sas_address);
 745	mpt2sas_port->rphy = rphy;
 746	spin_lock_irqsave(&ioc->sas_node_lock, flags);
 747	list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list);
 748	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 749
 750	/* fill in report manufacture */
 751	if (mpt2sas_port->remote_identify.device_type ==
 752	    MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
 753	    mpt2sas_port->remote_identify.device_type ==
 754	    MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
 755		_transport_expander_report_manufacture(ioc,
 756		    mpt2sas_port->remote_identify.sas_address,
 757		    rphy_to_expander_device(rphy));
 758
 759	return mpt2sas_port;
 760
 761 out_fail:
 762	list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list,
 763	    port_siblings)
 764		list_del(&mpt2sas_phy->port_siblings);
 765	kfree(mpt2sas_port);
 766	return NULL;
 767}
 768
 769/**
 770 * mpt2sas_transport_port_remove - remove port from the list
 771 * @ioc: per adapter object
 772 * @sas_address: sas address of attached device
 773 * @sas_address_parent: sas address of parent expander or sas host
 774 * Context: This function will acquire ioc->sas_node_lock.
 775 *
 776 * Removing object and freeing associated memory from the
 777 * ioc->sas_port_list.
 778 *
 779 * Return nothing.
 780 */
 781void
 782mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
 783    u64 sas_address_parent)
 784{
 785	int i;
 786	unsigned long flags;
 787	struct _sas_port *mpt2sas_port, *next;
 788	struct _sas_node *sas_node;
 789	u8 found = 0;
 790	struct _sas_phy *mpt2sas_phy, *next_phy;
 791
 792	spin_lock_irqsave(&ioc->sas_node_lock, flags);
 793	sas_node = _transport_sas_node_find_by_sas_address(ioc,
 794	    sas_address_parent);
 795	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 796	if (!sas_node)
 797		return;
 798	list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
 799	    port_list) {
 800		if (mpt2sas_port->remote_identify.sas_address != sas_address)
 801			continue;
 802		found = 1;
 803		list_del(&mpt2sas_port->port_list);
 804		goto out;
 805	}
 806 out:
 807	if (!found)
 808		return;
 809
 810	for (i = 0; i < sas_node->num_phys; i++) {
 811		if (sas_node->phy[i].remote_identify.sas_address == sas_address)
 812			memset(&sas_node->phy[i].remote_identify, 0 ,
 813			    sizeof(struct sas_identify));
 814	}
 815
 816	list_for_each_entry_safe(mpt2sas_phy, next_phy,
 817	    &mpt2sas_port->phy_list, port_siblings) {
 818		if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
 819			dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
 820			    "remove: sas_addr(0x%016llx), phy(%d)\n",
 821			    (unsigned long long)
 822			    mpt2sas_port->remote_identify.sas_address,
 823			    mpt2sas_phy->phy_id);
 824		mpt2sas_phy->phy_belongs_to_port = 0;
 825		sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
 826		list_del(&mpt2sas_phy->port_siblings);
 827	}
 828	sas_port_delete(mpt2sas_port->port);
 829	kfree(mpt2sas_port);
 830}
 831
 832/**
 833 * mpt2sas_transport_add_host_phy - report sas_host phy to transport
 834 * @ioc: per adapter object
 835 * @mpt2sas_phy: mpt2sas per phy object
 836 * @phy_pg0: sas phy page 0
 837 * @parent_dev: parent device class object
 838 *
 839 * Returns 0 for success, non-zero for failure.
 840 */
 841int
 842mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
 843    *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev)
 844{
 845	struct sas_phy *phy;
 846	int phy_index = mpt2sas_phy->phy_id;
 847
 848
 849	INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
 850	phy = sas_phy_alloc(parent_dev, phy_index);
 851	if (!phy) {
 852		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 853		    ioc->name, __FILE__, __LINE__, __func__);
 854		return -1;
 855	}
 856	if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
 857	    &mpt2sas_phy->identify))) {
 858		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 859		    ioc->name, __FILE__, __LINE__, __func__);
 860		return -1;
 861	}
 862	phy->identify = mpt2sas_phy->identify;
 863	mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle);
 864	if (mpt2sas_phy->attached_handle)
 865		_transport_set_identify(ioc, mpt2sas_phy->attached_handle,
 866		    &mpt2sas_phy->remote_identify);
 867	phy->identify.phy_identifier = mpt2sas_phy->phy_id;
 868	phy->negotiated_linkrate = _transport_convert_phy_link_rate(
 869	    phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
 870	phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
 871	    phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
 872	phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
 873	    phy_pg0.HwLinkRate >> 4);
 874	phy->minimum_linkrate = _transport_convert_phy_link_rate(
 875	    phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
 876	phy->maximum_linkrate = _transport_convert_phy_link_rate(
 877	    phy_pg0.ProgrammedLinkRate >> 4);
 878
 879	if ((sas_phy_add(phy))) {
 880		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 881		    ioc->name, __FILE__, __LINE__, __func__);
 882		sas_phy_free(phy);
 883		return -1;
 884	}
 885	if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
 886		dev_printk(KERN_INFO, &phy->dev,
 887		    "add: handle(0x%04x), sas_addr(0x%016llx)\n"
 888		    "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
 889		    mpt2sas_phy->handle, (unsigned long long)
 890		    mpt2sas_phy->identify.sas_address,
 891		    mpt2sas_phy->attached_handle,
 892		    (unsigned long long)
 893		    mpt2sas_phy->remote_identify.sas_address);
 894	mpt2sas_phy->phy = phy;
 895	return 0;
 896}
 897
 898
 899/**
 900 * mpt2sas_transport_add_expander_phy - report expander phy to transport
 901 * @ioc: per adapter object
 902 * @mpt2sas_phy: mpt2sas per phy object
 903 * @expander_pg1: expander page 1
 904 * @parent_dev: parent device class object
 905 *
 906 * Returns 0 for success, non-zero for failure.
 907 */
 908int
 909mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
 910    *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev)
 911{
 912	struct sas_phy *phy;
 913	int phy_index = mpt2sas_phy->phy_id;
 914
 915	INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
 916	phy = sas_phy_alloc(parent_dev, phy_index);
 917	if (!phy) {
 918		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 919		    ioc->name, __FILE__, __LINE__, __func__);
 920		return -1;
 921	}
 922	if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
 923	    &mpt2sas_phy->identify))) {
 924		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 925		    ioc->name, __FILE__, __LINE__, __func__);
 926		return -1;
 927	}
 928	phy->identify = mpt2sas_phy->identify;
 929	mpt2sas_phy->attached_handle =
 930	    le16_to_cpu(expander_pg1.AttachedDevHandle);
 931	if (mpt2sas_phy->attached_handle)
 932		_transport_set_identify(ioc, mpt2sas_phy->attached_handle,
 933		    &mpt2sas_phy->remote_identify);
 934	phy->identify.phy_identifier = mpt2sas_phy->phy_id;
 935	phy->negotiated_linkrate = _transport_convert_phy_link_rate(
 936	    expander_pg1.NegotiatedLinkRate &
 937	    MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
 938	phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
 939	    expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
 940	phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
 941	    expander_pg1.HwLinkRate >> 4);
 942	phy->minimum_linkrate = _transport_convert_phy_link_rate(
 943	    expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
 944	phy->maximum_linkrate = _transport_convert_phy_link_rate(
 945	    expander_pg1.ProgrammedLinkRate >> 4);
 946
 947	if ((sas_phy_add(phy))) {
 948		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
 949		    ioc->name, __FILE__, __LINE__, __func__);
 950		sas_phy_free(phy);
 951		return -1;
 952	}
 953	if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
 954		dev_printk(KERN_INFO, &phy->dev,
 955		    "add: handle(0x%04x), sas_addr(0x%016llx)\n"
 956		    "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
 957		    mpt2sas_phy->handle, (unsigned long long)
 958		    mpt2sas_phy->identify.sas_address,
 959		    mpt2sas_phy->attached_handle,
 960		    (unsigned long long)
 961		    mpt2sas_phy->remote_identify.sas_address);
 962	mpt2sas_phy->phy = phy;
 963	return 0;
 964}
 965
 966/**
 967 * mpt2sas_transport_update_links - refreshing phy link changes
 968 * @ioc: per adapter object
 969 * @sas_address: sas address of parent expander or sas host
 970 * @handle: attached device handle
 971 * @phy_numberv: phy number
 972 * @link_rate: new link rate
 973 *
 974 * Returns nothing.
 975 */
 976void
 977mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
 978     u64 sas_address, u16 handle, u8 phy_number, u8 link_rate)
 979{
 980	unsigned long flags;
 981	struct _sas_node *sas_node;
 982	struct _sas_phy *mpt2sas_phy;
 983
 984	if (ioc->shost_recovery || ioc->pci_error_recovery)
 985		return;
 986
 987	spin_lock_irqsave(&ioc->sas_node_lock, flags);
 988	sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
 989	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
 990	if (!sas_node)
 991		return;
 992
 993	mpt2sas_phy = &sas_node->phy[phy_number];
 994	mpt2sas_phy->attached_handle = handle;
 995	if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {
 996		_transport_set_identify(ioc, handle,
 997		    &mpt2sas_phy->remote_identify);
 998		_transport_add_phy_to_an_existing_port(ioc, sas_node,
 999		    mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address);
1000	} else
1001		memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
1002		    sas_identify));
1003
1004	if (mpt2sas_phy->phy)
1005		mpt2sas_phy->phy->negotiated_linkrate =
1006		    _transport_convert_phy_link_rate(link_rate);
1007
1008	if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
1009		dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
1010		    "refresh: parent sas_addr(0x%016llx),\n"
1011		    "\tlink_rate(0x%02x), phy(%d)\n"
1012		    "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
1013		    (unsigned long long)sas_address,
1014		    link_rate, phy_number, handle, (unsigned long long)
1015		    mpt2sas_phy->remote_identify.sas_address);
1016}
1017
1018static inline void *
1019phy_to_ioc(struct sas_phy *phy)
1020{
1021	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
1022	return shost_priv(shost);
1023}
1024
1025static inline void *
1026rphy_to_ioc(struct sas_rphy *rphy)
1027{
1028	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
1029	return shost_priv(shost);
1030}
1031
1032
1033/* report phy error log structure */
1034struct phy_error_log_request{
1035	u8 smp_frame_type; /* 0x40 */
1036	u8 function; /* 0x11 */
1037	u8 allocated_response_length;
1038	u8 request_length; /* 02 */
1039	u8 reserved_1[5];
1040	u8 phy_identifier;
1041	u8 reserved_2[2];
1042};
1043
1044/* report phy error log reply structure */
1045struct phy_error_log_reply{
1046	u8 smp_frame_type; /* 0x41 */
1047	u8 function; /* 0x11 */
1048	u8 function_result;
1049	u8 response_length;
1050	__be16 expander_change_count;
1051	u8 reserved_1[3];
1052	u8 phy_identifier;
1053	u8 reserved_2[2];
1054	__be32 invalid_dword;
1055	__be32 running_disparity_error;
1056	__be32 loss_of_dword_sync;
1057	__be32 phy_reset_problem;
1058};
1059
1060/**
1061 * _transport_get_expander_phy_error_log - return expander counters
1062 * @ioc: per adapter object
1063 * @phy: The sas phy object
1064 *
1065 * Returns 0 for success, non-zero for failure.
1066 *
1067 */
1068static int
1069_transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc,
1070    struct sas_phy *phy)
1071{
1072	Mpi2SmpPassthroughRequest_t *mpi_request;
1073	Mpi2SmpPassthroughReply_t *mpi_reply;
1074	struct phy_error_log_request *phy_error_log_request;
1075	struct phy_error_log_reply *phy_error_log_reply;
1076	int rc;
1077	u16 smid;
1078	u32 ioc_state;
1079	unsigned long timeleft;
1080	void *psge;
1081	u32 sgl_flags;
1082	u8 issue_reset = 0;
1083	void *data_out = NULL;
1084	dma_addr_t data_out_dma;
1085	u32 sz;
1086	u16 wait_state_count;
1087
1088	if (ioc->shost_recovery || ioc->pci_error_recovery) {
1089		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1090		    __func__, ioc->name);
1091		return -EFAULT;
1092	}
1093
1094	mutex_lock(&ioc->transport_cmds.mutex);
1095
1096	if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
1097		printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
1098		    ioc->name, __func__);
1099		rc = -EAGAIN;
1100		goto out;
1101	}
1102	ioc->transport_cmds.status = MPT2_CMD_PENDING;
1103
1104	wait_state_count = 0;
1105	ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1106	while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
1107		if (wait_state_count++ == 10) {
1108			printk(MPT2SAS_ERR_FMT
1109			    "%s: failed due to ioc not operational\n",
1110			    ioc->name, __func__);
1111			rc = -EFAULT;
1112			goto out;
1113		}
1114		ssleep(1);
1115		ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1116		printk(MPT2SAS_INFO_FMT "%s: waiting for "
1117		    "operational state(count=%d)\n", ioc->name,
1118		    __func__, wait_state_count);
1119	}
1120	if (wait_state_count)
1121		printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
1122		    ioc->name, __func__);
1123
1124	smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
1125	if (!smid) {
1126		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
1127		    ioc->name, __func__);
1128		rc = -EAGAIN;
1129		goto out;
1130	}
1131
1132	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1133	ioc->transport_cmds.smid = smid;
1134
1135	sz = sizeof(struct phy_error_log_request) +
1136	    sizeof(struct phy_error_log_reply);
1137	data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
1138	if (!data_out) {
1139		printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
1140		    __LINE__, __func__);
1141		rc = -ENOMEM;
1142		mpt2sas_base_free_smid(ioc, smid);
1143		goto out;
1144	}
1145
1146	rc = -EINVAL;
1147	memset(data_out, 0, sz);
1148	phy_error_log_request = data_out;
1149	phy_error_log_request->smp_frame_type = 0x40;
1150	phy_error_log_request->function = 0x11;
1151	phy_error_log_request->request_length = 2;
1152	phy_error_log_request->allocated_response_length = 0;
1153	phy_error_log_request->phy_identifier = phy->number;
1154
1155	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
1156	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
1157	mpi_request->PhysicalPort = 0xFF;
1158	mpi_request->VF_ID = 0; /* TODO */
1159	mpi_request->VP_ID = 0;
1160	mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);
1161	mpi_request->RequestDataLength =
1162	    cpu_to_le16(sizeof(struct phy_error_log_request));
1163	psge = &mpi_request->SGL;
1164
1165	/* WRITE sgel first */
1166	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1167	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
1168	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1169	ioc->base_add_sg_single(psge, sgl_flags |
1170	    sizeof(struct phy_error_log_request), data_out_dma);
1171
1172	/* incr sgel */
1173	psge += ioc->sge_size;
1174
1175	/* READ sgel last */
1176	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1177	    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
1178	    MPI2_SGE_FLAGS_END_OF_LIST);
1179	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1180	ioc->base_add_sg_single(psge, sgl_flags |
1181	    sizeof(struct phy_error_log_reply), data_out_dma +
1182	    sizeof(struct phy_error_log_request));
1183
1184	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - "
1185	    "send to sas_addr(0x%016llx), phy(%d)\n", ioc->name,
1186	    (unsigned long long)phy->identify.sas_address, phy->number));
1187	mpt2sas_base_put_smid_default(ioc, smid);
1188	init_completion(&ioc->transport_cmds.done);
1189	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
1190	    10*HZ);
1191
1192	if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
1193		printk(MPT2SAS_ERR_FMT "%s: timeout\n",
1194		    ioc->name, __func__);
1195		_debug_dump_mf(mpi_request,
1196		    sizeof(Mpi2SmpPassthroughRequest_t)/4);
1197		if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
1198			issue_reset = 1;
1199		goto issue_host_reset;
1200	}
1201
1202	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - "
1203	    "complete\n", ioc->name));
1204
1205	if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
1206
1207		mpi_reply = ioc->transport_cmds.reply;
1208
1209		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
1210		    "phy_error_log - reply data transfer size(%d)\n",
1211		    ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
1212
1213		if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
1214		    sizeof(struct phy_error_log_reply))
1215			goto out;
1216
1217		phy_error_log_reply = data_out +
1218		    sizeof(struct phy_error_log_request);
1219
1220		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
1221		    "phy_error_log - function_result(%d)\n",
1222		    ioc->name, phy_error_log_reply->function_result));
1223
1224		phy->invalid_dword_count =
1225		    be32_to_cpu(phy_error_log_reply->invalid_dword);
1226		phy->running_disparity_error_count =
1227		    be32_to_cpu(phy_error_log_reply->running_disparity_error);
1228		phy->loss_of_dword_sync_count =
1229		    be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
1230		phy->phy_reset_problem_count =
1231		    be32_to_cpu(phy_error_log_reply->phy_reset_problem);
1232		rc = 0;
1233	} else
1234		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
1235		    "phy_error_log - no reply\n", ioc->name));
1236
1237 issue_host_reset:
1238	if (issue_reset)
1239		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
1240		    FORCE_BIG_HAMMER);
1241 out:
1242	ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
1243	if (data_out)
1244		pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
1245
1246	mutex_unlock(&ioc->transport_cmds.mutex);
1247	return rc;
1248}
1249
1250/**
1251 * _transport_get_linkerrors - return phy counters for both hba and expanders
1252 * @phy: The sas phy object
1253 *
1254 * Returns 0 for success, non-zero for failure.
1255 *
1256 */
1257static int
1258_transport_get_linkerrors(struct sas_phy *phy)
1259{
1260	struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
1261	unsigned long flags;
1262	Mpi2ConfigReply_t mpi_reply;
1263	Mpi2SasPhyPage1_t phy_pg1;
1264
1265	spin_lock_irqsave(&ioc->sas_node_lock, flags);
1266	if (_transport_sas_node_find_by_sas_address(ioc,
1267	    phy->identify.sas_address) == NULL) {
1268		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
1269		return -EINVAL;
1270	}
1271	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
1272
1273	if (phy->identify.sas_address != ioc->sas_hba.sas_address)
1274		return _transport_get_expander_phy_error_log(ioc, phy);
1275
1276	/* get hba phy error logs */
1277	if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,
1278		    phy->number))) {
1279		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1280		    ioc->name, __FILE__, __LINE__, __func__);
1281		return -ENXIO;
1282	}
1283
1284	if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
1285		printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
1286		    "(0x%04x), loginfo(0x%08x)\n", ioc->name,
1287		    phy->number, le16_to_cpu(mpi_reply.IOCStatus),
1288		    le32_to_cpu(mpi_reply.IOCLogInfo));
1289
1290	phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);
1291	phy->running_disparity_error_count =
1292	    le32_to_cpu(phy_pg1.RunningDisparityErrorCount);
1293	phy->loss_of_dword_sync_count =
1294	    le32_to_cpu(phy_pg1.LossDwordSynchCount);
1295	phy->phy_reset_problem_count =
1296	    le32_to_cpu(phy_pg1.PhyResetProblemCount);
1297	return 0;
1298}
1299
1300/**
1301 * _transport_get_enclosure_identifier -
1302 * @phy: The sas phy object
1303 *
1304 * Obtain the enclosure logical id for an expander.
1305 * Returns 0 for success, non-zero for failure.
1306 */
1307static int
1308_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
1309{
1310	struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
1311	struct _sas_device *sas_device;
1312	unsigned long flags;
1313
1314	spin_lock_irqsave(&ioc->sas_device_lock, flags);
1315	sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1316	    rphy->identify.sas_address);
1317	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1318
1319	if (!sas_device)
1320		return -ENXIO;
1321
1322	*identifier = sas_device->enclosure_logical_id;
1323	return 0;
1324}
1325
1326/**
1327 * _transport_get_bay_identifier -
1328 * @phy: The sas phy object
1329 *
1330 * Returns the slot id for a device that resides inside an enclosure.
1331 */
1332static int
1333_transport_get_bay_identifier(struct sas_rphy *rphy)
1334{
1335	struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
1336	struct _sas_device *sas_device;
1337	unsigned long flags;
1338
1339	spin_lock_irqsave(&ioc->sas_device_lock, flags);
1340	sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc,
1341	    rphy->identify.sas_address);
1342	spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
1343
1344	if (!sas_device)
1345		return -ENXIO;
1346
1347	return sas_device->slot;
1348}
1349
1350/* phy control request structure */
1351struct phy_control_request{
1352	u8 smp_frame_type; /* 0x40 */
1353	u8 function; /* 0x91 */
1354	u8 allocated_response_length;
1355	u8 request_length; /* 0x09 */
1356	u16 expander_change_count;
1357	u8 reserved_1[3];
1358	u8 phy_identifier;
1359	u8 phy_operation;
1360	u8 reserved_2[13];
1361	u64 attached_device_name;
1362	u8 programmed_min_physical_link_rate;
1363	u8 programmed_max_physical_link_rate;
1364	u8 reserved_3[6];
1365};
1366
1367/* phy control reply structure */
1368struct phy_control_reply{
1369	u8 smp_frame_type; /* 0x41 */
1370	u8 function; /* 0x11 */
1371	u8 function_result;
1372	u8 response_length;
1373};
1374
1375#define SMP_PHY_CONTROL_LINK_RESET	(0x01)
1376#define SMP_PHY_CONTROL_HARD_RESET	(0x02)
1377#define SMP_PHY_CONTROL_DISABLE		(0x03)
1378
1379/**
1380 * _transport_expander_phy_control - expander phy control
1381 * @ioc: per adapter object
1382 * @phy: The sas phy object
1383 *
1384 * Returns 0 for success, non-zero for failure.
1385 *
1386 */
1387static int
1388_transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc,
1389    struct sas_phy *phy, u8 phy_operation)
1390{
1391	Mpi2SmpPassthroughRequest_t *mpi_request;
1392	Mpi2SmpPassthroughReply_t *mpi_reply;
1393	struct phy_control_request *phy_control_request;
1394	struct phy_control_reply *phy_control_reply;
1395	int rc;
1396	u16 smid;
1397	u32 ioc_state;
1398	unsigned long timeleft;
1399	void *psge;
1400	u32 sgl_flags;
1401	u8 issue_reset = 0;
1402	void *data_out = NULL;
1403	dma_addr_t data_out_dma;
1404	u32 sz;
1405	u16 wait_state_count;
1406
1407	if (ioc->shost_recovery) {
1408		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1409		    __func__, ioc->name);
1410		return -EFAULT;
1411	}
1412
1413	mutex_lock(&ioc->transport_cmds.mutex);
1414
1415	if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
1416		printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
1417		    ioc->name, __func__);
1418		rc = -EAGAIN;
1419		goto out;
1420	}
1421	ioc->transport_cmds.status = MPT2_CMD_PENDING;
1422
1423	wait_state_count = 0;
1424	ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1425	while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
1426		if (wait_state_count++ == 10) {
1427			printk(MPT2SAS_ERR_FMT
1428			    "%s: failed due to ioc not operational\n",
1429			    ioc->name, __func__);
1430			rc = -EFAULT;
1431			goto out;
1432		}
1433		ssleep(1);
1434		ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1435		printk(MPT2SAS_INFO_FMT "%s: waiting for "
1436		    "operational state(count=%d)\n", ioc->name,
1437		    __func__, wait_state_count);
1438	}
1439	if (wait_state_count)
1440		printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
1441		    ioc->name, __func__);
1442
1443	smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
1444	if (!smid) {
1445		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
1446		    ioc->name, __func__);
1447		rc = -EAGAIN;
1448		goto out;
1449	}
1450
1451	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1452	ioc->transport_cmds.smid = smid;
1453
1454	sz = sizeof(struct phy_control_request) +
1455	    sizeof(struct phy_control_reply);
1456	data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
1457	if (!data_out) {
1458		printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
1459		    __LINE__, __func__);
1460		rc = -ENOMEM;
1461		mpt2sas_base_free_smid(ioc, smid);
1462		goto out;
1463	}
1464
1465	rc = -EINVAL;
1466	memset(data_out, 0, sz);
1467	phy_control_request = data_out;
1468	phy_control_request->smp_frame_type = 0x40;
1469	phy_control_request->function = 0x91;
1470	phy_control_request->request_length = 9;
1471	phy_control_request->allocated_response_length = 0;
1472	phy_control_request->phy_identifier = phy->number;
1473	phy_control_request->phy_operation = phy_operation;
1474	phy_control_request->programmed_min_physical_link_rate =
1475	    phy->minimum_linkrate << 4;
1476	phy_control_request->programmed_max_physical_link_rate =
1477	    phy->maximum_linkrate << 4;
1478
1479	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
1480	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
1481	mpi_request->PhysicalPort = 0xFF;
1482	mpi_request->VF_ID = 0; /* TODO */
1483	mpi_request->VP_ID = 0;
1484	mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);
1485	mpi_request->RequestDataLength =
1486	    cpu_to_le16(sizeof(struct phy_error_log_request));
1487	psge = &mpi_request->SGL;
1488
1489	/* WRITE sgel first */
1490	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1491	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
1492	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1493	ioc->base_add_sg_single(psge, sgl_flags |
1494	    sizeof(struct phy_control_request), data_out_dma);
1495
1496	/* incr sgel */
1497	psge += ioc->sge_size;
1498
1499	/* READ sgel last */
1500	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1501	    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
1502	    MPI2_SGE_FLAGS_END_OF_LIST);
1503	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1504	ioc->base_add_sg_single(psge, sgl_flags |
1505	    sizeof(struct phy_control_reply), data_out_dma +
1506	    sizeof(struct phy_control_request));
1507
1508	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - "
1509	    "send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", ioc->name,
1510	    (unsigned long long)phy->identify.sas_address, phy->number,
1511	    phy_operation));
1512	mpt2sas_base_put_smid_default(ioc, smid);
1513	init_completion(&ioc->transport_cmds.done);
1514	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
1515	    10*HZ);
1516
1517	if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
1518		printk(MPT2SAS_ERR_FMT "%s: timeout\n",
1519		    ioc->name, __func__);
1520		_debug_dump_mf(mpi_request,
1521		    sizeof(Mpi2SmpPassthroughRequest_t)/4);
1522		if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
1523			issue_reset = 1;
1524		goto issue_host_reset;
1525	}
1526
1527	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - "
1528	    "complete\n", ioc->name));
1529
1530	if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
1531
1532		mpi_reply = ioc->transport_cmds.reply;
1533
1534		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
1535		    "phy_control - reply data transfer size(%d)\n",
1536		    ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
1537
1538		if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
1539		    sizeof(struct phy_control_reply))
1540			goto out;
1541
1542		phy_control_reply = data_out +
1543		    sizeof(struct phy_control_request);
1544
1545		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
1546		    "phy_control - function_result(%d)\n",
1547		    ioc->name, phy_control_reply->function_result));
1548
1549		rc = 0;
1550	} else
1551		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
1552		    "phy_control - no reply\n", ioc->name));
1553
1554 issue_host_reset:
1555	if (issue_reset)
1556		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
1557		    FORCE_BIG_HAMMER);
1558 out:
1559	ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
1560	if (data_out)
1561		pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
1562
1563	mutex_unlock(&ioc->transport_cmds.mutex);
1564	return rc;
1565}
1566
1567/**
1568 * _transport_phy_reset -
1569 * @phy: The sas phy object
1570 * @hard_reset:
1571 *
1572 * Returns 0 for success, non-zero for failure.
1573 */
1574static int
1575_transport_phy_reset(struct sas_phy *phy, int hard_reset)
1576{
1577	struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
1578	Mpi2SasIoUnitControlReply_t mpi_reply;
1579	Mpi2SasIoUnitControlRequest_t mpi_request;
1580	unsigned long flags;
1581
1582	spin_lock_irqsave(&ioc->sas_node_lock, flags);
1583	if (_transport_sas_node_find_by_sas_address(ioc,
1584	    phy->identify.sas_address) == NULL) {
1585		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
1586		return -EINVAL;
1587	}
1588	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
1589
1590	/* handle expander phys */
1591	if (phy->identify.sas_address != ioc->sas_hba.sas_address)
1592		return _transport_expander_phy_control(ioc, phy,
1593		    (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
1594		    SMP_PHY_CONTROL_LINK_RESET);
1595
1596	/* handle hba phys */
1597	memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
1598	mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
1599	mpi_request.Operation = hard_reset ?
1600	    MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
1601	mpi_request.PhyNum = phy->number;
1602
1603	if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {
1604		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1605		    ioc->name, __FILE__, __LINE__, __func__);
1606		return -ENXIO;
1607	}
1608
1609	if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
1610		printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
1611		    "(0x%04x), loginfo(0x%08x)\n", ioc->name,
1612		    phy->number, le16_to_cpu(mpi_reply.IOCStatus),
1613		    le32_to_cpu(mpi_reply.IOCLogInfo));
1614
1615	return 0;
1616}
1617
1618/**
1619 * _transport_phy_enable - enable/disable phys
1620 * @phy: The sas phy object
1621 * @enable: enable phy when true
1622 *
1623 * Only support sas_host direct attached phys.
1624 * Returns 0 for success, non-zero for failure.
1625 */
1626static int
1627_transport_phy_enable(struct sas_phy *phy, int enable)
1628{
1629	struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
1630	Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
1631	Mpi2ConfigReply_t mpi_reply;
1632	u16 ioc_status;
1633	u16 sz;
1634	int rc = 0;
1635	unsigned long flags;
1636
1637	spin_lock_irqsave(&ioc->sas_node_lock, flags);
1638	if (_transport_sas_node_find_by_sas_address(ioc,
1639	    phy->identify.sas_address) == NULL) {
1640		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
1641		return -EINVAL;
1642	}
1643	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
1644
1645	/* handle expander phys */
1646	if (phy->identify.sas_address != ioc->sas_hba.sas_address)
1647		return _transport_expander_phy_control(ioc, phy,
1648		    (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
1649		    SMP_PHY_CONTROL_DISABLE);
1650
1651	/* handle hba phys */
1652
1653	/* sas_iounit page 1 */
1654	sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
1655	    sizeof(Mpi2SasIOUnit1PhyData_t));
1656	sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
1657	if (!sas_iounit_pg1) {
1658		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1659		    ioc->name, __FILE__, __LINE__, __func__);
1660		rc = -ENOMEM;
1661		goto out;
1662	}
1663	if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
1664	    sas_iounit_pg1, sz))) {
1665		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1666		    ioc->name, __FILE__, __LINE__, __func__);
1667		rc = -ENXIO;
1668		goto out;
1669	}
1670	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1671	    MPI2_IOCSTATUS_MASK;
1672	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1673		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1674		    ioc->name, __FILE__, __LINE__, __func__);
1675		rc = -EIO;
1676		goto out;
1677	}
1678
1679	if (enable)
1680		sas_iounit_pg1->PhyData[phy->number].PhyFlags
1681		    &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
1682	else
1683		sas_iounit_pg1->PhyData[phy->number].PhyFlags
1684		    |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
1685
1686	mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);
1687
1688	/* link reset */
1689	if (enable)
1690		_transport_phy_reset(phy, 0);
1691
1692 out:
1693	kfree(sas_iounit_pg1);
1694	return rc;
1695}
1696
1697/**
1698 * _transport_phy_speed - set phy min/max link rates
1699 * @phy: The sas phy object
1700 * @rates: rates defined in sas_phy_linkrates
1701 *
1702 * Only support sas_host direct attached phys.
1703 * Returns 0 for success, non-zero for failure.
1704 */
1705static int
1706_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
1707{
1708	struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
1709	Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
1710	Mpi2SasPhyPage0_t phy_pg0;
1711	Mpi2ConfigReply_t mpi_reply;
1712	u16 ioc_status;
1713	u16 sz;
1714	int i;
1715	int rc = 0;
1716	unsigned long flags;
1717
1718	spin_lock_irqsave(&ioc->sas_node_lock, flags);
1719	if (_transport_sas_node_find_by_sas_address(ioc,
1720	    phy->identify.sas_address) == NULL) {
1721		spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
1722		return -EINVAL;
1723	}
1724	spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
1725
1726	if (!rates->minimum_linkrate)
1727		rates->minimum_linkrate = phy->minimum_linkrate;
1728	else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
1729		rates->minimum_linkrate = phy->minimum_linkrate_hw;
1730
1731	if (!rates->maximum_linkrate)
1732		rates->maximum_linkrate = phy->maximum_linkrate;
1733	else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
1734		rates->maximum_linkrate = phy->maximum_linkrate_hw;
1735
1736	/* handle expander phys */
1737	if (phy->identify.sas_address != ioc->sas_hba.sas_address) {
1738		phy->minimum_linkrate = rates->minimum_linkrate;
1739		phy->maximum_linkrate = rates->maximum_linkrate;
1740		return _transport_expander_phy_control(ioc, phy,
1741		    SMP_PHY_CONTROL_LINK_RESET);
1742	}
1743
1744	/* handle hba phys */
1745
1746	/* sas_iounit page 1 */
1747	sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
1748	    sizeof(Mpi2SasIOUnit1PhyData_t));
1749	sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
1750	if (!sas_iounit_pg1) {
1751		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1752		    ioc->name, __FILE__, __LINE__, __func__);
1753		rc = -ENOMEM;
1754		goto out;
1755	}
1756	if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
1757	    sas_iounit_pg1, sz))) {
1758		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1759		    ioc->name, __FILE__, __LINE__, __func__);
1760		rc = -ENXIO;
1761		goto out;
1762	}
1763	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
1764	    MPI2_IOCSTATUS_MASK;
1765	if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
1766		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1767		    ioc->name, __FILE__, __LINE__, __func__);
1768		rc = -EIO;
1769		goto out;
1770	}
1771
1772	for (i = 0; i < ioc->sas_hba.num_phys; i++) {
1773		if (phy->number != i) {
1774			sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
1775			    (ioc->sas_hba.phy[i].phy->minimum_linkrate +
1776			    (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));
1777		} else {
1778			sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
1779			    (rates->minimum_linkrate +
1780			    (rates->maximum_linkrate << 4));
1781		}
1782	}
1783
1784	if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
1785	    sz)) {
1786		printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
1787		    ioc->name, __FILE__, __LINE__, __func__);
1788		rc = -ENXIO;
1789		goto out;
1790	}
1791
1792	/* link reset */
1793	_transport_phy_reset(phy, 0);
1794
1795	/* read phy page 0, then update the rates in the sas transport phy */
1796	if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
1797	    phy->number)) {
1798		phy->minimum_linkrate = _transport_convert_phy_link_rate(
1799		    phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
1800		phy->maximum_linkrate = _transport_convert_phy_link_rate(
1801		    phy_pg0.ProgrammedLinkRate >> 4);
1802		phy->negotiated_linkrate = _transport_convert_phy_link_rate(
1803		    phy_pg0.NegotiatedLinkRate &
1804		    MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
1805	}
1806
1807 out:
1808	kfree(sas_iounit_pg1);
1809	return rc;
1810}
1811
1812
1813/**
1814 * _transport_smp_handler - transport portal for smp passthru
1815 * @shost: shost object
1816 * @rphy: sas transport rphy object
1817 * @req:
1818 *
1819 * This used primarily for smp_utils.
1820 * Example:
1821 *           smp_rep_general /sys/class/bsg/expander-5:0
1822 */
1823static int
1824_transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1825    struct request *req)
1826{
1827	struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
1828	Mpi2SmpPassthroughRequest_t *mpi_request;
1829	Mpi2SmpPassthroughReply_t *mpi_reply;
1830	int rc;
1831	u16 smid;
1832	u32 ioc_state;
1833	unsigned long timeleft;
1834	void *psge;
1835	u32 sgl_flags;
1836	u8 issue_reset = 0;
1837	dma_addr_t dma_addr_in = 0;
1838	dma_addr_t dma_addr_out = 0;
1839	u16 wait_state_count;
1840	struct request *rsp = req->next_rq;
1841
1842	if (!rsp) {
1843		printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
1844		    "missing\n", ioc->name, __func__);
1845		return -EINVAL;
1846	}
1847
1848	/* do we need to support multiple segments? */
1849	if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
1850		printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, "
1851		    "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt,
1852		    blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
1853		return -EINVAL;
1854	}
1855
1856	if (ioc->shost_recovery) {
1857		printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
1858		    __func__, ioc->name);
1859		return -EFAULT;
1860	}
1861
1862	rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
1863	if (rc)
1864		return rc;
1865
1866	if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
1867		printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", ioc->name,
1868		    __func__);
1869		rc = -EAGAIN;
1870		goto out;
1871	}
1872	ioc->transport_cmds.status = MPT2_CMD_PENDING;
1873
1874	wait_state_count = 0;
1875	ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1876	while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
1877		if (wait_state_count++ == 10) {
1878			printk(MPT2SAS_ERR_FMT
1879			    "%s: failed due to ioc not operational\n",
1880			    ioc->name, __func__);
1881			rc = -EFAULT;
1882			goto out;
1883		}
1884		ssleep(1);
1885		ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
1886		printk(MPT2SAS_INFO_FMT "%s: waiting for "
1887		    "operational state(count=%d)\n", ioc->name,
1888		    __func__, wait_state_count);
1889	}
1890	if (wait_state_count)
1891		printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
1892		    ioc->name, __func__);
1893
1894	smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
1895	if (!smid) {
1896		printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
1897		    ioc->name, __func__);
1898		rc = -EAGAIN;
1899		goto out;
1900	}
1901
1902	rc = 0;
1903	mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
1904	ioc->transport_cmds.smid = smid;
1905
1906	memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
1907	mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
1908	mpi_request->PhysicalPort = 0xFF;
1909	mpi_request->VF_ID = 0; /* TODO */
1910	mpi_request->VP_ID = 0;
1911	mpi_request->SASAddress = (rphy) ?
1912	    cpu_to_le64(rphy->identify.sas_address) :
1913	    cpu_to_le64(ioc->sas_hba.sas_address);
1914	mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
1915	psge = &mpi_request->SGL;
1916
1917	/* WRITE sgel first */
1918	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1919	    MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
1920	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1921	dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
1922		blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
1923	if (!dma_addr_out) {
1924		mpt2sas_base_free_smid(ioc, smid);
1925		goto unmap;
1926	}
1927
1928	ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4),
1929	    dma_addr_out);
1930
1931	/* incr sgel */
1932	psge += ioc->sge_size;
1933
1934	/* READ sgel last */
1935	sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
1936	    MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
1937	    MPI2_SGE_FLAGS_END_OF_LIST);
1938	sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
1939	dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
1940				     blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
1941	if (!dma_addr_in) {
1942		mpt2sas_base_free_smid(ioc, smid);
1943		goto unmap;
1944	}
1945
1946	ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4),
1947	    dma_addr_in);
1948
1949	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
1950	    "sending smp request\n", ioc->name, __func__));
1951
1952	mpt2sas_base_put_smid_default(ioc, smid);
1953	init_completion(&ioc->transport_cmds.done);
1954	timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
1955	    10*HZ);
1956
1957	if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
1958		printk(MPT2SAS_ERR_FMT "%s : timeout\n",
1959		    __func__, ioc->name);
1960		_debug_dump_mf(mpi_request,
1961		    sizeof(Mpi2SmpPassthroughRequest_t)/4);
1962		if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
1963			issue_reset = 1;
1964		goto issue_host_reset;
1965	}
1966
1967	dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
1968	    "complete\n", ioc->name, __func__));
1969
1970	if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
1971
1972		mpi_reply = ioc->transport_cmds.reply;
1973
1974		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
1975		    "%s - reply data transfer size(%d)\n",
1976		    ioc->name, __func__,
1977		    le16_to_cpu(mpi_reply->ResponseDataLength)));
1978
1979		memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));
1980		req->sense_len = sizeof(*mpi_reply);
1981		req->resid_len = 0;
1982		rsp->resid_len -=
1983		    le16_to_cpu(mpi_reply->ResponseDataLength);
1984	} else {
1985		dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
1986		    "%s - no reply\n", ioc->name, __func__));
1987		rc = -ENXIO;
1988	}
1989
1990 issue_host_reset:
1991	if (issue_reset) {
1992		mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
1993		    FORCE_BIG_HAMMER);
1994		rc = -ETIMEDOUT;
1995	}
1996
1997 unmap:
1998	if (dma_addr_out)
1999		pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req),
2000		    PCI_DMA_BIDIRECTIONAL);
2001	if (dma_addr_in)
2002		pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
2003		    PCI_DMA_BIDIRECTIONAL);
2004
2005 out:
2006	ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
2007	mutex_unlock(&ioc->transport_cmds.mutex);
2008	return rc;
2009}
2010
2011struct sas_function_template mpt2sas_transport_functions = {
2012	.get_linkerrors		= _transport_get_linkerrors,
2013	.get_enclosure_identifier = _transport_get_enclosure_identifier,
2014	.get_bay_identifier	= _transport_get_bay_identifier,
2015	.phy_reset		= _transport_phy_reset,
2016	.phy_enable		= _transport_phy_enable,
2017	.set_phy_speed		= _transport_phy_speed,
2018	.smp_handler		= _transport_smp_handler,
2019};
2020
2021struct scsi_transport_template *mpt2sas_transport_template;