Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Driver for Broadcom MPI3 Storage Controllers
   4 *
   5 * Copyright (C) 2017-2023 Broadcom Inc.
   6 *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
   7 *
   8 */
   9
  10#include "mpi3mr.h"
  11
  12/**
  13 * mpi3mr_post_transport_req - Issue transport requests and wait
  14 * @mrioc: Adapter instance reference
  15 * @request: Properly populated MPI3 request
  16 * @request_sz: Size of the MPI3 request
  17 * @reply: Pointer to return MPI3 reply
  18 * @reply_sz: Size of the MPI3 reply buffer
  19 * @timeout: Timeout in seconds
  20 * @ioc_status: Pointer to return ioc status
  21 *
  22 * A generic function for posting MPI3 requests from the SAS
  23 * transport layer that uses transport command infrastructure.
  24 * This blocks for the completion of request for timeout seconds
  25 * and if the request times out this function faults the
  26 * controller with proper reason code.
  27 *
  28 * On successful completion of the request this function returns
  29 * appropriate ioc status from the firmware back to the caller.
  30 *
  31 * Return: 0 on success, non-zero on failure.
  32 */
  33static int mpi3mr_post_transport_req(struct mpi3mr_ioc *mrioc, void *request,
  34	u16 request_sz, void *reply, u16 reply_sz, int timeout,
  35	u16 *ioc_status)
  36{
  37	int retval = 0;
  38
  39	mutex_lock(&mrioc->transport_cmds.mutex);
  40	if (mrioc->transport_cmds.state & MPI3MR_CMD_PENDING) {
  41		retval = -1;
  42		ioc_err(mrioc, "sending transport request failed due to command in use\n");
  43		mutex_unlock(&mrioc->transport_cmds.mutex);
  44		goto out;
  45	}
  46	mrioc->transport_cmds.state = MPI3MR_CMD_PENDING;
  47	mrioc->transport_cmds.is_waiting = 1;
  48	mrioc->transport_cmds.callback = NULL;
  49	mrioc->transport_cmds.ioc_status = 0;
  50	mrioc->transport_cmds.ioc_loginfo = 0;
  51
  52	init_completion(&mrioc->transport_cmds.done);
  53	dprint_cfg_info(mrioc, "posting transport request\n");
  54	if (mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO)
  55		dprint_dump(request, request_sz, "transport_req");
  56	retval = mpi3mr_admin_request_post(mrioc, request, request_sz, 1);
  57	if (retval) {
  58		ioc_err(mrioc, "posting transport request failed\n");
  59		goto out_unlock;
  60	}
  61	wait_for_completion_timeout(&mrioc->transport_cmds.done,
  62	    (timeout * HZ));
  63	if (!(mrioc->transport_cmds.state & MPI3MR_CMD_COMPLETE)) {
  64		mpi3mr_check_rh_fault_ioc(mrioc,
  65		    MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT);
  66		ioc_err(mrioc, "transport request timed out\n");
  67		retval = -1;
  68		goto out_unlock;
  69	}
  70	*ioc_status = mrioc->transport_cmds.ioc_status &
  71		MPI3_IOCSTATUS_STATUS_MASK;
  72	if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS)
  73		dprint_transport_err(mrioc,
  74		    "transport request returned with ioc_status(0x%04x), log_info(0x%08x)\n",
  75		    *ioc_status, mrioc->transport_cmds.ioc_loginfo);
  76
  77	if ((reply) && (mrioc->transport_cmds.state & MPI3MR_CMD_REPLY_VALID))
  78		memcpy((u8 *)reply, mrioc->transport_cmds.reply, reply_sz);
  79
  80out_unlock:
  81	mrioc->transport_cmds.state = MPI3MR_CMD_NOTUSED;
  82	mutex_unlock(&mrioc->transport_cmds.mutex);
  83
  84out:
  85	return retval;
  86}
  87
  88/* report manufacture request structure */
  89struct rep_manu_request {
  90	u8 smp_frame_type;
  91	u8 function;
  92	u8 reserved;
  93	u8 request_length;
  94};
  95
  96/* report manufacture reply structure */
  97struct rep_manu_reply {
  98	u8 smp_frame_type; /* 0x41 */
  99	u8 function; /* 0x01 */
 100	u8 function_result;
 101	u8 response_length;
 102	u16 expander_change_count;
 103	u8 reserved0[2];
 104	u8 sas_format;
 105	u8 reserved2[3];
 106	u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
 107	u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
 108	u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
 109	u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
 110	u16 component_id;
 111	u8 component_revision_id;
 112	u8 reserved3;
 113	u8 vendor_specific[8];
 114};
 115
 116/**
 117 * mpi3mr_report_manufacture - obtain SMP report_manufacture
 118 * @mrioc: Adapter instance reference
 119 * @sas_address: SAS address of the expander device
 120 * @edev: SAS transport layer sas_expander_device object
 121 * @port_id: ID of the HBA port
 122 *
 123 * Fills in the sas_expander_device with manufacturing info.
 124 *
 125 * Return: 0 for success, non-zero for failure.
 126 */
 127static int mpi3mr_report_manufacture(struct mpi3mr_ioc *mrioc,
 128	u64 sas_address, struct sas_expander_device *edev, u8 port_id)
 129{
 130	struct mpi3_smp_passthrough_request mpi_request;
 131	struct mpi3_smp_passthrough_reply mpi_reply;
 132	struct rep_manu_reply *manufacture_reply;
 133	struct rep_manu_request *manufacture_request;
 134	int rc = 0;
 135	void *psge;
 136	void *data_out = NULL;
 137	dma_addr_t data_out_dma;
 138	dma_addr_t data_in_dma;
 139	size_t data_in_sz;
 140	size_t data_out_sz;
 141	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
 142	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
 143	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
 144	u16 ioc_status;
 145	u8 *tmp;
 146
 147	if (mrioc->reset_in_progress) {
 148		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
 149		return -EFAULT;
 150	}
 151
 152	data_out_sz = sizeof(struct rep_manu_request);
 153	data_in_sz = sizeof(struct rep_manu_reply);
 154	data_out = dma_alloc_coherent(&mrioc->pdev->dev,
 155	    data_out_sz + data_in_sz, &data_out_dma, GFP_KERNEL);
 156	if (!data_out) {
 157		rc = -ENOMEM;
 158		goto out;
 159	}
 160
 161	data_in_dma = data_out_dma + data_out_sz;
 162	manufacture_reply = data_out + data_out_sz;
 163
 164	manufacture_request = data_out;
 165	manufacture_request->smp_frame_type = 0x40;
 166	manufacture_request->function = 1;
 167	manufacture_request->reserved = 0;
 168	manufacture_request->request_length = 0;
 169
 170	memset(&mpi_request, 0, request_sz);
 171	memset(&mpi_reply, 0, reply_sz);
 172	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
 173	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
 174	mpi_request.io_unit_port = (u8) port_id;
 175	mpi_request.sas_address = cpu_to_le64(sas_address);
 176
 177	psge = &mpi_request.request_sge;
 178	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
 179
 180	psge = &mpi_request.response_sge;
 181	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
 182
 183	dprint_transport_info(mrioc,
 184	    "sending report manufacturer SMP request to sas_address(0x%016llx), port(%d)\n",
 185	    (unsigned long long)sas_address, port_id);
 186
 187	rc = mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
 188				       &mpi_reply, reply_sz,
 189				       MPI3MR_INTADMCMD_TIMEOUT, &ioc_status);
 190	if (rc)
 191		goto out;
 192
 193	dprint_transport_info(mrioc,
 194	    "report manufacturer SMP request completed with ioc_status(0x%04x)\n",
 195	    ioc_status);
 196
 197	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
 198		rc = -EINVAL;
 199		goto out;
 200	}
 201
 202	dprint_transport_info(mrioc,
 203	    "report manufacturer - reply data transfer size(%d)\n",
 204	    le16_to_cpu(mpi_reply.response_data_length));
 205
 206	if (le16_to_cpu(mpi_reply.response_data_length) !=
 207	    sizeof(struct rep_manu_reply)) {
 208		rc = -EINVAL;
 209		goto out;
 210	}
 211
 212	strscpy(edev->vendor_id, manufacture_reply->vendor_id,
 213	     SAS_EXPANDER_VENDOR_ID_LEN);
 214	strscpy(edev->product_id, manufacture_reply->product_id,
 215	     SAS_EXPANDER_PRODUCT_ID_LEN);
 216	strscpy(edev->product_rev, manufacture_reply->product_rev,
 217	     SAS_EXPANDER_PRODUCT_REV_LEN);
 218	edev->level = manufacture_reply->sas_format & 1;
 219	if (edev->level) {
 220		strscpy(edev->component_vendor_id,
 221		    manufacture_reply->component_vendor_id,
 222		     SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
 223		tmp = (u8 *)&manufacture_reply->component_id;
 224		edev->component_id = tmp[0] << 8 | tmp[1];
 225		edev->component_revision_id =
 226		    manufacture_reply->component_revision_id;
 227	}
 228
 229out:
 230	if (data_out)
 231		dma_free_coherent(&mrioc->pdev->dev, data_out_sz + data_in_sz,
 232		    data_out, data_out_dma);
 233
 234	return rc;
 235}
 236
 237/**
 238 * __mpi3mr_expander_find_by_handle - expander search by handle
 239 * @mrioc: Adapter instance reference
 240 * @handle: Firmware device handle of the expander
 241 *
 242 * Context: The caller should acquire sas_node_lock
 243 *
 244 * This searches for expander device based on handle, then
 245 * returns the sas_node object.
 246 *
 247 * Return: Expander sas_node object reference or NULL
 248 */
 249struct mpi3mr_sas_node *__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc
 250	*mrioc, u16 handle)
 251{
 252	struct mpi3mr_sas_node *sas_expander, *r;
 253
 254	r = NULL;
 255	list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
 256		if (sas_expander->handle != handle)
 257			continue;
 258		r = sas_expander;
 259		goto out;
 260	}
 261 out:
 262	return r;
 263}
 264
 265/**
 266 * mpi3mr_is_expander_device - if device is an expander
 267 * @device_info: Bitfield providing information about the device
 268 *
 269 * Return: 1 if the device is expander device, else 0.
 270 */
 271u8 mpi3mr_is_expander_device(u16 device_info)
 272{
 273	if ((device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) ==
 274	     MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER)
 275		return 1;
 276	else
 277		return 0;
 278}
 279
 280/**
 281 * mpi3mr_get_sas_address - retrieve sas_address for handle
 282 * @mrioc: Adapter instance reference
 283 * @handle: Firmware device handle
 284 * @sas_address: Address to hold sas address
 285 *
 286 * This function issues device page0 read for a given device
 287 * handle and gets the SAS address and return it back
 288 *
 289 * Return: 0 for success, non-zero for failure
 290 */
 291static int mpi3mr_get_sas_address(struct mpi3mr_ioc *mrioc, u16 handle,
 292	u64 *sas_address)
 293{
 294	struct mpi3_device_page0 dev_pg0;
 295	u16 ioc_status;
 296	struct mpi3_device0_sas_sata_format *sasinf;
 297
 298	*sas_address = 0;
 299
 300	if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
 301	    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
 302	    handle))) {
 303		ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
 304		return -ENXIO;
 305	}
 306
 307	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
 308		ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
 309		    handle, ioc_status, __FILE__, __LINE__, __func__);
 310		return -ENXIO;
 311	}
 312
 313	if (le16_to_cpu(dev_pg0.flags) &
 314	    MPI3_DEVICE0_FLAGS_CONTROLLER_DEV_HANDLE)
 315		*sas_address = mrioc->sas_hba.sas_address;
 316	else if (dev_pg0.device_form == MPI3_DEVICE_DEVFORM_SAS_SATA) {
 317		sasinf = &dev_pg0.device_specific.sas_sata_format;
 318		*sas_address = le64_to_cpu(sasinf->sas_address);
 319	} else {
 320		ioc_err(mrioc, "%s: device_form(%d) is not SAS_SATA\n",
 321		    __func__, dev_pg0.device_form);
 322		return -ENXIO;
 323	}
 324	return 0;
 325}
 326
 327/**
 328 * __mpi3mr_get_tgtdev_by_addr - target device search
 329 * @mrioc: Adapter instance reference
 330 * @sas_address: SAS address of the device
 331 * @hba_port: HBA port entry
 332 *
 333 * This searches for target device from sas address and hba port
 334 * pointer then return mpi3mr_tgt_dev object.
 335 *
 336 * Return: Valid tget_dev or NULL
 337 */
 338static struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc,
 339	u64 sas_address, struct mpi3mr_hba_port *hba_port)
 340{
 341	struct mpi3mr_tgt_dev *tgtdev;
 342
 343	assert_spin_locked(&mrioc->tgtdev_lock);
 344
 345	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
 346		if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) &&
 347		    (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address)
 348		    && (tgtdev->dev_spec.sas_sata_inf.hba_port == hba_port))
 349			goto found_device;
 350	return NULL;
 351found_device:
 352	mpi3mr_tgtdev_get(tgtdev);
 353	return tgtdev;
 354}
 355
 356/**
 357 * mpi3mr_get_tgtdev_by_addr - target device search
 358 * @mrioc: Adapter instance reference
 359 * @sas_address: SAS address of the device
 360 * @hba_port: HBA port entry
 361 *
 362 * This searches for target device from sas address and hba port
 363 * pointer then return mpi3mr_tgt_dev object.
 364 *
 365 * Context: This function will acquire tgtdev_lock and will
 366 * release before returning the mpi3mr_tgt_dev object.
 367 *
 368 * Return: Valid tget_dev or NULL
 369 */
 370static struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc,
 371	u64 sas_address, struct mpi3mr_hba_port *hba_port)
 372{
 373	struct mpi3mr_tgt_dev *tgtdev = NULL;
 374	unsigned long flags;
 375
 376	if (!hba_port)
 377		goto out;
 378
 379	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
 380	tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc, sas_address, hba_port);
 381	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
 382
 383out:
 384	return tgtdev;
 385}
 386
 387/**
 388 * mpi3mr_remove_device_by_sas_address - remove the device
 389 * @mrioc: Adapter instance reference
 390 * @sas_address: SAS address of the device
 391 * @hba_port: HBA port entry
 392 *
 393 * This searches for target device using sas address and hba
 394 * port pointer then removes it from the OS.
 395 *
 396 * Return: None
 397 */
 398static void mpi3mr_remove_device_by_sas_address(struct mpi3mr_ioc *mrioc,
 399	u64 sas_address, struct mpi3mr_hba_port *hba_port)
 400{
 401	struct mpi3mr_tgt_dev *tgtdev = NULL;
 402	unsigned long flags;
 403	u8 was_on_tgtdev_list = 0;
 404
 405	if (!hba_port)
 406		return;
 407
 408	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
 409	tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc,
 410			 sas_address, hba_port);
 411	if (tgtdev) {
 412		if (!list_empty(&tgtdev->list)) {
 413			list_del_init(&tgtdev->list);
 414			was_on_tgtdev_list = 1;
 415			mpi3mr_tgtdev_put(tgtdev);
 416		}
 417	}
 418	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
 419	if (was_on_tgtdev_list) {
 420		if (tgtdev->host_exposed)
 421			mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
 422		mpi3mr_tgtdev_put(tgtdev);
 423	}
 424}
 425
 426/**
 427 * __mpi3mr_get_tgtdev_by_addr_and_rphy - target device search
 428 * @mrioc: Adapter instance reference
 429 * @sas_address: SAS address of the device
 430 * @rphy: SAS transport layer rphy object
 431 *
 432 * This searches for target device from sas address and rphy
 433 * pointer then return mpi3mr_tgt_dev object.
 434 *
 435 * Return: Valid tget_dev or NULL
 436 */
 437struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
 438	struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy)
 439{
 440	struct mpi3mr_tgt_dev *tgtdev;
 441
 442	assert_spin_locked(&mrioc->tgtdev_lock);
 443
 444	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)
 445		if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) &&
 446		    (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address)
 447		    && (tgtdev->dev_spec.sas_sata_inf.rphy == rphy))
 448			goto found_device;
 449	return NULL;
 450found_device:
 451	mpi3mr_tgtdev_get(tgtdev);
 452	return tgtdev;
 453}
 454
 455/**
 456 * mpi3mr_expander_find_by_sas_address - sas expander search
 457 * @mrioc: Adapter instance reference
 458 * @sas_address: SAS address of expander
 459 * @hba_port: HBA port entry
 460 *
 461 * Return: A valid SAS expander node or NULL.
 462 *
 463 */
 464static struct mpi3mr_sas_node *mpi3mr_expander_find_by_sas_address(
 465	struct mpi3mr_ioc *mrioc, u64 sas_address,
 466	struct mpi3mr_hba_port *hba_port)
 467{
 468	struct mpi3mr_sas_node *sas_expander, *r = NULL;
 469
 470	if (!hba_port)
 471		goto out;
 472
 473	list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
 474		if ((sas_expander->sas_address != sas_address) ||
 475					 (sas_expander->hba_port != hba_port))
 476			continue;
 477		r = sas_expander;
 478		goto out;
 479	}
 480out:
 481	return r;
 482}
 483
 484/**
 485 * __mpi3mr_sas_node_find_by_sas_address - sas node search
 486 * @mrioc: Adapter instance reference
 487 * @sas_address: SAS address of expander or sas host
 488 * @hba_port: HBA port entry
 489 * Context: Caller should acquire mrioc->sas_node_lock.
 490 *
 491 * If the SAS address indicates the device is direct attached to
 492 * the controller (controller's SAS address) then the SAS node
 493 * associated with the controller is returned back else the SAS
 494 * address and hba port are used to identify the exact expander
 495 * and the associated sas_node object is returned. If there is
 496 * no match NULL is returned.
 497 *
 498 * Return: A valid SAS node or NULL.
 499 *
 500 */
 501static struct mpi3mr_sas_node *__mpi3mr_sas_node_find_by_sas_address(
 502	struct mpi3mr_ioc *mrioc, u64 sas_address,
 503	struct mpi3mr_hba_port *hba_port)
 504{
 505
 506	if (mrioc->sas_hba.sas_address == sas_address)
 507		return &mrioc->sas_hba;
 508	return mpi3mr_expander_find_by_sas_address(mrioc, sas_address,
 509	    hba_port);
 510}
 511
 512/**
 513 * mpi3mr_parent_present - Is parent present for a phy
 514 * @mrioc: Adapter instance reference
 515 * @phy: SAS transport layer phy object
 516 *
 517 * Return: 0 if parent is present else non-zero
 518 */
 519static int mpi3mr_parent_present(struct mpi3mr_ioc *mrioc, struct sas_phy *phy)
 520{
 521	unsigned long flags;
 522	struct mpi3mr_hba_port *hba_port = phy->hostdata;
 523
 524	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
 525	if (__mpi3mr_sas_node_find_by_sas_address(mrioc,
 526	    phy->identify.sas_address,
 527	    hba_port) == NULL) {
 528		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
 529		return -1;
 530	}
 531	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
 532	return 0;
 533}
 534
 535/**
 536 * mpi3mr_convert_phy_link_rate -
 537 * @link_rate: link rate as defined in the MPI header
 538 *
 539 * Convert link_rate from mpi format into sas_transport layer
 540 * form.
 541 *
 542 * Return: A valid SAS transport layer defined link rate
 543 */
 544static enum sas_linkrate mpi3mr_convert_phy_link_rate(u8 link_rate)
 545{
 546	enum sas_linkrate rc;
 547
 548	switch (link_rate) {
 549	case MPI3_SAS_NEG_LINK_RATE_1_5:
 550		rc = SAS_LINK_RATE_1_5_GBPS;
 551		break;
 552	case MPI3_SAS_NEG_LINK_RATE_3_0:
 553		rc = SAS_LINK_RATE_3_0_GBPS;
 554		break;
 555	case MPI3_SAS_NEG_LINK_RATE_6_0:
 556		rc = SAS_LINK_RATE_6_0_GBPS;
 557		break;
 558	case MPI3_SAS_NEG_LINK_RATE_12_0:
 559		rc = SAS_LINK_RATE_12_0_GBPS;
 560		break;
 561	case MPI3_SAS_NEG_LINK_RATE_22_5:
 562		rc = SAS_LINK_RATE_22_5_GBPS;
 563		break;
 564	case MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED:
 565		rc = SAS_PHY_DISABLED;
 566		break;
 567	case MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
 568		rc = SAS_LINK_RATE_FAILED;
 569		break;
 570	case MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR:
 571		rc = SAS_SATA_PORT_SELECTOR;
 572		break;
 573	case MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
 574		rc = SAS_PHY_RESET_IN_PROGRESS;
 575		break;
 576	case MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
 577	case MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
 578	default:
 579		rc = SAS_LINK_RATE_UNKNOWN;
 580		break;
 581	}
 582	return rc;
 583}
 584
 585/**
 586 * mpi3mr_delete_sas_phy - Remove a single phy from port
 587 * @mrioc: Adapter instance reference
 588 * @mr_sas_port: Internal Port object
 589 * @mr_sas_phy: Internal Phy object
 590 *
 591 * Return: None.
 592 */
 593static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
 594	struct mpi3mr_sas_port *mr_sas_port,
 595	struct mpi3mr_sas_phy *mr_sas_phy)
 596{
 597	u64 sas_address = mr_sas_port->remote_identify.sas_address;
 598
 599	dev_info(&mr_sas_phy->phy->dev,
 600	    "remove: sas_address(0x%016llx), phy(%d)\n",
 601	    (unsigned long long) sas_address, mr_sas_phy->phy_id);
 602
 603	list_del(&mr_sas_phy->port_siblings);
 604	mr_sas_port->num_phys--;
 605	mr_sas_port->phy_mask &= ~(1 << mr_sas_phy->phy_id);
 606	if (mr_sas_port->lowest_phy == mr_sas_phy->phy_id)
 607		mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
 608	sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);
 609	mr_sas_phy->phy_belongs_to_port = 0;
 610}
 611
 612/**
 613 * mpi3mr_add_sas_phy - Adding a single phy to a port
 614 * @mrioc: Adapter instance reference
 615 * @mr_sas_port: Internal Port object
 616 * @mr_sas_phy: Internal Phy object
 617 *
 618 * Return: None.
 619 */
 620static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
 621	struct mpi3mr_sas_port *mr_sas_port,
 622	struct mpi3mr_sas_phy *mr_sas_phy)
 623{
 624	u64 sas_address = mr_sas_port->remote_identify.sas_address;
 625
 626	dev_info(&mr_sas_phy->phy->dev,
 627	    "add: sas_address(0x%016llx), phy(%d)\n", (unsigned long long)
 628	    sas_address, mr_sas_phy->phy_id);
 629
 630	list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);
 631	mr_sas_port->num_phys++;
 632	mr_sas_port->phy_mask |= (1 << mr_sas_phy->phy_id);
 633	if (mr_sas_phy->phy_id < mr_sas_port->lowest_phy)
 634		mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
 635	sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);
 636	mr_sas_phy->phy_belongs_to_port = 1;
 637}
 638
 639/**
 640 * mpi3mr_add_phy_to_an_existing_port - add phy to existing port
 641 * @mrioc: Adapter instance reference
 642 * @mr_sas_node: Internal sas node object (expander or host)
 643 * @mr_sas_phy: Internal Phy object *
 644 * @sas_address: SAS address of device/expander were phy needs
 645 *             to be added to
 646 * @hba_port: HBA port entry
 647 *
 648 * Return: None.
 649 */
 650static void mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc *mrioc,
 651	struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy,
 652	u64 sas_address, struct mpi3mr_hba_port *hba_port)
 653{
 654	struct mpi3mr_sas_port *mr_sas_port;
 655	struct mpi3mr_sas_phy *srch_phy;
 656
 657	if (mr_sas_phy->phy_belongs_to_port == 1)
 658		return;
 659
 660	if (!hba_port)
 661		return;
 662
 663	list_for_each_entry(mr_sas_port, &mr_sas_node->sas_port_list,
 664	    port_list) {
 665		if (mr_sas_port->remote_identify.sas_address !=
 666		    sas_address)
 667			continue;
 668		if (mr_sas_port->hba_port != hba_port)
 669			continue;
 670		list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
 671		    port_siblings) {
 672			if (srch_phy == mr_sas_phy)
 673				return;
 674		}
 675		mpi3mr_add_sas_phy(mrioc, mr_sas_port, mr_sas_phy);
 676		return;
 677	}
 678}
 679
 680/**
 681 * mpi3mr_delete_sas_port - helper function to removing a port
 682 * @mrioc: Adapter instance reference
 683 * @mr_sas_port: Internal Port object
 684 *
 685 * Return: None.
 686 */
 687static void  mpi3mr_delete_sas_port(struct mpi3mr_ioc *mrioc,
 688	struct mpi3mr_sas_port *mr_sas_port)
 689{
 690	u64 sas_address = mr_sas_port->remote_identify.sas_address;
 691	struct mpi3mr_hba_port *hba_port = mr_sas_port->hba_port;
 692	enum sas_device_type device_type =
 693	    mr_sas_port->remote_identify.device_type;
 694
 695	dev_info(&mr_sas_port->port->dev,
 696	    "remove: sas_address(0x%016llx)\n",
 697	    (unsigned long long) sas_address);
 698
 699	if (device_type == SAS_END_DEVICE)
 700		mpi3mr_remove_device_by_sas_address(mrioc, sas_address,
 701		    hba_port);
 702
 703	else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
 704	    device_type == SAS_FANOUT_EXPANDER_DEVICE)
 705		mpi3mr_expander_remove(mrioc, sas_address, hba_port);
 706}
 707
 708/**
 709 * mpi3mr_del_phy_from_an_existing_port - del phy from a port
 710 * @mrioc: Adapter instance reference
 711 * @mr_sas_node: Internal sas node object (expander or host)
 712 * @mr_sas_phy: Internal Phy object
 713 *
 714 * Return: None.
 715 */
 716static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,
 717	struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy)
 718{
 719	struct mpi3mr_sas_port *mr_sas_port, *next;
 720	struct mpi3mr_sas_phy *srch_phy;
 721
 722	if (mr_sas_phy->phy_belongs_to_port == 0)
 723		return;
 724
 725	list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
 726	    port_list) {
 727		list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
 728		    port_siblings) {
 729			if (srch_phy != mr_sas_phy)
 730				continue;
 731			if ((mr_sas_port->num_phys == 1) &&
 732			    !mrioc->reset_in_progress)
 733				mpi3mr_delete_sas_port(mrioc, mr_sas_port);
 734			else
 735				mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
 736				    mr_sas_phy);
 737			return;
 738		}
 739	}
 740}
 741
 742/**
 743 * mpi3mr_sas_port_sanity_check - sanity check while adding port
 744 * @mrioc: Adapter instance reference
 745 * @mr_sas_node: Internal sas node object (expander or host)
 746 * @sas_address: SAS address of device/expander
 747 * @hba_port: HBA port entry
 748 *
 749 * Verifies whether the Phys attached to a device with the given
 750 * SAS address already belongs to an existing sas port if so
 751 * will remove those phys from the sas port
 752 *
 753 * Return: None.
 754 */
 755static void mpi3mr_sas_port_sanity_check(struct mpi3mr_ioc *mrioc,
 756	struct mpi3mr_sas_node *mr_sas_node, u64 sas_address,
 757	struct mpi3mr_hba_port *hba_port)
 758{
 759	int i;
 760
 761	for (i = 0; i < mr_sas_node->num_phys; i++) {
 762		if ((mr_sas_node->phy[i].remote_identify.sas_address !=
 763		    sas_address) || (mr_sas_node->phy[i].hba_port != hba_port))
 764			continue;
 765		if (mr_sas_node->phy[i].phy_belongs_to_port == 1)
 766			mpi3mr_del_phy_from_an_existing_port(mrioc,
 767			    mr_sas_node, &mr_sas_node->phy[i]);
 768	}
 769}
 770
 771/**
 772 * mpi3mr_set_identify - set identify for phys and end devices
 773 * @mrioc: Adapter instance reference
 774 * @handle: Firmware device handle
 775 * @identify: SAS transport layer's identify info
 776 *
 777 * Populates sas identify info for a specific device.
 778 *
 779 * Return: 0 for success, non-zero for failure.
 780 */
 781static int mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle,
 782	struct sas_identify *identify)
 783{
 784
 785	struct mpi3_device_page0 device_pg0;
 786	struct mpi3_device0_sas_sata_format *sasinf;
 787	u16 device_info;
 788	u16 ioc_status;
 789
 790	if (mrioc->reset_in_progress) {
 791		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
 792		return -EFAULT;
 793	}
 794
 795	if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,
 796	    sizeof(device_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, handle))) {
 797		ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
 798		return -ENXIO;
 799	}
 800
 801	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
 802		ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
 803		    handle, ioc_status, __FILE__, __LINE__, __func__);
 804		return -EIO;
 805	}
 806
 807	memset(identify, 0, sizeof(struct sas_identify));
 808	sasinf = &device_pg0.device_specific.sas_sata_format;
 809	device_info = le16_to_cpu(sasinf->device_info);
 810
 811	/* sas_address */
 812	identify->sas_address = le64_to_cpu(sasinf->sas_address);
 813
 814	/* phy number of the parent device this device is linked to */
 815	identify->phy_identifier = sasinf->phy_num;
 816
 817	/* device_type */
 818	switch (device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) {
 819	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE:
 820		identify->device_type = SAS_PHY_UNUSED;
 821		break;
 822	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE:
 823		identify->device_type = SAS_END_DEVICE;
 824		break;
 825	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER:
 826		identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
 827		break;
 828	}
 829
 830	/* initiator_port_protocols */
 831	if (device_info & MPI3_SAS_DEVICE_INFO_SSP_INITIATOR)
 832		identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
 833	/* MPI3.0 doesn't have define for SATA INIT so setting both here*/
 834	if (device_info & MPI3_SAS_DEVICE_INFO_STP_INITIATOR)
 835		identify->initiator_port_protocols |= (SAS_PROTOCOL_STP |
 836		    SAS_PROTOCOL_SATA);
 837	if (device_info & MPI3_SAS_DEVICE_INFO_SMP_INITIATOR)
 838		identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
 839
 840	/* target_port_protocols */
 841	if (device_info & MPI3_SAS_DEVICE_INFO_SSP_TARGET)
 842		identify->target_port_protocols |= SAS_PROTOCOL_SSP;
 843	/* MPI3.0 doesn't have define for STP Target so setting both here*/
 844	if (device_info & MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET)
 845		identify->target_port_protocols |= (SAS_PROTOCOL_STP |
 846		    SAS_PROTOCOL_SATA);
 847	if (device_info & MPI3_SAS_DEVICE_INFO_SMP_TARGET)
 848		identify->target_port_protocols |= SAS_PROTOCOL_SMP;
 849	return 0;
 850}
 851
 852/**
 853 * mpi3mr_add_host_phy - report sas_host phy to SAS transport
 854 * @mrioc: Adapter instance reference
 855 * @mr_sas_phy: Internal Phy object
 856 * @phy_pg0: SAS phy page 0
 857 * @parent_dev: Prent device class object
 858 *
 859 * Return: 0 for success, non-zero for failure.
 860 */
 861static int mpi3mr_add_host_phy(struct mpi3mr_ioc *mrioc,
 862	struct mpi3mr_sas_phy *mr_sas_phy, struct mpi3_sas_phy_page0 phy_pg0,
 863	struct device *parent_dev)
 864{
 865	struct sas_phy *phy;
 866	int phy_index = mr_sas_phy->phy_id;
 867
 868
 869	INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
 870	phy = sas_phy_alloc(parent_dev, phy_index);
 871	if (!phy) {
 872		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
 873		    __FILE__, __LINE__, __func__);
 874		return -1;
 875	}
 876	if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
 877	    &mr_sas_phy->identify))) {
 878		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
 879		    __FILE__, __LINE__, __func__);
 880		sas_phy_free(phy);
 881		return -1;
 882	}
 883	phy->identify = mr_sas_phy->identify;
 884	mr_sas_phy->attached_handle = le16_to_cpu(phy_pg0.attached_dev_handle);
 885	if (mr_sas_phy->attached_handle)
 886		mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
 887		    &mr_sas_phy->remote_identify);
 888	phy->identify.phy_identifier = mr_sas_phy->phy_id;
 889	phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
 890	    (phy_pg0.negotiated_link_rate &
 891	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
 892	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
 893	phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
 894	    phy_pg0.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
 895	phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
 896	    phy_pg0.hw_link_rate >> 4);
 897	phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
 898	    phy_pg0.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
 899	phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
 900	    phy_pg0.programmed_link_rate >> 4);
 901	phy->hostdata = mr_sas_phy->hba_port;
 902
 903	if ((sas_phy_add(phy))) {
 904		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
 905		    __FILE__, __LINE__, __func__);
 906		sas_phy_free(phy);
 907		return -1;
 908	}
 909	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
 910		dev_info(&phy->dev,
 911		    "add: handle(0x%04x), sas_address(0x%016llx)\n"
 912		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
 913		    mr_sas_phy->handle, (unsigned long long)
 914		    mr_sas_phy->identify.sas_address,
 915		    mr_sas_phy->attached_handle,
 916		    (unsigned long long)
 917		    mr_sas_phy->remote_identify.sas_address);
 918	mr_sas_phy->phy = phy;
 919	return 0;
 920}
 921
 922/**
 923 * mpi3mr_add_expander_phy - report expander phy to transport
 924 * @mrioc: Adapter instance reference
 925 * @mr_sas_phy: Internal Phy object
 926 * @expander_pg1: SAS Expander page 1
 927 * @parent_dev: Parent device class object
 928 *
 929 * Return: 0 for success, non-zero for failure.
 930 */
 931static int mpi3mr_add_expander_phy(struct mpi3mr_ioc *mrioc,
 932	struct mpi3mr_sas_phy *mr_sas_phy,
 933	struct mpi3_sas_expander_page1 expander_pg1,
 934	struct device *parent_dev)
 935{
 936	struct sas_phy *phy;
 937	int phy_index = mr_sas_phy->phy_id;
 938
 939	INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
 940	phy = sas_phy_alloc(parent_dev, phy_index);
 941	if (!phy) {
 942		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
 943		    __FILE__, __LINE__, __func__);
 944		return -1;
 945	}
 946	if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
 947	    &mr_sas_phy->identify))) {
 948		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
 949		    __FILE__, __LINE__, __func__);
 950		sas_phy_free(phy);
 951		return -1;
 952	}
 953	phy->identify = mr_sas_phy->identify;
 954	mr_sas_phy->attached_handle =
 955	    le16_to_cpu(expander_pg1.attached_dev_handle);
 956	if (mr_sas_phy->attached_handle)
 957		mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
 958		    &mr_sas_phy->remote_identify);
 959	phy->identify.phy_identifier = mr_sas_phy->phy_id;
 960	phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
 961	    (expander_pg1.negotiated_link_rate &
 962	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
 963	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
 964	phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
 965	    expander_pg1.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
 966	phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
 967	    expander_pg1.hw_link_rate >> 4);
 968	phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
 969	    expander_pg1.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
 970	phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
 971	    expander_pg1.programmed_link_rate >> 4);
 972	phy->hostdata = mr_sas_phy->hba_port;
 973
 974	if ((sas_phy_add(phy))) {
 975		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
 976		    __FILE__, __LINE__, __func__);
 977		sas_phy_free(phy);
 978		return -1;
 979	}
 980	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
 981		dev_info(&phy->dev,
 982		    "add: handle(0x%04x), sas_address(0x%016llx)\n"
 983		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
 984		    mr_sas_phy->handle, (unsigned long long)
 985		    mr_sas_phy->identify.sas_address,
 986		    mr_sas_phy->attached_handle,
 987		    (unsigned long long)
 988		    mr_sas_phy->remote_identify.sas_address);
 989	mr_sas_phy->phy = phy;
 990	return 0;
 991}
 992
 993/**
 994 * mpi3mr_alloc_hba_port - alloc hba port object
 995 * @mrioc: Adapter instance reference
 996 * @port_id: Port number
 997 *
 998 * Alloc memory for hba port object.
 999 */
