forked from mirrors/linux
		
	scsi: mpi3mr: Add helper functions to manage device's port
Add the following helper functions: - Update the host phys with STL - Remove the device's SAS port with STL Link: https://lore.kernel.org/r/20220804131226.16653-8-sreekanth.reddy@broadcom.com Reviewed-by: Himanshu Madhani <himanshu.madani@oracle.com> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
		
							parent
							
								
									125ad1e6b4
								
							
						
					
					
						commit
						42fc9fee11
					
				
					 3 changed files with 539 additions and 1 deletions
				
			
		|  | @ -570,12 +570,18 @@ struct mpi3mr_enclosure_node { | ||||||
|  * |  * | ||||||
|  * @sas_address: World wide unique SAS address |  * @sas_address: World wide unique SAS address | ||||||
|  * @dev_info: Device information bits |  * @dev_info: Device information bits | ||||||
|  |  * @sas_transport_attached: Is this device exposed to transport | ||||||
|  |  * @pend_sas_rphy_add: Flag to check device is in process of add | ||||||
|  * @hba_port: HBA port entry |  * @hba_port: HBA port entry | ||||||
|  |  * @rphy: SAS transport layer rphy object | ||||||
|  */ |  */ | ||||||
| struct tgt_dev_sas_sata { | struct tgt_dev_sas_sata { | ||||||
| 	u64 sas_address; | 	u64 sas_address; | ||||||
| 	u16 dev_info; | 	u16 dev_info; | ||||||
|  | 	u8 sas_transport_attached; | ||||||
|  | 	u8 pend_sas_rphy_add; | ||||||
| 	struct mpi3mr_hba_port *hba_port; | 	struct mpi3mr_hba_port *hba_port; | ||||||
|  | 	struct sas_rphy *rphy; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -1331,4 +1337,11 @@ int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc, | ||||||
| u8 mpi3mr_is_expander_device(u16 device_info); | u8 mpi3mr_is_expander_device(u16 device_info); | ||||||
| struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc, | struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc, | ||||||
| 	u8 port_id); | 	u8 port_id); | ||||||
|  | void mpi3mr_sas_host_refresh(struct mpi3mr_ioc *mrioc); | ||||||
|  | void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc); | ||||||
|  | void mpi3mr_update_links(struct mpi3mr_ioc *mrioc, | ||||||
|  | 	u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate, | ||||||
|  | 	struct mpi3mr_hba_port *hba_port); | ||||||
|  | void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc, | ||||||
|  | 	bool device_add); | ||||||
| #endif /*MPI3MR_H_INCLUDED*/ | #endif /*MPI3MR_H_INCLUDED*/ | ||||||
|  |  | ||||||
|  | @ -796,7 +796,7 @@ static void mpi3mr_set_io_divert_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc, | ||||||
|  * |  * | ||||||
|  * Return: None. |  * Return: None. | ||||||
|  */ |  */ | ||||||
| static void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc, | void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc, | ||||||
| 	bool device_add) | 	bool device_add) | ||||||
| { | { | ||||||
| 	ioc_notice(mrioc, "Device %s was in progress before the reset and\n", | 	ioc_notice(mrioc, "Device %s was in progress before the reset and\n", | ||||||
|  |  | ||||||
|  | @ -706,3 +706,528 @@ struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc, | ||||||
| 
 | 
 | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * mpi3mr_update_links - refreshing SAS phy link changes | ||||||
|  |  * @mrioc: Adapter instance reference | ||||||
|  |  * @sas_address_parent: SAS address of parent expander or host | ||||||
|  |  * @handle: Firmware device handle of attached device | ||||||
|  |  * @phy_number: Phy number | ||||||
|  |  * @link_rate: New link rate | ||||||
|  |  * @hba_port: HBA port entry | ||||||
|  |  * | ||||||
|  |  * Return: None. | ||||||
|  |  */ | ||||||
|  | void mpi3mr_update_links(struct mpi3mr_ioc *mrioc, | ||||||
|  | 	u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate, | ||||||
|  | 	struct mpi3mr_hba_port *hba_port) | ||||||
|  | { | ||||||
|  | 	unsigned long flags; | ||||||
|  | 	struct mpi3mr_sas_node *mr_sas_node; | ||||||
|  | 	struct mpi3mr_sas_phy *mr_sas_phy; | ||||||
|  | 
 | ||||||
|  | 	if (mrioc->reset_in_progress) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	spin_lock_irqsave(&mrioc->sas_node_lock, flags); | ||||||
|  | 	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc, | ||||||
|  | 	    sas_address_parent, hba_port); | ||||||
|  | 	if (!mr_sas_node) { | ||||||
|  | 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mr_sas_phy = &mr_sas_node->phy[phy_number]; | ||||||
|  | 	mr_sas_phy->attached_handle = handle; | ||||||
|  | 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | 	if (handle && (link_rate >= MPI3_SAS_NEG_LINK_RATE_1_5)) { | ||||||
|  | 		mpi3mr_set_identify(mrioc, handle, | ||||||
|  | 		    &mr_sas_phy->remote_identify); | ||||||
|  | 		mpi3mr_add_phy_to_an_existing_port(mrioc, mr_sas_node, | ||||||
|  | 		    mr_sas_phy, mr_sas_phy->remote_identify.sas_address, | ||||||
|  | 		    hba_port); | ||||||
|  | 	} else | ||||||
|  | 		memset(&mr_sas_phy->remote_identify, 0, sizeof(struct | ||||||
|  | 		    sas_identify)); | ||||||
|  | 
 | ||||||
|  | 	if (mr_sas_phy->phy) | ||||||
|  | 		mr_sas_phy->phy->negotiated_linkrate = | ||||||
|  | 		    mpi3mr_convert_phy_link_rate(link_rate); | ||||||
|  | 
 | ||||||
|  | 	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO)) | ||||||
|  | 		dev_info(&mr_sas_phy->phy->dev, | ||||||
|  | 		    "refresh: parent sas_address(0x%016llx),\n" | ||||||
|  | 		    "\tlink_rate(0x%02x), phy(%d)\n" | ||||||
|  | 		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n", | ||||||
|  | 		    (unsigned long long)sas_address_parent, | ||||||
|  | 		    link_rate, phy_number, handle, (unsigned long long) | ||||||
|  | 		    mr_sas_phy->remote_identify.sas_address); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * mpi3mr_sas_host_refresh - refreshing sas host object contents | ||||||
|  |  * @mrioc: Adapter instance reference | ||||||
|  |  * | ||||||
|  |  * This function refreshes the controllers phy information and | ||||||
|  |  * updates the SAS transport layer with updated information, | ||||||
|  |  * this is executed for each device addition or device info | ||||||
|  |  * change events | ||||||
|  |  * | ||||||
|  |  * Return: None. | ||||||
|  |  */ | ||||||
|  | void mpi3mr_sas_host_refresh(struct mpi3mr_ioc *mrioc) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	u8 link_rate; | ||||||
|  | 	u16 sz, port_id, attached_handle; | ||||||
|  | 	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL; | ||||||
|  | 
 | ||||||
|  | 	dprint_transport_info(mrioc, | ||||||
|  | 	    "updating handles for sas_host(0x%016llx)\n", | ||||||
|  | 	    (unsigned long long)mrioc->sas_hba.sas_address); | ||||||
|  | 
 | ||||||
|  | 	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) + | ||||||
|  | 	    (mrioc->sas_hba.num_phys * | ||||||
|  | 	     sizeof(struct mpi3_sas_io_unit0_phy_data)); | ||||||
|  | 	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL); | ||||||
|  | 	if (!sas_io_unit_pg0) | ||||||
|  | 		return; | ||||||
|  | 	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mrioc->sas_hba.handle = 0; | ||||||
|  | 	for (i = 0; i < mrioc->sas_hba.num_phys; i++) { | ||||||
|  | 		if (sas_io_unit_pg0->phy_data[i].phy_flags & | ||||||
|  | 		    (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY | | ||||||
|  | 		     MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY)) | ||||||
|  | 			continue; | ||||||
|  | 		link_rate = | ||||||
|  | 		    sas_io_unit_pg0->phy_data[i].negotiated_link_rate >> 4; | ||||||
|  | 		if (!mrioc->sas_hba.handle) | ||||||
|  | 			mrioc->sas_hba.handle = le16_to_cpu( | ||||||
|  | 			    sas_io_unit_pg0->phy_data[i].controller_dev_handle); | ||||||
|  | 		port_id = sas_io_unit_pg0->phy_data[i].io_unit_port; | ||||||
|  | 		if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id))) | ||||||
|  | 			if (!mpi3mr_alloc_hba_port(mrioc, port_id)) | ||||||
|  | 				goto out; | ||||||
|  | 
 | ||||||
