mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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,6 +468,10 @@ 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;
 | 
				
			||||||
 | 
								if ((mr_sas_port->num_phys == 1) &&
 | 
				
			||||||
 | 
								    !mrioc->reset_in_progress)
 | 
				
			||||||
 | 
									mpi3mr_delete_sas_port(mrioc, mr_sas_port);
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
				mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
 | 
									mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
 | 
				
			||||||
				    mr_sas_phy);
 | 
									    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