Message ID | 20220804131226.16653-7-sreekanth.reddy@broadcom.com |
---|---|
State | New |
Headers | show |
Series | mpi3mr: Added Support for SAS Transport | expand |
> On Aug 4, 2022, at 6:12 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote: > > Added below helper functions, > - Get the device's sas address by reading > correspond device's Device page0, > - Get the expander object from expander list based > on expander's handle, > - Get the target device object from target device list > based on device's sas address, > - Get the expander device object from expander list > based on expanders's sas address, > - Get hba port object from hba port table list > based on port's port id > > Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com> > --- > drivers/scsi/mpi3mr/mpi3mr.h | 14 ++ > drivers/scsi/mpi3mr/mpi3mr_os.c | 3 + > drivers/scsi/mpi3mr/mpi3mr_transport.c | 278 +++++++++++++++++++++++++ > 3 files changed, 295 insertions(+) > > diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h > index 006bc5d..742caf5 100644 > --- a/drivers/scsi/mpi3mr/mpi3mr.h > +++ b/drivers/scsi/mpi3mr/mpi3mr.h > @@ -570,10 +570,12 @@ struct mpi3mr_enclosure_node { > * > * @sas_address: World wide unique SAS address > * @dev_info: Device information bits > + * @hba_port: HBA port entry > */ > struct tgt_dev_sas_sata { > u64 sas_address; > u16 dev_info; > + struct mpi3mr_hba_port *hba_port; > }; > > /** > @@ -984,6 +986,10 @@ struct scmd_priv { > * @cfg_page: Default memory for configuration pages > * @cfg_page_dma: Configuration page DMA address > * @cfg_page_sz: Default configuration page memory size > + * @sas_hba: SAS node for the controller > + * @sas_expander_list: SAS node list of expanders > + * @sas_node_lock: Lock to protect SAS node list > + * @hba_port_table_list: List of HBA Ports > * @enclosure_list: List of Enclosure objects > */ > struct mpi3mr_ioc { > @@ -1162,6 +1168,10 @@ struct mpi3mr_ioc { > dma_addr_t cfg_page_dma; > u16 cfg_page_sz; > > + struct mpi3mr_sas_node sas_hba; > + struct list_head sas_expander_list; > + spinlock_t sas_node_lock; > + struct list_head hba_port_table_list; > struct list_head enclosure_list; > }; > > @@ -1317,4 +1327,8 @@ int mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc, > struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz); > int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc, > struct mpi3_driver_page1 *driver_pg1, u16 pg_sz); > + > +u8 mpi3mr_is_expander_device(u16 device_info); > +struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc, > + u8 port_id); > #endif /*MPI3MR_H_INCLUDED*/ > diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c > index ca718cb..b75ce73 100644 > --- a/drivers/scsi/mpi3mr/mpi3mr_os.c > +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c > @@ -4692,11 +4692,14 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) > spin_lock_init(&mrioc->tgtdev_lock); > spin_lock_init(&mrioc->watchdog_lock); > spin_lock_init(&mrioc->chain_buf_lock); > + spin_lock_init(&mrioc->sas_node_lock); > > INIT_LIST_HEAD(&mrioc->fwevt_list); > INIT_LIST_HEAD(&mrioc->tgtdev_list); > INIT_LIST_HEAD(&mrioc->delayed_rmhs_list); > INIT_LIST_HEAD(&mrioc->delayed_evtack_cmds_list); > + INIT_LIST_HEAD(&mrioc->sas_expander_list); > + INIT_LIST_HEAD(&mrioc->hba_port_table_list); > INIT_LIST_HEAD(&mrioc->enclosure_list); > > mutex_init(&mrioc->reset_mutex); > diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c > index 8c76bf5..f1da7ef 100644 > --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c > +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c > @@ -9,6 +9,236 @@ > > #include "mpi3mr.h" > > +/** > + * __mpi3mr_expander_find_by_handle - expander search by handle > + * @mrioc: Adapter instance reference > + * @handle: Firmware device handle of the expander > + * > + * Context: The caller should acquire sas_node_lock > + * > + * This searches for expander device based on handle, then > + * returns the sas_node object. > + * > + * Return: Expander sas_node object reference or NULL > + */ > +static struct mpi3mr_sas_node *__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc > + *mrioc, u16 handle) > +{ > + struct mpi3mr_sas_node *sas_expander, *r; > + > + r = NULL; > + list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) { > + if (sas_expander->handle != handle) > + continue; > + r = sas_expander; > + goto out; > + } > + out: > + return r; > +} > + > +/** > + * mpi3mr_is_expander_device - if device is an expander > + * @device_info: Bitfield providing information about the device > + * > + * Return: 1 if the device is expander device, else 0. > + */ > +u8 mpi3mr_is_expander_device(u16 device_info) > +{ > + if ((device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) == > + MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER) > + return 1; > + else > + return 0; > +} > + > +/** > + * mpi3mr_get_sas_address - retrieve sas_address for handle > + * @mrioc: Adapter instance reference > + * @handle: Firmware device handle > + * @sas_address: Address to hold sas address > + * > + * This function issues device page0 read for a given device > + * handle and gets the SAS address and return it back > + * > + * Return: 0 for success, non-zero for failure > + */ > +static int mpi3mr_get_sas_address(struct mpi3mr_ioc *mrioc, u16 handle, > + u64 *sas_address) > +{ > + struct mpi3_device_page0 dev_pg0; > + u16 ioc_status; > + struct mpi3_device0_sas_sata_format *sasinf; > + > + *sas_address = 0; > + > + if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0, > + sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, > + handle))) { > + ioc_err(mrioc, "%s: device page0 read failed\n", __func__); > + return -ENXIO; > + } > + > + 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", > + handle, ioc_status, __FILE__, __LINE__, __func__); > + return -ENXIO; > + } > + > + if (le16_to_cpu(dev_pg0.flags) & > + MPI3_DEVICE0_FLAGS_CONTROLLER_DEV_HANDLE) > + *sas_address = mrioc->sas_hba.sas_address; > + else if (dev_pg0.device_form == MPI3_DEVICE_DEVFORM_SAS_SATA) { > + sasinf = &dev_pg0.device_specific.sas_sata_format; > + *sas_address = le64_to_cpu(sasinf->sas_address); > + } else { > + ioc_err(mrioc, "%s: device_form(%d) is not SAS_SATA\n", > + __func__, dev_pg0.device_form); > + return -ENXIO; > + } > + return 0; > +} > + > +/** > + * __mpi3mr_get_tgtdev_by_addr - target device search > + * @mrioc: Adapter instance reference > + * @sas_address: SAS address of the device > + * @hba_port: HBA port entry > + * > + * This searches for target device from sas address and hba port > + * pointer then return mpi3mr_tgt_dev object. > + * > + * Return: Valid tget_dev or NULL > + */ > +static struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc, > + u64 sas_address, struct mpi3mr_hba_port *hba_port) > +{ > + struct mpi3mr_tgt_dev *tgtdev; > + > + assert_spin_locked(&mrioc->tgtdev_lock); > + > + list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) > + if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) && > + (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address) > + && (tgtdev->dev_spec.sas_sata_inf.hba_port == hba_port)) > + goto found_device; > + return NULL; > +found_device: > + mpi3mr_tgtdev_get(tgtdev); > + return tgtdev; > +} > + > +/** > + * mpi3mr_get_tgtdev_by_addr - target device search > + * @mrioc: Adapter instance reference > + * @sas_address: SAS address of the device > + * @hba_port: HBA port entry > + * > + * This searches for target device from sas address and hba port > + * pointer then return mpi3mr_tgt_dev object. > + * > + * Context: This function will acquire tgtdev_lock and will > + * release before returning the mpi3mr_tgt_dev object. > + * > + * Return: Valid tget_dev or NULL > + */ > +static struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc, > + u64 sas_address, struct mpi3mr_hba_port *hba_port) > +{ > + struct mpi3mr_tgt_dev *tgtdev = NULL; > + unsigned long flags; > + > + if (!hba_port) > + goto out; > + > + spin_lock_irqsave(&mrioc->tgtdev_lock, flags); > + tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc, sas_address, hba_port); > + spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); > + > +out: > + return tgtdev; > +} > + > +/** > + * mpi3mr_expander_find_by_sas_address - sas expander search > + * @mrioc: Adapter instance reference > + * @sas_address: SAS address of expander > + * @hba_port: HBA port entry > + * > + * Return: A valid SAS expander node or NULL. > + * > + */ > +static struct mpi3mr_sas_node *mpi3mr_expander_find_by_sas_address( > + struct mpi3mr_ioc *mrioc, u64 sas_address, > + struct mpi3mr_hba_port *hba_port) > +{ > + struct mpi3mr_sas_node *sas_expander, *r = NULL; > + > + if (!hba_port) > + goto out; > + > + list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) { > + if ((sas_expander->sas_address != sas_address) || > + (sas_expander->hba_port != hba_port)) > + continue; > + r = sas_expander; > + goto out; > + } > +out: > + return r; > +} > + > +/** > + * __mpi3mr_sas_node_find_by_sas_address - sas node search > + * @mrioc: Adapter instance reference > + * @sas_address: SAS address of expander or sas host > + * @hba_port: HBA port entry > + * Context: Caller should acquire mrioc->sas_node_lock. > + * > + * If the SAS address indicates the device is direct attached to > + * the controller (controller's SAS address) then the SAS node > + * associated with the controller is returned back else the SAS > + * address and hba port are used to identify the exact expander > + * and the associated sas_node object is returned. If there is > + * no match NULL is returned. > + * > + * Return: A valid SAS node or NULL. > + * > + */ > +static struct mpi3mr_sas_node *__mpi3mr_sas_node_find_by_sas_address( > + struct mpi3mr_ioc *mrioc, u64 sas_address, > + struct mpi3mr_hba_port *hba_port) > +{ > + > + if (mrioc->sas_hba.sas_address == sas_address) > + return &mrioc->sas_hba; > + return mpi3mr_expander_find_by_sas_address(mrioc, sas_address, > + hba_port); > +} > + > +/** > + * mpi3mr_parent_present - Is parent present for a phy > + * @mrioc: Adapter instance reference > + * @phy: SAS transport layer phy object > + * > + * Return: 0 if parent is present else non-zero > + */ > +static int mpi3mr_parent_present(struct mpi3mr_ioc *mrioc, struct sas_phy *phy) > +{ > + unsigned long flags; > + struct mpi3mr_hba_port *hba_port = phy->hostdata; > + > + spin_lock_irqsave(&mrioc->sas_node_lock, flags); > + if (__mpi3mr_sas_node_find_by_sas_address(mrioc, > + phy->identify.sas_address, > + hba_port) == NULL) { > + spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); > + return -1; > + } > + spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); > + return 0; > +} > + > /** > * mpi3mr_convert_phy_link_rate - > * @link_rate: link rate as defined in the MPI header > @@ -428,3 +658,51 @@ static int mpi3mr_add_expander_phy(struct mpi3mr_ioc *mrioc, > mr_sas_phy->phy = phy; > return 0; > } > + > +/** > + * mpi3mr_alloc_hba_port - alloc hba port object > + * @mrioc: Adapter instance reference > + * @port_id: Port number > + * > + * Alloc memory for hba port object. > + */ > +static struct mpi3mr_hba_port * > +mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id) > +{ > + struct mpi3mr_hba_port *hba_port; > + > + hba_port = kzalloc(sizeof(struct mpi3mr_hba_port), > + GFP_KERNEL); > + if (!hba_port) > + return NULL; > + hba_port->port_id = port_id; > + ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n", > + hba_port, hba_port->port_id); > + list_add_tail(&hba_port->list, &mrioc->hba_port_table_list); > + return hba_port; > +} > + > +/** > + * mpi3mr_get_hba_port_by_id - find hba port by id > + * @mrioc: Adapter instance reference > + * @port_id - Port ID to search > + * > + * Return: mpi3mr_hba_port reference for the matched port > + */ > + > +struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc, > + u8 port_id) > +{ > + struct mpi3mr_hba_port *port, *port_next; > + > + list_for_each_entry_safe(port, port_next, > + &mrioc->hba_port_table_list, list) { > + if (port->port_id != port_id) > + continue; > + if (port->flags & MPI3MR_HBA_PORT_FLAG_DIRTY) > + continue; > + return port; > + } > + > + return NULL; > +} > -- > 2.27.0 > Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com> — Himanshu Madhani Oracle Linux Engineering
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index 006bc5d..742caf5 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -570,10 +570,12 @@ struct mpi3mr_enclosure_node { * * @sas_address: World wide unique SAS address * @dev_info: Device information bits + * @hba_port: HBA port entry */ struct tgt_dev_sas_sata { u64 sas_address; u16 dev_info; + struct mpi3mr_hba_port *hba_port; }; /** @@ -984,6 +986,10 @@ struct scmd_priv { * @cfg_page: Default memory for configuration pages * @cfg_page_dma: Configuration page DMA address * @cfg_page_sz: Default configuration page memory size + * @sas_hba: SAS node for the controller + * @sas_expander_list: SAS node list of expanders + * @sas_node_lock: Lock to protect SAS node list + * @hba_port_table_list: List of HBA Ports * @enclosure_list: List of Enclosure objects */ struct mpi3mr_ioc { @@ -1162,6 +1168,10 @@ struct mpi3mr_ioc { dma_addr_t cfg_page_dma; u16 cfg_page_sz; + struct mpi3mr_sas_node sas_hba; + struct list_head sas_expander_list; + spinlock_t sas_node_lock; + struct list_head hba_port_table_list; struct list_head enclosure_list; }; @@ -1317,4 +1327,8 @@ int mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc, struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz); int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc, struct mpi3_driver_page1 *driver_pg1, u16 pg_sz); + +u8 mpi3mr_is_expander_device(u16 device_info); +struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc, + u8 port_id); #endif /*MPI3MR_H_INCLUDED*/ diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index ca718cb..b75ce73 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -4692,11 +4692,14 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) spin_lock_init(&mrioc->tgtdev_lock); spin_lock_init(&mrioc->watchdog_lock); spin_lock_init(&mrioc->chain_buf_lock); + spin_lock_init(&mrioc->sas_node_lock); INIT_LIST_HEAD(&mrioc->fwevt_list); INIT_LIST_HEAD(&mrioc->tgtdev_list); INIT_LIST_HEAD(&mrioc->delayed_rmhs_list); INIT_LIST_HEAD(&mrioc->delayed_evtack_cmds_list); + INIT_LIST_HEAD(&mrioc->sas_expander_list); + INIT_LIST_HEAD(&mrioc->hba_port_table_list); INIT_LIST_HEAD(&mrioc->enclosure_list); mutex_init(&mrioc->reset_mutex); diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c index 8c76bf5..f1da7ef 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c @@ -9,6 +9,236 @@ #include "mpi3mr.h" +/** + * __mpi3mr_expander_find_by_handle - expander search by handle + * @mrioc: Adapter instance reference + * @handle: Firmware device handle of the expander + * + * Context: The caller should acquire sas_node_lock + * + * This searches for expander device based on handle, then + * returns the sas_node object. + * + * Return: Expander sas_node object reference or NULL + */ +static struct mpi3mr_sas_node *__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc + *mrioc, u16 handle) +{ + struct mpi3mr_sas_node *sas_expander, *r; + + r = NULL; + list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) { + if (sas_expander->handle != handle) + continue; + r = sas_expander; + goto out; + } + out: + return r; +} + +/** + * mpi3mr_is_expander_device - if device is an expander + * @device_info: Bitfield providing information about the device + * + * Return: 1 if the device is expander device, else 0. + */ +u8 mpi3mr_is_expander_device(u16 device_info) +{ + if ((device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) == + MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER) + return 1; + else + return 0; +} + +/** + * mpi3mr_get_sas_address - retrieve sas_address for handle + * @mrioc: Adapter instance reference + * @handle: Firmware device handle + * @sas_address: Address to hold sas address + * + * This function issues device page0 read for a given device + * handle and gets the SAS address and return it back + * + * Return: 0 for success, non-zero for failure + */ +static int mpi3mr_get_sas_address(struct mpi3mr_ioc *mrioc, u16 handle, + u64 *sas_address) +{ + struct mpi3_device_page0 dev_pg0; + u16 ioc_status; + struct mpi3_device0_sas_sata_format *sasinf; + + *sas_address = 0; + + if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0, + sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE, + handle))) { + ioc_err(mrioc, "%s: device page0 read failed\n", __func__); + return -ENXIO; + } + + 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", + handle, ioc_status, __FILE__, __LINE__, __func__); + return -ENXIO; + } + + if (le16_to_cpu(dev_pg0.flags) & + MPI3_DEVICE0_FLAGS_CONTROLLER_DEV_HANDLE) + *sas_address = mrioc->sas_hba.sas_address; + else if (dev_pg0.device_form == MPI3_DEVICE_DEVFORM_SAS_SATA) { + sasinf = &dev_pg0.device_specific.sas_sata_format; + *sas_address = le64_to_cpu(sasinf->sas_address); + } else { + ioc_err(mrioc, "%s: device_form(%d) is not SAS_SATA\n", + __func__, dev_pg0.device_form); + return -ENXIO; + } + return 0; +} + +/** + * __mpi3mr_get_tgtdev_by_addr - target device search + * @mrioc: Adapter instance reference + * @sas_address: SAS address of the device + * @hba_port: HBA port entry + * + * This searches for target device from sas address and hba port + * pointer then return mpi3mr_tgt_dev object. + * + * Return: Valid tget_dev or NULL + */ +static struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc, + u64 sas_address, struct mpi3mr_hba_port *hba_port) +{ + struct mpi3mr_tgt_dev *tgtdev; + + assert_spin_locked(&mrioc->tgtdev_lock); + + list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) + if ((tgtdev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA) && + (tgtdev->dev_spec.sas_sata_inf.sas_address == sas_address) + && (tgtdev->dev_spec.sas_sata_inf.hba_port == hba_port)) + goto found_device; + return NULL; +found_device: + mpi3mr_tgtdev_get(tgtdev); + return tgtdev; +} + +/** + * mpi3mr_get_tgtdev_by_addr - target device search + * @mrioc: Adapter instance reference + * @sas_address: SAS address of the device + * @hba_port: HBA port entry + * + * This searches for target device from sas address and hba port + * pointer then return mpi3mr_tgt_dev object. + * + * Context: This function will acquire tgtdev_lock and will + * release before returning the mpi3mr_tgt_dev object. + * + * Return: Valid tget_dev or NULL + */ +static struct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc, + u64 sas_address, struct mpi3mr_hba_port *hba_port) +{ + struct mpi3mr_tgt_dev *tgtdev = NULL; + unsigned long flags; + + if (!hba_port) + goto out; + + spin_lock_irqsave(&mrioc->tgtdev_lock, flags); + tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc, sas_address, hba_port); + spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); + +out: + return tgtdev; +} + +/** + * mpi3mr_expander_find_by_sas_address - sas expander search + * @mrioc: Adapter instance reference + * @sas_address: SAS address of expander + * @hba_port: HBA port entry + * + * Return: A valid SAS expander node or NULL. + * + */ +static struct mpi3mr_sas_node *mpi3mr_expander_find_by_sas_address( + struct mpi3mr_ioc *mrioc, u64 sas_address, + struct mpi3mr_hba_port *hba_port) +{ + struct mpi3mr_sas_node *sas_expander, *r = NULL; + + if (!hba_port) + goto out; + + list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) { + if ((sas_expander->sas_address != sas_address) || + (sas_expander->hba_port != hba_port)) + continue; + r = sas_expander; + goto out; + } +out: + return r; +} + +/** + * __mpi3mr_sas_node_find_by_sas_address - sas node search + * @mrioc: Adapter instance reference + * @sas_address: SAS address of expander or sas host + * @hba_port: HBA port entry + * Context: Caller should acquire mrioc->sas_node_lock. + * + * If the SAS address indicates the device is direct attached to + * the controller (controller's SAS address) then the SAS node + * associated with the controller is returned back else the SAS + * address and hba port are used to identify the exact expander + * and the associated sas_node object is returned. If there is + * no match NULL is returned. + * + * Return: A valid SAS node or NULL. + * + */ +static struct mpi3mr_sas_node *__mpi3mr_sas_node_find_by_sas_address( + struct mpi3mr_ioc *mrioc, u64 sas_address, + struct mpi3mr_hba_port *hba_port) +{ + + if (mrioc->sas_hba.sas_address == sas_address) + return &mrioc->sas_hba; + return mpi3mr_expander_find_by_sas_address(mrioc, sas_address, + hba_port); +} + +/** + * mpi3mr_parent_present - Is parent present for a phy + * @mrioc: Adapter instance reference + * @phy: SAS transport layer phy object + * + * Return: 0 if parent is present else non-zero + */ +static int mpi3mr_parent_present(struct mpi3mr_ioc *mrioc, struct sas_phy *phy) +{ + unsigned long flags; + struct mpi3mr_hba_port *hba_port = phy->hostdata; + + spin_lock_irqsave(&mrioc->sas_node_lock, flags); + if (__mpi3mr_sas_node_find_by_sas_address(mrioc, + phy->identify.sas_address, + hba_port) == NULL) { + spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); + return -1; + } + spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); + return 0; +} + /** * mpi3mr_convert_phy_link_rate - * @link_rate: link rate as defined in the MPI header @@ -428,3 +658,51 @@ static int mpi3mr_add_expander_phy(struct mpi3mr_ioc *mrioc, mr_sas_phy->phy = phy; return 0; } + +/** + * mpi3mr_alloc_hba_port - alloc hba port object + * @mrioc: Adapter instance reference + * @port_id: Port number + * + * Alloc memory for hba port object. + */ +static struct mpi3mr_hba_port * +mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id) +{ + struct mpi3mr_hba_port *hba_port; + + hba_port = kzalloc(sizeof(struct mpi3mr_hba_port), + GFP_KERNEL); + if (!hba_port) + return NULL; + hba_port->port_id = port_id; + ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n", + hba_port, hba_port->port_id); + list_add_tail(&hba_port->list, &mrioc->hba_port_table_list); + return hba_port; +} + +/** + * mpi3mr_get_hba_port_by_id - find hba port by id + * @mrioc: Adapter instance reference + * @port_id - Port ID to search + * + * Return: mpi3mr_hba_port reference for the matched port + */ + +struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc, + u8 port_id) +{ + struct mpi3mr_hba_port *port, *port_next; + + list_for_each_entry_safe(port, port_next, + &mrioc->hba_port_table_list, list) { + if (port->port_id != port_id) + continue; + if (port->flags & MPI3MR_HBA_PORT_FLAG_DIRTY) + continue; + return port; + } + + return NULL; +}
Added below helper functions, - Get the device's sas address by reading correspond device's Device page0, - Get the expander object from expander list based on expander's handle, - Get the target device object from target device list based on device's sas address, - Get the expander device object from expander list based on expanders's sas address, - Get hba port object from hba port table list based on port's port id Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com> --- drivers/scsi/mpi3mr/mpi3mr.h | 14 ++ drivers/scsi/mpi3mr/mpi3mr_os.c | 3 + drivers/scsi/mpi3mr/mpi3mr_transport.c | 278 +++++++++++++++++++++++++ 3 files changed, 295 insertions(+)