|  | 		mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle; | ||||||
|  | 		attached_handle = le16_to_cpu( | ||||||
|  | 		    sas_io_unit_pg0->phy_data[i].attached_dev_handle); | ||||||
|  | 		if (attached_handle && link_rate < MPI3_SAS_NEG_LINK_RATE_1_5) | ||||||
|  | 			link_rate = MPI3_SAS_NEG_LINK_RATE_1_5; | ||||||
|  | 		mrioc->sas_hba.phy[i].hba_port = | ||||||
|  | 			mpi3mr_get_hba_port_by_id(mrioc, port_id); | ||||||
|  | 		mpi3mr_update_links(mrioc, mrioc->sas_hba.sas_address, | ||||||
|  | 		    attached_handle, i, link_rate, | ||||||
|  | 		    mrioc->sas_hba.phy[i].hba_port); | ||||||
|  | 	} | ||||||
|  |  out: | ||||||
|  | 	kfree(sas_io_unit_pg0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * mpi3mr_sas_host_add - create sas host object | ||||||
|  |  * @mrioc: Adapter instance reference | ||||||
|  |  * | ||||||
|  |  * This function creates the controllers phy information and | ||||||
|  |  * updates the SAS transport layer with updated information, | ||||||
|  |  * this is executed for first device addition or device info | ||||||
|  |  * change event. | ||||||
|  |  * | ||||||
|  |  * Return: None. | ||||||
|  |  */ | ||||||
|  | void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	u16 sz, num_phys = 1, port_id, ioc_status; | ||||||
|  | 	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL; | ||||||
|  | 	struct mpi3_sas_phy_page0 phy_pg0; | ||||||
|  | 	struct mpi3_device_page0 dev_pg0; | ||||||
|  | 	struct mpi3_enclosure_page0 encl_pg0; | ||||||
|  | 	struct mpi3_device0_sas_sata_format *sasinf; | ||||||
|  | 
 | ||||||
|  | 	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) + | ||||||
|  | 	    (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data)); | ||||||
|  | 	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL); | ||||||
|  | 	if (!sas_io_unit_pg0) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	num_phys = sas_io_unit_pg0->num_phys; | ||||||
|  | 	kfree(sas_io_unit_pg0); | ||||||
|  | 
 | ||||||
