File Index
Files and directories
Sign in
FILE

mpi3mr_transport.c

File preview with syntax highlighting.

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