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