|  | 	mrioc->sas_hba.host_node = 1; | ||||||
|  | 	INIT_LIST_HEAD(&mrioc->sas_hba.sas_port_list); | ||||||
|  | 	mrioc->sas_hba.parent_dev = &mrioc->shost->shost_gendev; | ||||||
|  | 	mrioc->sas_hba.phy = kcalloc(num_phys, | ||||||
|  | 	    sizeof(struct mpi3mr_sas_phy), GFP_KERNEL); | ||||||
|  | 	if (!mrioc->sas_hba.phy) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	mrioc->sas_hba.num_phys = num_phys; | ||||||
|  | 
 | ||||||
|  | 	sz = offsetof(struct mpi3_sas_io_unit_page0, phy_data) + | ||||||
|  | 	    (num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data)); | ||||||
|  | 	sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL); | ||||||
|  | 	if (!sas_io_unit_pg0) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mrioc->sas_hba.handle = 0; | ||||||
|  | 	for (i = 0; i < mrioc->sas_hba.num_phys; i++) { | ||||||
|  | 		if (sas_io_unit_pg0->phy_data[i].phy_flags & | ||||||
|  | 		    (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY | | ||||||
|  | 		    MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY)) | ||||||
|  | 			continue; | ||||||
|  | 		if (mpi3mr_cfg_get_sas_phy_pg0(mrioc, &ioc_status, &phy_pg0, | ||||||
|  | 		    sizeof(struct mpi3_sas_phy_page0), | ||||||
|  | 		    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, i)) { | ||||||
|  | 			ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 			    __FILE__, __LINE__, __func__); | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { | ||||||
|  | 			ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 			    __FILE__, __LINE__, __func__); | ||||||
|  | 			goto out; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (!mrioc->sas_hba.handle) | ||||||
|  | 			mrioc->sas_hba.handle = le16_to_cpu( | ||||||
|  | 			    sas_io_unit_pg0->phy_data[i].controller_dev_handle); | ||||||
|  | 		port_id = sas_io_unit_pg0->phy_data[i].io_unit_port; | ||||||
|  | 
 | ||||||
|  | 		if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id))) | ||||||
|  | 			if (!mpi3mr_alloc_hba_port(mrioc, port_id)) | ||||||
|  | 				goto out; | ||||||
|  | 
 | ||||||
