From ccc59923ba8d44ecf7cb60135e9934bbb619da10 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 27 Oct 2020 18:38:43 +0530 Subject: scsi: mpt3sas: Handling HBA vSES device Each direct attached device will have a unique Port ID, but with an exception. HBA vSES may use the same Port ID of another direct attached device Port's ID. As a result, special handling is needed for vSES. Create a virtual_phy object when a new HBA vSES device is detected and add this virtual_phy object to vphys_list of port ID's hba_port object. When the HBA vSES device is removed then remove the corresponding virtual_phy object from its parent's hba_port's vphy_list and free this virtual_vphy object. In hba_port object add vphy_mask field to hold the list of HBA phy bits which are assigned to vSES devices. Also add vphy_list list to hold list of virtual_phy objects which holds the same portID of current hba_port's portID. Also, add a hba_vphy field in _sas_phy object to determine whether this _sas_phy object belongs to vSES device or not. - Allocate a virtual_phy object whenever a virtual phy is detected while processing the SASIOUnitPage0's phy data. And this allocated virtual_phy object to corresponding PortID's hba_port's vphy_list. - When a vSES device is added to the SML then initialize the corresponding virtual_phy objects's sas_address field with vSES device's SAS Address. - Free this virtual_phy object during driver unload time and when this vSES device is removed. Link: https://lore.kernel.org/r/20201027130847.9962-11-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_transport.c | 80 +++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 11 deletions(-) (limited to 'drivers/scsi/mpt3sas/mpt3sas_transport.c') diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index d52d8b3161f2..256dae106ec6 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -690,6 +690,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, struct _sas_device *sas_device = NULL; int i; struct sas_port *port; + struct virtual_phy *vphy = NULL; if (!hba_port) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -743,9 +744,20 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, continue; list_add_tail(&sas_node->phy[i].port_siblings, &mpt3sas_port->phy_list); - if (sas_node->handle <= ioc->sas_hba.num_phys) - hba_port->phy_mask |= (1 << i); mpt3sas_port->num_phys++; + if (sas_node->handle <= ioc->sas_hba.num_phys) { + if (!sas_node->phy[i].hba_vphy) { + hba_port->phy_mask |= (1 << i); + continue; + } + + vphy = mpt3sas_get_vphy_by_phy(ioc, hba_port, i); + if (!vphy) { + ioc_err(ioc, "failure at %s:%d/%s()!\n", + __FILE__, __LINE__, __func__); + goto out_fail; + } + } } if (!mpt3sas_port->num_phys) { @@ -795,8 +807,14 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { rphy = sas_end_device_alloc(port); sas_device->rphy = rphy; - if (sas_node->handle <= ioc->sas_hba.num_phys) - hba_port->sas_address = sas_device->sas_address; + if (sas_node->handle <= ioc->sas_hba.num_phys) { + if (!vphy) + hba_port->sas_address = + sas_device->sas_address; + else + vphy->sas_address = + sas_device->sas_address; + } } else { rphy = sas_expander_alloc(port, mpt3sas_port->remote_identify.device_type); @@ -866,6 +884,7 @@ mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, u8 found = 0; struct _sas_phy *mpt3sas_phy, *next_phy; struct hba_port *hba_port_next, *hba_port = NULL; + struct virtual_phy *vphy, *vphy_next = NULL; if (!port) return; @@ -894,17 +913,56 @@ mpt3sas_transport_port_remove(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, } if (sas_node->handle <= ioc->sas_hba.num_phys) { + if (port->vphys_mask) { + list_for_each_entry_safe(vphy, vphy_next, + &port->vphys_list, list) { + if (vphy->sas_address != sas_address) + continue; + ioc_info(ioc, + "remove vphy entry: %p of port:%p,from %d port's vphys list\n", + vphy, port, port->port_id); + port->vphys_mask &= ~vphy->phy_mask; + list_del(&vphy->list); + kfree(vphy); + } + } + list_for_each_entry_safe(hba_port, hba_port_next, &ioc->port_table_list, list) { if (hba_port != port) continue; - if (hba_port->sas_address != sas_address) - continue; - ioc_info(ioc, - "remove hba_port entry: %p port: %d from hba_port list\n", - hba_port, hba_port->port_id); - list_del(&hba_port->list); - kfree(hba_port); + /* + * Delete hba_port object if + * - hba_port object's sas address matches with current + * removed device's sas address and no vphy's + * associated with it. + * - Current removed device is a vSES device and + * none of the other direct attached device have + * this vSES device's port number (hence hba_port + * object sas_address field will be zero). + */ + if ((hba_port->sas_address == sas_address || + !hba_port->sas_address) && !hba_port->vphys_mask) { + ioc_info(ioc, + "remove hba_port entry: %p port: %d from hba_port list\n", + hba_port, hba_port->port_id); + list_del(&hba_port->list); + kfree(hba_port); + } else if (hba_port->sas_address == sas_address && + hba_port->vphys_mask) { + /* + * Current removed device is a non vSES device + * and a vSES device has the same port number + * as of current device's port number. Hence + * only clear the sas_address filed, don't + * delete the hba_port object. + */ + ioc_info(ioc, + "clearing sas_address from hba_port entry: %p port: %d from hba_port list\n", + hba_port, hba_port->port_id); + port->sas_address = 0; + } + break; } } -- cgit v1.2.3-59-g8ed1b