1000static struct mpi3mr_hba_port *
1001mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id)
1002{
1003	struct mpi3mr_hba_port *hba_port;
1004
1005	hba_port = kzalloc(sizeof(struct mpi3mr_hba_port),
1006	    GFP_KERNEL);
1007	if (!hba_port)
1008		return NULL;
1009	hba_port->port_id = port_id;
1010	ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n",
1011	    hba_port, hba_port->port_id);
1012	list_add_tail(&hba_port->list, &mrioc->hba_port_table_list);
1013	return hba_port;
1014}
1015
1016/**
1017 * mpi3mr_get_hba_port_by_id - find hba port by id
1018 * @mrioc: Adapter instance reference
1019 * @port_id - Port ID to search
1020 *
1021 * Return: mpi3mr_hba_port reference for the matched port
1022 */
1023
1024struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc,
1025	u8 port_id)
1026{
1027	struct mpi3mr_hba_port *port, *port_next;
1028
1029	list_for_each_entry_safe(port, port_next,
1030	    &mrioc->hba_port_table_list, list) {
1031		if (port->port_id != port_id)
1032			continue;
1033		if (port->flags & MPI3MR_HBA_PORT_FLAG_DIRTY)
1034			continue;
1035		return port;
1036	}
1037
1038	return NULL;
1039}
1040
1041/**
1042 * mpi3mr_update_links - refreshing SAS phy link changes
1043 * @mrioc: Adapter instance reference
1044 * @sas_address_parent: SAS address of parent expander or host
1045 * @handle: Firmware device handle of attached device
1046 * @phy_number: Phy number
1047 * @link_rate: New link rate
1048 * @hba_port: HBA port entry
1049 *
1050 * Return: None.
1051 */
1052void mpi3mr_update_links(struct mpi3mr_ioc *mrioc,
1053	u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate,
1054	struct mpi3mr_hba_port *hba_port)
1055{
1056	unsigned long flags;
1057	struct mpi3mr_sas_node *mr_sas_node;
1058	struct mpi3mr_sas_phy *mr_sas_phy;
1059
1060	if (mrioc->reset_in_progress)
1061		return;
1062
1063	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1064	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1065	    sas_address_parent, hba_port);
1066	if (!mr_sas_node) {
1067		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1068		return;
1069	}
1070
1071	mr_sas_phy = &mr_sas_node->phy[phy_number];
1072	mr_sas_phy->attached_handle = handle;
1073	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1074	if (handle && (link_rate >= MPI3_SAS_NEG_LINK_RATE_1_5)) {
1075		mpi3mr_set_identify(mrioc, handle,
1076		    &mr_sas_phy->remote_identify);
1077		mpi3mr_add_phy_to_an_existing_port(mrioc, mr_sas_node,
1078		    mr_sas_phy, mr_sas_phy->remote_identify.sas_address,
1079		    hba_port);
1080	} else
1081		memset(&mr_sas_phy->remote_identify, 0, sizeof(struct
1082		    sas_identify));
1083
1084	if (mr_sas_phy->phy)
1085		mr_sas_phy->phy->negotiated_linkrate =
1086		    mpi3mr_convert_phy_link_rate(link_rate);
1087
1088	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1089		dev_info(&mr_sas_phy->phy->dev,
1090		    "refresh: parent sas_address(0x%016llx),\n"
1091		    "\tlink_rate(0x%02x), phy(%d)\n"
1092		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
1093		    (unsigned long long)sas_address_parent,
1094		    link_rate, phy_number, handle, (unsigned long long)
1095		    mr_sas_phy->remote_identify.sas_address);
1096}
1097
1098/**
1099 * mpi3mr_sas_host_refresh - refreshing sas host object contents
1100 * @mrioc: Adapter instance reference
1101 *
1102 * This function refreshes the controllers phy information and
1103 * updates the SAS transport layer with updated information,
1104 * this is executed for each device addition or device info
1105 * change events
1106 *
1107 * Return: None.
1108 */
1109void mpi3mr_sas_host_refresh(struct mpi3mr_ioc *mrioc)
1110{
1111	int i;
1112	u8 link_rate;
1113	u16 sz, port_id, attached_handle;
1114	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1115
1116	dprint_transport_info(mrioc,
1117	    "updating handles for sas_host(0x%016llx)\n",
1118	    (unsigned long long)mrioc->sas_hba.sas_address);
1119
1120	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1121	    (mrioc->sas_hba.num_phys *
1122	     sizeof(struct mpi3_sas_io_unit0_phy_data));
1123	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1124	if (!sas_io_unit_pg0)
1125		return;
1126	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1127		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1128		    __FILE__, __LINE__, __func__);
1129		goto out;
1130	}
1131
1132	mrioc->sas_hba.handle = 0;
1133	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1134		if (sas_io_unit_pg0->phy_data[i].phy_flags &
1135		    (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
1136		     MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))
1137			continue;
1138		link_rate =
1139		    sas_io_unit_pg0->phy_data[i].negotiated_link_rate >> 4;
1140		if (!mrioc->sas_hba.handle)
1141			mrioc->sas_hba.handle = le16_to_cpu(
1142			    sas_io_unit_pg0->phy_data[i].controller_dev_handle);
1143		port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1144		if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
1145			if (!mpi3mr_alloc_hba_port(mrioc, port_id))
1146				goto out;
1147
1148		mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
1149		attached_handle = le16_to_cpu(
1150		    sas_io_unit_pg0->phy_data[i].attached_dev_handle);
1151		if (attached_handle && link_rate < MPI3_SAS_NEG_LINK_RATE_1_5)
1152			link_rate = MPI3_SAS_NEG_LINK_RATE_1_5;
1153		mrioc->sas_hba.phy[i].hba_port =
1154			mpi3mr_get_hba_port_by_id(mrioc, port_id);
1155		mpi3mr_update_links(mrioc, mrioc->sas_hba.sas_address,
1156		    attached_handle, i, link_rate,
1157		    mrioc->sas_hba.phy[i].hba_port);
1158	}
1159 out:
1160	kfree(sas_io_unit_pg0);
1161}
1162
1163/**
1164 * mpi3mr_sas_host_add - create sas host object
1165 * @mrioc: Adapter instance reference
1166 *
1167 * This function creates the controllers phy information and
1168 * updates the SAS transport layer with updated information,
1169 * this is executed for first device addition or device info
1170 * change event.
1171 *
1172 * Return: None.
1173 */
1174void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
1175{
1176	int i;
1177	u16 sz, num_phys = 1, port_id, ioc_status;
1178	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1179	struct mpi3_sas_phy_page0 phy_pg0;
1180	struct mpi3_device_page0 dev_pg0;
1181	struct mpi3_enclosure_page0 encl_pg0;
1182	struct mpi3_device0_sas_sata_format *sasinf;
1183
1184	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1185	    (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));
1186	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1187	if (!sas_io_unit_pg0)
1188		return;
1189
1190	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1191		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1192		    __FILE__, __LINE__, __func__);
1193		goto out;
1194	}
1195	num_phys = sas_io_unit_pg0->num_phys;
1196	kfree(sas_io_unit_pg0);
1197
1198	mrioc->sas_hba.host_node = 1;
1199	INIT_LIST_HEAD(&mrioc->sas_hba.sas_port_list);
1200	mrioc->sas_hba.parent_dev = &mrioc->shost->shost_gendev;
1201	mrioc->sas_hba.phy = kcalloc(num_phys,
1202	    sizeof(struct mpi3mr_sas_phy), GFP_KERNEL);
1203	if (!mrioc->sas_hba.phy)
1204		return;
1205
1206	mrioc->sas_hba.num_phys = num_phys;
1207
1208	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1209	    (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));
1210	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1211	if (!sas_io_unit_pg0)
1212		return;
1213
1214	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1215		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1216		    __FILE__, __LINE__, __func__);
1217		goto out;
1218	}
1219
1220	mrioc->sas_hba.handle = 0;
1221	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1222		if (sas_io_unit_pg0->phy_data[i].phy_flags &
1223		    (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
1224		    MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))
1225			continue;
1226		if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
1227		    sizeof(struct mpi3_sas_phy_page0),
1228		    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, i)) {
1229			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1230			    __FILE__, __LINE__, __func__);
1231			goto out;
1232		}
1233		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1234			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1235			    __FILE__, __LINE__, __func__);
1236			goto out;
1237		}
1238
1239		if (!mrioc->sas_hba.handle)
1240			mrioc->sas_hba.handle = le16_to_cpu(
1241			    sas_io_unit_pg0->phy_data[i].controller_dev_handle);
1242		port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1243
1244		if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
1245			if (!mpi3mr_alloc_hba_port(mrioc, port_id))
1246				goto out;
1247
1248		mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
1249		mrioc->sas_hba.phy[i].phy_id = i;
1250		mrioc->sas_hba.phy[i].hba_port =
1251		    mpi3mr_get_hba_port_by_id(mrioc, port_id);
1252		mpi3mr_add_host_phy(mrioc, &mrioc->sas_hba.phy[i],
1253		    phy_pg0, mrioc->sas_hba.parent_dev);
1254	}
1255	if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
1256	    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
1257	    mrioc->sas_hba.handle))) {
1258		ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
1259		goto out;
1260	}
1261	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1262		ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
1263		    mrioc->sas_hba.handle, ioc_status, __FILE__, __LINE__,
1264		    __func__);
1265		goto out;
1266	}
1267	mrioc->sas_hba.enclosure_handle =
1268	    le16_to_cpu(dev_pg0.enclosure_handle);
1269	sasinf = &dev_pg0.device_specific.sas_sata_format;
1270	mrioc->sas_hba.sas_address =
1271	    le64_to_cpu(sasinf->sas_address);
1272	ioc_info(mrioc,
1273	    "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
1274	    mrioc->sas_hba.handle,
1275	    (unsigned long long) mrioc->sas_hba.sas_address,
1276	    mrioc->sas_hba.num_phys);
1277
1278	if (mrioc->sas_hba.enclosure_handle) {
1279		if (!(mpi3mr_cfg_get_enclosure_pg0(mrioc, &ioc_status,
1280		    &encl_pg0, sizeof(encl_pg0),
1281		    MPI3_ENCLOS_PGAD_FORM_HANDLE,
1282		    mrioc->sas_hba.enclosure_handle)) &&
1283		    (ioc_status == MPI3_IOCSTATUS_SUCCESS))
1284			mrioc->sas_hba.enclosure_logical_id =
1285				le64_to_cpu(encl_pg0.enclosure_logical_id);
1286	}
1287
1288out:
1289	kfree(sas_io_unit_pg0);
1290}
1291
1292/**
1293 * mpi3mr_sas_port_add - Expose the SAS device to the SAS TL
1294 * @mrioc: Adapter instance reference
1295 * @handle: Firmware device handle of the attached device
1296 * @sas_address_parent: sas address of parent expander or host
1297 * @hba_port: HBA port entry
1298 *
1299 * This function creates a new sas port object for the given end
1300 * device matching sas address and hba_port and adds it to the
1301 * sas_node's sas_port_list and expose the attached sas device
1302 * to the SAS transport layer through sas_rphy_add.
1303 *
1304 * Returns a valid mpi3mr_sas_port reference or NULL.
1305 */
1306static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
1307	u16 handle, u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)
1308{
1309	struct mpi3mr_sas_phy *mr_sas_phy, *next;
1310	struct mpi3mr_sas_port *mr_sas_port;
1311	unsigned long flags;
1312	struct mpi3mr_sas_node *mr_sas_node;
1313	struct sas_rphy *rphy;
1314	struct mpi3mr_tgt_dev *tgtdev = NULL;
1315	int i;
1316	struct sas_port *port;
1317
1318	if (!hba_port) {
1319		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1320		    __FILE__, __LINE__, __func__);
1321		return NULL;
1322	}
1323
1324	mr_sas_port = kzalloc(sizeof(struct mpi3mr_sas_port), GFP_KERNEL);
1325	if (!mr_sas_port)
1326		return NULL;
1327
1328	INIT_LIST_HEAD(&mr_sas_port->port_list);
1329	INIT_LIST_HEAD(&mr_sas_port->phy_list);
1330	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1331	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1332	    sas_address_parent, hba_port);
1333	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1334
1335	if (!mr_sas_node) {
1336		ioc_err(mrioc, "%s:could not find parent sas_address(0x%016llx)!\n",
1337		    __func__, (unsigned long long)sas_address_parent);
1338		goto out_fail;
1339	}
1340
1341	if ((mpi3mr_set_identify(mrioc, handle,
1342	    &mr_sas_port->remote_identify))) {
1343		ioc_err(mrioc,  "failure at %s:%d/%s()!\n",
1344		    __FILE__, __LINE__, __func__);
1345		goto out_fail;
1346	}
1347
1348	if (mr_sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
1349		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1350		    __FILE__, __LINE__, __func__);
1351		goto out_fail;
1352	}
1353
1354	mr_sas_port->hba_port = hba_port;
1355	mpi3mr_sas_port_sanity_check(mrioc, mr_sas_node,
1356	    mr_sas_port->remote_identify.sas_address, hba_port);
1357
1358	for (i = 0; i < mr_sas_node->num_phys; i++) {
1359		if ((mr_sas_node->phy[i].remote_identify.sas_address !=
1360		    mr_sas_port->remote_identify.sas_address) ||
1361		    (mr_sas_node->phy[i].hba_port != hba_port))
1362			continue;
1363		list_add_tail(&mr_sas_node->phy[i].port_siblings,
1364		    &mr_sas_port->phy_list);
1365		mr_sas_port->num_phys++;
1366		mr_sas_port->phy_mask |= (1 << i);
1367	}
1368
1369	if (!mr_sas_port->num_phys) {
1370		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1371		    __FILE__, __LINE__, __func__);
1372		goto out_fail;
1373	}
1374
1375	mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
1376
1377	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1378		tgtdev = mpi3mr_get_tgtdev_by_addr(mrioc,
1379		    mr_sas_port->remote_identify.sas_address,
1380		    mr_sas_port->hba_port);
1381
1382		if (!tgtdev) {
1383			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1384			    __FILE__, __LINE__, __func__);
1385			goto out_fail;
1386		}
1387		tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 1;
1388	}
1389
1390	if (!mr_sas_node->parent_dev) {
1391		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1392		    __FILE__, __LINE__, __func__);
1393		goto out_fail;
1394	}
1395
1396	port = sas_port_alloc_num(mr_sas_node->parent_dev);
1397	if ((sas_port_add(port))) {
1398		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1399		    __FILE__, __LINE__, __func__);
1400		goto out_fail;
1401	}
1402
1403	list_for_each_entry(mr_sas_phy, &mr_sas_port->phy_list,
1404	    port_siblings) {
1405		if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1406			dev_info(&port->dev,
1407			    "add: handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
1408			    handle, (unsigned long long)
1409			    mr_sas_port->remote_identify.sas_address,
1410			    mr_sas_phy->phy_id);
1411		sas_port_add_phy(port, mr_sas_phy->phy);
1412		mr_sas_phy->phy_belongs_to_port = 1;
1413		mr_sas_phy->hba_port = hba_port;
1414	}
1415
1416	mr_sas_port->port = port;
1417	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1418		rphy = sas_end_device_alloc(port);
1419		tgtdev->dev_spec.sas_sata_inf.rphy = rphy;
1420	} else {
1421		rphy = sas_expander_alloc(port,
1422		    mr_sas_port->remote_identify.device_type);
1423	}
1424	rphy->identify = mr_sas_port->remote_identify;
1425
1426	if (mrioc->current_event)
1427		mrioc->current_event->pending_at_sml = 1;
1428
1429	if ((sas_rphy_add(rphy))) {
1430		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1431		    __FILE__, __LINE__, __func__);
1432	}
1433	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
1434		tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0;
1435		tgtdev->dev_spec.sas_sata_inf.sas_transport_attached = 1;
1436		mpi3mr_tgtdev_put(tgtdev);
1437	}
1438
1439	dev_info(&rphy->dev,
1440	    "%s: added: handle(0x%04x), sas_address(0x%016llx)\n",
1441	    __func__, handle, (unsigned long long)
1442	    mr_sas_port->remote_identify.sas_address);
1443
1444	mr_sas_port->rphy = rphy;
1445	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1446	list_add_tail(&mr_sas_port->port_list, &mr_sas_node->sas_port_list);
1447	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1448
1449	if (mrioc->current_event) {
1450		mrioc->current_event->pending_at_sml = 0;
1451		if (mrioc->current_event->discard)
1452			mpi3mr_print_device_event_notice(mrioc, true);
1453	}
1454
1455	/* fill in report manufacture */
1456	if (mr_sas_port->remote_identify.device_type ==
1457	    SAS_EDGE_EXPANDER_DEVICE ||
1458	    mr_sas_port->remote_identify.device_type ==
1459	    SAS_FANOUT_EXPANDER_DEVICE)
1460		mpi3mr_report_manufacture(mrioc,
1461		    mr_sas_port->remote_identify.sas_address,
1462		    rphy_to_expander_device(rphy), hba_port->port_id);
1463
1464	return mr_sas_port;
1465
1466 out_fail:
1467	list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list,
1468	    port_siblings)
1469		list_del(&mr_sas_phy->port_siblings);
1470	kfree(mr_sas_port);
1471	return NULL;
1472}
1473
1474/**
1475 * mpi3mr_sas_port_remove - remove port from the list
1476 * @mrioc: Adapter instance reference
1477 * @sas_address: SAS address of attached device
1478 * @sas_address_parent: SAS address of parent expander or host
1479 * @hba_port: HBA port entry
1480 *
1481 * Removing object and freeing associated memory from the
1482 * sas_port_list.
1483 *
1484 * Return: None
1485 */
1486static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
1487	u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)
1488{
1489	int i;
1490	unsigned long flags;
1491	struct mpi3mr_sas_port *mr_sas_port, *next;
1492	struct mpi3mr_sas_node *mr_sas_node;
1493	u8 found = 0;
1494	struct mpi3mr_sas_phy *mr_sas_phy, *next_phy;
1495	struct mpi3mr_hba_port *srch_port, *hba_port_next = NULL;
1496
1497	if (!hba_port)
1498		return;
1499
1500	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1501	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
1502	    sas_address_parent, hba_port);
1503	if (!mr_sas_node) {
1504		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1505		return;
1506	}
1507	list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
1508	    port_list) {
1509		if (mr_sas_port->remote_identify.sas_address != sas_address)
1510			continue;
1511		if (mr_sas_port->hba_port != hba_port)
1512			continue;
1513		found = 1;
1514		list_del(&mr_sas_port->port_list);
1515		goto out;
1516	}
1517
1518 out:
1519	if (!found) {
1520		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1521		return;
1522	}
1523
1524	if (mr_sas_node->host_node) {
1525		list_for_each_entry_safe(srch_port, hba_port_next,
1526		    &mrioc->hba_port_table_list, list) {
1527			if (srch_port != hba_port)
1528				continue;
1529			ioc_info(mrioc,
1530			    "removing hba_port entry: %p port: %d from hba_port list\n",
1531			    srch_port, srch_port->port_id);
1532			list_del(&hba_port->list);
1533			kfree(hba_port);
1534			break;
1535		}
1536	}
1537
1538	for (i = 0; i < mr_sas_node->num_phys; i++) {
1539		if (mr_sas_node->phy[i].remote_identify.sas_address ==
1540		    sas_address)
1541			memset(&mr_sas_node->phy[i].remote_identify, 0,
1542			    sizeof(struct sas_identify));
1543	}
1544
1545	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1546
1547	if (mrioc->current_event)
1548		mrioc->current_event->pending_at_sml = 1;
1549
1550	list_for_each_entry_safe(mr_sas_phy, next_phy,
1551	    &mr_sas_port->phy_list, port_siblings) {
1552		if ((!mrioc->stop_drv_processing) &&
1553		    (mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
1554			dev_info(&mr_sas_port->port->dev,
1555			    "remove: sas_address(0x%016llx), phy(%d)\n",
1556			    (unsigned long long)
1557			    mr_sas_port->remote_identify.sas_address,
1558			    mr_sas_phy->phy_id);
1559		mr_sas_phy->phy_belongs_to_port = 0;
1560		if (!mrioc->stop_drv_processing)
1561			sas_port_delete_phy(mr_sas_port->port,
1562			    mr_sas_phy->phy);
1563		list_del(&mr_sas_phy->port_siblings);
1564	}
1565	if (!mrioc->stop_drv_processing)
1566		sas_port_delete(mr_sas_port->port);
1567	ioc_info(mrioc, "%s: removed sas_address(0x%016llx)\n",
1568	    __func__, (unsigned long long)sas_address);
1569
1570	if (mrioc->current_event) {
1571		mrioc->current_event->pending_at_sml = 0;
1572		if (mrioc->current_event->discard)
1573			mpi3mr_print_device_event_notice(mrioc, false);
1574	}
1575
1576	kfree(mr_sas_port);
1577}
1578
1579/**
1580 * struct host_port - host port details
1581 * @sas_address: SAS Address of the attached device
1582 * @phy_mask: phy mask of host port
1583 * @handle: Device Handle of attached device
1584 * @iounit_port_id: port ID
1585 * @used: host port is already matched with sas port from sas_port_list
1586 * @lowest_phy: lowest phy ID of host port
1587 */
1588struct host_port {
1589	u64	sas_address;
1590	u64	phy_mask;
1591	u16	handle;
1592	u8	iounit_port_id;
1593	u8	used;
1594	u8	lowest_phy;
1595};
1596
1597/**
1598 * mpi3mr_update_mr_sas_port - update sas port objects during reset
1599 * @mrioc: Adapter instance reference
1600 * @h_port: host_port object
1601 * @mr_sas_port: sas_port objects which needs to be updated
1602 *
1603 * Update the port ID of sas port object. Also add the phys if new phys got
1604 * added to current sas port and remove the phys if some phys are moved
1605 * out of the current sas port.
1606 *
1607 * Return: Nothing.
1608 */
1609static void
1610mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port,
1611	struct mpi3mr_sas_port *mr_sas_port)
1612{
1613	struct mpi3mr_sas_phy *mr_sas_phy;
1614	u64 phy_mask_xor;
1615	u64 phys_to_be_added, phys_to_be_removed;
1616	int i;
1617
1618	h_port->used = 1;
1619	mr_sas_port->marked_responding = 1;
1620
1621	dev_info(&mr_sas_port->port->dev,
1622	    "sas_address(0x%016llx), old: port_id %d phy_mask 0x%llx, new: port_id %d phy_mask:0x%llx\n",
1623	    mr_sas_port->remote_identify.sas_address,
1624	    mr_sas_port->hba_port->port_id, mr_sas_port->phy_mask,
1625	    h_port->iounit_port_id, h_port->phy_mask);
1626
1627	mr_sas_port->hba_port->port_id = h_port->iounit_port_id;
1628	mr_sas_port->hba_port->flags &= ~MPI3MR_HBA_PORT_FLAG_DIRTY;
1629
1630	/* Get the newly added phys bit map & removed phys bit map */
1631	phy_mask_xor = mr_sas_port->phy_mask ^ h_port->phy_mask;
1632	phys_to_be_added = h_port->phy_mask & phy_mask_xor;
1633	phys_to_be_removed = mr_sas_port->phy_mask & phy_mask_xor;
1634
1635	/*
1636	 * Register these new phys to current mr_sas_port's port.
1637	 * if these phys are previously registered with another port
1638	 * then delete these phys from that port first.
1639	 */
1640	for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u64)) {
1641		mr_sas_phy = &mrioc->sas_hba.phy[i];
1642		if (mr_sas_phy->phy_belongs_to_port)
1643			mpi3mr_del_phy_from_an_existing_port(mrioc,
1644			    &mrioc->sas_hba, mr_sas_phy);
1645		mpi3mr_add_phy_to_an_existing_port(mrioc,
1646		    &mrioc->sas_hba, mr_sas_phy,
1647		    mr_sas_port->remote_identify.sas_address,
1648		    mr_sas_port->hba_port);
1649	}
1650
1651	/* Delete the phys which are not part of current mr_sas_port's port. */
1652	for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u64)) {
1653		mr_sas_phy = &mrioc->sas_hba.phy[i];
1654		if (mr_sas_phy->phy_belongs_to_port)
1655			mpi3mr_del_phy_from_an_existing_port(mrioc,
1656			    &mrioc->sas_hba, mr_sas_phy);
1657	}
1658}
1659
1660/**
1661 * mpi3mr_refresh_sas_ports - update host's sas ports during reset
1662 * @mrioc: Adapter instance reference
1663 *
1664 * Update the host's sas ports during reset by checking whether
1665 * sas ports are still intact or not. Add/remove phys if any hba
1666 * phys are (moved in)/(moved out) of sas port. Also update
1667 * io_unit_port if it got changed during reset.
1668 *
1669 * Return: Nothing.
1670 */
1671void
1672mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)
1673{
1674	struct host_port *h_port = NULL;
1675	int i, j, found, host_port_count = 0, port_idx;
1676	u16 sz, attached_handle, ioc_status;
1677	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
1678	struct mpi3_device_page0 dev_pg0;
1679	struct mpi3_device0_sas_sata_format *sasinf;
1680	struct mpi3mr_sas_port *mr_sas_port;
1681
1682	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
1683		(mrioc->sas_hba.num_phys *
1684		 sizeof(struct mpi3_sas_io_unit0_phy_data));
1685	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
1686	if (!sas_io_unit_pg0)
1687		return;
1688	h_port = kcalloc(64, sizeof(struct host_port), GFP_KERNEL);
1689	if (!h_port)
1690		goto out;
1691
1692	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
1693		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1694		    __FILE__, __LINE__, __func__);
1695		goto out;
1696	}
1697
1698	/* Create a new expander port table */
1699	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
1700		attached_handle = le16_to_cpu(
1701		    sas_io_unit_pg0->phy_data[i].attached_dev_handle);
1702		if (!attached_handle)
1703			continue;
1704		found = 0;
1705		for (j = 0; j < host_port_count; j++) {
1706			if (h_port[j].handle == attached_handle) {
1707				h_port[j].phy_mask |= (1 << i);
1708				found = 1;
1709				break;
1710			}
1711		}
1712		if (found)
1713			continue;
1714		if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
1715		    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
1716		    attached_handle))) {
1717			dprint_reset(mrioc,
1718			    "failed to read dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1719			    attached_handle, __FILE__, __LINE__, __func__);
1720			continue;
1721		}
1722		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1723			dprint_reset(mrioc,
1724			    "ioc_status(0x%x) while reading dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1725			    ioc_status, attached_handle,
1726			    __FILE__, __LINE__, __func__);
1727			continue;
1728		}
1729		sasinf = &dev_pg0.device_specific.sas_sata_format;
1730
1731		port_idx = host_port_count;
1732		h_port[port_idx].sas_address = le64_to_cpu(sasinf->sas_address);
1733		h_port[port_idx].handle = attached_handle;
1734		h_port[port_idx].phy_mask = (1 << i);
1735		h_port[port_idx].iounit_port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
1736		h_port[port_idx].lowest_phy = sasinf->phy_num;
1737		h_port[port_idx].used = 0;
1738		host_port_count++;
1739	}
1740
1741	if (!host_port_count)
1742		goto out;
1743
1744	if (mrioc->logging_level & MPI3_DEBUG_RESET) {
1745		ioc_info(mrioc, "Host port details before reset\n");
1746		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1747		    port_list) {
1748			ioc_info(mrioc,
1749			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",
1750			    mr_sas_port->hba_port->port_id,
1751			    mr_sas_port->remote_identify.sas_address,
1752			    mr_sas_port->phy_mask, mr_sas_port->lowest_phy);
1753		}
1754		mr_sas_port = NULL;
1755		ioc_info(mrioc, "Host port details after reset\n");
1756		for (i = 0; i < host_port_count; i++) {
1757			ioc_info(mrioc,
1758			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",
1759			    h_port[i].iounit_port_id, h_port[i].sas_address,
1760			    h_port[i].phy_mask, h_port[i].lowest_phy);
1761		}
1762	}
1763
1764	/* mark all host sas port entries as dirty */
1765	list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1766	    port_list) {
1767		mr_sas_port->marked_responding = 0;
1768		mr_sas_port->hba_port->flags |= MPI3MR_HBA_PORT_FLAG_DIRTY;
1769	}
1770
1771	/* First check for matching lowest phy */
1772	for (i = 0; i < host_port_count; i++) {
1773		mr_sas_port = NULL;
1774		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1775		    port_list) {
1776			if (mr_sas_port->marked_responding)
1777				continue;
1778			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1779				continue;
1780			if (h_port[i].lowest_phy == mr_sas_port->lowest_phy) {
1781				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1782				break;
1783			}
1784		}
1785	}
1786
1787	/* In case if lowest phy is got enabled or disabled during reset */
1788	for (i = 0; i < host_port_count; i++) {
1789		if (h_port[i].used)
1790			continue;
1791		mr_sas_port = NULL;
1792		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1793		    port_list) {
1794			if (mr_sas_port->marked_responding)
1795				continue;
1796			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1797				continue;
1798			if (h_port[i].phy_mask & mr_sas_port->phy_mask) {
1799				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1800				break;
1801			}
1802		}
1803	}
1804
1805	/* In case if expander cable is removed & connected to another HBA port during reset */
1806	for (i = 0; i < host_port_count; i++) {
1807		if (h_port[i].used)
1808			continue;
1809		mr_sas_port = NULL;
1810		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
1811		    port_list) {
1812			if (mr_sas_port->marked_responding)
1813				continue;
1814			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
1815				continue;
1816			mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
1817			break;
1818		}
1819	}
1820out:
1821	kfree(h_port);
1822	kfree(sas_io_unit_pg0);
1823}
1824
1825/**
1826 * mpi3mr_refresh_expanders - Refresh expander device exposure
1827 * @mrioc: Adapter instance reference
1828 *
1829 * This is executed post controller reset to identify any
1830 * missing expander devices during reset and remove from the upper layers
1831 * or expose any newly detected expander device to the upper layers.
1832 *
1833 * Return: Nothing.
1834 */
1835void
1836mpi3mr_refresh_expanders(struct mpi3mr_ioc *mrioc)
1837{
1838	struct mpi3mr_sas_node *sas_expander, *sas_expander_next;
1839	struct mpi3_sas_expander_page0 expander_pg0;
1840	u16 ioc_status, handle;
1841	u64 sas_address;
1842	int i;
1843	unsigned long flags;
1844	struct mpi3mr_hba_port *hba_port;
1845
1846	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1847	list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
1848		sas_expander->non_responding = 1;
1849	}
1850	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1851
1852	sas_expander = NULL;
1853
1854	handle = 0xffff;
1855
1856	/* Search for responding expander devices and add them if they are newly got added */
1857	while (true) {
1858		if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
1859		    sizeof(struct mpi3_sas_expander_page0),
1860		    MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
1861			dprint_reset(mrioc,
1862			    "failed to read exp pg0 for handle(0x%04x) at %s:%d/%s()!\n",
1863			    handle, __FILE__, __LINE__, __func__);
1864			break;
1865		}
1866
1867		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1868			dprint_reset(mrioc,
1869			   "ioc_status(0x%x) while reading exp pg0 for handle:(0x%04x), %s:%d/%s()!\n",
1870			   ioc_status, handle, __FILE__, __LINE__, __func__);
1871			break;
1872		}
1873
1874		handle = le16_to_cpu(expander_pg0.dev_handle);
1875		sas_address = le64_to_cpu(expander_pg0.sas_address);
1876		hba_port = mpi3mr_get_hba_port_by_id(mrioc, expander_pg0.io_unit_port);
1877
1878		if (!hba_port) {
1879			mpi3mr_sas_host_refresh(mrioc);
1880			mpi3mr_expander_add(mrioc, handle);
1881			continue;
1882		}
1883
1884		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1885		sas_expander =
1886		    mpi3mr_expander_find_by_sas_address(mrioc,
1887		    sas_address, hba_port);
1888		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1889
1890		if (!sas_expander) {
1891			mpi3mr_sas_host_refresh(mrioc);
1892			mpi3mr_expander_add(mrioc, handle);
1893			continue;
1894		}
1895
1896		sas_expander->non_responding = 0;
1897		if (sas_expander->handle == handle)
1898			continue;
1899
1900		sas_expander->handle = handle;
1901		for (i = 0 ; i < sas_expander->num_phys ; i++)
1902			sas_expander->phy[i].handle = handle;
1903	}
1904
1905	/*
1906	 * Delete non responding expander devices and the corresponding
1907	 * hba_port if the non responding expander device's parent device
1908	 * is a host node.
1909	 */
1910	sas_expander = NULL;
1911	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1912	list_for_each_entry_safe_reverse(sas_expander, sas_expander_next,
1913	    &mrioc->sas_expander_list, list) {
1914		if (sas_expander->non_responding) {
1915			spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1916			mpi3mr_expander_node_remove(mrioc, sas_expander);
1917			spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1918		}
1919	}
1920	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1921}
1922
1923/**
1924 * mpi3mr_expander_node_add - insert an expander to the list.
1925 * @mrioc: Adapter instance reference
1926 * @sas_expander: Expander sas node
1927 * Context: This function will acquire sas_node_lock.
1928 *
1929 * Adding new object to the ioc->sas_expander_list.
1930 *
1931 * Return: None.
1932 */
1933static void mpi3mr_expander_node_add(struct mpi3mr_ioc *mrioc,
1934	struct mpi3mr_sas_node *sas_expander)
1935{
1936	unsigned long flags;
1937
1938	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
1939	list_add_tail(&sas_expander->list, &mrioc->sas_expander_list);
1940	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
1941}
1942
1943/**
1944 * mpi3mr_expander_add -  Create expander object
1945 * @mrioc: Adapter instance reference
1946 * @handle: Expander firmware device handle
1947 *
1948 * This function creating expander object, stored in
1949 * sas_expander_list and expose it to the SAS transport
1950 * layer.
1951 *
1952 * Return: 0 for success, non-zero for failure.
1953 */
1954int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle)
1955{
1956	struct mpi3mr_sas_node *sas_expander;
1957	struct mpi3mr_enclosure_node *enclosure_dev;
1958	struct mpi3_sas_expander_page0 expander_pg0;
1959	struct mpi3_sas_expander_page1 expander_pg1;
1960	u16 ioc_status, parent_handle, temp_handle;
1961	u64 sas_address, sas_address_parent = 0;
1962	int i;
1963	unsigned long flags;
1964	u8 port_id, link_rate;
1965	struct mpi3mr_sas_port *mr_sas_port = NULL;
1966	struct mpi3mr_hba_port *hba_port;
1967	u32 phynum_handle;
1968	int rc = 0;
1969
1970	if (!handle)
1971		return -1;
1972
1973	if (mrioc->reset_in_progress)
1974		return -1;
1975
1976	if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
1977	    sizeof(expander_pg0), MPI3_SAS_EXPAND_PGAD_FORM_HANDLE, handle))) {
1978		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1979		    __FILE__, __LINE__, __func__);
1980		return -1;
1981	}
1982
1983	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
1984		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1985		    __FILE__, __LINE__, __func__);
1986		return -1;
1987	}
1988
1989	parent_handle = le16_to_cpu(expander_pg0.parent_dev_handle);
1990	if (mpi3mr_get_sas_address(mrioc, parent_handle, &sas_address_parent)
1991	    != 0) {
1992		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
1993		    __FILE__, __LINE__, __func__);
1994		return -1;
1995	}
1996
1997	port_id = expander_pg0.io_unit_port;
1998	hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);
1999	if (!hba_port) {
2000		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2001		    __FILE__, __LINE__, __func__);
2002		return -1;
2003	}
2004
2005	if (sas_address_parent != mrioc->sas_hba.sas_address) {
2006		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2007		sas_expander =
2008		   mpi3mr_expander_find_by_sas_address(mrioc,
2009		    sas_address_parent, hba_port);
2010		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2011		if (!sas_expander) {
2012			rc = mpi3mr_expander_add(mrioc, parent_handle);
2013			if (rc != 0)
2014				return rc;
2015		} else {
2016			/*
2017			 * When there is a parent expander present, update it's
2018			 * phys where child expander is connected with the link
2019			 * speed, attached dev handle and sas address.
2020			 */
2021			for (i = 0 ; i < sas_expander->num_phys ; i++) {
2022				phynum_handle =
2023				    (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
2024				    parent_handle;
2025				if (mpi3mr_cfg_get_sas_exp_pg1(mrioc,
2026				    &ioc_status, &expander_pg1,
2027				    sizeof(expander_pg1),
2028				    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2029				    phynum_handle)) {
2030					ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2031					    __FILE__, __LINE__, __func__);
2032					rc = -1;
2033					return rc;
2034				}
2035				if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2036					ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2037					    __FILE__, __LINE__, __func__);
2038					rc = -1;
2039					return rc;
2040				}
2041				temp_handle = le16_to_cpu(
2042				    expander_pg1.attached_dev_handle);
2043				if (temp_handle != handle)
2044					continue;
2045				link_rate = (expander_pg1.negotiated_link_rate &
2046				    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2047				    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2048				mpi3mr_update_links(mrioc, sas_address_parent,
2049				    handle, i, link_rate, hba_port);
2050			}
2051		}
2052	}
2053
2054	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2055	sas_address = le64_to_cpu(expander_pg0.sas_address);
2056	sas_expander = mpi3mr_expander_find_by_sas_address(mrioc,
2057	    sas_address, hba_port);
2058	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2059
2060	if (sas_expander)
2061		return 0;
2062
2063	sas_expander = kzalloc(sizeof(struct mpi3mr_sas_node),
2064	    GFP_KERNEL);
2065	if (!sas_expander)
2066		return -ENOMEM;
2067
2068	sas_expander->handle = handle;
2069	sas_expander->num_phys = expander_pg0.num_phys;
2070	sas_expander->sas_address_parent = sas_address_parent;
2071	sas_expander->sas_address = sas_address;
2072	sas_expander->hba_port = hba_port;
2073
2074	ioc_info(mrioc,
2075	    "expander_add: handle(0x%04x), parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n",
2076	    handle, parent_handle, (unsigned long long)
2077	    sas_expander->sas_address, sas_expander->num_phys);
2078
2079	if (!sas_expander->num_phys) {
2080		rc = -1;
2081		goto out_fail;
2082	}
2083	sas_expander->phy = kcalloc(sas_expander->num_phys,
2084	    sizeof(struct mpi3mr_sas_phy), GFP_KERNEL);
2085	if (!sas_expander->phy) {
2086		rc = -1;
2087		goto out_fail;
2088	}
2089
2090	INIT_LIST_HEAD(&sas_expander->sas_port_list);
2091	mr_sas_port = mpi3mr_sas_port_add(mrioc, handle, sas_address_parent,
2092	    sas_expander->hba_port);
2093	if (!mr_sas_port) {
2094		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2095		    __FILE__, __LINE__, __func__);
2096		rc = -1;
2097		goto out_fail;
2098	}
2099	sas_expander->parent_dev = &mr_sas_port->rphy->dev;
2100	sas_expander->rphy = mr_sas_port->rphy;
2101
2102	for (i = 0 ; i < sas_expander->num_phys ; i++) {
2103		phynum_handle = (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
2104		    handle;
2105		if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2106		    &expander_pg1, sizeof(expander_pg1),
2107		    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2108		    phynum_handle)) {
2109			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2110			    __FILE__, __LINE__, __func__);
2111			rc = -1;
2112			goto out_fail;
2113		}
2114		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2115			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2116			    __FILE__, __LINE__, __func__);
2117			rc = -1;
2118			goto out_fail;
2119		}
2120
2121		sas_expander->phy[i].handle = handle;
2122		sas_expander->phy[i].phy_id = i;
2123		sas_expander->phy[i].hba_port = hba_port;
2124
2125		if ((mpi3mr_add_expander_phy(mrioc, &sas_expander->phy[i],
2126		    expander_pg1, sas_expander->parent_dev))) {
2127			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2128			    __FILE__, __LINE__, __func__);
2129			rc = -1;
2130			goto out_fail;
2131		}
2132	}
2133
2134	if (sas_expander->enclosure_handle) {
2135		enclosure_dev =
2136			mpi3mr_enclosure_find_by_handle(mrioc,
2137						sas_expander->enclosure_handle);
2138		if (enclosure_dev)
2139			sas_expander->enclosure_logical_id = le64_to_cpu(
2140			    enclosure_dev->pg0.enclosure_logical_id);
2141	}
2142
2143	mpi3mr_expander_node_add(mrioc, sas_expander);
2144	return 0;
2145
2146out_fail:
2147
2148	if (mr_sas_port)
2149		mpi3mr_sas_port_remove(mrioc,
2150		    sas_expander->sas_address,
2151		    sas_address_parent, sas_expander->hba_port);
2152	kfree(sas_expander->phy);
2153	kfree(sas_expander);
2154	return rc;
2155}
2156
2157/**
2158 * mpi3mr_expander_node_remove - recursive removal of expander.
2159 * @mrioc: Adapter instance reference
2160 * @sas_expander: Expander device object
2161 *
2162 * Removes expander object and freeing associated memory from
2163 * the sas_expander_list and removes the same from SAS TL, if
2164 * one of the attached device is an expander then it recursively
2165 * removes the expander device too.
2166 *
2167 * Return nothing.
2168 */
2169void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
2170	struct mpi3mr_sas_node *sas_expander)
2171{
2172	struct mpi3mr_sas_port *mr_sas_port, *next;
2173	unsigned long flags;
2174	u8 port_id;
2175
2176	/* remove sibling ports attached to this expander */
2177	list_for_each_entry_safe(mr_sas_port, next,
2178	   &sas_expander->sas_port_list, port_list) {
2179		if (mrioc->reset_in_progress)
2180			return;
2181		if (mr_sas_port->remote_identify.device_type ==
2182		    SAS_END_DEVICE)
2183			mpi3mr_remove_device_by_sas_address(mrioc,
2184			    mr_sas_port->remote_identify.sas_address,
2185			    mr_sas_port->hba_port);
2186		else if (mr_sas_port->remote_identify.device_type ==
2187		    SAS_EDGE_EXPANDER_DEVICE ||
2188		    mr_sas_port->remote_identify.device_type ==
2189		    SAS_FANOUT_EXPANDER_DEVICE)
2190			mpi3mr_expander_remove(mrioc,
2191			    mr_sas_port->remote_identify.sas_address,
2192			    mr_sas_port->hba_port);
2193	}
2194
2195	port_id = sas_expander->hba_port->port_id;
2196	mpi3mr_sas_port_remove(mrioc, sas_expander->sas_address,
2197	    sas_expander->sas_address_parent, sas_expander->hba_port);
2198
2199	ioc_info(mrioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx), port:%d\n",
2200	    sas_expander->handle, (unsigned long long)
2201	    sas_expander->sas_address, port_id);
2202
2203	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2204	list_del(&sas_expander->list);
2205	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2206
2207	kfree(sas_expander->phy);
2208	kfree(sas_expander);
2209}
2210
2211/**
2212 * mpi3mr_expander_remove - Remove expander object
2213 * @mrioc: Adapter instance reference
2214 * @sas_address: Remove expander sas_address
2215 * @hba_port: HBA port reference
2216 *
2217 * This function remove expander object, stored in
2218 * mrioc->sas_expander_list and removes it from the SAS TL by
2219 * calling mpi3mr_expander_node_remove().
2220 *
2221 * Return: None
2222 */
2223void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
2224	struct mpi3mr_hba_port *hba_port)
2225{
2226	struct mpi3mr_sas_node *sas_expander;
2227	unsigned long flags;
2228
2229	if (mrioc->reset_in_progress)
2230		return;
2231
2232	if (!hba_port)
2233		return;
2234
2235	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2236	sas_expander = mpi3mr_expander_find_by_sas_address(mrioc, sas_address,
2237	    hba_port);
2238	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2239	if (sas_expander)
2240		mpi3mr_expander_node_remove(mrioc, sas_expander);
2241
2242}
2243
2244/**
2245 * mpi3mr_get_sas_negotiated_logical_linkrate - get linkrate
2246 * @mrioc: Adapter instance reference
2247 * @tgtdev: Target device
2248 *
2249 * This function identifies whether the target device is
2250 * attached directly or through expander and issues sas phy
2251 * page0 or expander phy page1 and gets the link rate, if there
2252 * is any failure in reading the pages then this returns link
2253 * rate of 1.5.
2254 *
2255 * Return: logical link rate.
2256 */
2257static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc,
2258	struct mpi3mr_tgt_dev *tgtdev)
2259{
2260	u8 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5, phy_number;
2261	struct mpi3_sas_expander_page1 expander_pg1;
2262	struct mpi3_sas_phy_page0 phy_pg0;
2263	u32 phynum_handle;
2264	u16 ioc_status;
2265
2266	phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2267	if (!(tgtdev->devpg0_flag & MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)) {
2268		phynum_handle = ((phy_number<<MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT)
2269				 | tgtdev->parent_handle);
2270		if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,
2271		    &expander_pg1, sizeof(expander_pg1),
2272		    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,
2273		    phynum_handle)) {
2274			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2275			    __FILE__, __LINE__, __func__);
2276			goto out;
2277		}
2278		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2279			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2280			    __FILE__, __LINE__, __func__);
2281			goto out;
2282		}
2283		link_rate = (expander_pg1.negotiated_link_rate &
2284			     MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2285			MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2286		goto out;
2287	}
2288	if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
2289	    sizeof(struct mpi3_sas_phy_page0),
2290	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy_number)) {
2291		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2292		    __FILE__, __LINE__, __func__);
2293		goto out;
2294	}
2295	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2296		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2297		    __FILE__, __LINE__, __func__);
2298		goto out;
2299	}
2300	link_rate = (phy_pg0.negotiated_link_rate &
2301		     MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
2302		MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
2303out:
2304	return link_rate;
2305}
2306
2307/**
2308 * mpi3mr_report_tgtdev_to_sas_transport - expose dev to SAS TL
2309 * @mrioc: Adapter instance reference
2310 * @tgtdev: Target device
2311 *
2312 * This function exposes the target device after
2313 * preparing host_phy, setting up link rate etc.
2314 *
2315 * Return: 0 on success, non-zero for failure.
2316 */
2317int mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc *mrioc,
2318	struct mpi3mr_tgt_dev *tgtdev)
2319{
2320	int retval = 0;
2321	u8 link_rate, parent_phy_number;
2322	u64 sas_address_parent, sas_address;
2323	struct mpi3mr_hba_port *hba_port;
2324	u8 port_id;
2325
2326	if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2327	    !mrioc->sas_transport_enabled)
2328		return -1;
2329
2330	sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2331	if (!mrioc->sas_hba.num_phys)
2332		mpi3mr_sas_host_add(mrioc);
2333	else
2334		mpi3mr_sas_host_refresh(mrioc);
2335
2336	if (mpi3mr_get_sas_address(mrioc, tgtdev->parent_handle,
2337	    &sas_address_parent) != 0) {
2338		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2339		    __FILE__, __LINE__, __func__);
2340		return -1;
2341	}
2342	tgtdev->dev_spec.sas_sata_inf.sas_address_parent = sas_address_parent;
2343
2344	parent_phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
2345	port_id = tgtdev->io_unit_port;
2346
2347	hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);
2348	if (!hba_port) {
2349		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2350		    __FILE__, __LINE__, __func__);
2351		return -1;
2352	}
2353	tgtdev->dev_spec.sas_sata_inf.hba_port = hba_port;
2354
2355	link_rate = mpi3mr_get_sas_negotiated_logical_linkrate(mrioc, tgtdev);
2356
2357	mpi3mr_update_links(mrioc, sas_address_parent, tgtdev->dev_handle,
2358	    parent_phy_number, link_rate, hba_port);
2359
2360	tgtdev->host_exposed = 1;
2361	if (!mpi3mr_sas_port_add(mrioc, tgtdev->dev_handle,
2362	    sas_address_parent, hba_port)) {
2363		retval = -1;
2364		} else if ((!tgtdev->starget) && (!mrioc->is_driver_loading)) {
2365			mpi3mr_sas_port_remove(mrioc, sas_address,
2366			    sas_address_parent, hba_port);
2367		retval = -1;
2368	}
2369	if (retval) {
2370		tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;
2371		tgtdev->host_exposed = 0;
2372	}
2373	return retval;
2374}
2375
2376/**
2377 * mpi3mr_remove_tgtdev_from_sas_transport - remove from SAS TL
2378 * @mrioc: Adapter instance reference
2379 * @tgtdev: Target device
2380 *
2381 * This function removes the target device
2382 *
2383 * Return: None.
2384 */
2385void mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc *mrioc,
2386	struct mpi3mr_tgt_dev *tgtdev)
2387{
2388	u64 sas_address_parent, sas_address;
2389	struct mpi3mr_hba_port *hba_port;
2390
2391	if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
2392	    !mrioc->sas_transport_enabled)
2393		return;
2394
2395	hba_port = tgtdev->dev_spec.sas_sata_inf.hba_port;
2396	sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
2397	sas_address_parent = tgtdev->dev_spec.sas_sata_inf.sas_address_parent;
2398	mpi3mr_sas_port_remove(mrioc, sas_address, sas_address_parent,
2399	    hba_port);
2400	tgtdev->host_exposed = 0;
2401	tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;
2402}
2403
2404/**
2405 * mpi3mr_get_port_id_by_sas_phy -  Get port ID of the given phy
2406 * @phy: SAS transport layer phy object
2407 *
2408 * Return: Port number for valid ID else 0xFFFF
2409 */
2410static inline u8 mpi3mr_get_port_id_by_sas_phy(struct sas_phy *phy)
2411{
2412	u8 port_id = 0xFF;
2413	struct mpi3mr_hba_port *hba_port = phy->hostdata;
2414
2415	if (hba_port)
2416		port_id = hba_port->port_id;
2417
2418	return port_id;
2419}
2420
2421/**
2422 * mpi3mr_get_port_id_by_rphy - Get Port number from SAS rphy
2423 *
2424 * @mrioc: Adapter instance reference
2425 * @rphy: SAS transport layer remote phy object
2426 *
2427 * Retrieves HBA port number in which the device pointed by the
2428 * rphy object is attached with.
2429 *
2430 * Return: Valid port number on success else OxFFFF.
2431 */
2432static u8 mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc *mrioc, struct sas_rphy *rphy)
2433{
2434	struct mpi3mr_sas_node *sas_expander;
2435	struct mpi3mr_tgt_dev *tgtdev;
2436	unsigned long flags;
2437	u8 port_id = 0xFF;
2438
2439	if (!rphy)
2440		return port_id;
2441
2442	if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
2443	    rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) {
2444		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
2445		list_for_each_entry(sas_expander, &mrioc->sas_expander_list,
2446		    list) {
2447			if (sas_expander->rphy == rphy) {
2448				port_id = sas_expander->hba_port->port_id;
2449				break;
2450			}
2451		}
2452		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
2453	} else if (rphy->identify.device_type == SAS_END_DEVICE) {
2454		spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2455
2456		tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2457			    rphy->identify.sas_address, rphy);
2458		if (tgtdev && tgtdev->dev_spec.sas_sata_inf.hba_port) {
2459			port_id =
2460				tgtdev->dev_spec.sas_sata_inf.hba_port->port_id;
2461			mpi3mr_tgtdev_put(tgtdev);
2462		}
2463		spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2464	}
2465	return port_id;
2466}
2467
2468static inline struct mpi3mr_ioc *phy_to_mrioc(struct sas_phy *phy)
2469{
2470	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
2471
2472	return shost_priv(shost);
2473}
2474
2475static inline struct mpi3mr_ioc *rphy_to_mrioc(struct sas_rphy *rphy)
2476{
2477	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
2478
2479	return shost_priv(shost);
2480}
2481
2482/* report phy error log structure */
2483struct phy_error_log_request {
2484	u8 smp_frame_type; /* 0x40 */
2485	u8 function; /* 0x11 */
2486	u8 allocated_response_length;
2487	u8 request_length; /* 02 */
2488	u8 reserved_1[5];
2489	u8 phy_identifier;
2490	u8 reserved_2[2];
2491};
2492
2493/* report phy error log reply structure */
2494struct phy_error_log_reply {
2495	u8 smp_frame_type; /* 0x41 */
2496	u8 function; /* 0x11 */
2497	u8 function_result;
2498	u8 response_length;
2499	__be16 expander_change_count;
2500	u8 reserved_1[3];
2501	u8 phy_identifier;
2502	u8 reserved_2[2];
2503	__be32 invalid_dword;
2504	__be32 running_disparity_error;
2505	__be32 loss_of_dword_sync;
2506	__be32 phy_reset_problem;
2507};
2508
2509
2510/**
2511 * mpi3mr_get_expander_phy_error_log - return expander counters:
2512 * @mrioc: Adapter instance reference
2513 * @phy: The SAS transport layer phy object
2514 *
2515 * Return: 0 for success, non-zero for failure.
2516 *
2517 */
2518static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,
2519	struct sas_phy *phy)
2520{
2521	struct mpi3_smp_passthrough_request mpi_request;
2522	struct mpi3_smp_passthrough_reply mpi_reply;
2523	struct phy_error_log_request *phy_error_log_request;
2524	struct phy_error_log_reply *phy_error_log_reply;
2525	int rc;
2526	void *psge;
2527	void *data_out = NULL;
2528	dma_addr_t data_out_dma, data_in_dma;
2529	u32 data_out_sz, data_in_sz, sz;
2530	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2531	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2532	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2533	u16 ioc_status;
2534
2535	if (mrioc->reset_in_progress) {
2536		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2537		return -EFAULT;
2538	}
2539
2540	data_out_sz = sizeof(struct phy_error_log_request);
2541	data_in_sz = sizeof(struct phy_error_log_reply);
2542	sz = data_out_sz + data_in_sz;
2543	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2544	    GFP_KERNEL);
2545	if (!data_out) {
2546		rc = -ENOMEM;
2547		goto out;
2548	}
2549
2550	data_in_dma = data_out_dma + data_out_sz;
2551	phy_error_log_reply = data_out + data_out_sz;
2552
2553	rc = -EINVAL;
2554	memset(data_out, 0, sz);
2555	phy_error_log_request = data_out;
2556	phy_error_log_request->smp_frame_type = 0x40;
2557	phy_error_log_request->function = 0x11;
2558	phy_error_log_request->request_length = 2;
2559	phy_error_log_request->allocated_response_length = 0;
2560	phy_error_log_request->phy_identifier = phy->number;
2561
2562	memset(&mpi_request, 0, request_sz);
2563	memset(&mpi_reply, 0, reply_sz);
2564	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2565	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2566	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2567	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2568
2569	psge = &mpi_request.request_sge;
2570	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2571
2572	psge = &mpi_request.response_sge;
2573	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2574
2575	dprint_transport_info(mrioc,
2576	    "sending phy error log SMP request to sas_address(0x%016llx), phy_id(%d)\n",
2577	    (unsigned long long)phy->identify.sas_address, phy->number);
2578
2579	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2580	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2581		goto out;
2582
2583	dprint_transport_info(mrioc,
2584	    "phy error log SMP request completed with ioc_status(0x%04x)\n",
2585	    ioc_status);
2586
2587	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2588		dprint_transport_info(mrioc,
2589		    "phy error log - reply data transfer size(%d)\n",
2590		    le16_to_cpu(mpi_reply.response_data_length));
2591
2592		if (le16_to_cpu(mpi_reply.response_data_length) !=
2593		    sizeof(struct phy_error_log_reply))
2594			goto out;
2595
2596		dprint_transport_info(mrioc,
2597		    "phy error log - function_result(%d)\n",
2598		    phy_error_log_reply->function_result);
2599
2600		phy->invalid_dword_count =
2601		    be32_to_cpu(phy_error_log_reply->invalid_dword);
2602		phy->running_disparity_error_count =
2603		    be32_to_cpu(phy_error_log_reply->running_disparity_error);
2604		phy->loss_of_dword_sync_count =
2605		    be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
2606		phy->phy_reset_problem_count =
2607		    be32_to_cpu(phy_error_log_reply->phy_reset_problem);
2608		rc = 0;
2609	}
2610
2611out:
2612	if (data_out)
2613		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2614		    data_out_dma);
2615
2616	return rc;
2617}
2618
2619/**
2620 * mpi3mr_transport_get_linkerrors - return phy error counters
2621 * @phy: The SAS transport layer phy object
2622 *
2623 * This function retrieves the phy error log information of the
2624 * HBA or expander for which the phy belongs to
2625 *
2626 * Return: 0 for success, non-zero for failure.
2627 */
2628static int mpi3mr_transport_get_linkerrors(struct sas_phy *phy)
2629{
2630	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2631	struct mpi3_sas_phy_page1 phy_pg1;
2632	int rc = 0;
2633	u16 ioc_status;
2634
2635	rc = mpi3mr_parent_present(mrioc, phy);
2636	if (rc)
2637		return rc;
2638
2639	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2640		return mpi3mr_get_expander_phy_error_log(mrioc, phy);
2641
2642	memset(&phy_pg1, 0, sizeof(struct mpi3_sas_phy_page1));
2643	/* get hba phy error logs */
2644	if ((mpi3mr_cfg_get_sas_phy_pg1(mrioc, &ioc_status, &phy_pg1,
2645	    sizeof(struct mpi3_sas_phy_page1),
2646	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number))) {
2647		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2648		    __FILE__, __LINE__, __func__);
2649		return -ENXIO;
2650	}
2651
2652	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
2653		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2654		    __FILE__, __LINE__, __func__);
2655		return -ENXIO;
2656	}
2657	phy->invalid_dword_count = le32_to_cpu(phy_pg1.invalid_dword_count);
2658	phy->running_disparity_error_count =
2659		le32_to_cpu(phy_pg1.running_disparity_error_count);
2660	phy->loss_of_dword_sync_count =
2661		le32_to_cpu(phy_pg1.loss_dword_synch_count);
2662	phy->phy_reset_problem_count =
2663		le32_to_cpu(phy_pg1.phy_reset_problem_count);
2664	return 0;
2665}
2666
2667/**
2668 * mpi3mr_transport_get_enclosure_identifier - Get Enclosure ID
2669 * @rphy: The SAS transport layer remote phy object
2670 * @identifier: Enclosure identifier to be returned
2671 *
2672 * Returns the enclosure id for the device pointed by the remote
2673 * phy object.
2674 *
2675 * Return: 0 on success or -ENXIO
2676 */
2677static int
2678mpi3mr_transport_get_enclosure_identifier(struct sas_rphy *rphy,
2679	u64 *identifier)
2680{
2681	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2682	struct mpi3mr_tgt_dev *tgtdev = NULL;
2683	unsigned long flags;
2684	int rc;
2685
2686	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2687	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2688	    rphy->identify.sas_address, rphy);
2689	if (tgtdev) {
2690		*identifier =
2691			tgtdev->enclosure_logical_id;
2692		rc = 0;
2693		mpi3mr_tgtdev_put(tgtdev);
2694	} else {
2695		*identifier = 0;
2696		rc = -ENXIO;
2697	}
2698	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2699
2700	return rc;
2701}
2702
2703/**
2704 * mpi3mr_transport_get_bay_identifier - Get bay ID
2705 * @rphy: The SAS transport layer remote phy object
2706 *
2707 * Returns the slot id for the device pointed by the remote phy
2708 * object.
2709 *
2710 * Return: Valid slot ID on success or -ENXIO
2711 */
2712static int
2713mpi3mr_transport_get_bay_identifier(struct sas_rphy *rphy)
2714{
2715	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
2716	struct mpi3mr_tgt_dev *tgtdev = NULL;
2717	unsigned long flags;
2718	int rc;
2719
2720	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
2721	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
2722	    rphy->identify.sas_address, rphy);
2723	if (tgtdev) {
2724		rc = tgtdev->slot;
2725		mpi3mr_tgtdev_put(tgtdev);
2726	} else
2727		rc = -ENXIO;
2728	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
2729
2730	return rc;
2731}
2732
2733/* phy control request structure */
2734struct phy_control_request {
2735	u8 smp_frame_type; /* 0x40 */
2736	u8 function; /* 0x91 */
2737	u8 allocated_response_length;
2738	u8 request_length; /* 0x09 */
2739	u16 expander_change_count;
2740	u8 reserved_1[3];
2741	u8 phy_identifier;
2742	u8 phy_operation;
2743	u8 reserved_2[13];
2744	u64 attached_device_name;
2745	u8 programmed_min_physical_link_rate;
2746	u8 programmed_max_physical_link_rate;
2747	u8 reserved_3[6];
2748};
2749
2750/* phy control reply structure */
2751struct phy_control_reply {
2752	u8 smp_frame_type; /* 0x41 */
2753	u8 function; /* 0x11 */
2754	u8 function_result;
2755	u8 response_length;
2756};
2757
2758#define SMP_PHY_CONTROL_LINK_RESET	(0x01)
2759#define SMP_PHY_CONTROL_HARD_RESET	(0x02)
2760#define SMP_PHY_CONTROL_DISABLE		(0x03)
2761
2762/**
2763 * mpi3mr_expander_phy_control - expander phy control
2764 * @mrioc: Adapter instance reference
2765 * @phy: The SAS transport layer phy object
2766 * @phy_operation: The phy operation to be executed
2767 *
2768 * Issues SMP passthru phy control request to execute a specific
2769 * phy operation for a given expander device.
2770 *
2771 * Return: 0 for success, non-zero for failure.
2772 */
2773static int
2774mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,
2775	struct sas_phy *phy, u8 phy_operation)
2776{
2777	struct mpi3_smp_passthrough_request mpi_request;
2778	struct mpi3_smp_passthrough_reply mpi_reply;
2779	struct phy_control_request *phy_control_request;
2780	struct phy_control_reply *phy_control_reply;
2781	int rc;
2782	void *psge;
2783	void *data_out = NULL;
2784	dma_addr_t data_out_dma;
2785	dma_addr_t data_in_dma;
2786	size_t data_in_sz;
2787	size_t data_out_sz;
2788	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
2789	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
2790	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
2791	u16 ioc_status;
2792	u16 sz;
2793
2794	if (mrioc->reset_in_progress) {
2795		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
2796		return -EFAULT;
2797	}
2798
2799	data_out_sz = sizeof(struct phy_control_request);
2800	data_in_sz = sizeof(struct phy_control_reply);
2801	sz = data_out_sz + data_in_sz;
2802	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
2803	    GFP_KERNEL);
2804	if (!data_out) {
2805		rc = -ENOMEM;
2806		goto out;
2807	}
2808
2809	data_in_dma = data_out_dma + data_out_sz;
2810	phy_control_reply = data_out + data_out_sz;
2811
2812	rc = -EINVAL;
2813	memset(data_out, 0, sz);
2814
2815	phy_control_request = data_out;
2816	phy_control_request->smp_frame_type = 0x40;
2817	phy_control_request->function = 0x91;
2818	phy_control_request->request_length = 9;
2819	phy_control_request->allocated_response_length = 0;
2820	phy_control_request->phy_identifier = phy->number;
2821	phy_control_request->phy_operation = phy_operation;
2822	phy_control_request->programmed_min_physical_link_rate =
2823	    phy->minimum_linkrate << 4;
2824	phy_control_request->programmed_max_physical_link_rate =
2825	    phy->maximum_linkrate << 4;
2826
2827	memset(&mpi_request, 0, request_sz);
2828	memset(&mpi_reply, 0, reply_sz);
2829	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2830	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
2831	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
2832	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
2833
2834	psge = &mpi_request.request_sge;
2835	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
2836
2837	psge = &mpi_request.response_sge;
2838	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
2839
2840	dprint_transport_info(mrioc,
2841	    "sending phy control SMP request to sas_address(0x%016llx), phy_id(%d) opcode(%d)\n",
2842	    (unsigned long long)phy->identify.sas_address, phy->number,
2843	    phy_operation);
2844
2845	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2846	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
2847		goto out;
2848
2849	dprint_transport_info(mrioc,
2850	    "phy control SMP request completed with ioc_status(0x%04x)\n",
2851	    ioc_status);
2852
2853	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
2854		dprint_transport_info(mrioc,
2855		    "phy control - reply data transfer size(%d)\n",
2856		    le16_to_cpu(mpi_reply.response_data_length));
2857
2858		if (le16_to_cpu(mpi_reply.response_data_length) !=
2859		    sizeof(struct phy_control_reply))
2860			goto out;
2861		dprint_transport_info(mrioc,
2862		    "phy control - function_result(%d)\n",
2863		    phy_control_reply->function_result);
2864		rc = 0;
2865	}
2866 out:
2867	if (data_out)
2868		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
2869		    data_out_dma);
2870
2871	return rc;
2872}
2873
2874/**
2875 * mpi3mr_transport_phy_reset - Reset a given phy
2876 * @phy: The SAS transport layer phy object
2877 * @hard_reset: Flag to indicate the type of reset
2878 *
2879 * Return: 0 for success, non-zero for failure.
2880 */
2881static int
2882mpi3mr_transport_phy_reset(struct sas_phy *phy, int hard_reset)
2883{
2884	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2885	struct mpi3_iounit_control_request mpi_request;
2886	struct mpi3_iounit_control_reply mpi_reply;
2887	u16 request_sz = sizeof(struct mpi3_iounit_control_request);
2888	u16 reply_sz = sizeof(struct mpi3_iounit_control_reply);
2889	int rc = 0;
2890	u16 ioc_status;
2891
2892	rc = mpi3mr_parent_present(mrioc, phy);
2893	if (rc)
2894		return rc;
2895
2896	/* handle expander phys */
2897	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2898		return mpi3mr_expander_phy_control(mrioc, phy,
2899		    (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
2900		    SMP_PHY_CONTROL_LINK_RESET);
2901
2902	/* handle hba phys */
2903	memset(&mpi_request, 0, request_sz);
2904	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
2905	mpi_request.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
2906	mpi_request.operation = MPI3_CTRL_OP_SAS_PHY_CONTROL;
2907	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_ACTION_INDEX] =
2908		(hard_reset ? MPI3_CTRL_ACTION_HARD_RESET :
2909		 MPI3_CTRL_ACTION_LINK_RESET);
2910	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_PHY_INDEX] =
2911		phy->number;
2912
2913	dprint_transport_info(mrioc,
2914	    "sending phy reset request to sas_address(0x%016llx), phy_id(%d) hard_reset(%d)\n",
2915	    (unsigned long long)phy->identify.sas_address, phy->number,
2916	    hard_reset);
2917
2918	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
2919	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status)) {
2920		rc = -EAGAIN;
2921		goto out;
2922	}
2923
2924	dprint_transport_info(mrioc,
2925	    "phy reset request completed with ioc_status(0x%04x)\n",
2926	    ioc_status);
2927out:
2928	return rc;
2929}
2930
2931/**
2932 * mpi3mr_transport_phy_enable - enable/disable phys
2933 * @phy: The SAS transport layer phy object
2934 * @enable: flag to enable/disable, enable phy when true
2935 *
2936 * This function enables/disables a given by executing required
2937 * configuration page changes or expander phy control command
2938 *
2939 * Return: 0 for success, non-zero for failure.
2940 */
2941static int
2942mpi3mr_transport_phy_enable(struct sas_phy *phy, int enable)
2943{
2944	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
2945	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
2946	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
2947	u16 sz;
2948	int rc = 0;
2949	int i, discovery_active;
2950
2951	rc = mpi3mr_parent_present(mrioc, phy);
2952	if (rc)
2953		return rc;
2954
2955	/* handle expander phys */
2956	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
2957		return mpi3mr_expander_phy_control(mrioc, phy,
2958		    (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
2959		    SMP_PHY_CONTROL_DISABLE);
2960
2961	/* handle hba phys */
2962	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +
2963		(mrioc->sas_hba.num_phys *
2964		 sizeof(struct mpi3_sas_io_unit0_phy_data));
2965	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
2966	if (!sas_io_unit_pg0) {
2967		rc = -ENOMEM;
2968		goto out;
2969	}
2970	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
2971		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2972		    __FILE__, __LINE__, __func__);
2973		rc = -ENXIO;
2974		goto out;
2975	}
2976
2977	/* unable to enable/disable phys when discovery is active */
2978	for (i = 0, discovery_active = 0; i < mrioc->sas_hba.num_phys ; i++) {
2979		if (sas_io_unit_pg0->phy_data[i].port_flags &
2980		    MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS) {
2981			ioc_err(mrioc,
2982			    "discovery is active on port = %d, phy = %d\n"
2983			    "\tunable to enable/disable phys, try again later!\n",
2984			    sas_io_unit_pg0->phy_data[i].io_unit_port, i);
2985			discovery_active = 1;
2986		}
2987	}
2988
2989	if (discovery_active) {
2990		rc = -EAGAIN;
2991		goto out;
2992	}
2993
2994	if ((sas_io_unit_pg0->phy_data[phy->number].phy_flags &
2995	     (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
2996	      MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))) {
2997		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
2998		    __FILE__, __LINE__, __func__);
2999		rc = -ENXIO;
3000		goto out;
3001	}
3002
3003	/* read sas_iounit page 1 */
3004	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
3005		(mrioc->sas_hba.num_phys *
3006		 sizeof(struct mpi3_sas_io_unit1_phy_data));
3007	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
3008	if (!sas_io_unit_pg1) {
3009		rc = -ENOMEM;
3010		goto out;
3011	}
3012
3013	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3014		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3015		    __FILE__, __LINE__, __func__);
3016		rc = -ENXIO;
3017		goto out;
3018	}
3019
3020	if (enable)
3021		sas_io_unit_pg1->phy_data[phy->number].phy_flags
3022		    &= ~MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3023	else
3024		sas_io_unit_pg1->phy_data[phy->number].phy_flags
3025		    |= MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
3026
3027	mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz);
3028
3029	/* link reset */
3030	if (enable)
3031		mpi3mr_transport_phy_reset(phy, 0);
3032
3033 out:
3034	kfree(sas_io_unit_pg1);
3035	kfree(sas_io_unit_pg0);
3036	return rc;
3037}
3038
3039/**
3040 * mpi3mr_transport_phy_speed - set phy min/max speed
3041 * @phy: The SAS transport later phy object
3042 * @rates: Rates defined as in sas_phy_linkrates
3043 *
3044 * This function sets the link rates given in the rates
3045 * argument to the given phy by executing required configuration
3046 * page changes or expander phy control command
3047 *
3048 * Return: 0 for success, non-zero for failure.
3049 */
3050static int
3051mpi3mr_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
3052{
3053	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
3054	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
3055	struct mpi3_sas_phy_page0 phy_pg0;
3056	u16 sz, ioc_status;
3057	int rc = 0;
3058
3059	rc = mpi3mr_parent_present(mrioc, phy);
3060	if (rc)
3061		return rc;
3062
3063	if (!rates->minimum_linkrate)
3064		rates->minimum_linkrate = phy->minimum_linkrate;
3065	else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
3066		rates->minimum_linkrate = phy->minimum_linkrate_hw;
3067
3068	if (!rates->maximum_linkrate)
3069		rates->maximum_linkrate = phy->maximum_linkrate;
3070	else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
3071		rates->maximum_linkrate = phy->maximum_linkrate_hw;
3072
3073	/* handle expander phys */
3074	if (phy->identify.sas_address != mrioc->sas_hba.sas_address) {
3075		phy->minimum_linkrate = rates->minimum_linkrate;
3076		phy->maximum_linkrate = rates->maximum_linkrate;
3077		return mpi3mr_expander_phy_control(mrioc, phy,
3078		    SMP_PHY_CONTROL_LINK_RESET);
3079	}
3080
3081	/* handle hba phys */
3082	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
3083		(mrioc->sas_hba.num_phys *
3084		 sizeof(struct mpi3_sas_io_unit1_phy_data));
3085	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
3086	if (!sas_io_unit_pg1) {
3087		rc = -ENOMEM;
3088		goto out;
3089	}
3090
3091	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3092		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3093		    __FILE__, __LINE__, __func__);
3094		rc = -ENXIO;
3095		goto out;
3096	}
3097
3098	sas_io_unit_pg1->phy_data[phy->number].max_min_link_rate =
3099		(rates->minimum_linkrate + (rates->maximum_linkrate << 4));
3100
3101	if (mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
3102		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
3103		    __FILE__, __LINE__, __func__);
3104		rc = -ENXIO;
3105		goto out;
3106	}
3107
3108	/* link reset */
3109	mpi3mr_transport_phy_reset(phy, 0);
3110
3111	/* read phy page 0, then update the rates in the sas transport phy */
3112	if (!mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,
3113	    sizeof(struct mpi3_sas_phy_page0),
3114	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number) &&
3115	    (ioc_status == MPI3_IOCSTATUS_SUCCESS)) {
3116		phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
3117		    phy_pg0.programmed_link_rate &
3118		    MPI3_SAS_PRATE_MIN_RATE_MASK);
3119		phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
3120		    phy_pg0.programmed_link_rate >> 4);
3121		phy->negotiated_linkrate =
3122			mpi3mr_convert_phy_link_rate(
3123			    (phy_pg0.negotiated_link_rate &
3124			    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK)
3125			    >> MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
3126	}
3127
3128out:
3129	kfree(sas_io_unit_pg1);
3130	return rc;
3131}
3132
3133/**
3134 * mpi3mr_map_smp_buffer - map BSG dma buffer
3135 * @dev: Generic device reference
3136 * @buf: BSG buffer pointer
3137 * @dma_addr: Physical address holder
3138 * @dma_len: Mapped DMA buffer length.
3139 * @p: Virtual address holder
3140 *
3141 * This function maps the DMAable buffer
3142 *
3143 * Return: 0 on success, non-zero on failure
3144 */
3145static int
3146mpi3mr_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3147		dma_addr_t *dma_addr, size_t *dma_len, void **p)
3148{
3149	/* Check if the request is split across multiple segments */
3150	if (buf->sg_cnt > 1) {
3151		*p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,
3152				GFP_KERNEL);
3153		if (!*p)
3154			return -ENOMEM;
3155		*dma_len = buf->payload_len;
3156	} else {
3157		if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))
3158			return -ENOMEM;
3159		*dma_addr = sg_dma_address(buf->sg_list);
3160		*dma_len = sg_dma_len(buf->sg_list);
3161		*p = NULL;
3162	}
3163
3164	return 0;
3165}
3166
3167/**
3168 * mpi3mr_unmap_smp_buffer - unmap BSG dma buffer
3169 * @dev: Generic device reference
3170 * @buf: BSG buffer pointer
3171 * @dma_addr: Physical address to be unmapped
3172 * @p: Virtual address
3173 *
3174 * This function unmaps the DMAable buffer
3175 */
3176static void
3177mpi3mr_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,
3178		dma_addr_t dma_addr, void *p)
3179{
3180	if (p)
3181		dma_free_coherent(dev, buf->payload_len, p, dma_addr);
3182	else
3183		dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);
3184}
3185
3186/**
3187 * mpi3mr_transport_smp_handler - handler for smp passthru
3188 * @job: BSG job reference
3189 * @shost: SCSI host object reference
3190 * @rphy: SAS transport rphy object pointing the expander
3191 *
3192 * This is used primarily by smp utils for sending the SMP
3193 * commands to the expanders attached to the controller
3194 */
3195static void
3196mpi3mr_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
3197	struct sas_rphy *rphy)
3198{
3199	struct mpi3mr_ioc *mrioc = shost_priv(shost);
3200	struct mpi3_smp_passthrough_request mpi_request;
3201	struct mpi3_smp_passthrough_reply mpi_reply;
3202	int rc;
3203	void *psge;
3204	dma_addr_t dma_addr_in;
3205	dma_addr_t dma_addr_out;
3206	void *addr_in = NULL;
3207	void *addr_out = NULL;
3208	size_t dma_len_in;
3209	size_t dma_len_out;
3210	unsigned int reslen = 0;
3211	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
3212	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
3213	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
3214	u16 ioc_status;
3215
3216	if (mrioc->reset_in_progress) {
3217		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
3218		rc = -EFAULT;
3219		goto out;
3220	}
3221
3222	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3223	    &dma_addr_out, &dma_len_out, &addr_out);
3224	if (rc)
3225		goto out;
3226
3227	if (addr_out)
3228		sg_copy_to_buffer(job->request_payload.sg_list,
3229		    job->request_payload.sg_cnt, addr_out,
3230		    job->request_payload.payload_len);
3231
3232	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3233			&dma_addr_in, &dma_len_in, &addr_in);
3234	if (rc)
3235		goto unmap_out;
3236
3237	memset(&mpi_request, 0, request_sz);
3238	memset(&mpi_reply, 0, reply_sz);
3239	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
3240	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
3241	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_rphy(mrioc, rphy);
3242	mpi_request.sas_address = ((rphy) ?
3243	    cpu_to_le64(rphy->identify.sas_address) :
3244	    cpu_to_le64(mrioc->sas_hba.sas_address));
3245	psge = &mpi_request.request_sge;
3246	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_out - 4, dma_addr_out);
3247
3248	psge = &mpi_request.response_sge;
3249	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_in - 4, dma_addr_in);
3250
3251	dprint_transport_info(mrioc, "sending SMP request\n");
3252
3253	rc = mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
3254				       &mpi_reply, reply_sz,
3255				       MPI3MR_INTADMCMD_TIMEOUT, &ioc_status);
3256	if (rc)
3257		goto unmap_in;
3258
3259	dprint_transport_info(mrioc,
3260	    "SMP request completed with ioc_status(0x%04x)\n", ioc_status);
3261
3262	dprint_transport_info(mrioc,
3263		    "SMP request - reply data transfer size(%d)\n",
3264		    le16_to_cpu(mpi_reply.response_data_length));
3265
3266	memcpy(job->reply, &mpi_reply, reply_sz);
3267	job->reply_len = reply_sz;
3268	reslen = le16_to_cpu(mpi_reply.response_data_length);
3269
3270	if (addr_in)
3271		sg_copy_from_buffer(job->reply_payload.sg_list,
3272				job->reply_payload.sg_cnt, addr_in,
3273				job->reply_payload.payload_len);
3274
3275	rc = 0;
3276unmap_in:
3277	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
3278			dma_addr_in, addr_in);
3279unmap_out:
3280	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
3281			dma_addr_out, addr_out);
3282out:
3283	bsg_job_done(job, rc, reslen);
3284}
3285
3286struct sas_function_template mpi3mr_transport_functions = {
3287	.get_linkerrors		= mpi3mr_transport_get_linkerrors,
3288	.get_enclosure_identifier = mpi3mr_transport_get_enclosure_identifier,
3289	.get_bay_identifier	= mpi3mr_transport_get_bay_identifier,
3290	.phy_reset		= mpi3mr_transport_phy_reset,
3291	.phy_enable		= mpi3mr_transport_phy_enable,
3292	.set_phy_speed		= mpi3mr_transport_phy_speed,
3293	.smp_handler		= mpi3mr_transport_smp_handler,
3294};
3295
3296struct scsi_transport_template *mpi3mr_transport_template;