|  | 		mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle; | ||||||
|  | 		mrioc->sas_hba.phy[i].phy_id = i; | ||||||
|  | 		mrioc->sas_hba.phy[i].hba_port = | ||||||
|  | 		    mpi3mr_get_hba_port_by_id(mrioc, port_id); | ||||||
|  | 		mpi3mr_add_host_phy(mrioc, &mrioc->sas_hba.phy[i], | ||||||
|  | 		    phy_pg0, mrioc->sas_hba.parent_dev); | ||||||
|  | 	} | ||||||
|  | 	if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0, | ||||||
|  | 	    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, | ||||||
|  | 	    mrioc->sas_hba.handle))) { | ||||||
|  | 		ioc_err(mrioc, "%s: device page0 read failed\n", __func__); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { | ||||||
|  | 		ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n", | ||||||
|  | 		    mrioc->sas_hba.handle, ioc_status, __FILE__, __LINE__, | ||||||
|  | 		    __func__); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	mrioc->sas_hba.enclosure_handle = | ||||||
|  | 	    le16_to_cpu(dev_pg0.enclosure_handle); | ||||||
|  | 	sasinf = &dev_pg0.device_specific.sas_sata_format; | ||||||
|  | 	mrioc->sas_hba.sas_address = | ||||||
|  | 	    le64_to_cpu(sasinf->sas_address); | ||||||
|  | 	ioc_info(mrioc, | ||||||
|  | 	    "host_add: handle(0x%04x), sas_addr(0x%016llx), phys(%d)\n", | ||||||
|  | 	    mrioc->sas_hba.handle, | ||||||
|  | 	    (unsigned long long) mrioc->sas_hba.sas_address, | ||||||
|  | 	    mrioc->sas_hba.num_phys); | ||||||
|  | 
 | ||||||
|  | 	if (mrioc->sas_hba.enclosure_handle) { | ||||||
|  | 		if (!(mpi3mr_cfg_get_enclosure_pg0(mrioc, &ioc_status, | ||||||
|  | 		    &encl_pg0, sizeof(dev_pg0), | ||||||
|  | 		    MPI3_ENCLOS_PGAD_FORM_HANDLE, | ||||||
|  | 		    mrioc->sas_hba.enclosure_handle)) && | ||||||
|  | 		    (ioc_status == MPI3_IOCSTATUS_SUCCESS)) | ||||||
|  | 			mrioc->sas_hba.enclosure_logical_id = | ||||||
|  | 				le64_to_cpu(encl_pg0.enclosure_logical_id); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	kfree(sas_io_unit_pg0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * mpi3mr_sas_port_add - Expose the SAS device to the SAS TL | ||||||
|  |  * @mrioc: Adapter instance reference | ||||||
|  |  * @handle: Firmware device handle of the attached device | ||||||
|  |  * @sas_address_parent: sas address of parent expander or host | ||||||
|  |  * @hba_port: HBA port entry | ||||||
|  |  * | ||||||
|  |  * This function creates a new sas port object for the given end | ||||||
|  |  * device matching sas address and hba_port and adds it to the | ||||||
|  |  * sas_node's sas_port_list and expose the attached sas device | ||||||
|  |  * to the SAS transport layer through sas_rphy_add. | ||||||
|  |  * | ||||||
|  |  * Returns a valid mpi3mr_sas_port reference or NULL. | ||||||
|  |  */ | ||||||
|  | static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc, | ||||||
|  | 	u16 handle, u64 sas_address_parent, struct mpi3mr_hba_port *hba_port) | ||||||
|  | { | ||||||
|  | 	struct mpi3mr_sas_phy *mr_sas_phy, *next; | ||||||
|  | 	struct mpi3mr_sas_port *mr_sas_port; | ||||||
|  | 	unsigned long flags; | ||||||
|  | 	struct mpi3mr_sas_node *mr_sas_node; | ||||||
|  | 	struct sas_rphy *rphy; | ||||||
|  | 	struct mpi3mr_tgt_dev *tgtdev = NULL; | ||||||
|  | 	int i; | ||||||
|  | 	struct sas_port *port; | ||||||
|  | 
 | ||||||
|  | 	if (!hba_port) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mr_sas_port = kzalloc(sizeof(struct mpi3mr_sas_port), GFP_KERNEL); | ||||||
|  | 	if (!mr_sas_port) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	INIT_LIST_HEAD(&mr_sas_port->port_list); | ||||||
|  | 	INIT_LIST_HEAD(&mr_sas_port->phy_list); | ||||||
|  | 	spin_lock_irqsave(&mrioc->sas_node_lock, flags); | ||||||
|  | 	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc, | ||||||
|  | 	    sas_address_parent, hba_port); | ||||||
|  | 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | 
 | ||||||
|  | 	if (!mr_sas_node) { | ||||||
|  | 		ioc_err(mrioc, "%s:could not find parent sas_address(0x%016llx)!\n", | ||||||
|  | 		    __func__, (unsigned long long)sas_address_parent); | ||||||
|  | 		goto out_fail; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if ((mpi3mr_set_identify(mrioc, handle, | ||||||
|  | 	    &mr_sas_port->remote_identify))) { | ||||||
|  | 		ioc_err(mrioc,  "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		goto out_fail; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (mr_sas_port->remote_identify.device_type == SAS_PHY_UNUSED) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		goto out_fail; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mr_sas_port->hba_port = hba_port; | ||||||
|  | 	mpi3mr_sas_port_sanity_check(mrioc, mr_sas_node, | ||||||
|  | 	    mr_sas_port->remote_identify.sas_address, hba_port); | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < mr_sas_node->num_phys; i++) { | ||||||
|  | 		if ((mr_sas_node->phy[i].remote_identify.sas_address != | ||||||
|  | 		    mr_sas_port->remote_identify.sas_address) || | ||||||
|  | 		    (mr_sas_node->phy[i].hba_port != hba_port)) | ||||||
|  | 			continue; | ||||||
|  | 		list_add_tail(&mr_sas_node->phy[i].port_siblings, | ||||||
|  | 		    &mr_sas_port->phy_list); | ||||||
|  | 		mr_sas_port->num_phys++; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!mr_sas_port->num_phys) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		goto out_fail; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) { | ||||||
|  | 		tgtdev = mpi3mr_get_tgtdev_by_addr(mrioc, | ||||||
|  | 		    mr_sas_port->remote_identify.sas_address, | ||||||
|  | 		    mr_sas_port->hba_port); | ||||||
|  | 
 | ||||||
|  | 		if (!tgtdev) { | ||||||
|  | 			ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 			    __FILE__, __LINE__, __func__); | ||||||
|  | 			goto out_fail; | ||||||
|  | 		} | ||||||
|  | 		tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!mr_sas_node->parent_dev) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		goto out_fail; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	port = sas_port_alloc_num(mr_sas_node->parent_dev); | ||||||
|  | 	if ((sas_port_add(port))) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		goto out_fail; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry(mr_sas_phy, &mr_sas_port->phy_list, | ||||||
|  | 	    port_siblings) { | ||||||
|  | 		if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO)) | ||||||
|  | 			dev_info(&port->dev, | ||||||
|  | 			    "add: handle(0x%04x), sas_address(0x%016llx), phy(%d)\n", | ||||||
|  | 			    handle, (unsigned long long) | ||||||
|  | 			    mr_sas_port->remote_identify.sas_address, | ||||||
|  | 			    mr_sas_phy->phy_id); | ||||||
|  | 		sas_port_add_phy(port, mr_sas_phy->phy); | ||||||
|  | 		mr_sas_phy->phy_belongs_to_port = 1; | ||||||
|  | 		mr_sas_phy->hba_port = hba_port; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mr_sas_port->port = port; | ||||||
|  | 	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) { | ||||||
|  | 		rphy = sas_end_device_alloc(port); | ||||||
|  | 		tgtdev->dev_spec.sas_sata_inf.rphy = rphy; | ||||||
|  | 	} else { | ||||||
|  | 		rphy = sas_expander_alloc(port, | ||||||
|  | 		    mr_sas_port->remote_identify.device_type); | ||||||
|  | 	} | ||||||
|  | 	rphy->identify = mr_sas_port->remote_identify; | ||||||
|  | 
 | ||||||
