forked from mirrors/linux
		
	scsi: mpi3mr: Add expander devices to STL
Register/unregister the expander devices to SCSI Transport Layer(STL) whenever the corresponding expander is added/removed from topology. Link: https://lore.kernel.org/r/20220804131226.16653-10-sreekanth.reddy@broadcom.com Reviewed-by: Himanshu Madhani <himanshu.madhani@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
							
								
									c4723e68a0
								
							
						
					
					
						commit
						e22bae3066
					
				
					 3 changed files with 432 additions and 9 deletions
				
			
		|  | @ -1341,6 +1341,11 @@ int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc, | ||||||
| 	struct mpi3_driver_page1 *driver_pg1, u16 pg_sz); | 	struct mpi3_driver_page1 *driver_pg1, u16 pg_sz); | ||||||
| 
 | 
 | ||||||
| u8 mpi3mr_is_expander_device(u16 device_info); | u8 mpi3mr_is_expander_device(u16 device_info); | ||||||
|  | int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle); | ||||||
|  | void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address, | ||||||
|  | 	struct mpi3mr_hba_port *hba_port); | ||||||
|  | struct mpi3mr_sas_node *__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc | ||||||
|  | 	*mrioc, u16 handle); | ||||||
| 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_refresh(struct mpi3mr_ioc *mrioc); | ||||||
|  | @ -1348,6 +1353,8 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc); | ||||||
| void mpi3mr_update_links(struct mpi3mr_ioc *mrioc, | void mpi3mr_update_links(struct mpi3mr_ioc *mrioc, | ||||||
| 	u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate, | 	u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate, | ||||||
| 	struct mpi3mr_hba_port *hba_port); | 	struct mpi3mr_hba_port *hba_port); | ||||||
|  | void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc, | ||||||
|  | 	struct mpi3mr_tgt_dev *tgtdev); | ||||||
| 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); | ||||||
| #endif /*MPI3MR_H_INCLUDED*/ | #endif /*MPI3MR_H_INCLUDED*/ | ||||||
|  |  | ||||||
|  | @ -816,7 +816,7 @@ void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc, | ||||||
|  * |  * | ||||||
|  * Return: 0 on success, non zero on failure. |  * Return: 0 on success, non zero on failure. | ||||||
|  */ |  */ | ||||||
| static void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc, | void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc, | ||||||
| 	struct mpi3mr_tgt_dev *tgtdev) | 	struct mpi3mr_tgt_dev *tgtdev) | ||||||
| { | { | ||||||
| 	struct mpi3mr_stgt_priv_data *tgt_priv; | 	struct mpi3mr_stgt_priv_data *tgt_priv; | ||||||
|  | @ -1486,7 +1486,10 @@ static void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc, | ||||||
| 	int i; | 	int i; | ||||||
| 	u16 handle; | 	u16 handle; | ||||||
| 	u8 reason_code; | 	u8 reason_code; | ||||||
|  | 	u64 exp_sas_address = 0; | ||||||
|  | 	struct mpi3mr_hba_port *hba_port = NULL; | ||||||
| 	struct mpi3mr_tgt_dev *tgtdev = NULL; | 	struct mpi3mr_tgt_dev *tgtdev = NULL; | ||||||
|  | 	struct mpi3mr_sas_node *sas_expander = NULL; | ||||||
| 
 | 
 | ||||||
| 	mpi3mr_sastopochg_evt_debug(mrioc, event_data); | 	mpi3mr_sastopochg_evt_debug(mrioc, event_data); | ||||||
| 
 | 
 | ||||||
|  | @ -1516,6 +1519,13 @@ static void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc, | ||||||
| 		if (tgtdev) | 		if (tgtdev) | ||||||
| 			mpi3mr_tgtdev_put(tgtdev); | 			mpi3mr_tgtdev_put(tgtdev); | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	if (mrioc->sas_transport_enabled && (event_data->exp_status == | ||||||
|  | 	    MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING)) { | ||||||
|  | 		if (sas_expander) | ||||||
|  | 			mpi3mr_expander_remove(mrioc, exp_sas_address, | ||||||
|  | 			    hba_port); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  | @ -1736,7 +1746,8 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc, | ||||||
| 	struct mpi3mr_fwevt *fwevt) | 	struct mpi3mr_fwevt *fwevt) | ||||||
| { | { | ||||||
| 	struct mpi3_device_page0 *dev_pg0 = NULL; | 	struct mpi3_device_page0 *dev_pg0 = NULL; | ||||||
| 	u16 perst_id; | 	u16 perst_id, handle, dev_info; | ||||||
|  | 	struct mpi3_device0_sas_sata_format *sasinf = NULL; | ||||||
| 
 | 
 | ||||||
| 	mpi3mr_fwevt_del_from_list(mrioc, fwevt); | 	mpi3mr_fwevt_del_from_list(mrioc, fwevt); | ||||||
| 	mrioc->current_event = fwevt; | 	mrioc->current_event = fwevt; | ||||||
|  | @ -1750,10 +1761,23 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc, | ||||||
| 	switch (fwevt->event_id) { | 	switch (fwevt->event_id) { | ||||||
| 	case MPI3_EVENT_DEVICE_ADDED: | 	case MPI3_EVENT_DEVICE_ADDED: | ||||||
| 	{ | 	{ | ||||||
| 		struct mpi3_device_page0 *dev_pg0 = | 		dev_pg0 = (struct mpi3_device_page0 *)fwevt->event_data; | ||||||
| 		    (struct mpi3_device_page0 *)fwevt->event_data; | 		perst_id = le16_to_cpu(dev_pg0->persistent_id); | ||||||
| 		mpi3mr_report_tgtdev_to_host(mrioc, | 		handle = le16_to_cpu(dev_pg0->dev_handle); | ||||||
| 		    le16_to_cpu(dev_pg0->persistent_id)); | 		if (perst_id != MPI3_DEVICE0_PERSISTENTID_INVALID) | ||||||
|  | 			mpi3mr_report_tgtdev_to_host(mrioc, perst_id); | ||||||
|  | 		else if (mrioc->sas_transport_enabled && | ||||||
|  | 		    (dev_pg0->device_form == MPI3_DEVICE_DEVFORM_SAS_SATA)) { | ||||||
|  | 			sasinf = &dev_pg0->device_specific.sas_sata_format; | ||||||
|  | 			dev_info = le16_to_cpu(sasinf->device_info); | ||||||
|  | 			if (!mrioc->sas_hba.num_phys) | ||||||
|  | 				mpi3mr_sas_host_add(mrioc); | ||||||
|  | 			else | ||||||
|  | 				mpi3mr_sas_host_refresh(mrioc); | ||||||
|  | 
 | ||||||
|  | 			if (mpi3mr_is_expander_device(dev_info)) | ||||||
|  | 				mpi3mr_expander_add(mrioc, handle); | ||||||
|  | 		} | ||||||
| 		break; | 		break; | ||||||
| 	} | 	} | ||||||
| 	case MPI3_EVENT_DEVICE_INFO_CHANGED: | 	case MPI3_EVENT_DEVICE_INFO_CHANGED: | ||||||
|  |  | ||||||
|  | @ -21,7 +21,7 @@ | ||||||
|  * |  * | ||||||
|  * Return: Expander sas_node object reference or NULL |  * Return: Expander sas_node object reference or NULL | ||||||
|  */ |  */ | ||||||
| static struct mpi3mr_sas_node *__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc | struct mpi3mr_sas_node *__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc | ||||||
| 	*mrioc, u16 handle) | 	*mrioc, u16 handle) | ||||||
| { | { | ||||||
| 	struct mpi3mr_sas_node *sas_expander, *r; | 	struct mpi3mr_sas_node *sas_expander, *r; | ||||||
|  | @ -159,6 +159,45 @@ static struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc | ||||||
| 	return tgtdev; | 	return tgtdev; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * mpi3mr_remove_device_by_sas_address - remove the device | ||||||
|  |  * @mrioc: Adapter instance reference | ||||||
|  |  * @sas_address: SAS address of the device | ||||||
|  |  * @hba_port: HBA port entry | ||||||
|  |  * | ||||||
|  |  * This searches for target device using sas address and hba | ||||||
|  |  * port pointer then removes it from the OS. | ||||||
|  |  * | ||||||
|  |  * Return: None | ||||||
|  |  */ | ||||||
|  | static void mpi3mr_remove_device_by_sas_address(struct mpi3mr_ioc *mrioc, | ||||||
|  | 	u64 sas_address, struct mpi3mr_hba_port *hba_port) | ||||||
|  | { | ||||||
|  | 	struct mpi3mr_tgt_dev *tgtdev = NULL; | ||||||
|  | 	unsigned long flags; | ||||||
|  | 	u8 was_on_tgtdev_list = 0; | ||||||
|  | 
 | ||||||
|  | 	if (!hba_port) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags); | ||||||
|  | 	tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc, | ||||||
|  | 			 sas_address, hba_port); | ||||||
|  | 	if (tgtdev) { | ||||||
|  | 		if (!list_empty(&tgtdev->list)) { | ||||||
|  | 			list_del_init(&tgtdev->list); | ||||||
|  | 			was_on_tgtdev_list = 1; | ||||||
|  | 			mpi3mr_tgtdev_put(tgtdev); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); | ||||||
|  | 	if (was_on_tgtdev_list) { | ||||||
|  | 		if (tgtdev->host_exposed) | ||||||
|  | 			mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); | ||||||
|  | 		mpi3mr_tgtdev_put(tgtdev); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * mpi3mr_expander_find_by_sas_address - sas expander search |  * mpi3mr_expander_find_by_sas_address - sas expander search | ||||||
|  * @mrioc: Adapter instance reference |  * @mrioc: Adapter instance reference | ||||||
|  | @ -378,6 +417,34 @@ static void mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc *mrioc, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * mpi3mr_delete_sas_port - helper function to removing a port | ||||||
|  |  * @mrioc: Adapter instance reference | ||||||
|  |  * @mr_sas_port: Internal Port object | ||||||
|  |  * | ||||||
|  |  * Return: None. | ||||||
|  |  */ | ||||||
|  | static void  mpi3mr_delete_sas_port(struct mpi3mr_ioc *mrioc, | ||||||
|  | 	struct mpi3mr_sas_port *mr_sas_port) | ||||||
|  | { | ||||||
|  | 	u64 sas_address = mr_sas_port->remote_identify.sas_address; | ||||||
|  | 	struct mpi3mr_hba_port *hba_port = mr_sas_port->hba_port; | ||||||
|  | 	enum sas_device_type device_type = | ||||||
|  | 	    mr_sas_port->remote_identify.device_type; | ||||||
|  | 
 | ||||||
|  | 	dev_info(&mr_sas_port->port->dev, | ||||||
|  | 	    "remove: sas_address(0x%016llx)\n", | ||||||
|  | 	    (unsigned long long) sas_address); | ||||||
|  | 
 | ||||||
|  | 	if (device_type == SAS_END_DEVICE) | ||||||
|  | 		mpi3mr_remove_device_by_sas_address(mrioc, sas_address, | ||||||
|  | 		    hba_port); | ||||||
|  | 
 | ||||||
|  | 	else if (device_type == SAS_EDGE_EXPANDER_DEVICE || | ||||||
|  | 	    device_type == SAS_FANOUT_EXPANDER_DEVICE) | ||||||
|  | 		mpi3mr_expander_remove(mrioc, sas_address, hba_port); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  * mpi3mr_del_phy_from_an_existing_port - del phy from a port |  * mpi3mr_del_phy_from_an_existing_port - del phy from a port | ||||||
|  * @mrioc: Adapter instance reference |  * @mrioc: Adapter instance reference | ||||||
|  | @ -401,8 +468,12 @@ static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc, | ||||||
| 		    port_siblings) { | 		    port_siblings) { | ||||||
| 			if (srch_phy != mr_sas_phy) | 			if (srch_phy != mr_sas_phy) | ||||||
| 				continue; | 				continue; | ||||||
| 			mpi3mr_delete_sas_phy(mrioc, mr_sas_port, | 			if ((mr_sas_port->num_phys == 1) && | ||||||
| 			    mr_sas_phy); | 			    !mrioc->reset_in_progress) | ||||||
|  | 				mpi3mr_delete_sas_port(mrioc, mr_sas_port); | ||||||
|  | 			else | ||||||
|  | 				mpi3mr_delete_sas_phy(mrioc, mr_sas_port, | ||||||
|  | 				    mr_sas_phy); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | @ -1231,3 +1302,324 @@ static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address, | ||||||
| 
 | 
 | ||||||
| 	kfree(mr_sas_port); | 	kfree(mr_sas_port); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * mpi3mr_expander_node_add - insert an expander to the list. | ||||||
|  |  * @mrioc: Adapter instance reference | ||||||
|  |  * @sas_expander: Expander sas node | ||||||
|  |  * Context: This function will acquire sas_node_lock. | ||||||
|  |  * | ||||||
|  |  * Adding new object to the ioc->sas_expander_list. | ||||||
|  |  * | ||||||
|  |  * Return: None. | ||||||
|  |  */ | ||||||
|  | static void mpi3mr_expander_node_add(struct mpi3mr_ioc *mrioc, | ||||||
|  | 	struct mpi3mr_sas_node *sas_expander) | ||||||
|  | { | ||||||
|  | 	unsigned long flags; | ||||||
|  | 
 | ||||||
|  | 	spin_lock_irqsave(&mrioc->sas_node_lock, flags); | ||||||
|  | 	list_add_tail(&sas_expander->list, &mrioc->sas_expander_list); | ||||||
|  | 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * mpi3mr_expander_add -  Create expander object | ||||||
|  |  * @mrioc: Adapter instance reference | ||||||
|  |  * @handle: Expander firmware device handle | ||||||
|  |  * | ||||||
|  |  * This function creating expander object, stored in | ||||||
|  |  * sas_expander_list and expose it to the SAS transport | ||||||
|  |  * layer. | ||||||
|  |  * | ||||||
|  |  * Return: 0 for success, non-zero for failure. | ||||||
|  |  */ | ||||||
|  | int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle) | ||||||
|  | { | ||||||
|  | 	struct mpi3mr_sas_node *sas_expander; | ||||||
|  | 	struct mpi3mr_enclosure_node *enclosure_dev; | ||||||
|  | 	struct mpi3_sas_expander_page0 expander_pg0; | ||||||
|  | 	struct mpi3_sas_expander_page1 expander_pg1; | ||||||
|  | 	u16 ioc_status, parent_handle, temp_handle; | ||||||
|  | 	u64 sas_address, sas_address_parent = 0; | ||||||
|  | 	int i; | ||||||
|  | 	unsigned long flags; | ||||||
|  | 	u8 port_id, link_rate; | ||||||
|  | 	struct mpi3mr_sas_port *mr_sas_port = NULL; | ||||||
|  | 	struct mpi3mr_hba_port *hba_port; | ||||||
|  | 	u32 phynum_handle; | ||||||
|  | 	int rc = 0; | ||||||
|  | 
 | ||||||
|  | 	if (!handle) | ||||||
|  | 		return -1; | ||||||
|  | 
 | ||||||
|  | 	if (mrioc->reset_in_progress) | ||||||
|  | 		return -1; | ||||||
|  | 
 | ||||||
|  | 	if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0, | ||||||
|  | 	    sizeof(expander_pg0), MPI3_SAS_EXPAND_PGAD_FORM_HANDLE, handle))) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	parent_handle = le16_to_cpu(expander_pg0.parent_dev_handle); | ||||||
|  | 	if (mpi3mr_get_sas_address(mrioc, parent_handle, &sas_address_parent) | ||||||
|  | 	    != 0) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	port_id = expander_pg0.io_unit_port; | ||||||
|  | 	hba_port = mpi3mr_get_hba_port_by_id(mrioc, port_id); | ||||||
|  | 	if (!hba_port) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		return -1; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (sas_address_parent != mrioc->sas_hba.sas_address) { | ||||||
|  | 		spin_lock_irqsave(&mrioc->sas_node_lock, flags); | ||||||
|  | 		sas_expander = | ||||||
|  | 		   mpi3mr_expander_find_by_sas_address(mrioc, | ||||||
|  | 		    sas_address_parent, hba_port); | ||||||
|  | 		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | 		if (!sas_expander) { | ||||||
|  | 			rc = mpi3mr_expander_add(mrioc, parent_handle); | ||||||
|  | 			if (rc != 0) | ||||||
|  | 				return rc; | ||||||
|  | 		} else { | ||||||
|  | 			/*
 | ||||||
|  | 			 * When there is a parent expander present, update it's | ||||||
|  | 			 * phys where child expander is connected with the link | ||||||
|  | 			 * speed, attached dev handle and sas address. | ||||||
|  | 			 */ | ||||||
|  | 			for (i = 0 ; i < sas_expander->num_phys ; i++) { | ||||||
|  | 				phynum_handle = | ||||||
|  | 				    (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | | ||||||
|  | 				    parent_handle; | ||||||
|  | 				if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, | ||||||
|  | 				    &ioc_status, &expander_pg1, | ||||||
|  | 				    sizeof(expander_pg1), | ||||||
|  | 				    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM, | ||||||
|  | 				    phynum_handle)) { | ||||||
|  | 					ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 					    __FILE__, __LINE__, __func__); | ||||||
|  | 					rc = -1; | ||||||
|  | 					return rc; | ||||||
|  | 				} | ||||||
|  | 				if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { | ||||||
|  | 					ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 					    __FILE__, __LINE__, __func__); | ||||||
|  | 					rc = -1; | ||||||
|  | 					return rc; | ||||||
|  | 				} | ||||||
|  | 				temp_handle = le16_to_cpu( | ||||||
|  | 				    expander_pg1.attached_dev_handle); | ||||||
|  | 				if (temp_handle != handle) | ||||||
|  | 					continue; | ||||||
|  | 				link_rate = (expander_pg1.negotiated_link_rate & | ||||||
|  | 				    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >> | ||||||
|  | 				    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT; | ||||||
|  | 				mpi3mr_update_links(mrioc, sas_address_parent, | ||||||
|  | 				    handle, i, link_rate, hba_port); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	spin_lock_irqsave(&mrioc->sas_node_lock, flags); | ||||||
|  | 	sas_address = le64_to_cpu(expander_pg0.sas_address); | ||||||
|  | 	sas_expander = mpi3mr_expander_find_by_sas_address(mrioc, | ||||||
|  | 	    sas_address, hba_port); | ||||||
|  | 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | 
 | ||||||
|  | 	if (sas_expander) | ||||||
|  | 		return 0; | ||||||
|  | 
 | ||||||
|  | 	sas_expander = kzalloc(sizeof(struct mpi3mr_sas_node), | ||||||
|  | 	    GFP_KERNEL); | ||||||
|  | 	if (!sas_expander) | ||||||
|  | 		return -1; | ||||||
|  | 
 | ||||||
|  | 	sas_expander->handle = handle; | ||||||
|  | 	sas_expander->num_phys = expander_pg0.num_phys; | ||||||
|  | 	sas_expander->sas_address_parent = sas_address_parent; | ||||||
|  | 	sas_expander->sas_address = sas_address; | ||||||
|  | 	sas_expander->hba_port = hba_port; | ||||||
|  | 
 | ||||||
|  | 	ioc_info(mrioc, | ||||||
|  | 	    "expander_add: handle(0x%04x), parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", | ||||||
|  | 	    handle, parent_handle, (unsigned long long) | ||||||
|  | 	    sas_expander->sas_address, sas_expander->num_phys); | ||||||
|  | 
 | ||||||
|  | 	if (!sas_expander->num_phys) { | ||||||
|  | 		rc = -1; | ||||||
|  | 		goto out_fail; | ||||||
|  | 	} | ||||||
|  | 	sas_expander->phy = kcalloc(sas_expander->num_phys, | ||||||
|  | 	    sizeof(struct mpi3mr_sas_phy), GFP_KERNEL); | ||||||
|  | 	if (!sas_expander->phy) { | ||||||
|  | 		rc = -1; | ||||||
|  | 		goto out_fail; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	INIT_LIST_HEAD(&sas_expander->sas_port_list); | ||||||
|  | 	mr_sas_port = mpi3mr_sas_port_add(mrioc, handle, sas_address_parent, | ||||||
|  | 	    sas_expander->hba_port); | ||||||
|  | 	if (!mr_sas_port) { | ||||||
|  | 		ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 		    __FILE__, __LINE__, __func__); | ||||||
|  | 		rc = -1; | ||||||
|  | 		goto out_fail; | ||||||
|  | 	} | ||||||
|  | 	sas_expander->parent_dev = &mr_sas_port->rphy->dev; | ||||||
|  | 	sas_expander->rphy = mr_sas_port->rphy; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0 ; i < sas_expander->num_phys ; i++) { | ||||||
|  | 		phynum_handle = (i << MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | | ||||||
|  | 		    handle; | ||||||
|  | 		if (mpi3mr_cfg_get_sas_exp_pg1(mrioc, &ioc_status, | ||||||
|  | 		    &expander_pg1, sizeof(expander_pg1), | ||||||
|  | 		    MPI3_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM, | ||||||
|  | 		    phynum_handle)) { | ||||||
|  | 			ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 			    __FILE__, __LINE__, __func__); | ||||||
|  | 			rc = -1; | ||||||
|  | 			goto out_fail; | ||||||
|  | 		} | ||||||
|  | 		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) { | ||||||
|  | 			ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 			    __FILE__, __LINE__, __func__); | ||||||
|  | 			rc = -1; | ||||||
|  | 			goto out_fail; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		sas_expander->phy[i].handle = handle; | ||||||
|  | 		sas_expander->phy[i].phy_id = i; | ||||||
|  | 		sas_expander->phy[i].hba_port = hba_port; | ||||||
|  | 
 | ||||||
|  | 		if ((mpi3mr_add_expander_phy(mrioc, &sas_expander->phy[i], | ||||||
|  | 		    expander_pg1, sas_expander->parent_dev))) { | ||||||
|  | 			ioc_err(mrioc, "failure at %s:%d/%s()!\n", | ||||||
|  | 			    __FILE__, __LINE__, __func__); | ||||||
|  | 			rc = -1; | ||||||
|  | 			goto out_fail; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (sas_expander->enclosure_handle) { | ||||||
|  | 		enclosure_dev = | ||||||
|  | 			mpi3mr_enclosure_find_by_handle(mrioc, | ||||||
|  | 						sas_expander->enclosure_handle); | ||||||
|  | 		if (enclosure_dev) | ||||||
|  | 			sas_expander->enclosure_logical_id = le64_to_cpu( | ||||||
|  | 			    enclosure_dev->pg0.enclosure_logical_id); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	mpi3mr_expander_node_add(mrioc, sas_expander); | ||||||
|  | 	return 0; | ||||||
|  | 
 | ||||||
|  | out_fail: | ||||||
|  | 
 | ||||||
|  | 	if (mr_sas_port) | ||||||
|  | 		mpi3mr_sas_port_remove(mrioc, | ||||||
|  | 		    sas_expander->sas_address, | ||||||
|  | 		    sas_address_parent, sas_expander->hba_port); | ||||||
|  | 	kfree(sas_expander->phy); | ||||||
|  | 	kfree(sas_expander); | ||||||
|  | 	return rc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * mpi3mr_expander_node_remove - recursive removal of expander. | ||||||
|  |  * @mrioc: Adapter instance reference | ||||||
|  |  * @sas_expander: Expander device object | ||||||
|  |  * | ||||||
|  |  * Removes expander object and freeing associated memory from | ||||||
|  |  * the sas_expander_list and removes the same from SAS TL, if | ||||||
|  |  * one of the attached device is an expander then it recursively | ||||||
|  |  * removes the expander device too. | ||||||
|  |  * | ||||||
|  |  * Return nothing. | ||||||
|  |  */ | ||||||
|  | static void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc, | ||||||
|  | 	struct mpi3mr_sas_node *sas_expander) | ||||||
|  | { | ||||||
|  | 	struct mpi3mr_sas_port *mr_sas_port, *next; | ||||||
|  | 	unsigned long flags; | ||||||
|  | 	u8 port_id; | ||||||
|  | 
 | ||||||
|  | 	/* remove sibling ports attached to this expander */ | ||||||
|  | 	list_for_each_entry_safe(mr_sas_port, next, | ||||||
|  | 	   &sas_expander->sas_port_list, port_list) { | ||||||
|  | 		if (mrioc->reset_in_progress) | ||||||
|  | 			return; | ||||||
|  | 		if (mr_sas_port->remote_identify.device_type == | ||||||
|  | 		    SAS_END_DEVICE) | ||||||
|  | 			mpi3mr_remove_device_by_sas_address(mrioc, | ||||||
|  | 			    mr_sas_port->remote_identify.sas_address, | ||||||
|  | 			    mr_sas_port->hba_port); | ||||||
|  | 		else if (mr_sas_port->remote_identify.device_type == | ||||||
|  | 		    SAS_EDGE_EXPANDER_DEVICE || | ||||||
|  | 		    mr_sas_port->remote_identify.device_type == | ||||||
|  | 		    SAS_FANOUT_EXPANDER_DEVICE) | ||||||
|  | 			mpi3mr_expander_remove(mrioc, | ||||||
|  | 			    mr_sas_port->remote_identify.sas_address, | ||||||
|  | 			    mr_sas_port->hba_port); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	port_id = sas_expander->hba_port->port_id; | ||||||
|  | 	mpi3mr_sas_port_remove(mrioc, sas_expander->sas_address, | ||||||
|  | 	    sas_expander->sas_address_parent, sas_expander->hba_port); | ||||||
|  | 
 | ||||||
|  | 	ioc_info(mrioc, "expander_remove: handle(0x%04x), sas_addr(0x%016llx), port:%d\n", | ||||||
|  | 	    sas_expander->handle, (unsigned long long) | ||||||
|  | 	    sas_expander->sas_address, port_id); | ||||||
|  | 
 | ||||||
|  | 	spin_lock_irqsave(&mrioc->sas_node_lock, flags); | ||||||
|  | 	list_del(&sas_expander->list); | ||||||
|  | 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | 
 | ||||||
|  | 	kfree(sas_expander->phy); | ||||||
|  | 	kfree(sas_expander); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * mpi3mr_expander_remove - Remove expander object | ||||||
|  |  * @mrioc: Adapter instance reference | ||||||
|  |  * @sas_address: Remove expander sas_address | ||||||
|  |  * @hba_port: HBA port reference | ||||||
|  |  * | ||||||
|  |  * This function remove expander object, stored in | ||||||
|  |  * mrioc->sas_expander_list and removes it from the SAS TL by | ||||||
|  |  * calling mpi3mr_expander_node_remove(). | ||||||
|  |  * | ||||||
|  |  * Return: None | ||||||
|  |  */ | ||||||
|  | void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address, | ||||||
|  | 	struct mpi3mr_hba_port *hba_port) | ||||||
|  | { | ||||||
|  | 	struct mpi3mr_sas_node *sas_expander; | ||||||
|  | 	unsigned long flags; | ||||||
|  | 
 | ||||||
|  | 	if (mrioc->reset_in_progress) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	if (!hba_port) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	spin_lock_irqsave(&mrioc->sas_node_lock, flags); | ||||||
|  | 	sas_expander = mpi3mr_expander_find_by_sas_address(mrioc, sas_address, | ||||||
|  | 	    hba_port); | ||||||
|  | 	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); | ||||||
|  | 	if (sas_expander) | ||||||
|  | 		mpi3mr_expander_node_remove(mrioc, sas_expander); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Sreekanth Reddy
						Sreekanth Reddy