brintos

brintos / linux-shallow public Read only

0
0
Text · 98.7 KiB · 0ba9e6a Raw
3348 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Driver for Broadcom MPI3 Storage Controllers4 *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 wait16 * @mrioc: Adapter instance reference17 * @request: Properly populated MPI3 request18 * @request_sz: Size of the MPI3 request19 * @reply: Pointer to return MPI3 reply20 * @reply_sz: Size of the MPI3 reply buffer21 * @timeout: Timeout in seconds22 * @ioc_status: Pointer to return ioc status23 *24 * A generic function for posting MPI3 requests from the SAS25 * transport layer that uses transport command infrastructure.26 * This blocks for the completion of request for timeout seconds27 * and if the request times out this function faults the28 * controller with proper reason code.29 *30 * On successful completion of the request this function returns31 * 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];109	u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];110	u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];111	u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];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_manufacture120 * @mrioc: Adapter instance reference121 * @sas_address: SAS address of the expander device122 * @edev: SAS transport layer sas_expander_device object123 * @port_id: ID of the HBA port124 *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 handle242 * @mrioc: Adapter instance reference243 * @handle: Firmware device handle of the expander244 *245 * Context: The caller should acquire sas_node_lock246 *247 * This searches for expander device based on handle, then248 * returns the sas_node object.249 *250 * Return: Expander sas_node object reference or NULL251 */252struct mpi3mr_sas_node *__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc253	*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 expander270 * @device_info: Bitfield providing information about the device271 *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	else280		return 0;281}282 283/**284 * mpi3mr_get_sas_address - retrieve sas_address for handle285 * @mrioc: Adapter instance reference286 * @handle: Firmware device handle287 * @sas_address: Address to hold sas address288 *289 * This function issues device page0 read for a given device290 * handle and gets the SAS address and return it back291 *292 * Return: 0 for success, non-zero for failure293 */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 search332 * @mrioc: Adapter instance reference333 * @sas_address: SAS address of the device334 * @hba_port: HBA port entry335 *336 * This searches for target device from sas address and hba port337 * pointer then return mpi3mr_tgt_dev object.338 *339 * Return: Valid tget_dev or NULL340 */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 search361 * @mrioc: Adapter instance reference362 * @sas_address: SAS address of the device363 * @hba_port: HBA port entry364 *365 * This searches for target device from sas address and hba port366 * pointer then return mpi3mr_tgt_dev object.367 *368 * Context: This function will acquire tgtdev_lock and will369 * release before returning the mpi3mr_tgt_dev object.370 *371 * Return: Valid tget_dev or NULL372 */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 device392 * @mrioc: Adapter instance reference393 * @sas_address: SAS address of the device394 * @hba_port: HBA port entry395 *396 * This searches for target device using sas address and hba397 * port pointer then removes it from the OS.398 *399 * Return: None400 */401static void mpi3mr_remove_device_by_sas_address(struct mpi3mr_ioc *mrioc,402	u64 sas_address, struct mpi3mr_hba_port *hba_port)403{404	struct mpi3mr_tgt_dev *tgtdev = NULL;405	unsigned long flags;406	u8 was_on_tgtdev_list = 0;407 408	if (!hba_port)409		return;410 411	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);412	tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc,413			 sas_address, hba_port);414	if (tgtdev) {415		if (!list_empty(&tgtdev->list)) {416			list_del_init(&tgtdev->list);417			was_on_tgtdev_list = 1;418			mpi3mr_tgtdev_put(tgtdev);419		}420	}421	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);422	if (was_on_tgtdev_list) {423		if (tgtdev->host_exposed)424			mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);425		mpi3mr_tgtdev_put(tgtdev);426	}427}428 429/**430 * __mpi3mr_get_tgtdev_by_addr_and_rphy - target device search431 * @mrioc: Adapter instance reference432 * @sas_address: SAS address of the device433 * @rphy: SAS transport layer rphy object434 *435 * This searches for target device from sas address and rphy436 * pointer then return mpi3mr_tgt_dev object.437 *438 * Return: Valid tget_dev or NULL439 */440struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(441	struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy)442{443	struct mpi3mr_tgt_dev *tgtdev;444 445	assert_spin_locked(&mrioc->tgtdev_lock);446 447	list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list)448		if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) &&449		    (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address)450		    && (tgtdev->dev_spec.sas_sata_inf.rphy == rphy))451			goto found_device;452	return NULL;453found_device:454	mpi3mr_tgtdev_get(tgtdev);455	return tgtdev;456}457 458/**459 * mpi3mr_expander_find_by_sas_address - sas expander search460 * @mrioc: Adapter instance reference461 * @sas_address: SAS address of expander462 * @hba_port: HBA port entry463 *464 * Return: A valid SAS expander node or NULL.465 *466 */467static struct mpi3mr_sas_node *mpi3mr_expander_find_by_sas_address(468	struct mpi3mr_ioc *mrioc, u64 sas_address,469	struct mpi3mr_hba_port *hba_port)470{471	struct mpi3mr_sas_node *sas_expander, *r = NULL;472 473	if (!hba_port)474		goto out;475 476	list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {477		if ((sas_expander->sas_address != sas_address) ||478					 (sas_expander->hba_port != hba_port))479			continue;480		r = sas_expander;481		goto out;482	}483out:484	return r;485}486 487/**488 * __mpi3mr_sas_node_find_by_sas_address - sas node search489 * @mrioc: Adapter instance reference490 * @sas_address: SAS address of expander or sas host491 * @hba_port: HBA port entry492 * Context: Caller should acquire mrioc->sas_node_lock.493 *494 * If the SAS address indicates the device is direct attached to495 * the controller (controller's SAS address) then the SAS node496 * associated with the controller is returned back else the SAS497 * address and hba port are used to identify the exact expander498 * and the associated sas_node object is returned. If there is499 * no match NULL is returned.500 *501 * Return: A valid SAS node or NULL.502 *503 */504static struct mpi3mr_sas_node *__mpi3mr_sas_node_find_by_sas_address(505	struct mpi3mr_ioc *mrioc, u64 sas_address,506	struct mpi3mr_hba_port *hba_port)507{508 509	if (mrioc->sas_hba.sas_address == sas_address)510		return &mrioc->sas_hba;511	return mpi3mr_expander_find_by_sas_address(mrioc, sas_address,512	    hba_port);513}514 515/**516 * mpi3mr_parent_present - Is parent present for a phy517 * @mrioc: Adapter instance reference518 * @phy: SAS transport layer phy object519 *520 * Return: 0 if parent is present else non-zero521 */522static int mpi3mr_parent_present(struct mpi3mr_ioc *mrioc, struct sas_phy *phy)523{524	unsigned long flags;525	struct mpi3mr_hba_port *hba_port = phy->hostdata;526 527	spin_lock_irqsave(&mrioc->sas_node_lock, flags);528	if (__mpi3mr_sas_node_find_by_sas_address(mrioc,529	    phy->identify.sas_address,530	    hba_port) == NULL) {531		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);532		return -1;533	}534	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);535	return 0;536}537 538/**539 * mpi3mr_convert_phy_link_rate -540 * @link_rate: link rate as defined in the MPI header541 *542 * Convert link_rate from mpi format into sas_transport layer543 * form.544 *545 * Return: A valid SAS transport layer defined link rate546 */547static enum sas_linkrate mpi3mr_convert_phy_link_rate(u8 link_rate)548{549	enum sas_linkrate rc;550 551	switch (link_rate) {552	case MPI3_SAS_NEG_LINK_RATE_1_5:553		rc = SAS_LINK_RATE_1_5_GBPS;554		break;555	case MPI3_SAS_NEG_LINK_RATE_3_0:556		rc = SAS_LINK_RATE_3_0_GBPS;557		break;558	case MPI3_SAS_NEG_LINK_RATE_6_0:559		rc = SAS_LINK_RATE_6_0_GBPS;560		break;561	case MPI3_SAS_NEG_LINK_RATE_12_0:562		rc = SAS_LINK_RATE_12_0_GBPS;563		break;564	case MPI3_SAS_NEG_LINK_RATE_22_5:565		rc = SAS_LINK_RATE_22_5_GBPS;566		break;567	case MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED:568		rc = SAS_PHY_DISABLED;569		break;570	case MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:571		rc = SAS_LINK_RATE_FAILED;572		break;573	case MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR:574		rc = SAS_SATA_PORT_SELECTOR;575		break;576	case MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:577		rc = SAS_PHY_RESET_IN_PROGRESS;578		break;579	case MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:580	case MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:581	default:582		rc = SAS_LINK_RATE_UNKNOWN;583		break;584	}585	return rc;586}587 588/**589 * mpi3mr_delete_sas_phy - Remove a single phy from port590 * @mrioc: Adapter instance reference591 * @mr_sas_port: Internal Port object592 * @mr_sas_phy: Internal Phy object593 * @host_node: Flag to indicate this is a host_node594 *595 * Return: None.596 */597static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,598	struct mpi3mr_sas_port *mr_sas_port,599	struct mpi3mr_sas_phy *mr_sas_phy, u8 host_node)600{601	u64 sas_address = mr_sas_port->remote_identify.sas_address;602 603	dev_info(&mr_sas_phy->phy->dev,604	    "remove: sas_address(0x%016llx), phy(%d)\n",605	    (unsigned long long) sas_address, mr_sas_phy->phy_id);606 607	list_del(&mr_sas_phy->port_siblings);608	mr_sas_port->num_phys--;609 610	if (host_node) {611		mr_sas_port->phy_mask &= ~(1 << mr_sas_phy->phy_id);612 613		if (mr_sas_port->lowest_phy == mr_sas_phy->phy_id)614			mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;615	}616	sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);617	mr_sas_phy->phy_belongs_to_port = 0;618}619 620/**621 * mpi3mr_add_sas_phy - Adding a single phy to a port622 * @mrioc: Adapter instance reference623 * @mr_sas_port: Internal Port object624 * @mr_sas_phy: Internal Phy object625 * @host_node: Flag to indicate this is a host_node626 *627 * Return: None.628 */629static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,630	struct mpi3mr_sas_port *mr_sas_port,631	struct mpi3mr_sas_phy *mr_sas_phy, u8 host_node)632{633	u64 sas_address = mr_sas_port->remote_identify.sas_address;634 635	dev_info(&mr_sas_phy->phy->dev,636	    "add: sas_address(0x%016llx), phy(%d)\n", (unsigned long long)637	    sas_address, mr_sas_phy->phy_id);638 639	list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);640	mr_sas_port->num_phys++;641	if (host_node) {642		mr_sas_port->phy_mask |= (1 << mr_sas_phy->phy_id);643 644		if (mr_sas_phy->phy_id < mr_sas_port->lowest_phy)645			mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;646	}647	sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);648	mr_sas_phy->phy_belongs_to_port = 1;649}650 651/**652 * mpi3mr_add_phy_to_an_existing_port - add phy to existing port653 * @mrioc: Adapter instance reference654 * @mr_sas_node: Internal sas node object (expander or host)655 * @mr_sas_phy: Internal Phy object *656 * @sas_address: SAS address of device/expander were phy needs657 *             to be added to658 * @hba_port: HBA port entry659 *660 * Return: None.661 */662static void mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc *mrioc,663	struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy,664	u64 sas_address, struct mpi3mr_hba_port *hba_port)665{666	struct mpi3mr_sas_port *mr_sas_port;667	struct mpi3mr_sas_phy *srch_phy;668 669	if (mr_sas_phy->phy_belongs_to_port == 1)670		return;671 672	if (!hba_port)673		return;674 675	list_for_each_entry(mr_sas_port, &mr_sas_node->sas_port_list,676	    port_list) {677		if (mr_sas_port->remote_identify.sas_address !=678		    sas_address)679			continue;680		if (mr_sas_port->hba_port != hba_port)681			continue;682		list_for_each_entry(srch_phy, &mr_sas_port->phy_list,683		    port_siblings) {684			if (srch_phy == mr_sas_phy)685				return;686		}687		mpi3mr_add_sas_phy(mrioc, mr_sas_port, mr_sas_phy, mr_sas_node->host_node);688		return;689	}690}691 692/**693 * mpi3mr_delete_sas_port - helper function to removing a port694 * @mrioc: Adapter instance reference695 * @mr_sas_port: Internal Port object696 *697 * Return: None.698 */699static void  mpi3mr_delete_sas_port(struct mpi3mr_ioc *mrioc,700	struct mpi3mr_sas_port *mr_sas_port)701{702	u64 sas_address = mr_sas_port->remote_identify.sas_address;703	struct mpi3mr_hba_port *hba_port = mr_sas_port->hba_port;704	enum sas_device_type device_type =705	    mr_sas_port->remote_identify.device_type;706 707	dev_info(&mr_sas_port->port->dev,708	    "remove: sas_address(0x%016llx)\n",709	    (unsigned long long) sas_address);710 711	if (device_type == SAS_END_DEVICE)712		mpi3mr_remove_device_by_sas_address(mrioc, sas_address,713		    hba_port);714 715	else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||716	    device_type == SAS_FANOUT_EXPANDER_DEVICE)717		mpi3mr_expander_remove(mrioc, sas_address, hba_port);718}719 720/**721 * mpi3mr_del_phy_from_an_existing_port - del phy from a port722 * @mrioc: Adapter instance reference723 * @mr_sas_node: Internal sas node object (expander or host)724 * @mr_sas_phy: Internal Phy object725 *726 * Return: None.727 */728static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,729	struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy)730{731	struct mpi3mr_sas_port *mr_sas_port, *next;732	struct mpi3mr_sas_phy *srch_phy;733 734	if (mr_sas_phy->phy_belongs_to_port == 0)735		return;736 737	list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,738	    port_list) {739		list_for_each_entry(srch_phy, &mr_sas_port->phy_list,740		    port_siblings) {741			if (srch_phy != mr_sas_phy)742				continue;743			if ((mr_sas_port->num_phys == 1) &&744			    !mrioc->reset_in_progress)745				mpi3mr_delete_sas_port(mrioc, mr_sas_port);746			else747				mpi3mr_delete_sas_phy(mrioc, mr_sas_port,748				    mr_sas_phy, mr_sas_node->host_node);749			return;750		}751	}752}753 754/**755 * mpi3mr_sas_port_sanity_check - sanity check while adding port756 * @mrioc: Adapter instance reference757 * @mr_sas_node: Internal sas node object (expander or host)758 * @sas_address: SAS address of device/expander759 * @hba_port: HBA port entry760 *761 * Verifies whether the Phys attached to a device with the given762 * SAS address already belongs to an existing sas port if so763 * will remove those phys from the sas port764 *765 * Return: None.766 */767static void mpi3mr_sas_port_sanity_check(struct mpi3mr_ioc *mrioc,768	struct mpi3mr_sas_node *mr_sas_node, u64 sas_address,769	struct mpi3mr_hba_port *hba_port)770{771	int i;772 773	for (i = 0; i < mr_sas_node->num_phys; i++) {774		if ((mr_sas_node->phy[i].remote_identify.sas_address !=775		    sas_address) || (mr_sas_node->phy[i].hba_port != hba_port))776			continue;777		if (mr_sas_node->phy[i].phy_belongs_to_port == 1)778			mpi3mr_del_phy_from_an_existing_port(mrioc,779			    mr_sas_node, &mr_sas_node->phy[i]);780	}781}782 783/**784 * mpi3mr_set_identify - set identify for phys and end devices785 * @mrioc: Adapter instance reference786 * @handle: Firmware device handle787 * @identify: SAS transport layer's identify info788 *789 * Populates sas identify info for a specific device.790 *791 * Return: 0 for success, non-zero for failure.792 */793static int mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle,794	struct sas_identify *identify)795{796 797	struct mpi3_device_page0 device_pg0;798	struct mpi3_device0_sas_sata_format *sasinf;799	u16 device_info;800	u16 ioc_status;801 802	if (mrioc->reset_in_progress) {803		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);804		return -EFAULT;805	}806 807	if (mrioc->pci_err_recovery) {808		ioc_err(mrioc, "%s: pci error recovery in progress!\n",809		    __func__);810		return -EFAULT;811	}812 813	if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,814	    sizeof(device_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, handle))) {815		ioc_err(mrioc, "%s: device page0 read failed\n", __func__);816		return -ENXIO;817	}818 819	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {820		ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",821		    handle, ioc_status, __FILE__, __LINE__, __func__);822		return -EIO;823	}824 825	memset(identify, 0, sizeof(struct sas_identify));826	sasinf = &device_pg0.device_specific.sas_sata_format;827	device_info = le16_to_cpu(sasinf->device_info);828 829	/* sas_address */830	identify->sas_address = le64_to_cpu(sasinf->sas_address);831 832	/* phy number of the parent device this device is linked to */833	identify->phy_identifier = sasinf->phy_num;834 835	/* device_type */836	switch (device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) {837	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE:838		identify->device_type = SAS_PHY_UNUSED;839		break;840	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE:841		identify->device_type = SAS_END_DEVICE;842		break;843	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER:844		identify->device_type = SAS_EDGE_EXPANDER_DEVICE;845		break;846	}847 848	/* initiator_port_protocols */849	if (device_info & MPI3_SAS_DEVICE_INFO_SSP_INITIATOR)850		identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;851	/* MPI3.0 doesn't have define for SATA INIT so setting both here*/852	if (device_info & MPI3_SAS_DEVICE_INFO_STP_INITIATOR)853		identify->initiator_port_protocols |= (SAS_PROTOCOL_STP |854		    SAS_PROTOCOL_SATA);855	if (device_info & MPI3_SAS_DEVICE_INFO_SMP_INITIATOR)856		identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;857 858	/* target_port_protocols */859	if (device_info & MPI3_SAS_DEVICE_INFO_SSP_TARGET)860		identify->target_port_protocols |= SAS_PROTOCOL_SSP;861	/* MPI3.0 doesn't have define for STP Target so setting both here*/862	if (device_info & MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET)863		identify->target_port_protocols |= (SAS_PROTOCOL_STP |864		    SAS_PROTOCOL_SATA);865	if (device_info & MPI3_SAS_DEVICE_INFO_SMP_TARGET)866		identify->target_port_protocols |= SAS_PROTOCOL_SMP;867	return 0;868}869 870/**871 * mpi3mr_add_host_phy - report sas_host phy to SAS transport872 * @mrioc: Adapter instance reference873 * @mr_sas_phy: Internal Phy object874 * @phy_pg0: SAS phy page 0875 * @parent_dev: Prent device class object876 *877 * Return: 0 for success, non-zero for failure.878 */879static int mpi3mr_add_host_phy(struct mpi3mr_ioc *mrioc,880	struct mpi3mr_sas_phy *mr_sas_phy, struct mpi3_sas_phy_page0 phy_pg0,881	struct device *parent_dev)882{883	struct sas_phy *phy;884	int phy_index = mr_sas_phy->phy_id;885 886 887	INIT_LIST_HEAD(&mr_sas_phy->port_siblings);888	phy = sas_phy_alloc(parent_dev, phy_index);889	if (!phy) {890		ioc_err(mrioc, "failure at %s:%d/%s()!\n",891		    __FILE__, __LINE__, __func__);892		return -1;893	}894	if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,895	    &mr_sas_phy->identify))) {896		ioc_err(mrioc, "failure at %s:%d/%s()!\n",897		    __FILE__, __LINE__, __func__);898		sas_phy_free(phy);899		return -1;900	}901	phy->identify = mr_sas_phy->identify;902	mr_sas_phy->attached_handle = le16_to_cpu(phy_pg0.attached_dev_handle);903	if (mr_sas_phy->attached_handle)904		mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,905		    &mr_sas_phy->remote_identify);906	phy->identify.phy_identifier = mr_sas_phy->phy_id;907	phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(908	    (phy_pg0.negotiated_link_rate &909	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>910	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);911	phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(912	    phy_pg0.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);913	phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(914	    phy_pg0.hw_link_rate >> 4);915	phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(916	    phy_pg0.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);917	phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(918	    phy_pg0.programmed_link_rate >> 4);919	phy->hostdata = mr_sas_phy->hba_port;920 921	if ((sas_phy_add(phy))) {922		ioc_err(mrioc, "failure at %s:%d/%s()!\n",923		    __FILE__, __LINE__, __func__);924		sas_phy_free(phy);925		return -1;926	}927	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))928		dev_info(&phy->dev,929		    "add: handle(0x%04x), sas_address(0x%016llx)\n"930		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",931		    mr_sas_phy->handle, (unsigned long long)932		    mr_sas_phy->identify.sas_address,933		    mr_sas_phy->attached_handle,934		    (unsigned long long)935		    mr_sas_phy->remote_identify.sas_address);936	mr_sas_phy->phy = phy;937	return 0;938}939 940/**941 * mpi3mr_add_expander_phy - report expander phy to transport942 * @mrioc: Adapter instance reference943 * @mr_sas_phy: Internal Phy object944 * @expander_pg1: SAS Expander page 1945 * @parent_dev: Parent device class object946 *947 * Return: 0 for success, non-zero for failure.948 */949static int mpi3mr_add_expander_phy(struct mpi3mr_ioc *mrioc,950	struct mpi3mr_sas_phy *mr_sas_phy,951	struct mpi3_sas_expander_page1 expander_pg1,952	struct device *parent_dev)953{954	struct sas_phy *phy;955	int phy_index = mr_sas_phy->phy_id;956 957	INIT_LIST_HEAD(&mr_sas_phy->port_siblings);958	phy = sas_phy_alloc(parent_dev, phy_index);959	if (!phy) {960		ioc_err(mrioc, "failure at %s:%d/%s()!\n",961		    __FILE__, __LINE__, __func__);962		return -1;963	}964	if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,965	    &mr_sas_phy->identify))) {966		ioc_err(mrioc, "failure at %s:%d/%s()!\n",967		    __FILE__, __LINE__, __func__);968		sas_phy_free(phy);969		return -1;970	}971	phy->identify = mr_sas_phy->identify;972	mr_sas_phy->attached_handle =973	    le16_to_cpu(expander_pg1.attached_dev_handle);974	if (mr_sas_phy->attached_handle)975		mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,976		    &mr_sas_phy->remote_identify);977	phy->identify.phy_identifier = mr_sas_phy->phy_id;978	phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(979	    (expander_pg1.negotiated_link_rate &980	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>981	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);982	phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(983	    expander_pg1.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);984	phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(985	    expander_pg1.hw_link_rate >> 4);986	phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(987	    expander_pg1.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);988	phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(989	    expander_pg1.programmed_link_rate >> 4);990	phy->hostdata = mr_sas_phy->hba_port;991 992	if ((sas_phy_add(phy))) {993		ioc_err(mrioc, "failure at %s:%d/%s()!\n",994		    __FILE__, __LINE__, __func__);995		sas_phy_free(phy);996		return -1;997	}998	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))999		dev_info(&phy->dev,1000		    "add: handle(0x%04x), sas_address(0x%016llx)\n"1001		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",1002		    mr_sas_phy->handle, (unsigned long long)1003		    mr_sas_phy->identify.sas_address,1004		    mr_sas_phy->attached_handle,1005		    (unsigned long long)1006		    mr_sas_phy->remote_identify.sas_address);1007	mr_sas_phy->phy = phy;1008	return 0;1009}1010 1011/**1012 * mpi3mr_alloc_hba_port - alloc hba port object1013 * @mrioc: Adapter instance reference1014 * @port_id: Port number1015 *1016 * Alloc memory for hba port object.1017 */1018static struct mpi3mr_hba_port *1019mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id)1020{1021	struct mpi3mr_hba_port *hba_port;1022 1023	hba_port = kzalloc(sizeof(struct mpi3mr_hba_port),1024	    GFP_KERNEL);1025	if (!hba_port)1026		return NULL;1027	hba_port->port_id = port_id;1028	ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n",1029	    hba_port, hba_port->port_id);1030	if (mrioc->reset_in_progress ||1031		mrioc->pci_err_recovery)1032		hba_port->flags = MPI3MR_HBA_PORT_FLAG_NEW;1033	list_add_tail(&hba_port->list, &mrioc->hba_port_table_list);1034	return hba_port;1035}1036 1037/**1038 * mpi3mr_get_hba_port_by_id - find hba port by id1039 * @mrioc: Adapter instance reference1040 * @port_id: Port ID to search1041 *1042 * Return: mpi3mr_hba_port reference for the matched port1043 */1044 1045struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc,1046	u8 port_id)1047{1048	struct mpi3mr_hba_port *port, *port_next;1049 1050	list_for_each_entry_safe(port, port_next,1051	    &mrioc->hba_port_table_list, list) {1052		if (port->port_id != port_id)1053			continue;1054		if (port->flags & MPI3MR_HBA_PORT_FLAG_DIRTY)1055			continue;1056		return port;1057	}1058 1059	return NULL;1060}1061 1062/**1063 * mpi3mr_update_links - refreshing SAS phy link changes1064 * @mrioc: Adapter instance reference1065 * @sas_address_parent: SAS address of parent expander or host1066 * @handle: Firmware device handle of attached device1067 * @phy_number: Phy number1068 * @link_rate: New link rate1069 * @hba_port: HBA port entry1070 *1071 * Return: None.1072 */1073void mpi3mr_update_links(struct mpi3mr_ioc *mrioc,1074	u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate,1075	struct mpi3mr_hba_port *hba_port)1076{1077	unsigned long flags;1078	struct mpi3mr_sas_node *mr_sas_node;1079	struct mpi3mr_sas_phy *mr_sas_phy;1080 1081	if (mrioc->reset_in_progress || mrioc->pci_err_recovery)1082		return;1083 1084	spin_lock_irqsave(&mrioc->sas_node_lock, flags);1085	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,1086	    sas_address_parent, hba_port);1087	if (!mr_sas_node) {1088		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1089		return;1090	}1091 1092	mr_sas_phy = &mr_sas_node->phy[phy_number];1093	mr_sas_phy->attached_handle = handle;1094	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1095	if (handle && (link_rate >= MPI3_SAS_NEG_LINK_RATE_1_5)) {1096		mpi3mr_set_identify(mrioc, handle,1097		    &mr_sas_phy->remote_identify);1098		mpi3mr_add_phy_to_an_existing_port(mrioc, mr_sas_node,1099		    mr_sas_phy, mr_sas_phy->remote_identify.sas_address,1100		    hba_port);1101	} else1102		memset(&mr_sas_phy->remote_identify, 0, sizeof(struct1103		    sas_identify));1104 1105	if (mr_sas_phy->phy)1106		mr_sas_phy->phy->negotiated_linkrate =1107		    mpi3mr_convert_phy_link_rate(link_rate);1108 1109	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))1110		dev_info(&mr_sas_phy->phy->dev,1111		    "refresh: parent sas_address(0x%016llx),\n"1112		    "\tlink_rate(0x%02x), phy(%d)\n"1113		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",1114		    (unsigned long long)sas_address_parent,1115		    link_rate, phy_number, handle, (unsigned long long)1116		    mr_sas_phy->remote_identify.sas_address);1117}1118 1119/**1120 * mpi3mr_sas_host_refresh - refreshing sas host object contents1121 * @mrioc: Adapter instance reference1122 *1123 * This function refreshes the controllers phy information and1124 * updates the SAS transport layer with updated information,1125 * this is executed for each device addition or device info1126 * change events1127 *1128 * Return: None.1129 */1130void mpi3mr_sas_host_refresh(struct mpi3mr_ioc *mrioc)1131{1132	int i;1133	u8 link_rate;1134	u16 sz, port_id, attached_handle;1135	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;1136 1137	dprint_transport_info(mrioc,1138	    "updating handles for sas_host(0x%016llx)\n",1139	    (unsigned long long)mrioc->sas_hba.sas_address);1140 1141	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +1142	    (mrioc->sas_hba.num_phys *1143	     sizeof(struct mpi3_sas_io_unit0_phy_data));1144	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);1145	if (!sas_io_unit_pg0)1146		return;1147	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {1148		ioc_err(mrioc, "failure at %s:%d/%s()!\n",1149		    __FILE__, __LINE__, __func__);1150		goto out;1151	}1152 1153	mrioc->sas_hba.handle = 0;1154	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {1155		if (sas_io_unit_pg0->phy_data[i].phy_flags &1156		    (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |1157		     MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))1158			continue;1159		link_rate =1160		    sas_io_unit_pg0->phy_data[i].negotiated_link_rate >> 4;1161		if (!mrioc->sas_hba.handle)1162			mrioc->sas_hba.handle = le16_to_cpu(1163			    sas_io_unit_pg0->phy_data[i].controller_dev_handle);1164		port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;1165		if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))1166			if (!mpi3mr_alloc_hba_port(mrioc, port_id))1167				goto out;1168 1169		mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;1170		attached_handle = le16_to_cpu(1171		    sas_io_unit_pg0->phy_data[i].attached_dev_handle);1172		if (attached_handle && link_rate < MPI3_SAS_NEG_LINK_RATE_1_5)1173			link_rate = MPI3_SAS_NEG_LINK_RATE_1_5;1174		mrioc->sas_hba.phy[i].hba_port =1175			mpi3mr_get_hba_port_by_id(mrioc, port_id);1176		mpi3mr_update_links(mrioc, mrioc->sas_hba.sas_address,1177		    attached_handle, i, link_rate,1178		    mrioc->sas_hba.phy[i].hba_port);1179	}1180 out:1181	kfree(sas_io_unit_pg0);1182}1183 1184/**1185 * mpi3mr_sas_host_add - create sas host object1186 * @mrioc: Adapter instance reference1187 *1188 * This function creates the controllers phy information and1189 * updates the SAS transport layer with updated information,1190 * this is executed for first device addition or device info1191 * change event.1192 *1193 * Return: None.1194 */1195void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)1196{1197	int i;1198	u16 sz, num_phys = 1, port_id, ioc_status;1199	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;1200	struct mpi3_sas_phy_page0 phy_pg0;1201	struct mpi3_device_page0 dev_pg0;1202	struct mpi3_enclosure_page0 encl_pg0;1203	struct mpi3_device0_sas_sata_format *sasinf;1204 1205	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +1206	    (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));1207	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);1208	if (!sas_io_unit_pg0)1209		return;1210 1211	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {1212		ioc_err(mrioc, "failure at %s:%d/%s()!\n",1213		    __FILE__, __LINE__, __func__);1214		goto out;1215	}1216	num_phys = sas_io_unit_pg0->num_phys;1217	kfree(sas_io_unit_pg0);1218 1219	mrioc->sas_hba.host_node = 1;1220	INIT_LIST_HEAD(&mrioc->sas_hba.sas_port_list);1221	mrioc->sas_hba.parent_dev = &mrioc->shost->shost_gendev;1222	mrioc->sas_hba.phy = kcalloc(num_phys,1223	    sizeof(struct mpi3mr_sas_phy), GFP_KERNEL);1224	if (!mrioc->sas_hba.phy)1225		return;1226 1227	mrioc->sas_hba.num_phys = num_phys;1228 1229	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +1230	    (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));1231	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);1232	if (!sas_io_unit_pg0)1233		return;1234 1235	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {1236		ioc_err(mrioc, "failure at %s:%d/%s()!\n",1237		    __FILE__, __LINE__, __func__);1238		goto out;1239	}1240 1241	mrioc->sas_hba.handle = 0;1242	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {1243		if (sas_io_unit_pg0->phy_data[i].phy_flags &1244		    (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |1245		    MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))1246			continue;1247		if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,1248		    sizeof(struct mpi3_sas_phy_page0),1249		    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, i)) {1250			ioc_err(mrioc, "failure at %s:%d/%s()!\n",1251			    __FILE__, __LINE__, __func__);1252			goto out;1253		}1254		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {1255			ioc_err(mrioc, "failure at %s:%d/%s()!\n",1256			    __FILE__, __LINE__, __func__);1257			goto out;1258		}1259 1260		if (!mrioc->sas_hba.handle)1261			mrioc->sas_hba.handle = le16_to_cpu(1262			    sas_io_unit_pg0->phy_data[i].controller_dev_handle);1263		port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;1264 1265		if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))1266			if (!mpi3mr_alloc_hba_port(mrioc, port_id))1267				goto out;1268 1269		mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;1270		mrioc->sas_hba.phy[i].phy_id = i;1271		mrioc->sas_hba.phy[i].hba_port =1272		    mpi3mr_get_hba_port_by_id(mrioc, port_id);1273		mpi3mr_add_host_phy(mrioc, &mrioc->sas_hba.phy[i],1274		    phy_pg0, mrioc->sas_hba.parent_dev);1275	}1276	if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,1277	    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,1278	    mrioc->sas_hba.handle))) {1279		ioc_err(mrioc, "%s: device page0 read failed\n", __func__);1280		goto out;1281	}1282	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {1283		ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",1284		    mrioc->sas_hba.handle, ioc_status, __FILE__, __LINE__,1285		    __func__);1286		goto out;1287	}1288	mrioc->sas_hba.enclosure_handle =1289	    le16_to_cpu(dev_pg0.enclosure_handle);1290	sasinf = &dev_pg0.device_specific.sas_sata_format;1291	mrioc->sas_hba.sas_address =1292	    le64_to_cpu(sasinf->sas_address);1293	ioc_info(mrioc,1294	    "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n",1295	    mrioc->sas_hba.handle,1296	    (unsigned long long) mrioc->sas_hba.sas_address,1297	    mrioc->sas_hba.num_phys);1298 1299	if (mrioc->sas_hba.enclosure_handle) {1300		if (!(mpi3mr_cfg_get_enclosure_pg0(mrioc, &ioc_status,1301		    &encl_pg0, sizeof(encl_pg0),1302		    MPI3_ENCLOS_PGAD_FORM_HANDLE,1303		    mrioc->sas_hba.enclosure_handle)) &&1304		    (ioc_status == MPI3_IOCSTATUS_SUCCESS))1305			mrioc->sas_hba.enclosure_logical_id =1306				le64_to_cpu(encl_pg0.enclosure_logical_id);1307	}1308 1309out:1310	kfree(sas_io_unit_pg0);1311}1312 1313/**1314 * mpi3mr_sas_port_add - Expose the SAS device to the SAS TL1315 * @mrioc: Adapter instance reference1316 * @handle: Firmware device handle of the attached device1317 * @sas_address_parent: sas address of parent expander or host1318 * @hba_port: HBA port entry1319 *1320 * This function creates a new sas port object for the given end1321 * device matching sas address and hba_port and adds it to the1322 * sas_node's sas_port_list and expose the attached sas device1323 * to the SAS transport layer through sas_rphy_add.1324 *1325 * Returns a valid mpi3mr_sas_port reference or NULL.1326 */1327static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,1328	u16 handle, u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)1329{1330	struct mpi3mr_sas_phy *mr_sas_phy, *next;1331	struct mpi3mr_sas_port *mr_sas_port;1332	unsigned long flags;1333	struct mpi3mr_sas_node *mr_sas_node;1334	struct sas_rphy *rphy;1335	struct mpi3mr_tgt_dev *tgtdev = NULL;1336	int i;1337	struct sas_port *port;1338 1339	if (!hba_port) {1340		ioc_err(mrioc, "failure at %s:%d/%s()!\n",1341		    __FILE__, __LINE__, __func__);1342		return NULL;1343	}1344 1345	mr_sas_port = kzalloc(sizeof(struct mpi3mr_sas_port), GFP_KERNEL);1346	if (!mr_sas_port)1347		return NULL;1348 1349	INIT_LIST_HEAD(&mr_sas_port->port_list);1350	INIT_LIST_HEAD(&mr_sas_port->phy_list);1351	spin_lock_irqsave(&mrioc->sas_node_lock, flags);1352	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,1353	    sas_address_parent, hba_port);1354	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1355 1356	if (!mr_sas_node) {1357		ioc_err(mrioc, "%s:could not find parent sas_address(0x%016llx)!\n",1358		    __func__, (unsigned long long)sas_address_parent);1359		goto out_fail;1360	}1361 1362	if ((mpi3mr_set_identify(mrioc, handle,1363	    &mr_sas_port->remote_identify))) {1364		ioc_err(mrioc,  "failure at %s:%d/%s()!\n",1365		    __FILE__, __LINE__, __func__);1366		goto out_fail;1367	}1368 1369	if (mr_sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {1370		ioc_err(mrioc, "failure at %s:%d/%s()!\n",1371		    __FILE__, __LINE__, __func__);1372		goto out_fail;1373	}1374 1375	mr_sas_port->hba_port = hba_port;1376	mpi3mr_sas_port_sanity_check(mrioc, mr_sas_node,1377	    mr_sas_port->remote_identify.sas_address, hba_port);1378 1379	if (mr_sas_node->host_node && mr_sas_node->num_phys >=1380			sizeof(mr_sas_port->phy_mask) * 8)1381		ioc_info(mrioc, "max port count %u could be too high\n",1382		    mr_sas_node->num_phys);1383 1384	for (i = 0; i < mr_sas_node->num_phys; i++) {1385		if ((mr_sas_node->phy[i].remote_identify.sas_address !=1386		    mr_sas_port->remote_identify.sas_address) ||1387		    (mr_sas_node->phy[i].hba_port != hba_port))1388			continue;1389 1390		if (mr_sas_node->host_node && (i >= sizeof(mr_sas_port->phy_mask) * 8)) {1391			ioc_warn(mrioc, "skipping port %u, max allowed value is %zu\n",1392			    i, sizeof(mr_sas_port->phy_mask) * 8);1393			goto out_fail;1394		}1395		list_add_tail(&mr_sas_node->phy[i].port_siblings,1396		    &mr_sas_port->phy_list);1397		mr_sas_port->num_phys++;1398		if (mr_sas_node->host_node)1399			mr_sas_port->phy_mask |= (1 << i);1400	}1401 1402	if (!mr_sas_port->num_phys) {1403		ioc_err(mrioc, "failure at %s:%d/%s()!\n",1404		    __FILE__, __LINE__, __func__);1405		goto out_fail;1406	}1407 1408	if (mr_sas_node->host_node)1409		mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;1410 1411	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {1412		tgtdev = mpi3mr_get_tgtdev_by_addr(mrioc,1413		    mr_sas_port->remote_identify.sas_address,1414		    mr_sas_port->hba_port);1415 1416		if (!tgtdev) {1417			ioc_err(mrioc, "failure at %s:%d/%s()!\n",1418			    __FILE__, __LINE__, __func__);1419			goto out_fail;1420		}1421		tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 1;1422	}1423 1424	if (!mr_sas_node->parent_dev) {1425		ioc_err(mrioc, "failure at %s:%d/%s()!\n",1426		    __FILE__, __LINE__, __func__);1427		goto out_fail;1428	}1429 1430	port = sas_port_alloc_num(mr_sas_node->parent_dev);1431	if ((sas_port_add(port))) {1432		ioc_err(mrioc, "failure at %s:%d/%s()!\n",1433		    __FILE__, __LINE__, __func__);1434		goto out_fail;1435	}1436 1437	list_for_each_entry(mr_sas_phy, &mr_sas_port->phy_list,1438	    port_siblings) {1439		if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))1440			dev_info(&port->dev,1441			    "add: handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",1442			    handle, (unsigned long long)1443			    mr_sas_port->remote_identify.sas_address,1444			    mr_sas_phy->phy_id);1445		sas_port_add_phy(port, mr_sas_phy->phy);1446		mr_sas_phy->phy_belongs_to_port = 1;1447		mr_sas_phy->hba_port = hba_port;1448	}1449 1450	mr_sas_port->port = port;1451	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {1452		rphy = sas_end_device_alloc(port);1453		tgtdev->dev_spec.sas_sata_inf.rphy = rphy;1454	} else {1455		rphy = sas_expander_alloc(port,1456		    mr_sas_port->remote_identify.device_type);1457	}1458	rphy->identify = mr_sas_port->remote_identify;1459 1460	if (mrioc->current_event)1461		mrioc->current_event->pending_at_sml = 1;1462 1463	if ((sas_rphy_add(rphy))) {1464		ioc_err(mrioc, "failure at %s:%d/%s()!\n",1465		    __FILE__, __LINE__, __func__);1466	}1467	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {1468		tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0;1469		tgtdev->dev_spec.sas_sata_inf.sas_transport_attached = 1;1470		mpi3mr_tgtdev_put(tgtdev);1471	}1472 1473	dev_info(&rphy->dev,1474	    "%s: added: handle(0x%04x), sas_address(0x%016llx)\n",1475	    __func__, handle, (unsigned long long)1476	    mr_sas_port->remote_identify.sas_address);1477 1478	mr_sas_port->rphy = rphy;1479	spin_lock_irqsave(&mrioc->sas_node_lock, flags);1480	list_add_tail(&mr_sas_port->port_list, &mr_sas_node->sas_port_list);1481	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1482 1483	if (mrioc->current_event) {1484		mrioc->current_event->pending_at_sml = 0;1485		if (mrioc->current_event->discard)1486			mpi3mr_print_device_event_notice(mrioc, true);1487	}1488 1489	/* fill in report manufacture */1490	if (mr_sas_port->remote_identify.device_type ==1491	    SAS_EDGE_EXPANDER_DEVICE ||1492	    mr_sas_port->remote_identify.device_type ==1493	    SAS_FANOUT_EXPANDER_DEVICE)1494		mpi3mr_report_manufacture(mrioc,1495		    mr_sas_port->remote_identify.sas_address,1496		    rphy_to_expander_device(rphy), hba_port->port_id);1497 1498	return mr_sas_port;1499 1500 out_fail:1501	list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list,1502	    port_siblings)1503		list_del(&mr_sas_phy->port_siblings);1504	kfree(mr_sas_port);1505	return NULL;1506}1507 1508/**1509 * mpi3mr_sas_port_remove - remove port from the list1510 * @mrioc: Adapter instance reference1511 * @sas_address: SAS address of attached device1512 * @sas_address_parent: SAS address of parent expander or host1513 * @hba_port: HBA port entry1514 *1515 * Removing object and freeing associated memory from the1516 * sas_port_list.1517 *1518 * Return: None1519 */1520static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,1521	u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)1522{1523	int i;1524	unsigned long flags;1525	struct mpi3mr_sas_port *mr_sas_port, *next;1526	struct mpi3mr_sas_node *mr_sas_node;1527	u8 found = 0;1528	struct mpi3mr_sas_phy *mr_sas_phy, *next_phy;1529	struct mpi3mr_hba_port *srch_port, *hba_port_next = NULL;1530 1531	if (!hba_port)1532		return;1533 1534	spin_lock_irqsave(&mrioc->sas_node_lock, flags);1535	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,1536	    sas_address_parent, hba_port);1537	if (!mr_sas_node) {1538		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1539		return;1540	}1541	list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,1542	    port_list) {1543		if (mr_sas_port->remote_identify.sas_address != sas_address)1544			continue;1545		if (mr_sas_port->hba_port != hba_port)1546			continue;1547		found = 1;1548		list_del(&mr_sas_port->port_list);1549		goto out;1550	}1551 1552 out:1553	if (!found) {1554		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1555		return;1556	}1557 1558	if (mr_sas_node->host_node) {1559		list_for_each_entry_safe(srch_port, hba_port_next,1560		    &mrioc->hba_port_table_list, list) {1561			if (srch_port != hba_port)1562				continue;1563			ioc_info(mrioc,1564			    "removing hba_port entry: %p port: %d from hba_port list\n",1565			    srch_port, srch_port->port_id);1566			list_del(&hba_port->list);1567			kfree(hba_port);1568			break;1569		}1570	}1571 1572	for (i = 0; i < mr_sas_node->num_phys; i++) {1573		if (mr_sas_node->phy[i].remote_identify.sas_address ==1574		    sas_address)1575			memset(&mr_sas_node->phy[i].remote_identify, 0,1576			    sizeof(struct sas_identify));1577	}1578 1579	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1580 1581	if (mrioc->current_event)1582		mrioc->current_event->pending_at_sml = 1;1583 1584	list_for_each_entry_safe(mr_sas_phy, next_phy,1585	    &mr_sas_port->phy_list, port_siblings) {1586		if ((!mrioc->stop_drv_processing) &&1587		    (mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))1588			dev_info(&mr_sas_port->port->dev,1589			    "remove: sas_address(0x%016llx), phy(%d)\n",1590			    (unsigned long long)1591			    mr_sas_port->remote_identify.sas_address,1592			    mr_sas_phy->phy_id);1593		mr_sas_phy->phy_belongs_to_port = 0;1594		if (!mrioc->stop_drv_processing)1595			sas_port_delete_phy(mr_sas_port->port,1596			    mr_sas_phy->phy);1597		list_del(&mr_sas_phy->port_siblings);1598	}1599	if (!mrioc->stop_drv_processing)1600		sas_port_delete(mr_sas_port->port);1601	ioc_info(mrioc, "%s: removed sas_address(0x%016llx)\n",1602	    __func__, (unsigned long long)sas_address);1603 1604	if (mrioc->current_event) {1605		mrioc->current_event->pending_at_sml = 0;1606		if (mrioc->current_event->discard)1607			mpi3mr_print_device_event_notice(mrioc, false);1608	}1609 1610	kfree(mr_sas_port);1611}1612 1613/**1614 * struct host_port - host port details1615 * @sas_address: SAS Address of the attached device1616 * @phy_mask: phy mask of host port1617 * @handle: Device Handle of attached device1618 * @iounit_port_id: port ID1619 * @used: host port is already matched with sas port from sas_port_list1620 * @lowest_phy: lowest phy ID of host port1621 */1622struct host_port {1623	u64	sas_address;1624	u64	phy_mask;1625	u16	handle;1626	u8	iounit_port_id;1627	u8	used;1628	u8	lowest_phy;1629};1630 1631/**1632 * mpi3mr_update_mr_sas_port - update sas port objects during reset1633 * @mrioc: Adapter instance reference1634 * @h_port: host_port object1635 * @mr_sas_port: sas_port objects which needs to be updated1636 *1637 * Update the port ID of sas port object. Also add the phys if new phys got1638 * added to current sas port and remove the phys if some phys are moved1639 * out of the current sas port.1640 *1641 * Return: Nothing.1642 */1643static void1644mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port,1645	struct mpi3mr_sas_port *mr_sas_port)1646{1647	struct mpi3mr_sas_phy *mr_sas_phy;1648	u64 phy_mask_xor;1649	u64 phys_to_be_added, phys_to_be_removed;1650	int i;1651 1652	h_port->used = 1;1653	mr_sas_port->marked_responding = 1;1654 1655	dev_info(&mr_sas_port->port->dev,1656	    "sas_address(0x%016llx), old: port_id %d phy_mask 0x%llx, new: port_id %d phy_mask:0x%llx\n",1657	    mr_sas_port->remote_identify.sas_address,1658	    mr_sas_port->hba_port->port_id, mr_sas_port->phy_mask,1659	    h_port->iounit_port_id, h_port->phy_mask);1660 1661	mr_sas_port->hba_port->port_id = h_port->iounit_port_id;1662	mr_sas_port->hba_port->flags &= ~MPI3MR_HBA_PORT_FLAG_DIRTY;1663 1664	/* Get the newly added phys bit map & removed phys bit map */1665	phy_mask_xor = mr_sas_port->phy_mask ^ h_port->phy_mask;1666	phys_to_be_added = h_port->phy_mask & phy_mask_xor;1667	phys_to_be_removed = mr_sas_port->phy_mask & phy_mask_xor;1668 1669	/*1670	 * Register these new phys to current mr_sas_port's port.1671	 * if these phys are previously registered with another port1672	 * then delete these phys from that port first.1673	 */1674	for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u64)) {1675		mr_sas_phy = &mrioc->sas_hba.phy[i];1676		if (mr_sas_phy->phy_belongs_to_port)1677			mpi3mr_del_phy_from_an_existing_port(mrioc,1678			    &mrioc->sas_hba, mr_sas_phy);1679		mpi3mr_add_phy_to_an_existing_port(mrioc,1680		    &mrioc->sas_hba, mr_sas_phy,1681		    mr_sas_port->remote_identify.sas_address,1682		    mr_sas_port->hba_port);1683	}1684 1685	/* Delete the phys which are not part of current mr_sas_port's port. */1686	for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u64)) {1687		mr_sas_phy = &mrioc->sas_hba.phy[i];1688		if (mr_sas_phy->phy_belongs_to_port)1689			mpi3mr_del_phy_from_an_existing_port(mrioc,1690			    &mrioc->sas_hba, mr_sas_phy);1691	}1692}1693 1694/**1695 * mpi3mr_refresh_sas_ports - update host's sas ports during reset1696 * @mrioc: Adapter instance reference1697 *1698 * Update the host's sas ports during reset by checking whether1699 * sas ports are still intact or not. Add/remove phys if any hba1700 * phys are (moved in)/(moved out) of sas port. Also update1701 * io_unit_port if it got changed during reset.1702 *1703 * Return: Nothing.1704 */1705void1706mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)1707{1708	struct host_port *h_port = NULL;1709	int i, j, found, host_port_count = 0, port_idx;1710	u16 sz, attached_handle, ioc_status;1711	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;1712	struct mpi3_device_page0 dev_pg0;1713	struct mpi3_device0_sas_sata_format *sasinf;1714	struct mpi3mr_sas_port *mr_sas_port;1715 1716	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +1717		(mrioc->sas_hba.num_phys *1718		 sizeof(struct mpi3_sas_io_unit0_phy_data));1719	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);1720	if (!sas_io_unit_pg0)1721		return;1722	h_port = kcalloc(64, sizeof(struct host_port), GFP_KERNEL);1723	if (!h_port)1724		goto out;1725 1726	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {1727		ioc_err(mrioc, "failure at %s:%d/%s()!\n",1728		    __FILE__, __LINE__, __func__);1729		goto out;1730	}1731 1732	/* Create a new expander port table */1733	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {1734		attached_handle = le16_to_cpu(1735		    sas_io_unit_pg0->phy_data[i].attached_dev_handle);1736		if (!attached_handle)1737			continue;1738		found = 0;1739		for (j = 0; j < host_port_count; j++) {1740			if (h_port[j].handle == attached_handle) {1741				h_port[j].phy_mask |= (1 << i);1742				found = 1;1743				break;1744			}1745		}1746		if (found)1747			continue;1748		if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,1749		    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,1750		    attached_handle))) {1751			dprint_reset(mrioc,1752			    "failed to read dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",1753			    attached_handle, __FILE__, __LINE__, __func__);1754			continue;1755		}1756		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {1757			dprint_reset(mrioc,1758			    "ioc_status(0x%x) while reading dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",1759			    ioc_status, attached_handle,1760			    __FILE__, __LINE__, __func__);1761			continue;1762		}1763		sasinf = &dev_pg0.device_specific.sas_sata_format;1764 1765		port_idx = host_port_count;1766		h_port[port_idx].sas_address = le64_to_cpu(sasinf->sas_address);1767		h_port[port_idx].handle = attached_handle;1768		h_port[port_idx].phy_mask = (1 << i);1769		h_port[port_idx].iounit_port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;1770		h_port[port_idx].lowest_phy = sasinf->phy_num;1771		h_port[port_idx].used = 0;1772		host_port_count++;1773	}1774 1775	if (!host_port_count)1776		goto out;1777 1778	if (mrioc->logging_level & MPI3_DEBUG_RESET) {1779		ioc_info(mrioc, "Host port details before reset\n");1780		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,1781		    port_list) {1782			ioc_info(mrioc,1783			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",1784			    mr_sas_port->hba_port->port_id,1785			    mr_sas_port->remote_identify.sas_address,1786			    mr_sas_port->phy_mask, mr_sas_port->lowest_phy);1787		}1788		mr_sas_port = NULL;1789		ioc_info(mrioc, "Host port details after reset\n");1790		for (i = 0; i < host_port_count; i++) {1791			ioc_info(mrioc,1792			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",1793			    h_port[i].iounit_port_id, h_port[i].sas_address,1794			    h_port[i].phy_mask, h_port[i].lowest_phy);1795		}1796	}1797 1798	/* mark all host sas port entries as dirty */1799	list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,1800	    port_list) {1801		mr_sas_port->marked_responding = 0;1802		mr_sas_port->hba_port->flags |= MPI3MR_HBA_PORT_FLAG_DIRTY;1803	}1804 1805	/* First check for matching lowest phy */1806	for (i = 0; i < host_port_count; i++) {1807		mr_sas_port = NULL;1808		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,1809		    port_list) {1810			if (mr_sas_port->marked_responding)1811				continue;1812			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)1813				continue;1814			if (h_port[i].lowest_phy == mr_sas_port->lowest_phy) {1815				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);1816				break;1817			}1818		}1819	}1820 1821	/* In case if lowest phy is got enabled or disabled during reset */1822	for (i = 0; i < host_port_count; i++) {1823		if (h_port[i].used)1824			continue;1825		mr_sas_port = NULL;1826		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,1827		    port_list) {1828			if (mr_sas_port->marked_responding)1829				continue;1830			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)1831				continue;1832			if (h_port[i].phy_mask & mr_sas_port->phy_mask) {1833				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);1834				break;1835			}1836		}1837	}1838 1839	/* In case if expander cable is removed & connected to another HBA port during reset */1840	for (i = 0; i < host_port_count; i++) {1841		if (h_port[i].used)1842			continue;1843		mr_sas_port = NULL;1844		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,1845		    port_list) {1846			if (mr_sas_port->marked_responding)1847				continue;1848			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)1849				continue;1850			mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);1851			break;1852		}1853	}1854out:1855	kfree(h_port);1856	kfree(sas_io_unit_pg0);1857}1858 1859/**1860 * mpi3mr_refresh_expanders - Refresh expander device exposure1861 * @mrioc: Adapter instance reference1862 *1863 * This is executed post controller reset to identify any1864 * missing expander devices during reset and remove from the upper layers1865 * or expose any newly detected expander device to the upper layers.1866 *1867 * Return: Nothing.1868 */1869void1870mpi3mr_refresh_expanders(struct mpi3mr_ioc *mrioc)1871{1872	struct mpi3mr_sas_node *sas_expander, *sas_expander_next;1873	struct mpi3_sas_expander_page0 expander_pg0;1874	u16 ioc_status, handle;1875	u64 sas_address;1876	int i;1877	unsigned long flags;1878	struct mpi3mr_hba_port *hba_port;1879 1880	spin_lock_irqsave(&mrioc->sas_node_lock, flags);1881	list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {1882		sas_expander->non_responding = 1;1883	}1884	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1885 1886	sas_expander = NULL;1887 1888	handle = 0xffff;1889 1890	/* Search for responding expander devices and add them if they are newly got added */1891	while (true) {1892		if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,1893		    sizeof(struct mpi3_sas_expander_page0),1894		    MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE, handle))) {1895			dprint_reset(mrioc,1896			    "failed to read exp pg0 for handle(0x%04x) at %s:%d/%s()!\n",1897			    handle, __FILE__, __LINE__, __func__);1898			break;1899		}1900 1901		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {1902			dprint_reset(mrioc,1903			   "ioc_status(0x%x) while reading exp pg0 for handle:(0x%04x), %s:%d/%s()!\n",1904			   ioc_status, handle, __FILE__, __LINE__, __func__);1905			break;1906		}1907 1908		handle = le16_to_cpu(expander_pg0.dev_handle);1909		sas_address = le64_to_cpu(expander_pg0.sas_address);1910		hba_port = mpi3mr_get_hba_port_by_id(mrioc, expander_pg0.io_unit_port);1911 1912		if (!hba_port) {1913			mpi3mr_sas_host_refresh(mrioc);1914			mpi3mr_expander_add(mrioc, handle);1915			continue;1916		}1917 1918		spin_lock_irqsave(&mrioc->sas_node_lock, flags);1919		sas_expander =1920		    mpi3mr_expander_find_by_sas_address(mrioc,1921		    sas_address, hba_port);1922		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1923 1924		if (!sas_expander) {1925			mpi3mr_sas_host_refresh(mrioc);1926			mpi3mr_expander_add(mrioc, handle);1927			continue;1928		}1929 1930		sas_expander->non_responding = 0;1931		if (sas_expander->handle == handle)1932			continue;1933 1934		sas_expander->handle = handle;1935		for (i = 0 ; i < sas_expander->num_phys ; i++)1936			sas_expander->phy[i].handle = handle;1937	}1938 1939	/*1940	 * Delete non responding expander devices and the corresponding1941	 * hba_port if the non responding expander device's parent device1942	 * is a host node.1943	 */1944	sas_expander = NULL;1945	spin_lock_irqsave(&mrioc->sas_node_lock, flags);1946	list_for_each_entry_safe_reverse(sas_expander, sas_expander_next,1947	    &mrioc->sas_expander_list, list) {1948		if (sas_expander->non_responding) {1949			spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1950			mpi3mr_expander_node_remove(mrioc, sas_expander);1951			spin_lock_irqsave(&mrioc->sas_node_lock, flags);1952		}1953	}1954	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1955}1956 1957/**1958 * mpi3mr_expander_node_add - insert an expander to the list.1959 * @mrioc: Adapter instance reference1960 * @sas_expander: Expander sas node1961 * Context: This function will acquire sas_node_lock.1962 *1963 * Adding new object to the ioc->sas_expander_list.1964 *1965 * Return: None.1966 */1967static void mpi3mr_expander_node_add(struct mpi3mr_ioc *mrioc,1968	struct mpi3mr_sas_node *sas_expander)1969{1970	unsigned long flags;1971 1972	spin_lock_irqsave(&mrioc->sas_node_lock, flags);1973	list_add_tail(&sas_expander->list, &mrioc->sas_expander_list);1974	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);1975}1976 1977/**1978 * mpi3mr_expander_add -  Create expander object1979 * @mrioc: Adapter instance reference1980 * @handle: Expander firmware device handle1981 *1982 * This function creating expander object, stored in1983 * sas_expander_list and expose it to the SAS transport1984 * layer.1985 *1986 * Return: 0 for success, non-zero for failure.1987 */1988int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle)1989{1990	struct mpi3mr_sas_node *sas_expander;1991	struct mpi3mr_enclosure_node *enclosure_dev;1992	struct mpi3_sas_expander_page0 expander_pg0;1993	struct mpi3_sas_expander_page1 expander_pg1;1994	u16 ioc_status, parent_handle, temp_handle;1995	u64 sas_address, sas_address_parent = 0;1996	int i;1997	unsigned long flags;1998	u8 port_id, link_rate;1999	struct mpi3mr_sas_port *mr_sas_port = NULL;2000	struct mpi3mr_hba_port *hba_port;2001	u32 phynum_handle;2002	int rc = 0;2003 2004	if (!handle)2005		return -1;2006 2007	if (mrioc->reset_in_progress || mrioc->pci_err_recovery)2008		return -1;2009 2010	if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,2011	    sizeof(expander_pg0), MPI3_SAS_EXPAND_PGAD_FORM_HANDLE, handle))) {2012		ioc_err(mrioc, "failure at %s:%d/%s()!\n",2013		    __FILE__, __LINE__, __func__);2014		return -1;2015	}2016 2017	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {2018		ioc_err(mrioc, "failure at %s:%d/%s()!\n",2019		    __FILE__, __LINE__, __func__);2020		return -1;2021	}2022 2023	parent_handle = le16_to_cpu(expander_pg0.parent_dev_handle);2024	if (mpi3mr_get_sas_address(mrioc, parent_handle, &sas_address_parent)2025	    != 0) {2026		ioc_err(mrioc, "failure at %s:%d/%s()!\n",2027		    __FILE__, __LINE__, __func__);2028		return -1;2029	}2030 2031	port_id = expander_pg0.io_unit_port;2032	hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);2033	if (!hba_port) {2034		ioc_err(mrioc, "failure at %s:%d/%s()!\n",2035		    __FILE__, __LINE__, __func__);2036		return -1;2037	}2038 2039	if (sas_address_parent != mrioc->sas_hba.sas_address) {2040		spin_lock_irqsave(&mrioc->sas_node_lock, flags);2041		sas_expander =2042		   mpi3mr_expander_find_by_sas_address(mrioc,2043		    sas_address_parent, hba_port);2044		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);2045		if (!sas_expander) {2046			rc = mpi3mr_expander_add(mrioc, parent_handle);2047			if (rc != 0)2048				return rc;2049		} else {2050			/*2051			 * When there is a parent expander present, update it's2052			 * phys where child expander is connected with the link2053			 * speed, attached dev handle and sas address.2054			 */2055			for (i = 0 ; i < sas_expander->num_phys ; i++) {2056				phynum_handle =2057				    (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |2058				    parent_handle;2059				if (mpi3mr_cfg_get_sas_exp_pg1(mrioc,2060				    &ioc_status, &expander_pg1,2061				    sizeof(expander_pg1),2062				    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,2063				    phynum_handle)) {2064					ioc_err(mrioc, "failure at %s:%d/%s()!\n",2065					    __FILE__, __LINE__, __func__);2066					rc = -1;2067					return rc;2068				}2069				if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {2070					ioc_err(mrioc, "failure at %s:%d/%s()!\n",2071					    __FILE__, __LINE__, __func__);2072					rc = -1;2073					return rc;2074				}2075				temp_handle = le16_to_cpu(2076				    expander_pg1.attached_dev_handle);2077				if (temp_handle != handle)2078					continue;2079				link_rate = (expander_pg1.negotiated_link_rate &2080				    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>2081				    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;2082				mpi3mr_update_links(mrioc, sas_address_parent,2083				    handle, i, link_rate, hba_port);2084			}2085		}2086	}2087 2088	spin_lock_irqsave(&mrioc->sas_node_lock, flags);2089	sas_address = le64_to_cpu(expander_pg0.sas_address);2090	sas_expander = mpi3mr_expander_find_by_sas_address(mrioc,2091	    sas_address, hba_port);2092	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);2093 2094	if (sas_expander)2095		return 0;2096 2097	sas_expander = kzalloc(sizeof(struct mpi3mr_sas_node),2098	    GFP_KERNEL);2099	if (!sas_expander)2100		return -ENOMEM;2101 2102	sas_expander->handle = handle;2103	sas_expander->num_phys = expander_pg0.num_phys;2104	sas_expander->sas_address_parent = sas_address_parent;2105	sas_expander->sas_address = sas_address;2106	sas_expander->hba_port = hba_port;2107 2108	ioc_info(mrioc,2109	    "expander_add: handle(0x%04x), parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n",2110	    handle, parent_handle, (unsigned long long)2111	    sas_expander->sas_address, sas_expander->num_phys);2112 2113	if (!sas_expander->num_phys) {2114		rc = -1;2115		goto out_fail;2116	}2117	sas_expander->phy = kcalloc(sas_expander->num_phys,2118	    sizeof(struct mpi3mr_sas_phy), GFP_KERNEL);2119	if (!sas_expander->phy) {2120		rc = -1;2121		goto out_fail;2122	}2123 2124	INIT_LIST_HEAD(&sas_expander->sas_port_list);2125	mr_sas_port = mpi3mr_sas_port_add(mrioc, handle, sas_address_parent,2126	    sas_expander->hba_port);2127	if (!mr_sas_port) {2128		ioc_err(mrioc, "failure at %s:%d/%s()!\n",2129		    __FILE__, __LINE__, __func__);2130		rc = -1;2131		goto out_fail;2132	}2133	sas_expander->parent_dev = &mr_sas_port->rphy->dev;2134	sas_expander->rphy = mr_sas_port->rphy;2135 2136	for (i = 0 ; i < sas_expander->num_phys ; i++) {2137		phynum_handle = (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |2138		    handle;2139		if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,2140		    &expander_pg1, sizeof(expander_pg1),2141		    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,2142		    phynum_handle)) {2143			ioc_err(mrioc, "failure at %s:%d/%s()!\n",2144			    __FILE__, __LINE__, __func__);2145			rc = -1;2146			goto out_fail;2147		}2148		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {2149			ioc_err(mrioc, "failure at %s:%d/%s()!\n",2150			    __FILE__, __LINE__, __func__);2151			rc = -1;2152			goto out_fail;2153		}2154 2155		sas_expander->phy[i].handle = handle;2156		sas_expander->phy[i].phy_id = i;2157		sas_expander->phy[i].hba_port = hba_port;2158 2159		if ((mpi3mr_add_expander_phy(mrioc, &sas_expander->phy[i],2160		    expander_pg1, sas_expander->parent_dev))) {2161			ioc_err(mrioc, "failure at %s:%d/%s()!\n",2162			    __FILE__, __LINE__, __func__);2163			rc = -1;2164			goto out_fail;2165		}2166	}2167 2168	if (sas_expander->enclosure_handle) {2169		enclosure_dev =2170			mpi3mr_enclosure_find_by_handle(mrioc,2171						sas_expander->enclosure_handle);2172		if (enclosure_dev)2173			sas_expander->enclosure_logical_id = le64_to_cpu(2174			    enclosure_dev->pg0.enclosure_logical_id);2175	}2176 2177	mpi3mr_expander_node_add(mrioc, sas_expander);2178	return 0;2179 2180out_fail:2181 2182	if (mr_sas_port)2183		mpi3mr_sas_port_remove(mrioc,2184		    sas_expander->sas_address,2185		    sas_address_parent, sas_expander->hba_port);2186	kfree(sas_expander->phy);2187	kfree(sas_expander);2188	return rc;2189}2190 2191/**2192 * mpi3mr_expander_node_remove - recursive removal of expander.2193 * @mrioc: Adapter instance reference2194 * @sas_expander: Expander device object2195 *2196 * Removes expander object and freeing associated memory from2197 * the sas_expander_list and removes the same from SAS TL, if2198 * one of the attached device is an expander then it recursively2199 * removes the expander device too.2200 *2201 * Return nothing.2202 */2203void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,2204	struct mpi3mr_sas_node *sas_expander)2205{2206	struct mpi3mr_sas_port *mr_sas_port, *next;2207	unsigned long flags;2208	u8 port_id;2209 2210	/* remove sibling ports attached to this expander */2211	list_for_each_entry_safe(mr_sas_port, next,2212	   &sas_expander->sas_port_list, port_list) {2213		if (mrioc->reset_in_progress || mrioc->pci_err_recovery)2214			return;2215		if (mr_sas_port->remote_identify.device_type ==2216		    SAS_END_DEVICE)2217			mpi3mr_remove_device_by_sas_address(mrioc,2218			    mr_sas_port->remote_identify.sas_address,2219			    mr_sas_port->hba_port);2220		else if (mr_sas_port->remote_identify.device_type ==2221		    SAS_EDGE_EXPANDER_DEVICE ||2222		    mr_sas_port->remote_identify.device_type ==2223		    SAS_FANOUT_EXPANDER_DEVICE)2224			mpi3mr_expander_remove(mrioc,2225			    mr_sas_port->remote_identify.sas_address,2226			    mr_sas_port->hba_port);2227	}2228 2229	port_id = sas_expander->hba_port->port_id;2230	mpi3mr_sas_port_remove(mrioc, sas_expander->sas_address,2231	    sas_expander->sas_address_parent, sas_expander->hba_port);2232 2233	ioc_info(mrioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx), port:%d\n",2234	    sas_expander->handle, (unsigned long long)2235	    sas_expander->sas_address, port_id);2236 2237	spin_lock_irqsave(&mrioc->sas_node_lock, flags);2238	list_del(&sas_expander->list);2239	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);2240 2241	kfree(sas_expander->phy);2242	kfree(sas_expander);2243}2244 2245/**2246 * mpi3mr_expander_remove - Remove expander object2247 * @mrioc: Adapter instance reference2248 * @sas_address: Remove expander sas_address2249 * @hba_port: HBA port reference2250 *2251 * This function remove expander object, stored in2252 * mrioc->sas_expander_list and removes it from the SAS TL by2253 * calling mpi3mr_expander_node_remove().2254 *2255 * Return: None2256 */2257void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,2258	struct mpi3mr_hba_port *hba_port)2259{2260	struct mpi3mr_sas_node *sas_expander;2261	unsigned long flags;2262 2263	if (mrioc->reset_in_progress || mrioc->pci_err_recovery)2264		return;2265 2266	if (!hba_port)2267		return;2268 2269	spin_lock_irqsave(&mrioc->sas_node_lock, flags);2270	sas_expander = mpi3mr_expander_find_by_sas_address(mrioc, sas_address,2271	    hba_port);2272	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);2273	if (sas_expander)2274		mpi3mr_expander_node_remove(mrioc, sas_expander);2275 2276}2277 2278/**2279 * mpi3mr_get_sas_negotiated_logical_linkrate - get linkrate2280 * @mrioc: Adapter instance reference2281 * @tgtdev: Target device2282 *2283 * This function identifies whether the target device is2284 * attached directly or through expander and issues sas phy2285 * page0 or expander phy page1 and gets the link rate, if there2286 * is any failure in reading the pages then this returns link2287 * rate of 1.5.2288 *2289 * Return: logical link rate.2290 */2291static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc,2292	struct mpi3mr_tgt_dev *tgtdev)2293{2294	u8 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5, phy_number;2295	struct mpi3_sas_expander_page1 expander_pg1;2296	struct mpi3_sas_phy_page0 phy_pg0;2297	u32 phynum_handle;2298	u16 ioc_status;2299 2300	phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;2301	if (!(tgtdev->devpg0_flag & MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)) {2302		phynum_handle = ((phy_number<<MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT)2303				 | tgtdev->parent_handle);2304		if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status,2305		    &expander_pg1, sizeof(expander_pg1),2306		    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM,2307		    phynum_handle)) {2308			ioc_err(mrioc, "failure at %s:%d/%s()!\n",2309			    __FILE__, __LINE__, __func__);2310			goto out;2311		}2312		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {2313			ioc_err(mrioc, "failure at %s:%d/%s()!\n",2314			    __FILE__, __LINE__, __func__);2315			goto out;2316		}2317		link_rate = (expander_pg1.negotiated_link_rate &2318			     MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>2319			MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;2320		goto out;2321	}2322	if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,2323	    sizeof(struct mpi3_sas_phy_page0),2324	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy_number)) {2325		ioc_err(mrioc, "failure at %s:%d/%s()!\n",2326		    __FILE__, __LINE__, __func__);2327		goto out;2328	}2329	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {2330		ioc_err(mrioc, "failure at %s:%d/%s()!\n",2331		    __FILE__, __LINE__, __func__);2332		goto out;2333	}2334	link_rate = (phy_pg0.negotiated_link_rate &2335		     MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>2336		MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;2337out:2338	return link_rate;2339}2340 2341/**2342 * mpi3mr_report_tgtdev_to_sas_transport - expose dev to SAS TL2343 * @mrioc: Adapter instance reference2344 * @tgtdev: Target device2345 *2346 * This function exposes the target device after2347 * preparing host_phy, setting up link rate etc.2348 *2349 * Return: 0 on success, non-zero for failure.2350 */2351int mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc *mrioc,2352	struct mpi3mr_tgt_dev *tgtdev)2353{2354	int retval = 0;2355	u8 link_rate, parent_phy_number;2356	u64 sas_address_parent, sas_address;2357	struct mpi3mr_hba_port *hba_port;2358	u8 port_id;2359 2360	if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||2361	    !mrioc->sas_transport_enabled)2362		return -1;2363 2364	sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;2365	if (!mrioc->sas_hba.num_phys)2366		mpi3mr_sas_host_add(mrioc);2367	else2368		mpi3mr_sas_host_refresh(mrioc);2369 2370	if (mpi3mr_get_sas_address(mrioc, tgtdev->parent_handle,2371	    &sas_address_parent) != 0) {2372		ioc_err(mrioc, "failure at %s:%d/%s()!\n",2373		    __FILE__, __LINE__, __func__);2374		return -1;2375	}2376	tgtdev->dev_spec.sas_sata_inf.sas_address_parent = sas_address_parent;2377 2378	parent_phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;2379	port_id = tgtdev->io_unit_port;2380 2381	hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id);2382	if (!hba_port) {2383		ioc_err(mrioc, "failure at %s:%d/%s()!\n",2384		    __FILE__, __LINE__, __func__);2385		return -1;2386	}2387	tgtdev->dev_spec.sas_sata_inf.hba_port = hba_port;2388 2389	link_rate = mpi3mr_get_sas_negotiated_logical_linkrate(mrioc, tgtdev);2390 2391	mpi3mr_update_links(mrioc, sas_address_parent, tgtdev->dev_handle,2392	    parent_phy_number, link_rate, hba_port);2393 2394	tgtdev->host_exposed = 1;2395	if (!mpi3mr_sas_port_add(mrioc, tgtdev->dev_handle,2396	    sas_address_parent, hba_port)) {2397		retval = -1;2398		} else if ((!tgtdev->starget) && (!mrioc->is_driver_loading)) {2399			mpi3mr_sas_port_remove(mrioc, sas_address,2400			    sas_address_parent, hba_port);2401		retval = -1;2402	}2403	if (retval) {2404		tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;2405		tgtdev->host_exposed = 0;2406	}2407	return retval;2408}2409 2410/**2411 * mpi3mr_remove_tgtdev_from_sas_transport - remove from SAS TL2412 * @mrioc: Adapter instance reference2413 * @tgtdev: Target device2414 *2415 * This function removes the target device2416 *2417 * Return: None.2418 */2419void mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc *mrioc,2420	struct mpi3mr_tgt_dev *tgtdev)2421{2422	u64 sas_address_parent, sas_address;2423	struct mpi3mr_hba_port *hba_port;2424 2425	if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||2426	    !mrioc->sas_transport_enabled)2427		return;2428 2429	hba_port = tgtdev->dev_spec.sas_sata_inf.hba_port;2430	sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;2431	sas_address_parent = tgtdev->dev_spec.sas_sata_inf.sas_address_parent;2432	mpi3mr_sas_port_remove(mrioc, sas_address, sas_address_parent,2433	    hba_port);2434	tgtdev->host_exposed = 0;2435	tgtdev->dev_spec.sas_sata_inf.hba_port = NULL;2436}2437 2438/**2439 * mpi3mr_get_port_id_by_sas_phy -  Get port ID of the given phy2440 * @phy: SAS transport layer phy object2441 *2442 * Return: Port number for valid ID else 0xFFFF2443 */2444static inline u8 mpi3mr_get_port_id_by_sas_phy(struct sas_phy *phy)2445{2446	u8 port_id = 0xFF;2447	struct mpi3mr_hba_port *hba_port = phy->hostdata;2448 2449	if (hba_port)2450		port_id = hba_port->port_id;2451 2452	return port_id;2453}2454 2455/**2456 * mpi3mr_get_port_id_by_rphy - Get Port number from SAS rphy2457 *2458 * @mrioc: Adapter instance reference2459 * @rphy: SAS transport layer remote phy object2460 *2461 * Retrieves HBA port number in which the device pointed by the2462 * rphy object is attached with.2463 *2464 * Return: Valid port number on success else OxFFFF.2465 */2466static u8 mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc *mrioc, struct sas_rphy *rphy)2467{2468	struct mpi3mr_sas_node *sas_expander;2469	struct mpi3mr_tgt_dev *tgtdev;2470	unsigned long flags;2471	u8 port_id = 0xFF;2472 2473	if (!rphy)2474		return port_id;2475 2476	if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||2477	    rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) {2478		spin_lock_irqsave(&mrioc->sas_node_lock, flags);2479		list_for_each_entry(sas_expander, &mrioc->sas_expander_list,2480		    list) {2481			if (sas_expander->rphy == rphy) {2482				port_id = sas_expander->hba_port->port_id;2483				break;2484			}2485		}2486		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);2487	} else if (rphy->identify.device_type == SAS_END_DEVICE) {2488		spin_lock_irqsave(&mrioc->tgtdev_lock, flags);2489 2490		tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,2491			    rphy->identify.sas_address, rphy);2492		if (tgtdev && tgtdev->dev_spec.sas_sata_inf.hba_port) {2493			port_id =2494				tgtdev->dev_spec.sas_sata_inf.hba_port->port_id;2495			mpi3mr_tgtdev_put(tgtdev);2496		}2497		spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);2498	}2499	return port_id;2500}2501 2502static inline struct mpi3mr_ioc *phy_to_mrioc(struct sas_phy *phy)2503{2504	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);2505 2506	return shost_priv(shost);2507}2508 2509static inline struct mpi3mr_ioc *rphy_to_mrioc(struct sas_rphy *rphy)2510{2511	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);2512 2513	return shost_priv(shost);2514}2515 2516/* report phy error log structure */2517struct phy_error_log_request {2518	u8 smp_frame_type; /* 0x40 */2519	u8 function; /* 0x11 */2520	u8 allocated_response_length;2521	u8 request_length; /* 02 */2522	u8 reserved_1[5];2523	u8 phy_identifier;2524	u8 reserved_2[2];2525};2526 2527/* report phy error log reply structure */2528struct phy_error_log_reply {2529	u8 smp_frame_type; /* 0x41 */2530	u8 function; /* 0x11 */2531	u8 function_result;2532	u8 response_length;2533	__be16 expander_change_count;2534	u8 reserved_1[3];2535	u8 phy_identifier;2536	u8 reserved_2[2];2537	__be32 invalid_dword;2538	__be32 running_disparity_error;2539	__be32 loss_of_dword_sync;2540	__be32 phy_reset_problem;2541};2542 2543 2544/**2545 * mpi3mr_get_expander_phy_error_log - return expander counters:2546 * @mrioc: Adapter instance reference2547 * @phy: The SAS transport layer phy object2548 *2549 * Return: 0 for success, non-zero for failure.2550 *2551 */2552static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,2553	struct sas_phy *phy)2554{2555	struct mpi3_smp_passthrough_request mpi_request;2556	struct mpi3_smp_passthrough_reply mpi_reply;2557	struct phy_error_log_request *phy_error_log_request;2558	struct phy_error_log_reply *phy_error_log_reply;2559	int rc;2560	void *psge;2561	void *data_out = NULL;2562	dma_addr_t data_out_dma, data_in_dma;2563	u32 data_out_sz, data_in_sz, sz;2564	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;2565	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);2566	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);2567	u16 ioc_status;2568 2569	if (mrioc->reset_in_progress) {2570		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);2571		return -EFAULT;2572	}2573 2574	if (mrioc->pci_err_recovery) {2575		ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);2576		return -EFAULT;2577	}2578 2579	data_out_sz = sizeof(struct phy_error_log_request);2580	data_in_sz = sizeof(struct phy_error_log_reply);2581	sz = data_out_sz + data_in_sz;2582	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,2583	    GFP_KERNEL);2584	if (!data_out) {2585		rc = -ENOMEM;2586		goto out;2587	}2588 2589	data_in_dma = data_out_dma + data_out_sz;2590	phy_error_log_reply = data_out + data_out_sz;2591 2592	rc = -EINVAL;2593	memset(data_out, 0, sz);2594	phy_error_log_request = data_out;2595	phy_error_log_request->smp_frame_type = 0x40;2596	phy_error_log_request->function = 0x11;2597	phy_error_log_request->request_length = 2;2598	phy_error_log_request->allocated_response_length = 0;2599	phy_error_log_request->phy_identifier = phy->number;2600 2601	memset(&mpi_request, 0, request_sz);2602	memset(&mpi_reply, 0, reply_sz);2603	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);2604	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;2605	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);2606	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);2607 2608	psge = &mpi_request.request_sge;2609	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);2610 2611	psge = &mpi_request.response_sge;2612	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);2613 2614	dprint_transport_info(mrioc,2615	    "sending phy error log SMP request to sas_address(0x%016llx), phy_id(%d)\n",2616	    (unsigned long long)phy->identify.sas_address, phy->number);2617 2618	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,2619	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))2620		goto out;2621 2622	dprint_transport_info(mrioc,2623	    "phy error log SMP request completed with ioc_status(0x%04x)\n",2624	    ioc_status);2625 2626	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {2627		dprint_transport_info(mrioc,2628		    "phy error log - reply data transfer size(%d)\n",2629		    le16_to_cpu(mpi_reply.response_data_length));2630 2631		if (le16_to_cpu(mpi_reply.response_data_length) !=2632		    sizeof(struct phy_error_log_reply))2633			goto out;2634 2635		dprint_transport_info(mrioc,2636		    "phy error log - function_result(%d)\n",2637		    phy_error_log_reply->function_result);2638 2639		phy->invalid_dword_count =2640		    be32_to_cpu(phy_error_log_reply->invalid_dword);2641		phy->running_disparity_error_count =2642		    be32_to_cpu(phy_error_log_reply->running_disparity_error);2643		phy->loss_of_dword_sync_count =2644		    be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);2645		phy->phy_reset_problem_count =2646		    be32_to_cpu(phy_error_log_reply->phy_reset_problem);2647		rc = 0;2648	}2649 2650out:2651	if (data_out)2652		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,2653		    data_out_dma);2654 2655	return rc;2656}2657 2658/**2659 * mpi3mr_transport_get_linkerrors - return phy error counters2660 * @phy: The SAS transport layer phy object2661 *2662 * This function retrieves the phy error log information of the2663 * HBA or expander for which the phy belongs to2664 *2665 * Return: 0 for success, non-zero for failure.2666 */2667static int mpi3mr_transport_get_linkerrors(struct sas_phy *phy)2668{2669	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);2670	struct mpi3_sas_phy_page1 phy_pg1;2671	int rc = 0;2672	u16 ioc_status;2673 2674	rc = mpi3mr_parent_present(mrioc, phy);2675	if (rc)2676		return rc;2677 2678	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)2679		return mpi3mr_get_expander_phy_error_log(mrioc, phy);2680 2681	memset(&phy_pg1, 0, sizeof(struct mpi3_sas_phy_page1));2682	/* get hba phy error logs */2683	if ((mpi3mr_cfg_get_sas_phy_pg1(mrioc, &ioc_status, &phy_pg1,2684	    sizeof(struct mpi3_sas_phy_page1),2685	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number))) {2686		ioc_err(mrioc, "failure at %s:%d/%s()!\n",2687		    __FILE__, __LINE__, __func__);2688		return -ENXIO;2689	}2690 2691	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {2692		ioc_err(mrioc, "failure at %s:%d/%s()!\n",2693		    __FILE__, __LINE__, __func__);2694		return -ENXIO;2695	}2696	phy->invalid_dword_count = le32_to_cpu(phy_pg1.invalid_dword_count);2697	phy->running_disparity_error_count =2698		le32_to_cpu(phy_pg1.running_disparity_error_count);2699	phy->loss_of_dword_sync_count =2700		le32_to_cpu(phy_pg1.loss_dword_synch_count);2701	phy->phy_reset_problem_count =2702		le32_to_cpu(phy_pg1.phy_reset_problem_count);2703	return 0;2704}2705 2706/**2707 * mpi3mr_transport_get_enclosure_identifier - Get Enclosure ID2708 * @rphy: The SAS transport layer remote phy object2709 * @identifier: Enclosure identifier to be returned2710 *2711 * Returns the enclosure id for the device pointed by the remote2712 * phy object.2713 *2714 * Return: 0 on success or -ENXIO2715 */2716static int2717mpi3mr_transport_get_enclosure_identifier(struct sas_rphy *rphy,2718	u64 *identifier)2719{2720	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);2721	struct mpi3mr_tgt_dev *tgtdev = NULL;2722	unsigned long flags;2723	int rc;2724 2725	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);2726	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,2727	    rphy->identify.sas_address, rphy);2728	if (tgtdev) {2729		*identifier =2730			tgtdev->enclosure_logical_id;2731		rc = 0;2732		mpi3mr_tgtdev_put(tgtdev);2733	} else {2734		*identifier = 0;2735		rc = -ENXIO;2736	}2737	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);2738 2739	return rc;2740}2741 2742/**2743 * mpi3mr_transport_get_bay_identifier - Get bay ID2744 * @rphy: The SAS transport layer remote phy object2745 *2746 * Returns the slot id for the device pointed by the remote phy2747 * object.2748 *2749 * Return: Valid slot ID on success or -ENXIO2750 */2751static int2752mpi3mr_transport_get_bay_identifier(struct sas_rphy *rphy)2753{2754	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);2755	struct mpi3mr_tgt_dev *tgtdev = NULL;2756	unsigned long flags;2757	int rc;2758 2759	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);2760	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,2761	    rphy->identify.sas_address, rphy);2762	if (tgtdev) {2763		rc = tgtdev->slot;2764		mpi3mr_tgtdev_put(tgtdev);2765	} else2766		rc = -ENXIO;2767	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);2768 2769	return rc;2770}2771 2772/* phy control request structure */2773struct phy_control_request {2774	u8 smp_frame_type; /* 0x40 */2775	u8 function; /* 0x91 */2776	u8 allocated_response_length;2777	u8 request_length; /* 0x09 */2778	u16 expander_change_count;2779	u8 reserved_1[3];2780	u8 phy_identifier;2781	u8 phy_operation;2782	u8 reserved_2[13];2783	u64 attached_device_name;2784	u8 programmed_min_physical_link_rate;2785	u8 programmed_max_physical_link_rate;2786	u8 reserved_3[6];2787};2788 2789/* phy control reply structure */2790struct phy_control_reply {2791	u8 smp_frame_type; /* 0x41 */2792	u8 function; /* 0x11 */2793	u8 function_result;2794	u8 response_length;2795};2796 2797#define SMP_PHY_CONTROL_LINK_RESET	(0x01)2798#define SMP_PHY_CONTROL_HARD_RESET	(0x02)2799#define SMP_PHY_CONTROL_DISABLE		(0x03)2800 2801/**2802 * mpi3mr_expander_phy_control - expander phy control2803 * @mrioc: Adapter instance reference2804 * @phy: The SAS transport layer phy object2805 * @phy_operation: The phy operation to be executed2806 *2807 * Issues SMP passthru phy control request to execute a specific2808 * phy operation for a given expander device.2809 *2810 * Return: 0 for success, non-zero for failure.2811 */2812static int2813mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,2814	struct sas_phy *phy, u8 phy_operation)2815{2816	struct mpi3_smp_passthrough_request mpi_request;2817	struct mpi3_smp_passthrough_reply mpi_reply;2818	struct phy_control_request *phy_control_request;2819	struct phy_control_reply *phy_control_reply;2820	int rc;2821	void *psge;2822	void *data_out = NULL;2823	dma_addr_t data_out_dma;2824	dma_addr_t data_in_dma;2825	size_t data_in_sz;2826	size_t data_out_sz;2827	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;2828	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);2829	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);2830	u16 ioc_status;2831	u16 sz;2832 2833	if (mrioc->reset_in_progress) {2834		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);2835		return -EFAULT;2836	}2837 2838	if (mrioc->pci_err_recovery) {2839		ioc_err(mrioc, "%s: pci error recovery in progress!\n",2840		    __func__);2841		return -EFAULT;2842	}2843 2844	data_out_sz = sizeof(struct phy_control_request);2845	data_in_sz = sizeof(struct phy_control_reply);2846	sz = data_out_sz + data_in_sz;2847	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,2848	    GFP_KERNEL);2849	if (!data_out) {2850		rc = -ENOMEM;2851		goto out;2852	}2853 2854	data_in_dma = data_out_dma + data_out_sz;2855	phy_control_reply = data_out + data_out_sz;2856 2857	rc = -EINVAL;2858	memset(data_out, 0, sz);2859 2860	phy_control_request = data_out;2861	phy_control_request->smp_frame_type = 0x40;2862	phy_control_request->function = 0x91;2863	phy_control_request->request_length = 9;2864	phy_control_request->allocated_response_length = 0;2865	phy_control_request->phy_identifier = phy->number;2866	phy_control_request->phy_operation = phy_operation;2867	phy_control_request->programmed_min_physical_link_rate =2868	    phy->minimum_linkrate << 4;2869	phy_control_request->programmed_max_physical_link_rate =2870	    phy->maximum_linkrate << 4;2871 2872	memset(&mpi_request, 0, request_sz);2873	memset(&mpi_reply, 0, reply_sz);2874	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);2875	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;2876	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);2877	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);2878 2879	psge = &mpi_request.request_sge;2880	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);2881 2882	psge = &mpi_request.response_sge;2883	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);2884 2885	dprint_transport_info(mrioc,2886	    "sending phy control SMP request to sas_address(0x%016llx), phy_id(%d) opcode(%d)\n",2887	    (unsigned long long)phy->identify.sas_address, phy->number,2888	    phy_operation);2889 2890	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,2891	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))2892		goto out;2893 2894	dprint_transport_info(mrioc,2895	    "phy control SMP request completed with ioc_status(0x%04x)\n",2896	    ioc_status);2897 2898	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {2899		dprint_transport_info(mrioc,2900		    "phy control - reply data transfer size(%d)\n",2901		    le16_to_cpu(mpi_reply.response_data_length));2902 2903		if (le16_to_cpu(mpi_reply.response_data_length) !=2904		    sizeof(struct phy_control_reply))2905			goto out;2906		dprint_transport_info(mrioc,2907		    "phy control - function_result(%d)\n",2908		    phy_control_reply->function_result);2909		rc = 0;2910	}2911 out:2912	if (data_out)2913		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,2914		    data_out_dma);2915 2916	return rc;2917}2918 2919/**2920 * mpi3mr_transport_phy_reset - Reset a given phy2921 * @phy: The SAS transport layer phy object2922 * @hard_reset: Flag to indicate the type of reset2923 *2924 * Return: 0 for success, non-zero for failure.2925 */2926static int2927mpi3mr_transport_phy_reset(struct sas_phy *phy, int hard_reset)2928{2929	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);2930	struct mpi3_iounit_control_request mpi_request;2931	struct mpi3_iounit_control_reply mpi_reply;2932	u16 request_sz = sizeof(struct mpi3_iounit_control_request);2933	u16 reply_sz = sizeof(struct mpi3_iounit_control_reply);2934	int rc = 0;2935	u16 ioc_status;2936 2937	rc = mpi3mr_parent_present(mrioc, phy);2938	if (rc)2939		return rc;2940 2941	/* handle expander phys */2942	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)2943		return mpi3mr_expander_phy_control(mrioc, phy,2944		    (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :2945		    SMP_PHY_CONTROL_LINK_RESET);2946 2947	/* handle hba phys */2948	memset(&mpi_request, 0, request_sz);2949	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);2950	mpi_request.function = MPI3_FUNCTION_IO_UNIT_CONTROL;2951	mpi_request.operation = MPI3_CTRL_OP_SAS_PHY_CONTROL;2952	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_ACTION_INDEX] =2953		(hard_reset ? MPI3_CTRL_ACTION_HARD_RESET :2954		 MPI3_CTRL_ACTION_LINK_RESET);2955	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_PHY_INDEX] =2956		phy->number;2957 2958	dprint_transport_info(mrioc,2959	    "sending phy reset request to sas_address(0x%016llx), phy_id(%d) hard_reset(%d)\n",2960	    (unsigned long long)phy->identify.sas_address, phy->number,2961	    hard_reset);2962 2963	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,2964	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status)) {2965		rc = -EAGAIN;2966		goto out;2967	}2968 2969	dprint_transport_info(mrioc,2970	    "phy reset request completed with ioc_status(0x%04x)\n",2971	    ioc_status);2972out:2973	return rc;2974}2975 2976/**2977 * mpi3mr_transport_phy_enable - enable/disable phys2978 * @phy: The SAS transport layer phy object2979 * @enable: flag to enable/disable, enable phy when true2980 *2981 * This function enables/disables a given by executing required2982 * configuration page changes or expander phy control command2983 *2984 * Return: 0 for success, non-zero for failure.2985 */2986static int2987mpi3mr_transport_phy_enable(struct sas_phy *phy, int enable)2988{2989	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);2990	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;2991	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;2992	u16 sz;2993	int rc = 0;2994	int i, discovery_active;2995 2996	rc = mpi3mr_parent_present(mrioc, phy);2997	if (rc)2998		return rc;2999 3000	/* handle expander phys */3001	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)3002		return mpi3mr_expander_phy_control(mrioc, phy,3003		    (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :3004		    SMP_PHY_CONTROL_DISABLE);3005 3006	/* handle hba phys */3007	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) +3008		(mrioc->sas_hba.num_phys *3009		 sizeof(struct mpi3_sas_io_unit0_phy_data));3010	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);3011	if (!sas_io_unit_pg0) {3012		rc = -ENOMEM;3013		goto out;3014	}3015	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {3016		ioc_err(mrioc, "failure at %s:%d/%s()!\n",3017		    __FILE__, __LINE__, __func__);3018		rc = -ENXIO;3019		goto out;3020	}3021 3022	/* unable to enable/disable phys when discovery is active */3023	for (i = 0, discovery_active = 0; i < mrioc->sas_hba.num_phys ; i++) {3024		if (sas_io_unit_pg0->phy_data[i].port_flags &3025		    MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS) {3026			ioc_err(mrioc,3027			    "discovery is active on port = %d, phy = %d\n"3028			    "\tunable to enable/disable phys, try again later!\n",3029			    sas_io_unit_pg0->phy_data[i].io_unit_port, i);3030			discovery_active = 1;3031		}3032	}3033 3034	if (discovery_active) {3035		rc = -EAGAIN;3036		goto out;3037	}3038 3039	if ((sas_io_unit_pg0->phy_data[phy->number].phy_flags &3040	     (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |3041	      MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))) {3042		ioc_err(mrioc, "failure at %s:%d/%s()!\n",3043		    __FILE__, __LINE__, __func__);3044		rc = -ENXIO;3045		goto out;3046	}3047 3048	/* read sas_iounit page 1 */3049	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +3050		(mrioc->sas_hba.num_phys *3051		 sizeof(struct mpi3_sas_io_unit1_phy_data));3052	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);3053	if (!sas_io_unit_pg1) {3054		rc = -ENOMEM;3055		goto out;3056	}3057 3058	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {3059		ioc_err(mrioc, "failure at %s:%d/%s()!\n",3060		    __FILE__, __LINE__, __func__);3061		rc = -ENXIO;3062		goto out;3063	}3064 3065	if (enable)3066		sas_io_unit_pg1->phy_data[phy->number].phy_flags3067		    &= ~MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;3068	else3069		sas_io_unit_pg1->phy_data[phy->number].phy_flags3070		    |= MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;3071 3072	mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz);3073 3074	/* link reset */3075	if (enable)3076		mpi3mr_transport_phy_reset(phy, 0);3077 3078 out:3079	kfree(sas_io_unit_pg1);3080	kfree(sas_io_unit_pg0);3081	return rc;3082}3083 3084/**3085 * mpi3mr_transport_phy_speed - set phy min/max speed3086 * @phy: The SAS transport later phy object3087 * @rates: Rates defined as in sas_phy_linkrates3088 *3089 * This function sets the link rates given in the rates3090 * argument to the given phy by executing required configuration3091 * page changes or expander phy control command3092 *3093 * Return: 0 for success, non-zero for failure.3094 */3095static int3096mpi3mr_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)3097{3098	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);3099	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;3100	struct mpi3_sas_phy_page0 phy_pg0;3101	u16 sz, ioc_status;3102	int rc = 0;3103 3104	rc = mpi3mr_parent_present(mrioc, phy);3105	if (rc)3106		return rc;3107 3108	if (!rates->minimum_linkrate)3109		rates->minimum_linkrate = phy->minimum_linkrate;3110	else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)3111		rates->minimum_linkrate = phy->minimum_linkrate_hw;3112 3113	if (!rates->maximum_linkrate)3114		rates->maximum_linkrate = phy->maximum_linkrate;3115	else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)3116		rates->maximum_linkrate = phy->maximum_linkrate_hw;3117 3118	/* handle expander phys */3119	if (phy->identify.sas_address != mrioc->sas_hba.sas_address) {3120		phy->minimum_linkrate = rates->minimum_linkrate;3121		phy->maximum_linkrate = rates->maximum_linkrate;3122		return mpi3mr_expander_phy_control(mrioc, phy,3123		    SMP_PHY_CONTROL_LINK_RESET);3124	}3125 3126	/* handle hba phys */3127	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +3128		(mrioc->sas_hba.num_phys *3129		 sizeof(struct mpi3_sas_io_unit1_phy_data));3130	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);3131	if (!sas_io_unit_pg1) {3132		rc = -ENOMEM;3133		goto out;3134	}3135 3136	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {3137		ioc_err(mrioc, "failure at %s:%d/%s()!\n",3138		    __FILE__, __LINE__, __func__);3139		rc = -ENXIO;3140		goto out;3141	}3142 3143	sas_io_unit_pg1->phy_data[phy->number].max_min_link_rate =3144		(rates->minimum_linkrate + (rates->maximum_linkrate << 4));3145 3146	if (mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {3147		ioc_err(mrioc, "failure at %s:%d/%s()!\n",3148		    __FILE__, __LINE__, __func__);3149		rc = -ENXIO;3150		goto out;3151	}3152 3153	/* link reset */3154	mpi3mr_transport_phy_reset(phy, 0);3155 3156	/* read phy page 0, then update the rates in the sas transport phy */3157	if (!mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0,3158	    sizeof(struct mpi3_sas_phy_page0),3159	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number) &&3160	    (ioc_status == MPI3_IOCSTATUS_SUCCESS)) {3161		phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(3162		    phy_pg0.programmed_link_rate &3163		    MPI3_SAS_PRATE_MIN_RATE_MASK);3164		phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(3165		    phy_pg0.programmed_link_rate >> 4);3166		phy->negotiated_linkrate =3167			mpi3mr_convert_phy_link_rate(3168			    (phy_pg0.negotiated_link_rate &3169			    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK)3170			    >> MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);3171	}3172 3173out:3174	kfree(sas_io_unit_pg1);3175	return rc;3176}3177 3178/**3179 * mpi3mr_map_smp_buffer - map BSG dma buffer3180 * @dev: Generic device reference3181 * @buf: BSG buffer pointer3182 * @dma_addr: Physical address holder3183 * @dma_len: Mapped DMA buffer length.3184 * @p: Virtual address holder3185 *3186 * This function maps the DMAable buffer3187 *3188 * Return: 0 on success, non-zero on failure3189 */3190static int3191mpi3mr_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,3192		dma_addr_t *dma_addr, size_t *dma_len, void **p)3193{3194	/* Check if the request is split across multiple segments */3195	if (buf->sg_cnt > 1) {3196		*p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,3197				GFP_KERNEL);3198		if (!*p)3199			return -ENOMEM;3200		*dma_len = buf->payload_len;3201	} else {3202		if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))3203			return -ENOMEM;3204		*dma_addr = sg_dma_address(buf->sg_list);3205		*dma_len = sg_dma_len(buf->sg_list);3206		*p = NULL;3207	}3208 3209	return 0;3210}3211 3212/**3213 * mpi3mr_unmap_smp_buffer - unmap BSG dma buffer3214 * @dev: Generic device reference3215 * @buf: BSG buffer pointer3216 * @dma_addr: Physical address to be unmapped3217 * @p: Virtual address3218 *3219 * This function unmaps the DMAable buffer3220 */3221static void3222mpi3mr_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,3223		dma_addr_t dma_addr, void *p)3224{3225	if (p)3226		dma_free_coherent(dev, buf->payload_len, p, dma_addr);3227	else3228		dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);3229}3230 3231/**3232 * mpi3mr_transport_smp_handler - handler for smp passthru3233 * @job: BSG job reference3234 * @shost: SCSI host object reference3235 * @rphy: SAS transport rphy object pointing the expander3236 *3237 * This is used primarily by smp utils for sending the SMP3238 * commands to the expanders attached to the controller3239 */3240static void3241mpi3mr_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,3242	struct sas_rphy *rphy)3243{3244	struct mpi3mr_ioc *mrioc = shost_priv(shost);3245	struct mpi3_smp_passthrough_request mpi_request;3246	struct mpi3_smp_passthrough_reply mpi_reply;3247	int rc;3248	void *psge;3249	dma_addr_t dma_addr_in;3250	dma_addr_t dma_addr_out;3251	void *addr_in = NULL;3252	void *addr_out = NULL;3253	size_t dma_len_in;3254	size_t dma_len_out;3255	unsigned int reslen = 0;3256	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);3257	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);3258	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;3259	u16 ioc_status;3260 3261	if (mrioc->reset_in_progress) {3262		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);3263		rc = -EFAULT;3264		goto out;3265	}3266 3267	if (mrioc->pci_err_recovery) {3268		ioc_err(mrioc, "%s: pci error recovery in progress!\n", __func__);3269		rc = -EFAULT;3270		goto out;3271	}3272 3273	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,3274	    &dma_addr_out, &dma_len_out, &addr_out);3275	if (rc)3276		goto out;3277 3278	if (addr_out)3279		sg_copy_to_buffer(job->request_payload.sg_list,3280		    job->request_payload.sg_cnt, addr_out,3281		    job->request_payload.payload_len);3282 3283	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,3284			&dma_addr_in, &dma_len_in, &addr_in);3285	if (rc)3286		goto unmap_out;3287 3288	memset(&mpi_request, 0, request_sz);3289	memset(&mpi_reply, 0, reply_sz);3290	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);3291	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;3292	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_rphy(mrioc, rphy);3293	mpi_request.sas_address = ((rphy) ?3294	    cpu_to_le64(rphy->identify.sas_address) :3295	    cpu_to_le64(mrioc->sas_hba.sas_address));3296	psge = &mpi_request.request_sge;3297	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_out - 4, dma_addr_out);3298 3299	psge = &mpi_request.response_sge;3300	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_in - 4, dma_addr_in);3301 3302	dprint_transport_info(mrioc, "sending SMP request\n");3303 3304	rc = mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,3305				       &mpi_reply, reply_sz,3306				       MPI3MR_INTADMCMD_TIMEOUT, &ioc_status);3307	if (rc)3308		goto unmap_in;3309 3310	dprint_transport_info(mrioc,3311	    "SMP request completed with ioc_status(0x%04x)\n", ioc_status);3312 3313	dprint_transport_info(mrioc,3314		    "SMP request - reply data transfer size(%d)\n",3315		    le16_to_cpu(mpi_reply.response_data_length));3316 3317	memcpy(job->reply, &mpi_reply, reply_sz);3318	job->reply_len = reply_sz;3319	reslen = le16_to_cpu(mpi_reply.response_data_length);3320 3321	if (addr_in)3322		sg_copy_from_buffer(job->reply_payload.sg_list,3323				job->reply_payload.sg_cnt, addr_in,3324				job->reply_payload.payload_len);3325 3326	rc = 0;3327unmap_in:3328	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,3329			dma_addr_in, addr_in);3330unmap_out:3331	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->request_payload,3332			dma_addr_out, addr_out);3333out:3334	bsg_job_done(job, rc, reslen);3335}3336 3337struct sas_function_template mpi3mr_transport_functions = {3338	.get_linkerrors		= mpi3mr_transport_get_linkerrors,3339	.get_enclosure_identifier = mpi3mr_transport_get_enclosure_identifier,3340	.get_bay_identifier	= mpi3mr_transport_get_bay_identifier,3341	.phy_reset		= mpi3mr_transport_phy_reset,3342	.phy_enable		= mpi3mr_transport_phy_enable,3343	.set_phy_speed		= mpi3mr_transport_phy_speed,3344	.smp_handler		= mpi3mr_transport_smp_handler,3345};3346 3347struct scsi_transport_template *mpi3mr_transport_template;3348