|  | 	if (mrioc->current_event) | ||||||
|  | 		mrioc->current_event->pending_at_sml = 1; | ||||||
|  | 
 | ||||||
|  | 	if ((sas_rphy_add(rphy))) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 	} | ||||||
|  | 	if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) { | ||||||
|  | 		tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0; | ||||||
|  | 		tgtdev->dev_spec.sas_sata_inf.sas_transport_attached = 1; | ||||||
|  | 		mpi3mr_tgtdev_put(tgtdev); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	dev_info(&rphy->dev, | ||||||
|  | 	    "%s: added: handle(0x%04x), sas_address(0x%016llx)\n", | ||||||
|  | 	    __func__, handle, (unsigned long long) | ||||||
|  | 	    mr_sas_port->remote_identify.sas_address); | ||||||
|  | 
 | ||||||
|  | 	mr_sas_port->rphy = rphy; | ||||||
|  | 	spin_lock_irqsave(&mrioc->sas_node_lock, flags); | ||||||
|  | 	list_add_tail(&mr_sas_port->port_list, &mr_sas_node->sas_port_list); | ||||||
|  | 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | 
 | ||||||
|  | 	if (mrioc->current_event) { | ||||||
|  | 		mrioc->current_event->pending_at_sml = 0; | ||||||
|  | 		if (mrioc->current_event->discard) | ||||||
|  | 			mpi3mr_print_device_event_notice(mrioc, true); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return mr_sas_port; | ||||||
|  | 
 | ||||||
|  |  out_fail: | ||||||
|  | 	list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list, | ||||||
|  | 	    port_siblings) | ||||||
|  | 		list_del(&mr_sas_phy->port_siblings); | ||||||
|  | 	kfree(mr_sas_port); | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * mpi3mr_sas_port_remove - remove port from the list | ||||||
|  |  * @mrioc: Adapter instance reference | ||||||
|  |  * @sas_address: SAS address of attached device | ||||||
|  |  * @sas_address_parent: SAS address of parent expander or host | ||||||
|  |  * @hba_port: HBA port entry | ||||||
|  |  * | ||||||
|  |  * Removing object and freeing associated memory from the | ||||||
|  |  * sas_port_list. | ||||||
|  |  * | ||||||
|  |  * Return: None | ||||||
|  |  */ | ||||||
|  | static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address, | ||||||
|  | 	u64 sas_address_parent, struct mpi3mr_hba_port *hba_port) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	unsigned long flags; | ||||||
|  | 	struct mpi3mr_sas_port *mr_sas_port, *next; | ||||||
|  | 	struct mpi3mr_sas_node *mr_sas_node; | ||||||
|  | 	u8 found = 0; | ||||||
|  | 	struct mpi3mr_sas_phy *mr_sas_phy, *next_phy; | ||||||
|  | 	struct mpi3mr_hba_port *srch_port, *hba_port_next = NULL; | ||||||
|  | 
 | ||||||
|  | 	if (!hba_port) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	spin_lock_irqsave(&mrioc->sas_node_lock, flags); | ||||||
|  | 	mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc, | ||||||
|  | 	    sas_address_parent, hba_port); | ||||||
|  | 	if (!mr_sas_node) { | ||||||
|  | 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list, | ||||||
|  | 	    port_list) { | ||||||
|  | 		if (mr_sas_port->remote_identify.sas_address != sas_address) | ||||||
|  | 			continue; | ||||||
|  | 		if (mr_sas_port->hba_port != hba_port) | ||||||
|  | 			continue; | ||||||
|  | 		found = 1; | ||||||
|  | 		list_del(&mr_sas_port->port_list); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  |  out: | ||||||
|  | 	if (!found) { | ||||||
|  | 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (mr_sas_node->host_node) { | ||||||
|  | 		list_for_each_entry_safe(srch_port, hba_port_next, | ||||||
|  | 		    &mrioc->hba_port_table_list, list) { | ||||||
|  | 			if (srch_port != hba_port) | ||||||
|  | 				continue; | ||||||
|  | 			ioc_info(mrioc, | ||||||
|  | 			    "removing hba_port entry: %p port: %d from hba_port list\n", | ||||||
|  | 			    srch_port, srch_port->port_id); | ||||||
|  | 			list_del(&hba_port->list); | ||||||
|  | 			kfree(hba_port); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < mr_sas_node->num_phys; i++) { | ||||||
|  | 		if (mr_sas_node->phy[i].remote_identify.sas_address == | ||||||
|  | 		    sas_address) | ||||||
|  | 			memset(&mr_sas_node->phy[i].remote_identify, 0, | ||||||
|  | 			    sizeof(struct sas_identify)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | 
 | ||||||
|  | 	if (mrioc->current_event) | ||||||
|  | 		mrioc->current_event->pending_at_sml = 1; | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry_safe(mr_sas_phy, next_phy, | ||||||
|  | 	    &mr_sas_port->phy_list, port_siblings) { | ||||||
|  | 		if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO)) | ||||||
|  | 			dev_info(&mr_sas_port->port->dev, | ||||||
|  | 			    "remove: sas_address(0x%016llx), phy(%d)\n", | ||||||
|  | 			    (unsigned long long) | ||||||
|  | 			    mr_sas_port->remote_identify.sas_address, | ||||||
|  | 			    mr_sas_phy->phy_id); | ||||||
|  | 		mr_sas_phy->phy_belongs_to_port = 0; | ||||||
|  | 		if (!mrioc->stop_drv_processing) | ||||||
|  | 			sas_port_delete_phy(mr_sas_port->port, | ||||||
|  | 			    mr_sas_phy->phy); | ||||||
|  | 		list_del(&mr_sas_phy->port_siblings); | ||||||
|  | 	} | ||||||
|  | 	if (!mrioc->stop_drv_processing) | ||||||
|  | 		sas_port_delete(mr_sas_port->port); | ||||||
|  | 	ioc_info(mrioc, "%s: removed sas_address(0x%016llx)\n", | ||||||
|  | 	    __func__, (unsigned long long)sas_address); | ||||||
|  | 
 | ||||||
|  | 	if (mrioc->current_event) { | ||||||
|  | 		mrioc->current_event->pending_at_sml = 0; | ||||||
|  | 		if (mrioc->current_event->discard) | ||||||
|  | 			mpi3mr_print_device_event_notice(mrioc, false); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	kfree(mr_sas_port); | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Sreekanth Reddy
						Sreekanth Reddy