All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/15] mpi3mr: Added Support for SAS Transport
@ 2022-07-29 13:16 Sreekanth Reddy
  2022-07-29 13:16 ` [PATCH 01/15] mpi3mr: Add config and transport related debug flags Sreekanth Reddy
                   ` (14 more replies)
  0 siblings, 15 replies; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 1856 bytes --]

- Enhanced the driver to support SAS transport layer and
 expose SAS controller PHYs, ports, attached expander, expander PHYs,
 expander ports and SAS/SATA end devices to the kernel through
 SAS transport class.
- The driver also provides call back handlers for get_linkerrors,
 get_enclosure_identifier, get_bay_identifier, phy_reset, phy_enable,
 set_phy_speed and smp_handler to the kernel as defined by the
 SAS transport layer.
- The SAS transport layer support is enabled only when the
 controller multipath capability is not enabled.
- The NVMe devices, VDs, vSES and PCIe Managed SES devices
 are not exposed through SAS transport.

Sreekanth Reddy (15):
  mpi3mr: Add config and transport related debug flags
  mpi3mr: Add framework to issue cnfg requests
  mpi3mr: Added helper functions to retrieve cnfg pages
  mpi3mr: Enable Enclosure device add event
  mpi3mr: Add framework to add phys to STL
  mpi3mr: Add helper functions to retrieve device objects
  mpi3mr: Add helper functions to manage device's port
  mpi3mr: Enable STL on HBAs where multipath is disabled
  mpi3mr: Add expander devices to STL
  mpi3mr: Get target object based on rphy
  mpi3mr: Add SAS SATA end devices to STL
  mpi3mr: Add framework to issue MPT transport cmds
  mpi3mr: Support sas transport class callbacks
  mpi3mr: Refresh sas ports during soft reset
  mpi3mr: Block IOs while refreshing target dev objects

 drivers/scsi/mpi3mr/Makefile           |    1 +
 drivers/scsi/mpi3mr/mpi3mr.h           |  240 +-
 drivers/scsi/mpi3mr/mpi3mr_debug.h     |   27 +
 drivers/scsi/mpi3mr/mpi3mr_fw.c        |  898 ++++++-
 drivers/scsi/mpi3mr/mpi3mr_os.c        |  443 +++-
 drivers/scsi/mpi3mr/mpi3mr_transport.c | 3316 ++++++++++++++++++++++++
 6 files changed, 4873 insertions(+), 52 deletions(-)
 create mode 100644 drivers/scsi/mpi3mr/mpi3mr_transport.c

-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH 01/15] mpi3mr: Add config and transport related debug flags
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-07-29 16:59   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 02/15] mpi3mr: Add framework to issue cnfg requests Sreekanth Reddy
                   ` (13 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 1823 bytes --]

Add config and transport request related error & info debug
flags and functions.

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr_debug.h | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/scsi/mpi3mr/mpi3mr_debug.h b/drivers/scsi/mpi3mr/mpi3mr_debug.h
index 2464c40..ee6edd8 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_debug.h
+++ b/drivers/scsi/mpi3mr/mpi3mr_debug.h
@@ -23,9 +23,13 @@
 #define MPI3_DEBUG_RESET		0x00000020
 #define MPI3_DEBUG_SCSI_ERROR		0x00000040
 #define MPI3_DEBUG_REPLY		0x00000080
+#define MPI3_DEBUG_CFG_ERROR		0x00000100
+#define MPI3_DEBUG_TRANSPORT_ERROR	0x00000200
 #define MPI3_DEBUG_BSG_ERROR		0x00008000
 #define MPI3_DEBUG_BSG_INFO		0x00010000
 #define MPI3_DEBUG_SCSI_INFO		0x00020000
+#define MPI3_DEBUG_CFG_INFO		0x00040000
+#define MPI3_DEBUG_TRANSPORT_INFO	0x00080000
 #define MPI3_DEBUG			0x01000000
 #define MPI3_DEBUG_SG			0x02000000
 
@@ -122,6 +126,29 @@
 			pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
 	} while (0)
 
+#define dprint_cfg_info(ioc, fmt, ...) \
+	do { \
+		if (ioc->logging_level & MPI3_DEBUG_CFG_INFO) \
+			pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
+	} while (0)
+
+#define dprint_cfg_err(ioc, fmt, ...) \
+	do { \
+		if (ioc->logging_level & MPI3_DEBUG_CFG_ERROR) \
+			pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
+	} while (0)
+#define dprint_transport_info(ioc, fmt, ...) \
+	do { \
+		if (ioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO) \
+			pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
+	} while (0)
+
+#define dprint_transport_err(ioc, fmt, ...) \
+	do { \
+		if (ioc->logging_level & MPI3_DEBUG_TRANSPORT_ERROR) \
+			pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
+	} while (0)
+
 #endif /* MPT3SAS_DEBUG_H_INCLUDED */
 
 /**
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 02/15] mpi3mr: Add framework to issue cnfg requests
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
  2022-07-29 13:16 ` [PATCH 01/15] mpi3mr: Add config and transport related debug flags Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-07-29 17:00   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 03/15] mpi3mr: Added helper functions to retrieve cnfg pages Sreekanth Reddy
                   ` (12 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 13610 bytes --]

Added framework to issue config requests commands to
controller firmware.

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h    |  28 ++++
 drivers/scsi/mpi3mr/mpi3mr_fw.c | 256 ++++++++++++++++++++++++++++++++
 drivers/scsi/mpi3mr/mpi3mr_os.c |   1 +
 3 files changed, 285 insertions(+)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 0935b2e..e15ad0e 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -97,6 +97,7 @@ extern atomic64_t event_counter;
 #define MPI3MR_HOSTTAG_PEL_ABORT	3
 #define MPI3MR_HOSTTAG_PEL_WAIT		4
 #define MPI3MR_HOSTTAG_BLK_TMS		5
+#define MPI3MR_HOSTTAG_CFG_CMDS		6
 
 #define MPI3MR_NUM_DEVRMCMD		16
 #define MPI3MR_HOSTTAG_DEVRMCMD_MIN	(MPI3MR_HOSTTAG_BLK_TMS + 1)
@@ -126,6 +127,8 @@ extern atomic64_t event_counter;
 
 #define MPI3MR_WATCHDOG_INTERVAL		1000 /* in milli seconds */
 
+#define MPI3MR_DEFAULT_CFG_PAGE_SZ		1024 /* in bytes */
+
 #define MPI3MR_SCMD_TIMEOUT    (60 * HZ)
 #define MPI3MR_EH_SCMD_TIMEOUT (60 * HZ)
 
@@ -274,6 +277,7 @@ enum mpi3mr_reset_reason {
 	MPI3MR_RESET_FROM_SYSFS = 23,
 	MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24,
 	MPI3MR_RESET_FROM_FIRMWARE = 27,
+	MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT = 29,
 };
 
 /* Queue type definitions */
@@ -679,6 +683,21 @@ struct mpi3mr_drv_cmd {
 	    struct mpi3mr_drv_cmd *drv_cmd);
 };
 
+/**
+ * struct dma_memory_desc - memory descriptor structure to store
+ * virtual address, dma address and size for any generic dma
+ * memory allocations in the driver.
+ *
+ * @size: buffer size
+ * @addr: virtual address
+ * @dma_addr: dma address
+ */
+struct dma_memory_desc {
+	u32 size;
+	void *addr;
+	dma_addr_t dma_addr;
+};
+
 
 /**
  * struct chain_element - memory descriptor structure to store
@@ -756,6 +775,7 @@ struct scmd_priv {
  * @num_op_reply_q: Number of operational reply queues
  * @op_reply_qinfo: Operational reply queue info pointer
  * @init_cmds: Command tracker for initialization commands
+ * @cfg_cmds: Command tracker for configuration requests
  * @facts: Cached IOC facts data
  * @op_reply_desc_sz: Operational reply descriptor size
  * @num_reply_bufs: Number of reply buffers allocated
@@ -854,6 +874,9 @@ struct scmd_priv {
  * @io_throttle_low: I/O size to stop throttle in 512b blocks
  * @num_io_throttle_group: Maximum number of throttle groups
  * @throttle_groups: Pointer to throttle group info structures
+ * @cfg_page: Default memory for configuration pages
+ * @cfg_page_dma: Configuration page DMA address
+ * @cfg_page_sz: Default configuration page memory size
  */
 struct mpi3mr_ioc {
 	struct list_head list;
@@ -904,6 +927,7 @@ struct mpi3mr_ioc {
 	struct op_reply_qinfo *op_reply_qinfo;
 
 	struct mpi3mr_drv_cmd init_cmds;
+	struct mpi3mr_drv_cmd cfg_cmds;
 	struct mpi3mr_ioc_facts facts;
 	u16 op_reply_desc_sz;
 
@@ -1025,6 +1049,10 @@ struct mpi3mr_ioc {
 	u32 io_throttle_low;
 	u16 num_io_throttle_group;
 	struct mpi3mr_throttle_group_info *throttle_groups;
+
+	void *cfg_page;
+	dma_addr_t cfg_page_dma;
+	u16 cfg_page_sz;
 };
 
 /**
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 0866dfd..da6eceb 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -299,6 +299,8 @@ mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
 	switch (host_tag) {
 	case MPI3MR_HOSTTAG_INITCMDS:
 		return &mrioc->init_cmds;
+	case MPI3MR_HOSTTAG_CFG_CMDS:
+		return &mrioc->cfg_cmds;
 	case MPI3MR_HOSTTAG_BSG_CMDS:
 		return &mrioc->bsg_cmds;
 	case MPI3MR_HOSTTAG_BLK_TMS:
@@ -907,6 +909,7 @@ static const struct {
 	{ MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
 	{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
 	{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronous reset" },
+	{ MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout"},
 };
 
 /**
@@ -3738,6 +3741,14 @@ retry_init:
 
 	mpi3mr_print_ioc_info(mrioc);
 
+	dprint_init(mrioc, "allocating config page buffers\n");
+	mrioc->cfg_page = dma_alloc_coherent(&mrioc->pdev->dev,
+	    MPI3MR_DEFAULT_CFG_PAGE_SZ, &mrioc->cfg_page_dma, GFP_KERNEL);
+	if (!mrioc->cfg_page)
+		goto out_failed_noretry;
+
+	mrioc->cfg_page_sz = MPI3MR_DEFAULT_CFG_PAGE_SZ;
+
 	retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
 	if (retval) {
 		ioc_err(mrioc,
@@ -4362,6 +4373,10 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
 
 	cmdptr = &mrioc->init_cmds;
 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
+
+	cmdptr = &mrioc->cfg_cmds;
+	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
+
 	cmdptr = &mrioc->bsg_cmds;
 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
 	cmdptr = &mrioc->host_tm_cmds;
@@ -4786,3 +4801,244 @@ out:
 	    ((retval == 0) ? "successful" : "failed"));
 	return retval;
 }
+
+
+/**
+ * mpi3mr_free_config_dma_memory - free memory for config page
+ * @mrioc: Adapter instance reference
+ * @mem_desc: memory descriptor structure
+ *
+ * Check whether the size of the buffer specified by the memory
+ * descriptor is greater than the default page size if so then
+ * free the memory pointed by the descriptor.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static void mpi3mr_free_config_dma_memory(struct mpi3mr_ioc *mrioc,
+	struct dma_memory_desc *mem_desc)
+{
+	if ((mem_desc->size > mrioc->cfg_page_sz) && mem_desc->addr) {
+		dma_free_coherent(&mrioc->pdev->dev, mem_desc->size,
+		    mem_desc->addr, mem_desc->dma_addr);
+		mem_desc->addr = NULL;
+	}
+}
+
+
+
+/**
+ * mpi3mr_alloc_config_dma_memory - Alloc memory for config page
+ * @mrioc: Adapter instance reference
+ * @mem_desc: Memory descriptor to hold dma memory info
+ *
+ * This function allocates new dmaable memory or provides the
+ * default config page dmaable memory based on the memory size
+ * described by the descriptor.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_alloc_config_dma_memory(struct mpi3mr_ioc *mrioc,
+	struct dma_memory_desc *mem_desc)
+{
+	if (mem_desc->size > mrioc->cfg_page_sz) {
+		mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev,
+		    mem_desc->size, &mem_desc->dma_addr, GFP_KERNEL);
+		if (!mem_desc->addr)
+			return -ENOMEM;
+	} else {
+		mem_desc->addr = mrioc->cfg_page;
+		mem_desc->dma_addr = mrioc->cfg_page_dma;
+		memset(mem_desc->addr, 0, mrioc->cfg_page_sz);
+	}
+	return 0;
+}
+
+
+/**
+ * mpi3mr_post_cfg_req - Issue config requests and wait
+ * @mrioc: Adapter instance reference
+ * @cfg_req: Configuration request
+ * @timeout: Timeout in seconds
+ * @ioc_status: Pointer to return ioc status
+ *
+ * A generic function for posting MPI3 configuration request to
+ * the firmware. This blocks for the completion of request for
+ * timeout seconds and if the request times out this function
+ * faults the controller with proper reason code.
+ *
+ * On successful completion of the request this function returns
+ * appropriate ioc status from the firmware back to the caller.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_post_cfg_req(struct mpi3mr_ioc *mrioc,
+	struct mpi3_config_request *cfg_req, int timeout, u16 *ioc_status)
+{
+	int retval = 0;
+
+	mutex_lock(&mrioc->cfg_cmds.mutex);
+	if (mrioc->cfg_cmds.state & MPI3MR_CMD_PENDING) {
+		retval = -1;
+		ioc_err(mrioc, "sending config request failed due to command in use\n");
+		mutex_unlock(&mrioc->cfg_cmds.mutex);
+		goto out;
+	}
+	mrioc->cfg_cmds.state = MPI3MR_CMD_PENDING;
+	mrioc->cfg_cmds.is_waiting = 1;
+	mrioc->cfg_cmds.callback = NULL;
+	mrioc->cfg_cmds.ioc_status = 0;
+	mrioc->cfg_cmds.ioc_loginfo = 0;
+
+	cfg_req->host_tag = cpu_to_le16(MPI3MR_HOSTTAG_CFG_CMDS);
+	cfg_req->function = MPI3_FUNCTION_CONFIG;
+
+	init_completion(&mrioc->cfg_cmds.done);
+	dprint_cfg_info(mrioc, "posting config request\n");
+	if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
+		dprint_dump(cfg_req, sizeof(struct mpi3_config_request),
+		    "mpi3_cfg_req");
+	retval = mpi3mr_admin_request_post(mrioc, cfg_req, sizeof(*cfg_req), 1);
+	if (retval) {
+		ioc_err(mrioc, "posting config request failed\n");
+		goto out_unlock;
+	}
+	wait_for_completion_timeout(&mrioc->cfg_cmds.done, (timeout * HZ));
+	if (!(mrioc->cfg_cmds.state & MPI3MR_CMD_COMPLETE)) {
+		mpi3mr_check_rh_fault_ioc(mrioc,
+		    MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT);
+		ioc_err(mrioc, "config request timed out\n");
+		retval = -1;
+		goto out_unlock;
+	}
+	*ioc_status = mrioc->cfg_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
+	if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS)
+		dprint_cfg_err(mrioc,
+		    "cfg_page request returned with ioc_status(0x%04x), log_info(0x%08x)\n",
+		    *ioc_status, mrioc->cfg_cmds.ioc_loginfo);
+
+out_unlock:
+	mrioc->cfg_cmds.state = MPI3MR_CMD_NOTUSED;
+	mutex_unlock(&mrioc->cfg_cmds.mutex);
+
+out:
+	return retval;
+}
+
+/**
+ * mpi3mr_process_cfg_req - config page request processor
+ * @mrioc: Adapter instance reference
+ * @cfg_req: Configuration request
+ * @cfg_hdr: Configuration page header
+ * @timeout: Timeout in seconds
+ * @ioc_status: Pointer to return ioc status
+ * @cfg_buf: Memory pointer to copy config page or header
+ * @cfg_buf_sz: Size of the memory to get config page or header
+ *
+ * This is handler for config page read, write and config page
+ * header read operations.
+ *
+ * This function expects the cfg_req to be populated with page
+ * type, page number, action for the header read and with page
+ * address for all other operations.
+ *
+ * The cfg_hdr can be passed as null for reading required header
+ * details for read/write pages the cfg_hdr should point valid
+ * configuration page header.
+ *
+ * This allocates dmaable memory based on the size of the config
+ * buffer and set the SGE of the cfg_req.
+ *
+ * For write actions, the config page data has to be passed in
+ * the cfg_buf and size of the data has to be mentioned in the
+ * cfg_buf_sz.
+ *
+ * For read/header actions, on successful completion of the
+ * request with successful ioc_status the data will be copied
+ * into the cfg_buf limited to a minimum of actual page size and
+ * cfg_buf_sz
+ *
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc,
+	struct mpi3_config_request *cfg_req,
+	struct mpi3_config_page_header *cfg_hdr, int timeout, u16 *ioc_status,
+	void *cfg_buf, u32 cfg_buf_sz)
+{
+	struct dma_memory_desc mem_desc;
+	int retval = -1;
+	u8 invalid_action = 0;
+	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
+
+	memset(&mem_desc, 0, sizeof(struct dma_memory_desc));
+
+	if (cfg_req->action == MPI3_CONFIG_ACTION_PAGE_HEADER)
+		mem_desc.size = sizeof(struct mpi3_config_page_header);
+	else {
+		if (!cfg_hdr) {
+			ioc_err(mrioc, "null config header passed for config action(%d), page_type(0x%02x), page_num(%d)\n",
+			    cfg_req->action, cfg_req->page_type,
+			    cfg_req->page_number);
+			goto out;
+		}
+		switch (cfg_hdr->page_attribute & MPI3_CONFIG_PAGEATTR_MASK) {
+		case MPI3_CONFIG_PAGEATTR_READ_ONLY:
+			if (cfg_req->action
+			    != MPI3_CONFIG_ACTION_READ_CURRENT)
+				invalid_action = 1;
+			break;
+		case MPI3_CONFIG_PAGEATTR_CHANGEABLE:
+			if ((cfg_req->action ==
+			     MPI3_CONFIG_ACTION_READ_PERSISTENT) ||
+			    (cfg_req->action ==
+			     MPI3_CONFIG_ACTION_WRITE_PERSISTENT))
+				invalid_action = 1;
+			break;
+		case MPI3_CONFIG_PAGEATTR_PERSISTENT:
+		default:
+			break;
+		}
+		if (invalid_action) {
+			ioc_err(mrioc,
+			    "config action(%d) is not allowed for page_type(0x%02x), page_num(%d) with page_attribute(0x%02x)\n",
+			    cfg_req->action, cfg_req->page_type,
+			    cfg_req->page_number, cfg_hdr->page_attribute);
+			goto out;
+		}
+		mem_desc.size = le16_to_cpu(cfg_hdr->page_length) * 4;
+		cfg_req->page_length = cfg_hdr->page_length;
+		cfg_req->page_version = cfg_hdr->page_version;
+	}
+	if (mpi3mr_alloc_config_dma_memory(mrioc, &mem_desc))
+		goto out;
+
+	mpi3mr_add_sg_single(&cfg_req->sgl, sgl_flags, mem_desc.size,
+	    mem_desc.dma_addr);
+
+	if ((cfg_req->action == MPI3_CONFIG_ACTION_WRITE_PERSISTENT) ||
+	    (cfg_req->action == MPI3_CONFIG_ACTION_WRITE_CURRENT)) {
+		memcpy(mem_desc.addr, cfg_buf, min_t(u16, mem_desc.size,
+		    cfg_buf_sz));
+		dprint_cfg_info(mrioc, "config buffer to be written\n");
+		if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
+			dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf");
+	}
+
+	if (mpi3mr_post_cfg_req(mrioc, cfg_req, timeout, ioc_status))
+		goto out;
+
+	retval = 0;
+	if ((*ioc_status == MPI3_IOCSTATUS_SUCCESS) &&
+	    (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_PERSISTENT) &&
+	    (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_CURRENT)) {
+		memcpy(cfg_buf, mem_desc.addr, min_t(u16, mem_desc.size,
+		    cfg_buf_sz));
+		dprint_cfg_info(mrioc, "config buffer read\n");
+		if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
+			dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf");
+	}
+
+out:
+	mpi3mr_free_config_dma_memory(mrioc, &mem_desc);
+	return retval;
+}
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 8bdf927..40bed22 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -4574,6 +4574,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
 	mpi3mr_init_drv_cmd(&mrioc->host_tm_cmds, MPI3MR_HOSTTAG_BLK_TMS);
 	mpi3mr_init_drv_cmd(&mrioc->bsg_cmds, MPI3MR_HOSTTAG_BSG_CMDS);
+	mpi3mr_init_drv_cmd(&mrioc->cfg_cmds, MPI3MR_HOSTTAG_CFG_CMDS);
 
 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
 		mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i],
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 03/15] mpi3mr: Added helper functions to retrieve cnfg pages
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
  2022-07-29 13:16 ` [PATCH 01/15] mpi3mr: Add config and transport related debug flags Sreekanth Reddy
  2022-07-29 13:16 ` [PATCH 02/15] mpi3mr: Add framework to issue cnfg requests Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-07-29 18:13   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 04/15] mpi3mr: Enable Enclosure device add event Sreekanth Reddy
                   ` (11 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 23271 bytes --]

Added helper functions to retrieve below controller's
config pages,
- SAS IOUnit Page0
- SAS IOUnit Page1
- Driver Page1
- Device Page0
- SAS Phy Page0
- SAS Phy Page1
- SAS Expander Page0
- SAS Expander Page1
- Enclosure Page0

Also added the helper function to set the SAS IOUnit Page1.

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h    |  26 ++
 drivers/scsi/mpi3mr/mpi3mr_fw.c | 595 ++++++++++++++++++++++++++++++++
 2 files changed, 621 insertions(+)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index e15ad0e..8af94d3 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -1179,4 +1179,30 @@ void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data,
 	u16 event_data_size);
 extern const struct attribute_group *mpi3mr_host_groups[];
 extern const struct attribute_group *mpi3mr_dev_groups[];
+
+int mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_device_page0 *dev_pg0, u16 pg_sz, u32 form, u32 form_spec);
+int mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_sas_phy_page0 *phy_pg0, u16 pg_sz, u32 form,
+	u32 form_spec);
+int mpi3mr_cfg_get_sas_phy_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_sas_phy_page1 *phy_pg1, u16 pg_sz, u32 form,
+	u32 form_spec);
+int mpi3mr_cfg_get_sas_exp_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_sas_expander_page0 *exp_pg0, u16 pg_sz, u32 form,
+	u32 form_spec);
+int mpi3mr_cfg_get_sas_exp_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_sas_expander_page1 *exp_pg1, u16 pg_sz, u32 form,
+	u32 form_spec);
+int mpi3mr_cfg_get_enclosure_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_enclosure_page0 *encl_pg0, u16 pg_sz, u32 form,
+	u32 form_spec);
+int mpi3mr_cfg_get_sas_io_unit_pg0(struct mpi3mr_ioc *mrioc,
+	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0, u16 pg_sz);
+int mpi3mr_cfg_get_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
+	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz);
+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);
 #endif /*MPI3MR_H_INCLUDED*/
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index da6eceb..50e88d4 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -5042,3 +5042,598 @@ out:
 	mpi3mr_free_config_dma_memory(mrioc, &mem_desc);
 	return retval;
 }
+
+/**
+ * mpi3mr_cfg_get_dev_pg0 - Read current device page0
+ * @mrioc: Adapter instance reference
+ * @ioc_status: Pointer to return ioc status
+ * @dev_pg0: Pointer to return device page 0
+ * @pg_sz: Size of the memory allocated to the page pointer
+ * @form: The form to be used for addressing the page
+ * @form_spec: Form specific information like device handle
+ *
+ * This is handler for config page read for a specific device
+ * page0. The ioc_status has the controller returned ioc_status.
+ * This routine doesn't check ioc_status to decide whether the
+ * page read is success or not and it is the callers
+ * responsibility.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_device_page0 *dev_pg0, u16 pg_sz, u32 form, u32 form_spec)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u32 page_address;
+
+	memset(dev_pg0, 0, pg_sz);
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DEVICE;
+	cfg_req.page_number = 0;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "device page0 header read failed\n");
+		goto out_failed;
+	}
+	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "device page0 header read failed with ioc_status(0x%04x)\n",
+		    *ioc_status);
+		goto out_failed;
+	}
+	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
+	page_address = ((form & MPI3_DEVICE_PGAD_FORM_MASK) |
+	    (form_spec & MPI3_DEVICE_PGAD_HANDLE_MASK));
+	cfg_req.page_address = cpu_to_le32(page_address);
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, dev_pg0, pg_sz)) {
+		ioc_err(mrioc, "device page0 read failed\n");
+		goto out_failed;
+	}
+	return 0;
+out_failed:
+	return -1;
+}
+
+
+/**
+ * mpi3mr_cfg_get_sas_phy_pg0 - Read current SAS Phy page0
+ * @mrioc: Adapter instance reference
+ * @ioc_status: Pointer to return ioc status
+ * @phy_pg0: Pointer to return SAS Phy page 0
+ * @pg_sz: Size of the memory allocated to the page pointer
+ * @form: The form to be used for addressing the page
+ * @form_spec: Form specific information like phy number
+ *
+ * This is handler for config page read for a specific SAS Phy
+ * page0. The ioc_status has the controller returned ioc_status.
+ * This routine doesn't check ioc_status to decide whether the
+ * page read is success or not and it is the callers
+ * responsibility.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_sas_phy_page0 *phy_pg0, u16 pg_sz, u32 form,
+	u32 form_spec)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u32 page_address;
+
+	memset(phy_pg0, 0, pg_sz);
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_PHY;
+	cfg_req.page_number = 0;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "sas phy page0 header read failed\n");
+		goto out_failed;
+	}
+	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "sas phy page0 header read failed with ioc_status(0x%04x)\n",
+		    *ioc_status);
+		goto out_failed;
+	}
+	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
+	page_address = ((form & MPI3_SAS_PHY_PGAD_FORM_MASK) |
+	    (form_spec & MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK));
+	cfg_req.page_address = cpu_to_le32(page_address);
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, phy_pg0, pg_sz)) {
+		ioc_err(mrioc, "sas phy page0 read failed\n");
+		goto out_failed;
+	}
+	return 0;
+out_failed:
+	return -1;
+}
+
+/**
+ * mpi3mr_cfg_get_sas_phy_pg1 - Read current SAS Phy page1
+ * @mrioc: Adapter instance reference
+ * @ioc_status: Pointer to return ioc status
+ * @phy_pg1: Pointer to return SAS Phy page 1
+ * @pg_sz: Size of the memory allocated to the page pointer
+ * @form: The form to be used for addressing the page
+ * @form_spec: Form specific information like phy number
+ *
+ * This is handler for config page read for a specific SAS Phy
+ * page1. The ioc_status has the controller returned ioc_status.
+ * This routine doesn't check ioc_status to decide whether the
+ * page read is success or not and it is the callers
+ * responsibility.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_get_sas_phy_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_sas_phy_page1 *phy_pg1, u16 pg_sz, u32 form,
+	u32 form_spec)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u32 page_address;
+
+	memset(phy_pg1, 0, pg_sz);
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_PHY;
+	cfg_req.page_number = 1;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "sas phy page1 header read failed\n");
+		goto out_failed;
+	}
+	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "sas phy page1 header read failed with ioc_status(0x%04x)\n",
+		    *ioc_status);
+		goto out_failed;
+	}
+	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
+	page_address = ((form & MPI3_SAS_PHY_PGAD_FORM_MASK) |
+	    (form_spec & MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK));
+	cfg_req.page_address = cpu_to_le32(page_address);
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, phy_pg1, pg_sz)) {
+		ioc_err(mrioc, "sas phy page1 read failed\n");
+		goto out_failed;
+	}
+	return 0;
+out_failed:
+	return -1;
+}
+
+
+/**
+ * mpi3mr_cfg_get_sas_exp_pg0 - Read current SAS Expander page0
+ * @mrioc: Adapter instance reference
+ * @ioc_status: Pointer to return ioc status
+ * @exp_pg0: Pointer to return SAS Expander page 0
+ * @pg_sz: Size of the memory allocated to the page pointer
+ * @form: The form to be used for addressing the page
+ * @form_spec: Form specific information like device handle
+ *
+ * This is handler for config page read for a specific SAS
+ * Expander page0. The ioc_status has the controller returned
+ * ioc_status. This routine doesn't check ioc_status to decide
+ * whether the page read is success or not and it is the callers
+ * responsibility.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_get_sas_exp_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_sas_expander_page0 *exp_pg0, u16 pg_sz, u32 form,
+	u32 form_spec)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u32 page_address;
+
+	memset(exp_pg0, 0, pg_sz);
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_EXPANDER;
+	cfg_req.page_number = 0;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "expander page0 header read failed\n");
+		goto out_failed;
+	}
+	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "expander page0 header read failed with ioc_status(0x%04x)\n",
+		    *ioc_status);
+		goto out_failed;
+	}
+	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
+	page_address = ((form & MPI3_SAS_EXPAND_PGAD_FORM_MASK) |
+	    (form_spec & (MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK |
+	    MPI3_SAS_EXPAND_PGAD_HANDLE_MASK)));
+	cfg_req.page_address = cpu_to_le32(page_address);
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, exp_pg0, pg_sz)) {
+		ioc_err(mrioc, "expander page0 read failed\n");
+		goto out_failed;
+	}
+	return 0;
+out_failed:
+	return -1;
+}
+
+/**
+ * mpi3mr_cfg_get_sas_exp_pg1 - Read current SAS Expander page1
+ * @mrioc: Adapter instance reference
+ * @ioc_status: Pointer to return ioc status
+ * @exp_pg1: Pointer to return SAS Expander page 1
+ * @pg_sz: Size of the memory allocated to the page pointer
+ * @form: The form to be used for addressing the page
+ * @form_spec: Form specific information like phy number
+ *
+ * This is handler for config page read for a specific SAS
+ * Expander page1. The ioc_status has the controller returned
+ * ioc_status. This routine doesn't check ioc_status to decide
+ * whether the page read is success or not and it is the callers
+ * responsibility.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_get_sas_exp_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_sas_expander_page1 *exp_pg1, u16 pg_sz, u32 form,
+	u32 form_spec)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u32 page_address;
+
+	memset(exp_pg1, 0, pg_sz);
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_EXPANDER;
+	cfg_req.page_number = 1;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "expander page1 header read failed\n");
+		goto out_failed;
+	}
+	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "expander page1 header read failed with ioc_status(0x%04x)\n",
+		    *ioc_status);
+		goto out_failed;
+	}
+	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
+	page_address = ((form & MPI3_SAS_EXPAND_PGAD_FORM_MASK) |
+	    (form_spec & (MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK |
+	    MPI3_SAS_EXPAND_PGAD_HANDLE_MASK)));
+	cfg_req.page_address = cpu_to_le32(page_address);
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, exp_pg1, pg_sz)) {
+		ioc_err(mrioc, "expander page1 read failed\n");
+		goto out_failed;
+	}
+	return 0;
+out_failed:
+	return -1;
+}
+
+/**
+ * mpi3mr_cfg_get_enclosure_pg0 - Read current Enclosure page0
+ * @mrioc: Adapter instance reference
+ * @ioc_status: Pointer to return ioc status
+ * @encl_pg0: Pointer to return Enclosure page 0
+ * @pg_sz: Size of the memory allocated to the page pointer
+ * @form: The form to be used for addressing the page
+ * @form_spec: Form specific information like device handle
+ *
+ * This is handler for config page read for a specific Enclosure
+ * page0. The ioc_status has the controller returned ioc_status.
+ * This routine doesn't check ioc_status to decide whether the
+ * page read is success or not and it is the callers
+ * responsibility.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_get_enclosure_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
+	struct mpi3_enclosure_page0 *encl_pg0, u16 pg_sz, u32 form,
+	u32 form_spec)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u32 page_address;
+
+	memset(encl_pg0, 0, pg_sz);
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_ENCLOSURE;
+	cfg_req.page_number = 0;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "enclosure page0 header read failed\n");
+		goto out_failed;
+	}
+	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "enclosure page0 header read failed with ioc_status(0x%04x)\n",
+		    *ioc_status);
+		goto out_failed;
+	}
+	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
+	page_address = ((form & MPI3_ENCLOS_PGAD_FORM_MASK) |
+	    (form_spec & MPI3_ENCLOS_PGAD_HANDLE_MASK));
+	cfg_req.page_address = cpu_to_le32(page_address);
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, encl_pg0, pg_sz)) {
+		ioc_err(mrioc, "enclosure page0 read failed\n");
+		goto out_failed;
+	}
+	return 0;
+out_failed:
+	return -1;
+}
+
+
+/**
+ * mpi3mr_cfg_get_sas_io_unit_pg0 - Read current SASIOUnit page0
+ * @mrioc: Adapter instance reference
+ * @sas_io_unit_pg0: Pointer to return SAS IO Unit page 0
+ * @pg_sz: Size of the memory allocated to the page pointer
+ *
+ * This is handler for config page read for the SAS IO Unit
+ * page0. This routine checks ioc_status to decide whether the
+ * page read is success or not.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_get_sas_io_unit_pg0(struct mpi3mr_ioc *mrioc,
+	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0, u16 pg_sz)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u16 ioc_status = 0;
+
+	memset(sas_io_unit_pg0, 0, pg_sz);
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
+	cfg_req.page_number = 0;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "sas io unit page0 header read failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "sas io unit page0 header read failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg0, pg_sz)) {
+		ioc_err(mrioc, "sas io unit page0 read failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "sas io unit page0 read failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+	return 0;
+out_failed:
+	return -1;
+}
+
+/**
+ * mpi3mr_cfg_get_sas_io_unit_pg1 - Read current SASIOUnit page1
+ * @mrioc: Adapter instance reference
+ * @sas_io_unit_pg1: Pointer to return SAS IO Unit page 1
+ * @pg_sz: Size of the memory allocated to the page pointer
+ *
+ * This is handler for config page read for the SAS IO Unit
+ * page1. This routine checks ioc_status to decide whether the
+ * page read is success or not.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_get_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
+	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u16 ioc_status = 0;
+
+	memset(sas_io_unit_pg1, 0, pg_sz);
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
+	cfg_req.page_number = 1;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "sas io unit page1 header read failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "sas io unit page1 header read failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
+		ioc_err(mrioc, "sas io unit page1 read failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "sas io unit page1 read failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+	return 0;
+out_failed:
+	return -1;
+}
+
+/**
+ * mpi3mr_cfg_set_sas_io_unit_pg1 - Write SASIOUnit page1
+ * @mrioc: Adapter instance reference
+ * @sas_io_unit_pg1: Pointer to the SAS IO Unit page 1 to write
+ * @pg_sz: Size of the memory allocated to the page pointer
+ *
+ * This is handler for config page write for the SAS IO Unit
+ * page1. This routine checks ioc_status to decide whether the
+ * page read is success or not. This will modify both current
+ * and persistent page.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+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)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u16 ioc_status = 0;
+
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
+	cfg_req.page_number = 1;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "sas io unit page1 header read failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "sas io unit page1 header read failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+	cfg_req.action = MPI3_CONFIG_ACTION_WRITE_CURRENT;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
+		ioc_err(mrioc, "sas io unit page1 write current failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "sas io unit page1 write current failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+
+	cfg_req.action = MPI3_CONFIG_ACTION_WRITE_PERSISTENT;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
+		ioc_err(mrioc, "sas io unit page1 write persistent failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "sas io unit page1 write persistent failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+	return 0;
+out_failed:
+	return -1;
+}
+
+/**
+ * mpi3mr_cfg_get_driver_pg1 - Read current Driver page1
+ * @mrioc: Adapter instance reference
+ * @driver_pg1: Pointer to return Driver page 1
+ * @pg_sz: Size of the memory allocated to the page pointer
+ *
+ * This is handler for config page read for the Driver page1.
+ * This routine checks ioc_status to decide whether the page
+ * read is success or not.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc,
+	struct mpi3_driver_page1 *driver_pg1, u16 pg_sz)
+{
+	struct mpi3_config_page_header cfg_hdr;
+	struct mpi3_config_request cfg_req;
+	u16 ioc_status = 0;
+
+	memset(driver_pg1, 0, pg_sz);
+	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
+	memset(&cfg_req, 0, sizeof(cfg_req));
+
+	cfg_req.function = MPI3_FUNCTION_CONFIG;
+	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
+	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DRIVER;
+	cfg_req.page_number = 1;
+	cfg_req.page_address = 0;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
+		ioc_err(mrioc, "driver page1 header read failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "driver page1 header read failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
+
+	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
+	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, driver_pg1, pg_sz)) {
+		ioc_err(mrioc, "driver page1 read failed\n");
+		goto out_failed;
+	}
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "driver page1 read failed with ioc_status(0x%04x)\n",
+		    ioc_status);
+		goto out_failed;
+	}
+	return 0;
+out_failed:
+	return -1;
+}
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 04/15] mpi3mr: Enable Enclosure device add event
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (2 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 03/15] mpi3mr: Added helper functions to retrieve cnfg pages Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-07-29 18:33   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 05/15] mpi3mr: Add framework to add phys to STL Sreekanth Reddy
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 9667 bytes --]

Enable and process the Enclosure device add event.

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h    |  19 +++++
 drivers/scsi/mpi3mr/mpi3mr_fw.c |   4 +
 drivers/scsi/mpi3mr/mpi3mr_os.c | 133 +++++++++++++++++++++++++++++++-
 3 files changed, 154 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 8af94d3..542b462 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -461,6 +461,16 @@ struct mpi3mr_throttle_group_info {
 	atomic_t pend_large_data_sz;
 };
 
+/**
+ * struct mpi3mr_enclosure_node - enclosure information
+ * @list: List of enclosures
+ * @pg0: Enclosure page 0;
+ */
+struct mpi3mr_enclosure_node {
+	struct list_head list;
+	struct mpi3_enclosure_page0 pg0;
+};
+
 /**
  * struct tgt_dev_sas_sata - SAS/SATA device specific
  * information cached from firmware given data
@@ -535,12 +545,14 @@ union _form_spec_inf {
  * @slot: Slot number
  * @encl_handle: FW enclosure handle
  * @perst_id: FW assigned Persistent ID
+ * @devpg0_flag: Device Page0 flag
  * @dev_type: SAS/SATA/PCIE device type
  * @is_hidden: Should be exposed to upper layers or not
  * @host_exposed: Already exposed to host or not
  * @io_throttle_enabled: I/O throttling needed or not
  * @q_depth: Device specific Queue Depth
  * @wwid: World wide ID
+ * @enclosure_logical_id: Enclosure logical identifier
  * @dev_spec: Device type specific information
  * @ref_count: Reference count
  */
@@ -552,12 +564,14 @@ struct mpi3mr_tgt_dev {
 	u16 slot;
 	u16 encl_handle;
 	u16 perst_id;
+	u16 devpg0_flag;
 	u8 dev_type;
 	u8 is_hidden;
 	u8 host_exposed;
 	u8 io_throttle_enabled;
 	u16 q_depth;
 	u64 wwid;
+	u64 enclosure_logical_id;
 	union _form_spec_inf dev_spec;
 	struct kref ref_count;
 };
@@ -877,6 +891,7 @@ 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
+ * @enclosure_list: List of Enclosure objects
  */
 struct mpi3mr_ioc {
 	struct list_head list;
@@ -1053,6 +1068,8 @@ struct mpi3mr_ioc {
 	void *cfg_page;
 	dma_addr_t cfg_page_dma;
 	u16 cfg_page_sz;
+
+	struct list_head enclosure_list;
 };
 
 /**
@@ -1177,6 +1194,8 @@ int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc,
 	struct mpi3mr_drv_cmd *drv_cmd);
 void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data,
 	u16 event_data_size);
+struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
+	struct mpi3mr_ioc *mrioc, u16 handle);
 extern const struct attribute_group *mpi3mr_host_groups[];
 extern const struct attribute_group *mpi3mr_dev_groups[];
 
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 50e88d4..9c36f52 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -244,6 +244,9 @@ static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
 		desc = "Enclosure Device Status Change";
 		break;
+	case MPI3_EVENT_ENCL_DEVICE_ADDED:
+		desc = "Enclosure Added";
+		break;
 	case MPI3_EVENT_HARD_RESET_RECEIVED:
 		desc = "Hard Reset Received";
 		break;
@@ -3660,6 +3663,7 @@ static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc)
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
+	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_ADDED);
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 40bed22..ca718cb 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -1026,6 +1026,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
 {
 	u16 flags = 0;
 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
+	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
 	u8 prot_mask = 0;
 
 	tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id);
@@ -1036,8 +1037,17 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
 	tgtdev->slot = le16_to_cpu(dev_pg0->slot);
 	tgtdev->q_depth = le16_to_cpu(dev_pg0->queue_depth);
 	tgtdev->wwid = le64_to_cpu(dev_pg0->wwid);
+	tgtdev->devpg0_flag = le16_to_cpu(dev_pg0->flags);
+
+	if (tgtdev->encl_handle)
+		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
+		    tgtdev->encl_handle);
+	if (enclosure_dev)
+		tgtdev->enclosure_logical_id = le64_to_cpu(
+		    enclosure_dev->pg0.enclosure_logical_id);
+
+	flags = tgtdev->devpg0_flag;
 
-	flags = le16_to_cpu(dev_pg0->flags);
 	tgtdev->is_hidden = (flags & MPI3_DEVICE0_FLAGS_HIDDEN);
 
 	if (is_added == true)
@@ -1265,6 +1275,116 @@ out:
 		mpi3mr_tgtdev_put(tgtdev);
 }
 
+/**
+ * mpi3mr_enclosure_find_by_handle - enclosure search by handle
+ * @mrioc: Adapter instance reference
+ * @handle: Firmware device handle of the enclosure
+ *
+ * This searches for enclosure device based on handle, then returns the
+ * enclosure object.
+ *
+ * Return: Enclosure object reference or NULL
+ */
+struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
+	struct mpi3mr_ioc *mrioc, u16 handle)
+{
+	struct mpi3mr_enclosure_node *enclosure_dev, *r = NULL;
+
+	list_for_each_entry(enclosure_dev, &mrioc->enclosure_list, list) {
+		if (le16_to_cpu(enclosure_dev->pg0.enclosure_handle) != handle)
+			continue;
+		r = enclosure_dev;
+		goto out;
+	}
+out:
+	return r;
+}
+
+/**
+ * mpi3mr_encldev_add_chg_evt_debug - debug for enclosure event
+ * @mrioc: Adapter instance reference
+ * @encl_pg0: Enclosure page 0.
+ * @is_added: Added event or not
+ *
+ * Return nothing.
+ */
+static void mpi3mr_encldev_add_chg_evt_debug(struct mpi3mr_ioc *mrioc,
+	struct mpi3_enclosure_page0 *encl_pg0, u8 is_added)
+{
+	char *reason_str = NULL;
+
+	if (!(mrioc->logging_level & MPI3_DEBUG_EVENT_WORK_TASK))
+		return;
+
+	if (is_added)
+		reason_str = "enclosure added";
+	else
+		reason_str = "enclosure dev status changed";
+
+	ioc_info(mrioc,
+	    "%s: handle(0x%04x), enclosure logical id(0x%016llx)\n",
+	    reason_str, le16_to_cpu(encl_pg0->enclosure_handle),
+	    (unsigned long long)le64_to_cpu(encl_pg0->enclosure_logical_id));
+	ioc_info(mrioc,
+	    "number of slots(%d), port(%d), flags(0x%04x), present(%d)\n",
+	    le16_to_cpu(encl_pg0->num_slots), encl_pg0->io_unit_port,
+	    le16_to_cpu(encl_pg0->flags),
+	    ((le16_to_cpu(encl_pg0->flags) &
+	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4));
+}
+
+/**
+ * mpi3mr_encldev_add_chg_evt_bh - Enclosure evt bottomhalf
+ * @mrioc: Adapter instance reference
+ * @fwevt: Firmware event reference
+ *
+ * Prints information about the Enclosure device status or
+ * Enclosure add events if logging is enabled and add or remove
+ * the enclosure from the controller's internal list of
+ * enclosures.
+ *
+ * Return: Nothing.
+ */
+static void mpi3mr_encldev_add_chg_evt_bh(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_fwevt *fwevt)
+{
+	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
+	struct mpi3_enclosure_page0 *encl_pg0;
+	u16 encl_handle;
+	u8 added, present;
+
+	encl_pg0 = (struct mpi3_enclosure_page0 *) fwevt->event_data;
+	added = (fwevt->event_id == MPI3_EVENT_ENCL_DEVICE_ADDED) ? 1 : 0;
+	mpi3mr_encldev_add_chg_evt_debug(mrioc, encl_pg0, added);
+
+
+	encl_handle = le16_to_cpu(encl_pg0->enclosure_handle);
+	present = ((le16_to_cpu(encl_pg0->flags) &
+	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4);
+
+	if (encl_handle)
+		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
+		    encl_handle);
+	if (!enclosure_dev && present) {
+		enclosure_dev =
+			kzalloc(sizeof(struct mpi3mr_enclosure_node),
+			    GFP_KERNEL);
+		if (!enclosure_dev)
+			return;
+		list_add_tail(&enclosure_dev->list,
+		    &mrioc->enclosure_list);
+	}
+	if (enclosure_dev) {
+		if (!present) {
+			list_del(&enclosure_dev->list);
+			kfree(enclosure_dev);
+		} else
+			memcpy(&enclosure_dev->pg0, encl_pg0,
+			    sizeof(enclosure_dev->pg0));
+
+	}
+}
+
 /**
  * mpi3mr_sastopochg_evt_debug - SASTopoChange details
  * @mrioc: Adapter instance reference
@@ -1641,6 +1761,13 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
 		mpi3mr_devstatuschg_evt_bh(mrioc, fwevt);
 		break;
 	}
+	case MPI3_EVENT_ENCL_DEVICE_ADDED:
+	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
+	{
+		mpi3mr_encldev_add_chg_evt_bh(mrioc, fwevt);
+		break;
+	}
+
 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
 	{
 		mpi3mr_sastopochg_evt_bh(mrioc, fwevt);
@@ -2502,6 +2629,8 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
 	}
 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
 	case MPI3_EVENT_LOG_DATA:
+	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
+	case MPI3_EVENT_ENCL_DEVICE_ADDED:
 	{
 		process_evt_bh = 1;
 		break;
@@ -2516,7 +2645,6 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
 		mpi3mr_cablemgmt_evt_th(mrioc, event_reply);
 		break;
 	}
-	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
 	case MPI3_EVENT_SAS_DISCOVERY:
 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
@@ -4569,6 +4697,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	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->enclosure_list);
 
 	mutex_init(&mrioc->reset_mutex);
 	mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 05/15] mpi3mr: Add framework to add phys to STL
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (3 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 04/15] mpi3mr: Enable Enclosure device add event Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-07-29 19:42   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 06/15] mpi3mr: Add helper functions to retrieve device objects Sreekanth Reddy
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 18197 bytes --]

Added framework to register and unregister the
host and expander phys with SCSI Transport Layer (STL).

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/Makefile           |   1 +
 drivers/scsi/mpi3mr/mpi3mr.h           |  93 ++++++
 drivers/scsi/mpi3mr/mpi3mr_transport.c | 430 +++++++++++++++++++++++++
 3 files changed, 524 insertions(+)
 create mode 100644 drivers/scsi/mpi3mr/mpi3mr_transport.c

diff --git a/drivers/scsi/mpi3mr/Makefile b/drivers/scsi/mpi3mr/Makefile
index f5cdbe4..ef86ca4 100644
--- a/drivers/scsi/mpi3mr/Makefile
+++ b/drivers/scsi/mpi3mr/Makefile
@@ -3,3 +3,4 @@ obj-m += mpi3mr.o
 mpi3mr-y +=  mpi3mr_os.o     \
 		mpi3mr_fw.o \
 		mpi3mr_app.o \
+		mpi3mr_transport.o
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 542b462..006bc5d 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -39,6 +39,7 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_tcq.h>
 #include <uapi/scsi/scsi_bsg_mpi3mr.h>
+#include <scsi/scsi_transport_sas.h>
 
 #include "mpi/mpi30_transport.h"
 #include "mpi/mpi30_cnfg.h"
@@ -461,6 +462,98 @@ struct mpi3mr_throttle_group_info {
 	atomic_t pend_large_data_sz;
 };
 
+/* HBA port flags */
+#define MPI3MR_HBA_PORT_FLAG_DIRTY	0x01
+
+/**
+ * struct mpi3mr_hba_port - HBA's port information
+ * @port_id: Port number
+ * @flags: HBA port flags
+ */
+struct mpi3mr_hba_port {
+	struct list_head list;
+	u8 port_id;
+	u8 flags;
+};
+
+/**
+ * struct mpi3mr_sas_port - Internal SAS port information
+ * @port_list: List of ports belonging to a SAS node
+ * @num_phys: Number of phys associated with port
+ * @hba_port: HBA port entry
+ * @remote_identify: Attached device identification
+ * @rphy: SAS transport layer rphy object
+ * @port: SAS transport layer port object
+ * @phy_list: mpi3mr_sas_phy objects belonging to this port
+ */
+struct mpi3mr_sas_port {
+	struct list_head port_list;
+	u8 num_phys;
+	struct mpi3mr_hba_port *hba_port;
+	struct sas_identify remote_identify;
+	struct sas_rphy *rphy;
+	struct sas_port *port;
+	struct list_head phy_list;
+};
+
+/**
+ * struct mpi3mr_sas_phy - Internal SAS Phy information
+ * @port_siblings: List of phys belonging to a port
+ * @identify: Phy identification
+ * @remote_identify: Attached device identification
+ * @phy: SAS transport layer Phy object
+ * @phy_id: Unique phy id within a port
+ * @handle: Firmware device handle for this phy
+ * @attached_handle: Firmware device handle for attached device
+ * @phy_belongs_to_port: Flag to indicate phy belongs to port
+   @hba_port: HBA port entry
+ */
+struct mpi3mr_sas_phy {
+	struct list_head port_siblings;
+	struct sas_identify identify;
+	struct sas_identify remote_identify;
+	struct sas_phy *phy;
+	u8 phy_id;
+	u16 handle;
+	u16 attached_handle;
+	u8 phy_belongs_to_port;
+	struct mpi3mr_hba_port *hba_port;
+};
+
+/**
+ * struct mpi3mr_sas_node - SAS host/expander information
+ * @list: List of sas nodes in a controller
+ * @parent_dev: Parent device class
+ * @num_phys: Number phys belonging to sas_node
+ * @sas_address: SAS address of sas_node
+ * @handle: Firmware device handle for this sas_host/expander
+ * @sas_address_parent: SAS address of parent expander or host
+ * @enclosure_handle: Firmware handle of enclosure of this node
+ * @device_info: Capabilities of this sas_host/expander
+ * @non_responding: used to refresh the expander devices during reset
+ * @host_node: Flag to indicate this is a host_node
+ * @hba_port: HBA port entry
+ * @phy: A list of phys that make up this sas_host/expander
+ * @sas_port_list: List of internal ports of this node
+ * @rphy: sas_rphy object of this expander node
+ */
+struct mpi3mr_sas_node {
+	struct list_head list;
+	struct device *parent_dev;
+	u8 num_phys;
+	u64 sas_address;
+	u16 handle;
+	u64 sas_address_parent;
+	u16 enclosure_handle;
+	u64 enclosure_logical_id;
+	u8 non_responding;
+	u8 host_node;
+	struct mpi3mr_hba_port *hba_port;
+	struct mpi3mr_sas_phy *phy;
+	struct list_head sas_port_list;
+	struct sas_rphy *rphy;
+};
+
 /**
  * struct mpi3mr_enclosure_node - enclosure information
  * @list: List of enclosures
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
new file mode 100644
index 0000000..989bf63
--- /dev/null
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -0,0 +1,430 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for Broadcom MPI3 Storage Controllers
+ *
+ * Copyright (C) 2017-2022 Broadcom Inc.
+ *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
+ *
+ */
+
+#include "mpi3mr.h"
+
+/**
+ * mpi3mr_convert_phy_link_rate -
+ * @link_rate: link rate as defined in the MPI header
+ *
+ * Convert link_rate from mpi format into sas_transport layer
+ * form.
+ *
+ * Return: A valid SAS transport layer defined link rate
+ */
+static enum sas_linkrate mpi3mr_convert_phy_link_rate(u8 link_rate)
+{
+	enum sas_linkrate rc;
+
+	switch (link_rate) {
+	case MPI3_SAS_NEG_LINK_RATE_1_5:
+		rc = SAS_LINK_RATE_1_5_GBPS;
+		break;
+	case MPI3_SAS_NEG_LINK_RATE_3_0:
+		rc = SAS_LINK_RATE_3_0_GBPS;
+		break;
+	case MPI3_SAS_NEG_LINK_RATE_6_0:
+		rc = SAS_LINK_RATE_6_0_GBPS;
+		break;
+	case MPI3_SAS_NEG_LINK_RATE_12_0:
+		rc = SAS_LINK_RATE_12_0_GBPS;
+		break;
+	case MPI3_SAS_NEG_LINK_RATE_22_5:
+		rc = SAS_LINK_RATE_12_0_GBPS;
+		break;
+	case MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED:
+		rc = SAS_PHY_DISABLED;
+		break;
+	case MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
+		rc = SAS_LINK_RATE_FAILED;
+		break;
+	case MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR:
+		rc = SAS_SATA_PORT_SELECTOR;
+		break;
+	case MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
+		rc = SAS_PHY_RESET_IN_PROGRESS;
+		break;
+	case MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
+	case MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
+	default:
+		rc = SAS_LINK_RATE_UNKNOWN;
+		break;
+	}
+	return rc;
+}
+
+/**
+ * mpi3mr_delete_sas_phy - Remove a single phy from port
+ * @mrioc: Adapter instance reference
+ * @mr_sas_port: Internal Port object
+ * @mr_sas_phy: Internal Phy object
+ *
+ * Return: None.
+ */
+static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_sas_port *mr_sas_port,
+	struct mpi3mr_sas_phy *mr_sas_phy)
+{
+	u64 sas_address = mr_sas_port->remote_identify.sas_address;
+
+	dev_info(&mr_sas_phy->phy->dev,
+	    "remove: sas_address(0x%016llx), phy(%d)\n",
+	    (unsigned long long) sas_address, mr_sas_phy->phy_id);
+
+	list_del(&mr_sas_phy->port_siblings);
+	mr_sas_port->num_phys--;
+	sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);
+	mr_sas_phy->phy_belongs_to_port = 0;
+}
+
+/**
+ * mpi3mr_add_sas_phy - Adding a single phy to a port
+ * @mrioc: Adapter instance reference
+ * @mr_sas_port: Internal Port object
+ * @mr_sas_phy: Internal Phy object
+ *
+ * Return: None.
+ */
+static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_sas_port *mr_sas_port,
+	struct mpi3mr_sas_phy *mr_sas_phy)
+{
+	u64 sas_address = mr_sas_port->remote_identify.sas_address;
+
+	dev_info(&mr_sas_phy->phy->dev,
+	    "add: sas_address(0x%016llx), phy(%d)\n", (unsigned long long)
+	    sas_address, mr_sas_phy->phy_id);
+
+	list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);
+	mr_sas_port->num_phys++;
+	sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);
+	mr_sas_phy->phy_belongs_to_port = 1;
+}
+
+/**
+ * mpi3mr_add_phy_to_an_existing_port - add phy to existing port
+ * @mrioc: Adapter instance reference
+ * @mr_sas_node: Internal sas node object (expander or host)
+ * @mr_sas_phy: Internal Phy object *
+ * @sas_address: SAS address of device/expander were phy needs
+ *             to be added to
+ * @hba_port: HBA port entry
+ *
+ * Return: None.
+ */
+static void mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy,
+	u64 sas_address, struct mpi3mr_hba_port *hba_port)
+{
+	struct mpi3mr_sas_port *mr_sas_port;
+	struct mpi3mr_sas_phy *srch_phy;
+
+	if (mr_sas_phy->phy_belongs_to_port == 1)
+		return;
+
+	if (!hba_port)
+		return;
+
+	list_for_each_entry(mr_sas_port, &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;
+		list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
+		    port_siblings) {
+			if (srch_phy == mr_sas_phy)
+				return;
+		}
+		mpi3mr_add_sas_phy(mrioc, mr_sas_port, mr_sas_phy);
+		return;
+	}
+}
+
+/**
+ * mpi3mr_del_phy_from_an_existing_port - del phy from a port
+ * @mrioc: Adapter instance reference
+ * @mr_sas_node: Internal sas node object (expander or host)
+ * @mr_sas_phy: Internal Phy object
+ *
+ * Return: None.
+ */
+static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy)
+{
+	struct mpi3mr_sas_port *mr_sas_port, *next;
+	struct mpi3mr_sas_phy *srch_phy;
+
+	if (mr_sas_phy->phy_belongs_to_port == 0)
+		return;
+
+	list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
+	    port_list) {
+		list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
+		    port_siblings) {
+			if (srch_phy != mr_sas_phy)
+				continue;
+			mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
+			    mr_sas_phy);
+			return;
+		}
+	}
+}
+
+/**
+ * mpi3mr_sas_port_sanity_check - sanity check while adding port
+ * @mrioc: Adapter instance reference
+ * @mr_sas_node: Internal sas node object (expander or host)
+ * @sas_address: SAS address of device/expander
+ * @hba_port: HBA port entry
+ *
+ * Verifies whether the Phys attached to a device with the given
+ * SAS address already belongs to an existing sas port if so
+ * will remove those phys from the sas port
+ *
+ * Return: None.
+ */
+static void mpi3mr_sas_port_sanity_check(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_sas_node *mr_sas_node, u64 sas_address,
+	struct mpi3mr_hba_port *hba_port)
+{
+	int i;
+
+	for (i = 0; i < mr_sas_node->num_phys; i++) {
+		if ((mr_sas_node->phy[i].remote_identify.sas_address !=
+		    sas_address) || (mr_sas_node->phy[i].hba_port != hba_port))
+			continue;
+		if (mr_sas_node->phy[i].phy_belongs_to_port == 1)
+			mpi3mr_del_phy_from_an_existing_port(mrioc,
+			    mr_sas_node, &mr_sas_node->phy[i]);
+	}
+}
+
+/**
+ * mpi3mr_set_identify - set identify for phys and end devices
+ * @mrioc: Adapter instance reference
+ * @handle: Firmware device handle
+ * @identify: SAS transport layer's identify info
+ *
+ * Populates sas identify info for a specific device.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+static int mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle,
+	struct sas_identify *identify)
+{
+
+	struct mpi3_device_page0 device_pg0;
+	struct mpi3_device0_sas_sata_format *sasinf;
+	u16 device_info;
+	u16 ioc_status;
+
+	if (mrioc->reset_in_progress) {
+		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
+		return -EFAULT;
+	}
+
+	if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,
+	    sizeof(device_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 -EIO;
+	}
+
+	memset(identify, 0, sizeof(struct sas_identify));
+	sasinf = &device_pg0.device_specific.sas_sata_format;
+	device_info = le16_to_cpu(sasinf->device_info);
+
+	/* sas_address */
+	identify->sas_address = le64_to_cpu(sasinf->sas_address);
+
+	/* phy number of the parent device this device is linked to */
+	identify->phy_identifier = sasinf->phy_num;
+
+	/* device_type */
+	switch (device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) {
+	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE:
+		identify->device_type = SAS_PHY_UNUSED;
+		break;
+	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE:
+		identify->device_type = SAS_END_DEVICE;
+		break;
+	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER:
+		identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
+		break;
+	}
+
+	/* initiator_port_protocols */
+	if (device_info & MPI3_SAS_DEVICE_INFO_SSP_INITIATOR)
+		identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
+	/* MPI3.0 doesn't have define for SATA INIT so setting both here*/
+	if (device_info & MPI3_SAS_DEVICE_INFO_STP_INITIATOR)
+		identify->initiator_port_protocols |= (SAS_PROTOCOL_STP |
+		    SAS_PROTOCOL_SATA);
+	if (device_info & MPI3_SAS_DEVICE_INFO_SMP_INITIATOR)
+		identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
+
+	/* target_port_protocols */
+	if (device_info & MPI3_SAS_DEVICE_INFO_SSP_TARGET)
+		identify->target_port_protocols |= SAS_PROTOCOL_SSP;
+	/* MPI3.0 doesn't have define for STP Target so setting both here*/
+	if (device_info & MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET)
+		identify->target_port_protocols |= (SAS_PROTOCOL_STP |
+		    SAS_PROTOCOL_SATA);
+	if (device_info & MPI3_SAS_DEVICE_INFO_SMP_TARGET)
+		identify->target_port_protocols |= SAS_PROTOCOL_SMP;
+	return 0;
+}
+
+/**
+ * mpi3mr_add_host_phy - report sas_host phy to SAS transport
+ * @mrioc: Adapter instance reference
+ * @mr_sas_phy: Internal Phy object
+ * @phy_pg0: SAS phy page 0
+ * @parent_dev: Prent device class object
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+static int mpi3mr_add_host_phy(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_sas_phy *mr_sas_phy, struct mpi3_sas_phy_page0 phy_pg0,
+	struct device *parent_dev)
+{
+	struct sas_phy *phy;
+	int phy_index = mr_sas_phy->phy_id;
+
+
+	INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
+	phy = sas_phy_alloc(parent_dev, phy_index);
+	if (!phy) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		return -1;
+	}
+	if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
+	    &mr_sas_phy->identify))) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		sas_phy_free(phy);
+		return -1;
+	}
+	phy->identify = mr_sas_phy->identify;
+	mr_sas_phy->attached_handle = le16_to_cpu(phy_pg0.attached_dev_handle);
+	if (mr_sas_phy->attached_handle)
+		mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
+		    &mr_sas_phy->remote_identify);
+	phy->identify.phy_identifier = mr_sas_phy->phy_id;
+	phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
+	    (phy_pg0.negotiated_link_rate &
+	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
+	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
+	phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
+	    phy_pg0.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
+	phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
+	    phy_pg0.hw_link_rate >> 4);
+	phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
+	    phy_pg0.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
+	phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
+	    phy_pg0.programmed_link_rate >> 4);
+	phy->hostdata = mr_sas_phy->hba_port;
+
+	if ((sas_phy_add(phy))) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		sas_phy_free(phy);
+		return -1;
+	}
+	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
+		dev_info(&phy->dev,
+		    "add: handle(0x%04x), sas_address(0x%016llx)\n"
+		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
+		    mr_sas_phy->handle, (unsigned long long)
+		    mr_sas_phy->identify.sas_address,
+		    mr_sas_phy->attached_handle,
+		    (unsigned long long)
+		    mr_sas_phy->remote_identify.sas_address);
+	mr_sas_phy->phy = phy;
+	return 0;
+}
+
+/**
+ * mpi3mr_add_expander_phy - report expander phy to transport
+ * @mrioc: Adapter instance reference
+ * @mr_sas_phy: Internal Phy object
+ * @expander_pg1: SAS Expander page 1
+ * @parent_dev: Parent device class object
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+static int mpi3mr_add_expander_phy(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_sas_phy *mr_sas_phy,
+	struct mpi3_sas_expander_page1 expander_pg1,
+	struct device *parent_dev)
+{
+	struct sas_phy *phy;
+	int phy_index = mr_sas_phy->phy_id;
+
+	INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
+	phy = sas_phy_alloc(parent_dev, phy_index);
+	if (!phy) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		return -1;
+	}
+	if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
+	    &mr_sas_phy->identify))) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		sas_phy_free(phy);
+		return -1;
+	}
+	phy->identify = mr_sas_phy->identify;
+	mr_sas_phy->attached_handle =
+	    le16_to_cpu(expander_pg1.attached_dev_handle);
+	if (mr_sas_phy->attached_handle)
+		mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
+		    &mr_sas_phy->remote_identify);
+	phy->identify.phy_identifier = mr_sas_phy->phy_id;
+	phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
+	    (expander_pg1.negotiated_link_rate &
+	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
+	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
+	phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
+	    expander_pg1.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
+	phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
+	    expander_pg1.hw_link_rate >> 4);
+	phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
+	    expander_pg1.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
+	phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
+	    expander_pg1.programmed_link_rate >> 4);
+	phy->hostdata = mr_sas_phy->hba_port;
+
+	if ((sas_phy_add(phy))) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		sas_phy_free(phy);
+		return -1;
+	}
+	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
+		dev_info(&phy->dev,
+		    "add: handle(0x%04x), sas_address(0x%016llx)\n"
+		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
+		    mr_sas_phy->handle, (unsigned long long)
+		    mr_sas_phy->identify.sas_address,
+		    mr_sas_phy->attached_handle,
+		    (unsigned long long)
+		    mr_sas_phy->remote_identify.sas_address);
+	mr_sas_phy->phy = phy;
+	return 0;
+}
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 06/15] mpi3mr: Add helper functions to retrieve device objects
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (4 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 05/15] mpi3mr: Add framework to add phys to STL Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-07-29 20:11   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 07/15] mpi3mr: Add helper functions to manage device's port Sreekanth Reddy
                   ` (8 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 11602 bytes --]

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 | 280 +++++++++++++++++++++++++
 3 files changed, 297 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 989bf63..fea3aae 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -9,6 +9,237 @@
 
 #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 +659,52 @@ 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


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 07/15] mpi3mr: Add helper functions to manage device's port
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (5 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 06/15] mpi3mr: Add helper functions to retrieve device objects Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-08-01 19:07   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 08/15] mpi3mr: Enable STL on HBAs where multipath is disabled Sreekanth Reddy
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 19450 bytes --]

Added below helper functions,
- Add, update the host phys with STL
- Add, remove the device's sas port with STL

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h           |  13 +
 drivers/scsi/mpi3mr/mpi3mr_os.c        |   2 +-
 drivers/scsi/mpi3mr/mpi3mr_transport.c | 527 +++++++++++++++++++++++++
 3 files changed, 541 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 742caf5..8ab843a 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -570,12 +570,18 @@ struct mpi3mr_enclosure_node {
  *
  * @sas_address: World wide unique SAS address
  * @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
+ * @rphy: SAS transport layer rphy object
  */
 struct tgt_dev_sas_sata {
 	u64 sas_address;
 	u16 dev_info;
+	u8 sas_transport_attached;
+	u8 pend_sas_rphy_add;
 	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);
 struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc,
 	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*/
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index b75ce73..905b434 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -804,7 +804,7 @@ static void mpi3mr_set_io_divert_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc,
  *
  * 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)
 {
 	ioc_notice(mrioc, "Device %s was in progress before the reset and\n",
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index fea3aae..b85d60f 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -708,3 +708,530 @@ struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc,
 
 	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);
+}
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 08/15] mpi3mr: Enable STL on HBAs where multipath is disabled
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (6 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 07/15] mpi3mr: Add helper functions to manage device's port Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-08-01 19:12   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 09/15] mpi3mr: Add expander devices to STL Sreekanth Reddy
                   ` (6 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 7171 bytes --]

Register the SAS, SATA devices to SCSI Transport Layer (STL)
only if multipath capability is disabled on the controller's
firmware.

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h    |  6 ++++++
 drivers/scsi/mpi3mr/mpi3mr_fw.c | 13 +++++++++++++
 drivers/scsi/mpi3mr/mpi3mr_os.c | 31 +++++++++++++++++++++++++++----
 3 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 8ab843a..8c8703e 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -650,6 +650,8 @@ union _form_spec_inf {
  * @dev_type: SAS/SATA/PCIE device type
  * @is_hidden: Should be exposed to upper layers or not
  * @host_exposed: Already exposed to host or not
+ * @io_unit_port: IO Unit port ID
+ * @non_stl: Is this device not to be attached with SAS TL
  * @io_throttle_enabled: I/O throttling needed or not
  * @q_depth: Device specific Queue Depth
  * @wwid: World wide ID
@@ -669,6 +671,8 @@ struct mpi3mr_tgt_dev {
 	u8 dev_type;
 	u8 is_hidden;
 	u8 host_exposed;
+	u8 io_unit_port;
+	u8 non_stl;
 	u8 io_throttle_enabled;
 	u16 q_depth;
 	u64 wwid;
@@ -992,6 +996,7 @@ 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_transport_enabled: SAS transport enabled or not
  * @sas_hba: SAS node for the controller
  * @sas_expander_list: SAS node list of expanders
  * @sas_node_lock: Lock to protect SAS node list
@@ -1174,6 +1179,7 @@ struct mpi3mr_ioc {
 	dma_addr_t cfg_page_dma;
 	u16 cfg_page_sz;
 
+	u8 sas_transport_enabled;
 	struct mpi3mr_sas_node sas_hba;
 	struct list_head sas_expander_list;
 	spinlock_t sas_node_lock;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 9c36f52..0659d3f 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -1136,6 +1136,13 @@ mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
 		return -EPERM;
 	}
 
+	if ((mrioc->sas_transport_enabled) && (mrioc->facts.ioc_capabilities &
+	    MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED))
+		ioc_err(mrioc,
+		    "critical error: multipath capability is enabled at the\n"
+		    "\tcontroller while sas transport support is enabled at the\n"
+		    "\tdriver, please reboot the system or reload the driver\n");
+
 	dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8;
 	if (mrioc->facts.max_devhandle % 8)
 		dev_handle_bitmap_sz++;
@@ -3453,6 +3460,7 @@ static const struct {
 	char *name;
 } mpi3mr_capabilities[] = {
 	{ MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" },
+	{ MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED, "MultiPath" },
 };
 
 /**
@@ -3734,6 +3742,11 @@ retry_init:
 		mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
 		    MPI3MR_HOST_IOS_KDUMP);
 
+	if (!(mrioc->facts.ioc_capabilities &
+	    MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED)) {
+		mrioc->sas_transport_enabled = 1;
+	}
+
 	mrioc->reply_sz = mrioc->facts.reply_sz;
 
 	retval = mpi3mr_check_reset_dma_mask(mrioc);
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 905b434..ae77422 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -1032,6 +1032,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
 	tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id);
 	tgtdev->dev_handle = le16_to_cpu(dev_pg0->dev_handle);
 	tgtdev->dev_type = dev_pg0->device_form;
+	tgtdev->io_unit_port = dev_pg0->io_unit_port;
 	tgtdev->encl_handle = le16_to_cpu(dev_pg0->enclosure_handle);
 	tgtdev->parent_handle = le16_to_cpu(dev_pg0->parent_dev_handle);
 	tgtdev->slot = le16_to_cpu(dev_pg0->slot);
@@ -1092,6 +1093,13 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
 		else if (!(dev_info & (MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET |
 		    MPI3_SAS_DEVICE_INFO_SSP_TARGET)))
 			tgtdev->is_hidden = 1;
+
+		if (((tgtdev->devpg0_flag &
+		    MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)
+		    && (tgtdev->devpg0_flag &
+		    MPI3_DEVICE0_FLAGS_ATT_METHOD_VIRTUAL)) ||
+		    (tgtdev->parent_handle == 0xFFFF))
+			tgtdev->non_stl = 1;
 		break;
 	}
 	case MPI3_DEVICE_DEVFORM_PCIE:
@@ -1124,6 +1132,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
 		    ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE))
 			tgtdev->is_hidden = 1;
+		tgtdev->non_stl = 1;
 		if (!mrioc->shost)
 			break;
 		prot_mask = scsi_host_get_prot(mrioc->shost);
@@ -1147,6 +1156,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
 		tgtdev->dev_spec.vd_inf.state = vdinf->vd_state;
 		if (vdinf->vd_state == MPI3_DEVICE0_VD_STATE_OFFLINE)
 			tgtdev->is_hidden = 1;
+		tgtdev->non_stl = 1;
 		tgtdev->dev_spec.vd_inf.tg_id = vdinf_io_throttle_group;
 		tgtdev->dev_spec.vd_inf.tg_high =
 		    le16_to_cpu(vdinf->io_throttle_group_high) * 2048;
@@ -1424,8 +1434,9 @@ mpi3mr_sastopochg_evt_debug(struct mpi3mr_ioc *mrioc,
 	ioc_info(mrioc, "%s :sas topology change: (%s)\n",
 	    __func__, status_str);
 	ioc_info(mrioc,
-	    "%s :\texpander_handle(0x%04x), enclosure_handle(0x%04x) start_phy(%02d), num_entries(%d)\n",
+	    "%s :\texpander_handle(0x%04x), port(%d), enclosure_handle(0x%04x) start_phy(%02d), num_entries(%d)\n",
 	    __func__, le16_to_cpu(event_data->expander_dev_handle),
+	    event_data->io_unit_port,
 	    le16_to_cpu(event_data->enclosure_handle),
 	    event_data->start_phy_num, event_data->num_entries);
 	for (i = 0; i < event_data->num_entries; i++) {
@@ -1732,6 +1743,9 @@ static void mpi3mr_set_qd_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc,
 static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
 	struct mpi3mr_fwevt *fwevt)
 {
+	struct mpi3_device_page0 *dev_pg0 = NULL;
+	u16 perst_id;
+
 	mpi3mr_fwevt_del_from_list(mrioc, fwevt);
 	mrioc->current_event = fwevt;
 
@@ -1752,8 +1766,10 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
 	}
 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
 	{
-		mpi3mr_devinfochg_evt_bh(mrioc,
-		    (struct mpi3_device_page0 *)fwevt->event_data);
+		dev_pg0 = (struct mpi3_device_page0 *)fwevt->event_data;
+		perst_id = le16_to_cpu(dev_pg0->persistent_id);
+		if (perst_id != MPI3_DEVICE0_PERSISTENTID_INVALID)
+			mpi3mr_devinfochg_evt_bh(mrioc, dev_pg0);
 		break;
 	}
 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
@@ -1851,6 +1867,9 @@ static int mpi3mr_create_tgtdev(struct mpi3mr_ioc *mrioc,
 	u16 perst_id = 0;
 
 	perst_id = le16_to_cpu(dev_pg0->persistent_id);
+	if (perst_id == MPI3_DEVICE0_PERSISTENTID_INVALID)
+		return retval;
+
 	tgtdev = mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
 	if (tgtdev) {
 		mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, true);
@@ -4850,7 +4869,11 @@ static void mpi3mr_remove(struct pci_dev *pdev)
 	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
 	if (wq)
 		destroy_workqueue(wq);
-	scsi_remove_host(shost);
+
+	if (mrioc->sas_transport_enabled)
+		sas_remove_host(shost);
+	else
+		scsi_remove_host(shost);
 
 	list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
 	    list) {
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 09/15] mpi3mr: Add expander devices to STL
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (7 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 08/15] mpi3mr: Enable STL on HBAs where multipath is disabled Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-08-01 20:50   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 10/15] mpi3mr: Get target object based on rphy Sreekanth Reddy
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 17407 bytes --]

Register/unregister the expander devices to
SCSI Transport Layer(STL) whenever the corresponding expander
is added/removed from topology.

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h           |   7 +
 drivers/scsi/mpi3mr/mpi3mr_os.c        |  36 ++-
 drivers/scsi/mpi3mr/mpi3mr_transport.c | 402 ++++++++++++++++++++++++-
 3 files changed, 436 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 8c8703e..9cd5f88 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -1341,6 +1341,11 @@ 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);
+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,
 	u8 port_id);
 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,
 	u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate,
 	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,
 	bool device_add);
 #endif /*MPI3MR_H_INCLUDED*/
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index ae77422..9a32dc6 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -824,7 +824,7 @@ void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc,
  *
  * 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_stgt_priv_data *tgt_priv;
@@ -1494,7 +1494,10 @@ static void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc,
 	int i;
 	u16 handle;
 	u8 reason_code;
+	u64 exp_sas_address = 0;
+	struct mpi3mr_hba_port *hba_port = NULL;
 	struct mpi3mr_tgt_dev *tgtdev = NULL;
+	struct mpi3mr_sas_node *sas_expander = NULL;
 
 	mpi3mr_sastopochg_evt_debug(mrioc, event_data);
 
@@ -1524,6 +1527,13 @@ static void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc,
 		if (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);
+	}
 }
 
 /**
@@ -1744,7 +1754,8 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
 	struct mpi3mr_fwevt *fwevt)
 {
 	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);
 	mrioc->current_event = fwevt;
@@ -1758,10 +1769,23 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
 	switch (fwevt->event_id) {
 	case MPI3_EVENT_DEVICE_ADDED:
 	{
-		struct mpi3_device_page0 *dev_pg0 =
-		    (struct mpi3_device_page0 *)fwevt->event_data;
-		mpi3mr_report_tgtdev_to_host(mrioc,
-		    le16_to_cpu(dev_pg0->persistent_id));
+		dev_pg0 = (struct mpi3_device_page0 *)fwevt->event_data;
+		perst_id = le16_to_cpu(dev_pg0->persistent_id);
+		handle = le16_to_cpu(dev_pg0->dev_handle);
+		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;
 	}
 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index b85d60f..1d6ae9d 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -21,7 +21,7 @@
  *
  * 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)
 {
 	struct mpi3mr_sas_node *sas_expander, *r;
@@ -159,6 +159,45 @@ out:
 	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
  * @mrioc: Adapter instance reference
@@ -379,6 +418,35 @@ 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
  * @mrioc: Adapter instance reference
@@ -402,8 +470,12 @@ static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,
 		    port_siblings) {
 			if (srch_phy != mr_sas_phy)
 				continue;
-			mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
-			    mr_sas_phy);
+			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,
+				    mr_sas_phy);
 			return;
 		}
 	}
@@ -1235,3 +1307,327 @@ static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
 
 	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);
+
+}
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 10/15] mpi3mr: Get target object based on rphy
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (8 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 09/15] mpi3mr: Add expander devices to STL Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-08-01 21:27   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 11/15] mpi3mr: Add SAS SATA end devices to STL Sreekanth Reddy
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 8659 bytes --]

When device is registered with the STL then
get the corresponding device's target object
using the rphy in below callback functions,

- mpi3mr_target_alloc,
- mpi3mr_slave_alloc,
- mpi3mr_slave_configure,
- mpi3mr_slave_destroy

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h           |  4 ++
 drivers/scsi/mpi3mr/mpi3mr_fw.c        |  2 +
 drivers/scsi/mpi3mr/mpi3mr_os.c        | 61 +++++++++++++++++++++-----
 drivers/scsi/mpi3mr/mpi3mr_transport.c | 29 ++++++++++++
 4 files changed, 86 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 9cd5f88..a91a57b 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -997,6 +997,7 @@ struct scmd_priv {
  * @cfg_page_dma: Configuration page DMA address
  * @cfg_page_sz: Default configuration page memory size
  * @sas_transport_enabled: SAS transport enabled or not
+ * @scsi_device_channel: Channel ID for SCSI devices
  * @sas_hba: SAS node for the controller
  * @sas_expander_list: SAS node list of expanders
  * @sas_node_lock: Lock to protect SAS node list
@@ -1180,6 +1181,7 @@ struct mpi3mr_ioc {
 	u16 cfg_page_sz;
 
 	u8 sas_transport_enabled;
+	u8 scsi_device_channel;
 	struct mpi3mr_sas_node sas_hba;
 	struct list_head sas_expander_list;
 	spinlock_t sas_node_lock;
@@ -1355,6 +1357,8 @@ void mpi3mr_update_links(struct mpi3mr_ioc *mrioc,
 	struct mpi3mr_hba_port *hba_port);
 void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
 	struct mpi3mr_tgt_dev *tgtdev);
+struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
+	struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy);
 void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc,
 	bool device_add);
 #endif /*MPI3MR_H_INCLUDED*/
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 0659d3f..9155434 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -3745,6 +3745,8 @@ retry_init:
 	if (!(mrioc->facts.ioc_capabilities &
 	    MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED)) {
 		mrioc->sas_transport_enabled = 1;
+		mrioc->scsi_device_channel = 1;
+		mrioc->shost->max_channel = 1;
 	}
 
 	mrioc->reply_sz = mrioc->facts.reply_sz;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 9a32dc6..aed9b60 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -4031,9 +4031,10 @@ static void mpi3mr_slave_destroy(struct scsi_device *sdev)
 	struct Scsi_Host *shost;
 	struct mpi3mr_ioc *mrioc;
 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
-	struct mpi3mr_tgt_dev *tgt_dev;
+	struct mpi3mr_tgt_dev *tgt_dev = NULL;
 	unsigned long flags;
 	struct scsi_target *starget;
+	struct sas_rphy *rphy = NULL;
 
 	if (!sdev->hostdata)
 		return;
@@ -4046,7 +4047,14 @@ static void mpi3mr_slave_destroy(struct scsi_device *sdev)
 	scsi_tgt_priv_data->num_luns--;
 
 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
-	tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
+	if (starget->channel == mrioc->scsi_device_channel)
+		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
+	else if (mrioc->sas_transport_enabled && !starget->channel) {
+		rphy = dev_to_rphy(starget->dev.parent);
+		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
+		    rphy->identify.sas_address, rphy);
+	}
+
 	if (tgt_dev && (!scsi_tgt_priv_data->num_luns))
 		tgt_dev->starget = NULL;
 	if (tgt_dev)
@@ -4111,16 +4119,23 @@ static int mpi3mr_slave_configure(struct scsi_device *sdev)
 	struct scsi_target *starget;
 	struct Scsi_Host *shost;
 	struct mpi3mr_ioc *mrioc;
-	struct mpi3mr_tgt_dev *tgt_dev;
+	struct mpi3mr_tgt_dev *tgt_dev = NULL;
 	unsigned long flags;
 	int retval = 0;
+	struct sas_rphy *rphy = NULL;
 
 	starget = scsi_target(sdev);
 	shost = dev_to_shost(&starget->dev);
 	mrioc = shost_priv(shost);
 
 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
-	tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
+	if (starget->channel == mrioc->scsi_device_channel)
+		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
+	else if (mrioc->sas_transport_enabled && !starget->channel) {
+		rphy = dev_to_rphy(starget->dev.parent);
+		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
+		    rphy->identify.sas_address, rphy);
+	}
 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
 	if (!tgt_dev)
 		return -ENXIO;
@@ -4168,11 +4183,12 @@ static int mpi3mr_slave_alloc(struct scsi_device *sdev)
 	struct Scsi_Host *shost;
 	struct mpi3mr_ioc *mrioc;
 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
-	struct mpi3mr_tgt_dev *tgt_dev;
+	struct mpi3mr_tgt_dev *tgt_dev = NULL;
 	struct mpi3mr_sdev_priv_data *scsi_dev_priv_data;
 	unsigned long flags;
 	struct scsi_target *starget;
 	int retval = 0;
+	struct sas_rphy *rphy = NULL;
 
 	starget = scsi_target(sdev);
 	shost = dev_to_shost(&starget->dev);
@@ -4180,7 +4196,14 @@ static int mpi3mr_slave_alloc(struct scsi_device *sdev)
 	scsi_tgt_priv_data = starget->hostdata;
 
 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
-	tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
+
+	if (starget->channel == mrioc->scsi_device_channel)
+		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
+	else if (mrioc->sas_transport_enabled && !starget->channel) {
+		rphy = dev_to_rphy(starget->dev.parent);
+		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
+		    rphy->identify.sas_address, rphy);
+	}
 
 	if (tgt_dev) {
 		if (tgt_dev->starget == NULL)
@@ -4223,6 +4246,8 @@ static int mpi3mr_target_alloc(struct scsi_target *starget)
 	struct mpi3mr_tgt_dev *tgt_dev;
 	unsigned long flags;
 	int retval = 0;
+	struct sas_rphy *rphy = NULL;
+	bool update_stgt_priv_data = false;
 
 	scsi_tgt_priv_data = kzalloc(sizeof(*scsi_tgt_priv_data), GFP_KERNEL);
 	if (!scsi_tgt_priv_data)
@@ -4231,8 +4256,25 @@ static int mpi3mr_target_alloc(struct scsi_target *starget)
 	starget->hostdata = scsi_tgt_priv_data;
 
 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
-	tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
-	if (tgt_dev && !tgt_dev->is_hidden) {
+
+	if (starget->channel == mrioc->scsi_device_channel) {
+		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
+		if (tgt_dev && !tgt_dev->is_hidden)
+			update_stgt_priv_data = true;
+		else
+			retval = -ENXIO;
+	} else if (mrioc->sas_transport_enabled && !starget->channel) {
+		rphy = dev_to_rphy(starget->dev.parent);
+		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
+		    rphy->identify.sas_address, rphy);
+		if (tgt_dev && !tgt_dev->is_hidden && !tgt_dev->non_stl &&
+		    (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA))
+			update_stgt_priv_data = true;
+		else
+			retval = -ENXIO;
+	}
+
+	if (update_stgt_priv_data) {
 		scsi_tgt_priv_data->starget = starget;
 		scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
 		scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
@@ -4246,8 +4288,7 @@ static int mpi3mr_target_alloc(struct scsi_target *starget)
 		if (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_VD)
 			scsi_tgt_priv_data->throttle_group =
 			    tgt_dev->dev_spec.vd_inf.tg;
-	} else
-		retval = -ENXIO;
+	}
 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
 
 	return retval;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index 1d6ae9d..f7faf6e 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -198,6 +198,35 @@ static void mpi3mr_remove_device_by_sas_address(struct mpi3mr_ioc *mrioc,
 	}
 }
 
+/**
+ * __mpi3mr_get_tgtdev_by_addr_and_rphy - target device search
+ * @mrioc: Adapter instance reference
+ * @sas_address: SAS address of the device
+ * @rphy: SAS transport layer rphy object
+ *
+ * This searches for target device from sas address and rphy
+ * pointer then return mpi3mr_tgt_dev object.
+ *
+ * Return: Valid tget_dev or NULL
+ */
+struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
+	struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy)
+{
+	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.rphy == rphy))
+			goto found_device;
+	return NULL;
+found_device:
+	mpi3mr_tgtdev_get(tgtdev);
+	return tgtdev;
+}
+
 /**
  * mpi3mr_expander_find_by_sas_address - sas expander search
  * @mrioc: Adapter instance reference
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 11/15] mpi3mr: Add SAS SATA end devices to STL
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (9 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 10/15] mpi3mr: Get target object based on rphy Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-07-29 17:32   ` kernel test robot
  2022-07-29 13:16 ` [PATCH 12/15] mpi3mr: Add framework to issue MPT transport cmds Sreekanth Reddy
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 12482 bytes --]

Register/unregister the SAS, SATA devices to
SCSI Transport Layer(STL) whenever the corresponding device
is added/removed from topology.

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h           |  10 ++
 drivers/scsi/mpi3mr/mpi3mr_os.c        |  83 ++++++++++---
 drivers/scsi/mpi3mr/mpi3mr_transport.c | 158 +++++++++++++++++++++++++
 3 files changed, 234 insertions(+), 17 deletions(-)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index a91a57b..21ea021 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -569,7 +569,10 @@ struct mpi3mr_enclosure_node {
  * information cached from firmware given data
  *
  * @sas_address: World wide unique SAS address
+ * @sas_address_parent: Sas address of parent expander or host
  * @dev_info: Device information bits
+ * @phy_id: Phy identifier provided in device page 0
+ * @attached_phy_id: Attached phy identifier provided in device page 0
  * @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
@@ -577,7 +580,10 @@ struct mpi3mr_enclosure_node {
  */
 struct tgt_dev_sas_sata {
 	u64 sas_address;
+	u64 sas_address_parent;
 	u16 dev_info;
+	u8 phy_id;
+	u8 attached_phy_id;
 	u8 sas_transport_attached;
 	u8 pend_sas_rphy_add;
 	struct mpi3mr_hba_port *hba_port;
@@ -1357,6 +1363,10 @@ void mpi3mr_update_links(struct mpi3mr_ioc *mrioc,
 	struct mpi3mr_hba_port *hba_port);
 void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
 	struct mpi3mr_tgt_dev *tgtdev);
+int mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_tgt_dev *tgtdev);
+void mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_tgt_dev *tgtdev);
 struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
 	struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy);
 void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc,
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index aed9b60..a486fe3 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -836,19 +836,25 @@ void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
 		tgt_priv->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
 	}
 
-	if (tgtdev->starget) {
-		if (mrioc->current_event)
-			mrioc->current_event->pending_at_sml = 1;
-		scsi_remove_target(&tgtdev->starget->dev);
-		tgtdev->host_exposed = 0;
-		if (mrioc->current_event) {
-			mrioc->current_event->pending_at_sml = 0;
-			if (mrioc->current_event->discard) {
-				mpi3mr_print_device_event_notice(mrioc, false);
-				return;
+	if (!mrioc->sas_transport_enabled || (tgtdev->dev_type !=
+	    MPI3_DEVICE_DEVFORM_SAS_SATA) || tgtdev->non_stl) {
+		if (tgtdev->starget) {
+			if (mrioc->current_event)
+				mrioc->current_event->pending_at_sml = 1;
+			scsi_remove_target(&tgtdev->starget->dev);
+			tgtdev->host_exposed = 0;
+			if (mrioc->current_event) {
+				mrioc->current_event->pending_at_sml = 0;
+				if (mrioc->current_event->discard) {
+					mpi3mr_print_device_event_notice(mrioc,
+					    false);
+					return;
+				}
 			}
 		}
-	}
+	} else
+		mpi3mr_remove_tgtdev_from_sas_transport(mrioc, tgtdev);
+
 	ioc_info(mrioc, "%s :Removed handle(0x%04x), wwid(0x%016llx)\n",
 	    __func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
 }
@@ -870,21 +876,25 @@ static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
 	int retval = 0;
 	struct mpi3mr_tgt_dev *tgtdev;
 
+	if (mrioc->reset_in_progress)
+		return -1;
+
 	tgtdev = mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
 	if (!tgtdev) {
 		retval = -1;
 		goto out;
 	}
-	if (tgtdev->is_hidden) {
+	if (tgtdev->is_hidden || tgtdev->host_exposed) {
 		retval = -1;
 		goto out;
 	}
-	if (!tgtdev->host_exposed && !mrioc->reset_in_progress) {
+	if (!mrioc->sas_transport_enabled || (tgtdev->dev_type !=
+	    MPI3_DEVICE_DEVFORM_SAS_SATA) || tgtdev->non_stl){
 		tgtdev->host_exposed = 1;
 		if (mrioc->current_event)
 			mrioc->current_event->pending_at_sml = 1;
-		scsi_scan_target(&mrioc->shost->shost_gendev, 0,
-		    tgtdev->perst_id,
+		scsi_scan_target(&mrioc->shost->shost_gendev,
+		    mrioc->scsi_device_channel, tgtdev->perst_id,
 		    SCAN_WILD_CARD, SCSI_SCAN_INITIAL);
 		if (!tgtdev->starget)
 			tgtdev->host_exposed = 0;
@@ -895,7 +905,8 @@ static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
 				goto out;
 			}
 		}
-	}
+	} else
+		mpi3mr_report_tgtdev_to_sas_transport(mrioc, tgtdev);
 out:
 	if (tgtdev)
 		mpi3mr_tgtdev_put(tgtdev);
@@ -1087,6 +1098,9 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
 		tgtdev->dev_spec.sas_sata_inf.dev_info = dev_info;
 		tgtdev->dev_spec.sas_sata_inf.sas_address =
 		    le64_to_cpu(sasinf->sas_address);
+		tgtdev->dev_spec.sas_sata_inf.phy_id = sasinf->phy_num;
+		tgtdev->dev_spec.sas_sata_inf.attached_phy_id =
+		    sasinf->attached_phy_identifier;
 		if ((dev_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) !=
 		    MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE)
 			tgtdev->is_hidden = 1;
@@ -1494,12 +1508,30 @@ static void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc,
 	int i;
 	u16 handle;
 	u8 reason_code;
-	u64 exp_sas_address = 0;
+	u64 exp_sas_address = 0, parent_sas_address = 0;
 	struct mpi3mr_hba_port *hba_port = NULL;
 	struct mpi3mr_tgt_dev *tgtdev = NULL;
 	struct mpi3mr_sas_node *sas_expander = NULL;
+	unsigned long flags;
+	u8 link_rate, prev_link_rate, parent_phy_number;
 
 	mpi3mr_sastopochg_evt_debug(mrioc, event_data);
+	if (mrioc->sas_transport_enabled) {
+		hba_port = mpi3mr_get_hba_port_by_id(mrioc,
+		    event_data->io_unit_port);
+		if (le16_to_cpu(event_data->expander_dev_handle)) {
+			spin_lock_irqsave(&mrioc->sas_node_lock, flags);
+			sas_expander = __mpi3mr_expander_find_by_handle(mrioc,
+			    le16_to_cpu(event_data->expander_dev_handle));
+			if (sas_expander) {
+				exp_sas_address = sas_expander->sas_address;
+				hba_port = sas_expander->hba_port;
+			}
+			spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
+			parent_sas_address = exp_sas_address;
+		} else
+			parent_sas_address = mrioc->sas_hba.sas_address;
+	}
 
 	for (i = 0; i < event_data->num_entries; i++) {
 		if (fwevt->discard)
@@ -1521,6 +1553,23 @@ static void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc,
 			mpi3mr_tgtdev_del_from_list(mrioc, tgtdev);
 			mpi3mr_tgtdev_put(tgtdev);
 			break;
+		case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
+		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
+		case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE:
+		{
+			if (!mrioc->sas_transport_enabled || tgtdev->non_stl
+			    || tgtdev->is_hidden)
+				break;
+			link_rate = event_data->phy_entry[i].link_rate >> 4;
+			prev_link_rate = event_data->phy_entry[i].link_rate & 0xF;
+			if (link_rate == prev_link_rate)
+				break;
+			if (!parent_sas_address)
+				break;
+			parent_phy_number = event_data->start_phy_num + i;
+			mpi3mr_update_links(mrioc, parent_sas_address, handle,
+			    parent_phy_number, link_rate, hba_port);
+		}
 		default:
 			break;
 		}
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index f7faf6e..c449820 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -1660,3 +1660,161 @@ void mpi3mr_expander_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
 		mpi3mr_expander_node_remove(mrioc, sas_expander);
 
 }
+
+/**
+ * mpi3mr_get_sas_negotiated_logical_linkrate - get linkrate
+ * @mrioc: Adapter instance reference
+ * @tgtdev: Target device
+ *
+ * This function identifies whether the target device is
+ * attached directly or through expander and issues sas phy
+ * page0 or expander phy page1 and gets the link rate, if there
+ * is any failure in reading the pages then this returns link
+ * rate of 1.5.
+ *
+ * Return: logical link rate.
+ */
+static u8 mpi3mr_get_sas_negotiated_logical_linkrate(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_tgt_dev *tgtdev)
+{
+	u8 link_rate = MPI3_SAS_NEG_LINK_RATE_1_5, phy_number;
+	struct mpi3_sas_expander_page1 expander_pg1;
+	struct mpi3_sas_phy_page0 phy_pg0;
+	u32 phynum_handle;
+	u16 ioc_status;
+
+	phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
+	if (!(tgtdev->devpg0_flag & MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)) {
+		phynum_handle = ((phy_number<<MPI3_SAS_EXPAND_PGAD_PHYNUM_SHIFT)
+				 | tgtdev->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__);
+			goto out;
+		}
+		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+			ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+			    __FILE__, __LINE__, __func__);
+			goto out;
+		}
+		link_rate = (expander_pg1.negotiated_link_rate &
+			     MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
+			MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
+		goto out;
+	}
+	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, phy_number)) {
+		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;
+	}
+	link_rate = (phy_pg0.negotiated_link_rate &
+		     MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
+		MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT;
+out:
+	return link_rate;
+}
+
+/**
+ * mpi3mr_report_tgtdev_to_sas_transport - expose dev to SAS TL
+ * @mrioc: Adapter instance reference
+ * @tgtdev: Target device
+ *
+ * This function exposes the target device after
+ * preparing host_phy, setting up link rate etc.
+ *
+ * Return: 0 on success, non-zero for failure.
+ */
+int mpi3mr_report_tgtdev_to_sas_transport(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_tgt_dev *tgtdev)
+{
+	int retval = 0;
+	u8 link_rate, parent_phy_number;
+	u64 sas_address_parent, sas_address;
+	struct mpi3mr_hba_port *hba_port;
+	u8 port_id;
+
+	if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
+	    !mrioc->sas_transport_enabled)
+		return -1;
+
+	sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
+	if (!mrioc->sas_hba.num_phys)
+		mpi3mr_sas_host_add(mrioc);
+	else
+		mpi3mr_sas_host_refresh(mrioc);
+
+	if (mpi3mr_get_sas_address(mrioc, tgtdev->parent_handle,
+	    &sas_address_parent) != 0) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		return -1;
+	}
+	tgtdev->dev_spec.sas_sata_inf.sas_address_parent = sas_address_parent;
+
+	parent_phy_number = tgtdev->dev_spec.sas_sata_inf.phy_id;
+	port_id = tgtdev->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;
+	}
+	tgtdev->dev_spec.sas_sata_inf.hba_port = hba_port;
+
+	link_rate = mpi3mr_get_sas_negotiated_logical_linkrate(mrioc, tgtdev);
+
+	mpi3mr_update_links(mrioc, sas_address_parent, tgtdev->dev_handle,
+	    parent_phy_number, link_rate, hba_port);
+
+	tgtdev->host_exposed = 1;
+	if (!mpi3mr_sas_port_add(mrioc, tgtdev->dev_handle,
+	    sas_address_parent, hba_port)) {
+		tgtdev->host_exposed = 0;
+		retval = -1;
+	} else if ((!tgtdev->starget)) {
+		if (!mrioc->is_driver_loading)
+			mpi3mr_sas_port_remove(mrioc, sas_address,
+			    sas_address_parent, hba_port);
+		tgtdev->host_exposed = 0;
+		retval = -1;
+	}
+	return retval;
+}
+
+/**
+ * mpi3mr_remove_tgtdev_from_sas_transport - remove from SAS TL
+ * @mrioc: Adapter instance reference
+ * @tgtdev: Target device
+ *
+ * This function removes the target device
+ *
+ * Return: None.
+ */
+void mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_tgt_dev *tgtdev)
+{
+	u64 sas_address_parent, sas_address;
+	struct mpi3mr_hba_port *hba_port;
+
+	if ((tgtdev->dev_type != MPI3_DEVICE_DEVFORM_SAS_SATA) ||
+	    !mrioc->sas_transport_enabled)
+		return;
+
+	hba_port = tgtdev->dev_spec.sas_sata_inf.hba_port;
+	sas_address = tgtdev->dev_spec.sas_sata_inf.sas_address;
+	sas_address_parent = tgtdev->dev_spec.sas_sata_inf.sas_address_parent;
+	mpi3mr_sas_port_remove(mrioc, sas_address, sas_address_parent,
+	    hba_port);
+	tgtdev->host_exposed = 0;
+}
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 12/15] mpi3mr: Add framework to issue MPT transport cmds
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (10 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 11/15] mpi3mr: Add SAS SATA end devices to STL Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-08-02  0:13   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 13/15] mpi3mr: Support sas transport class callbacks Sreekanth Reddy
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 13236 bytes --]

Added framework to issue MPT transport commands to
controllers.
Also issued the MPT transport commands to get the
manufacturing info of sas expander device.

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h           |   6 +-
 drivers/scsi/mpi3mr/mpi3mr_fw.c        |  17 ++
 drivers/scsi/mpi3mr/mpi3mr_os.c        |   2 +
 drivers/scsi/mpi3mr/mpi3mr_transport.c | 228 +++++++++++++++++++++++++
 4 files changed, 252 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 21ea021..a6c880c 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -99,9 +99,10 @@ extern atomic64_t event_counter;
 #define MPI3MR_HOSTTAG_PEL_WAIT		4
 #define MPI3MR_HOSTTAG_BLK_TMS		5
 #define MPI3MR_HOSTTAG_CFG_CMDS		6
+#define MPI3MR_HOSTTAG_TRANSPORT_CMDS	7
 
 #define MPI3MR_NUM_DEVRMCMD		16
-#define MPI3MR_HOSTTAG_DEVRMCMD_MIN	(MPI3MR_HOSTTAG_BLK_TMS + 1)
+#define MPI3MR_HOSTTAG_DEVRMCMD_MIN	(MPI3MR_HOSTTAG_TRANSPORT_CMDS + 1)
 #define MPI3MR_HOSTTAG_DEVRMCMD_MAX	(MPI3MR_HOSTTAG_DEVRMCMD_MIN + \
 						MPI3MR_NUM_DEVRMCMD - 1)
 
@@ -279,6 +280,7 @@ enum mpi3mr_reset_reason {
 	MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24,
 	MPI3MR_RESET_FROM_FIRMWARE = 27,
 	MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT = 29,
+	MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT = 30,
 };
 
 /* Queue type definitions */
@@ -1004,6 +1006,7 @@ struct scmd_priv {
  * @cfg_page_sz: Default configuration page memory size
  * @sas_transport_enabled: SAS transport enabled or not
  * @scsi_device_channel: Channel ID for SCSI devices
+ * @transport_cmds: Command tracker for SAS transport commands
  * @sas_hba: SAS node for the controller
  * @sas_expander_list: SAS node list of expanders
  * @sas_node_lock: Lock to protect SAS node list
@@ -1188,6 +1191,7 @@ struct mpi3mr_ioc {
 
 	u8 sas_transport_enabled;
 	u8 scsi_device_channel;
+	struct mpi3mr_drv_cmd transport_cmds;
 	struct mpi3mr_sas_node sas_hba;
 	struct list_head sas_expander_list;
 	spinlock_t sas_node_lock;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 9155434..1bf3cae 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -312,6 +312,8 @@ mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
 		return &mrioc->pel_abort_cmd;
 	case MPI3MR_HOSTTAG_PEL_WAIT:
 		return &mrioc->pel_cmds;
+	case MPI3MR_HOSTTAG_TRANSPORT_CMDS:
+		return &mrioc->transport_cmds;
 	case MPI3MR_HOSTTAG_INVALID:
 		if (def_reply && def_reply->function ==
 		    MPI3_FUNCTION_EVENT_NOTIFICATION)
@@ -913,6 +915,10 @@ static const struct {
 	{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
 	{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronous reset" },
 	{ MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout"},
+	{
+		MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT,
+		"timeout of a SAS transport layer request"
+	},
 };
 
 /**
@@ -2866,6 +2872,10 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
 	if (!mrioc->bsg_cmds.reply)
 		goto out_failed;
 
+	mrioc->transport_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
+	if (!mrioc->transport_cmds.reply)
+		goto out_failed;
+
 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
 		mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz,
 		    GFP_KERNEL);
@@ -4072,6 +4082,8 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
 		    sizeof(*mrioc->pel_cmds.reply));
 		memset(mrioc->pel_abort_cmd.reply, 0,
 		    sizeof(*mrioc->pel_abort_cmd.reply));
+		memset(mrioc->transport_cmds.reply, 0,
+		    sizeof(*mrioc->transport_cmds.reply));
 		for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
 			memset(mrioc->dev_rmhs_cmds[i].reply, 0,
 			    sizeof(*mrioc->dev_rmhs_cmds[i].reply));
@@ -4217,6 +4229,9 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
 	kfree(mrioc->chain_bitmap);
 	mrioc->chain_bitmap = NULL;
 
+	kfree(mrioc->transport_cmds.reply);
+	mrioc->transport_cmds.reply = NULL;
+
 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
 		kfree(mrioc->dev_rmhs_cmds[i].reply);
 		mrioc->dev_rmhs_cmds[i].reply = NULL;
@@ -4417,6 +4432,8 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
 	cmdptr = &mrioc->pel_abort_cmd;
 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
 
+	cmdptr = &mrioc->transport_cmds;
+	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
 }
 
 /**
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index a486fe3..3b20096 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -4840,6 +4840,8 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	mpi3mr_init_drv_cmd(&mrioc->host_tm_cmds, MPI3MR_HOSTTAG_BLK_TMS);
 	mpi3mr_init_drv_cmd(&mrioc->bsg_cmds, MPI3MR_HOSTTAG_BSG_CMDS);
 	mpi3mr_init_drv_cmd(&mrioc->cfg_cmds, MPI3MR_HOSTTAG_CFG_CMDS);
+	mpi3mr_init_drv_cmd(&mrioc->transport_cmds,
+	    MPI3MR_HOSTTAG_TRANSPORT_CMDS);
 
 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
 		mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i],
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index c449820..44a30d7 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -9,6 +9,225 @@
 
 #include "mpi3mr.h"
 
+/**
+ * mpi3mr_post_transport_req - Issue transport requests and wait
+ * @mrioc: Adapter instance reference
+ * @request: Properly populated MPI3 request
+ * @request_sz: Size of the MPI3 request
+ * @reply: Pointer to return MPI3 reply
+ * @reply_sz: Size of the MPI3 reply buffer
+ * @timeout: Timeout in seconds
+ * @ioc_status: Pointer to return ioc status
+ *
+ * A generic function for posting MPI3 requests from the SAS
+ * transport layer that uses transport command infrastructure.
+ * This blocks for the completion of request for timeout seconds
+ * and if the request times out this function faults the
+ * controller with proper reason code.
+ *
+ * On successful completion of the request this function returns
+ * appropriate ioc status from the firmware back to the caller.
+ *
+ * Return: 0 on success, non-zero on failure.
+ */
+static int mpi3mr_post_transport_req(struct mpi3mr_ioc *mrioc, void *request,
+	u16 request_sz, void *reply, u16 reply_sz, int timeout,
+	u16 *ioc_status)
+{
+	int retval = 0;
+
+	mutex_lock(&mrioc->transport_cmds.mutex);
+	if (mrioc->transport_cmds.state & MPI3MR_CMD_PENDING) {
+		retval = -1;
+		ioc_err(mrioc, "sending transport request failed due to command in use\n");
+		mutex_unlock(&mrioc->transport_cmds.mutex);
+		goto out;
+	}
+	mrioc->transport_cmds.state = MPI3MR_CMD_PENDING;
+	mrioc->transport_cmds.is_waiting = 1;
+	mrioc->transport_cmds.callback = NULL;
+	mrioc->transport_cmds.ioc_status = 0;
+	mrioc->transport_cmds.ioc_loginfo = 0;
+
+	init_completion(&mrioc->transport_cmds.done);
+	dprint_cfg_info(mrioc, "posting transport request\n");
+	if (mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO)
+		dprint_dump(request, request_sz, "transport_req");
+	retval = mpi3mr_admin_request_post(mrioc, request, request_sz, 1);
+	if (retval) {
+		ioc_err(mrioc, "posting transport request failed\n");
+		goto out_unlock;
+	}
+	wait_for_completion_timeout(&mrioc->transport_cmds.done,
+	    (timeout * HZ));
+	if (!(mrioc->transport_cmds.state & MPI3MR_CMD_COMPLETE)) {
+		mpi3mr_check_rh_fault_ioc(mrioc,
+		    MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT);
+		ioc_err(mrioc, "transport request timed out\n");
+		retval = -1;
+		goto out_unlock;
+	}
+	*ioc_status = mrioc->transport_cmds.ioc_status &
+		MPI3_IOCSTATUS_STATUS_MASK;
+	if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS)
+		dprint_transport_err(mrioc,
+		    "transport request returned with ioc_status(0x%04x), log_info(0x%08x)\n",
+		    *ioc_status, mrioc->transport_cmds.ioc_loginfo);
+
+	if ((reply) && (mrioc->transport_cmds.state & MPI3MR_CMD_REPLY_VALID))
+		memcpy((u8 *)reply, mrioc->transport_cmds.reply, reply_sz);
+
+out_unlock:
+	mrioc->transport_cmds.state = MPI3MR_CMD_NOTUSED;
+	mutex_unlock(&mrioc->transport_cmds.mutex);
+
+out:
+	return retval;
+}
+
+/* report manufacture request structure */
+struct rep_manu_request {
+	u8 smp_frame_type;
+	u8 function;
+	u8 reserved;
+	u8 request_length;
+};
+
+/* report manufacture reply structure */
+struct rep_manu_reply {
+	u8 smp_frame_type; /* 0x41 */
+	u8 function; /* 0x01 */
+	u8 function_result;
+	u8 response_length;
+	u16 expander_change_count;
+	u8 reserved0[2];
+	u8 sas_format;
+	u8 reserved2[3];
+	u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
+	u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
+	u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
+	u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
+	u16 component_id;
+	u8 component_revision_id;
+	u8 reserved3;
+	u8 vendor_specific[8];
+};
+
+/**
+ * mpi3mr_report_manufacture - obtain SMP report_manufacture
+ * @mrioc: Adapter instance reference
+ * @sas_address: SAS address of the expander device
+ * @edev: SAS transport layer sas_expander_device object
+ * @port_id: ID of the HBA port
+ *
+ * Fills in the sas_expander_device with manufacturing info.
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+static int mpi3mr_report_manufacture(struct mpi3mr_ioc *mrioc,
+	u64 sas_address, struct sas_expander_device *edev, u8 port_id)
+{
+	struct mpi3_smp_passthrough_request mpi_request;
+	struct mpi3_smp_passthrough_reply mpi_reply;
+	struct rep_manu_reply *manufacture_reply;
+	struct rep_manu_request *manufacture_request;
+	int rc = 0;
+	void *psge;
+	void *data_out = NULL;
+	dma_addr_t data_out_dma;
+	dma_addr_t data_in_dma;
+	size_t data_in_sz;
+	size_t data_out_sz;
+	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
+	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
+	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
+	u16 ioc_status;
+
+	if (mrioc->reset_in_progress) {
+		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
+		return -EFAULT;
+	}
+
+	data_out_sz = sizeof(struct rep_manu_request);
+	data_in_sz = sizeof(struct rep_manu_reply);
+	data_out = dma_alloc_coherent(&mrioc->pdev->dev,
+	    data_out_sz + data_in_sz, &data_out_dma, GFP_KERNEL);
+	if (!data_out) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	data_in_dma = data_out_dma + data_out_sz;
+	manufacture_reply = data_out + data_out_sz;
+
+	manufacture_request = data_out;
+	manufacture_request->smp_frame_type = 0x40;
+	manufacture_request->function = 1;
+	manufacture_request->reserved = 0;
+	manufacture_request->request_length = 0;
+
+	memset(&mpi_request, 0, request_sz);
+	memset(&mpi_reply, 0, reply_sz);
+	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
+	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
+	mpi_request.io_unit_port = (u8) port_id;
+	mpi_request.sas_address = cpu_to_le64(sas_address);
+
+	psge = &mpi_request.request_sge;
+	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
+
+	psge = &mpi_request.response_sge;
+	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
+
+	dprint_transport_info(mrioc,
+	    "sending report manufacturer SMP request to sas_address(0x%016llx), port(%d)\n",
+	    (unsigned long long)sas_address, port_id);
+
+	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
+	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
+		goto out;
+
+	dprint_transport_info(mrioc,
+	    "report manufacturer SMP request completed with ioc_status(0x%04x)\n",
+	    ioc_status);
+
+	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
+		u8 *tmp;
+
+		dprint_transport_info(mrioc,
+		    "report manufacturer - reply data transfer size(%d)\n",
+		    le16_to_cpu(mpi_reply.response_data_length));
+
+		if (le16_to_cpu(mpi_reply.response_data_length) !=
+		    sizeof(struct rep_manu_reply))
+			goto out;
+
+		strscpy(edev->vendor_id, manufacture_reply->vendor_id,
+		     SAS_EXPANDER_VENDOR_ID_LEN);
+		strscpy(edev->product_id, manufacture_reply->product_id,
+		     SAS_EXPANDER_PRODUCT_ID_LEN);
+		strscpy(edev->product_rev, manufacture_reply->product_rev,
+		     SAS_EXPANDER_PRODUCT_REV_LEN);
+		edev->level = manufacture_reply->sas_format & 1;
+		if (edev->level) {
+			strscpy(edev->component_vendor_id,
+			    manufacture_reply->component_vendor_id,
+			     SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
+			tmp = (u8 *)&manufacture_reply->component_id;
+			edev->component_id = tmp[0] << 8 | tmp[1];
+			edev->component_revision_id =
+			    manufacture_reply->component_revision_id;
+		}
+	}
+
+out:
+	if (data_out)
+		dma_free_coherent(&mrioc->pdev->dev, data_out_sz + data_in_sz,
+		    data_out, data_out_dma);
+
+	return rc;
+}
+
 /**
  * __mpi3mr_expander_find_by_handle - expander search by handle
  * @mrioc: Adapter instance reference
@@ -1223,6 +1442,15 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
 			mpi3mr_print_device_event_notice(mrioc, true);
 	}
 
+	/* fill in report manufacture */
+	if (mr_sas_port->remote_identify.device_type ==
+	    SAS_EDGE_EXPANDER_DEVICE ||
+	    mr_sas_port->remote_identify.device_type ==
+	    SAS_FANOUT_EXPANDER_DEVICE)
+		mpi3mr_report_manufacture(mrioc,
+		    mr_sas_port->remote_identify.sas_address,
+		    rphy_to_expander_device(rphy), hba_port->port_id);
+
 	return mr_sas_port;
 
  out_fail:
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 13/15] mpi3mr: Support sas transport class callbacks
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (11 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 12/15] mpi3mr: Add framework to issue MPT transport cmds Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-08-02 18:11   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 14/15] mpi3mr: Refresh sas ports during soft reset Sreekanth Reddy
  2022-07-29 13:16 ` [PATCH 15/15] mpi3mr: Block IOs while refreshing target dev objects Sreekanth Reddy
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 30705 bytes --]

Added support for below sas transport class callbacks,
- get_linkerrors
- get_enclosure_identifier
- get_bay_identifier
- phy_reset
- phy_enable
- set_phy_speed
- smp_handler

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h           |   3 +
 drivers/scsi/mpi3mr/mpi3mr_fw.c        |   1 +
 drivers/scsi/mpi3mr/mpi3mr_os.c        |  20 +-
 drivers/scsi/mpi3mr/mpi3mr_transport.c | 917 +++++++++++++++++++++++++
 4 files changed, 939 insertions(+), 2 deletions(-)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index a6c880c..d203167 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -1326,6 +1326,9 @@ struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
 extern const struct attribute_group *mpi3mr_host_groups[];
 extern const struct attribute_group *mpi3mr_dev_groups[];
 
+extern struct sas_function_template mpi3mr_transport_functions;
+extern struct scsi_transport_template *mpi3mr_transport_template;
+
 int mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
 	struct mpi3_device_page0 *dev_pg0, u16 pg_sz, u32 form, u32 form_spec);
 int mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 1bf3cae..59ef373 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -3757,6 +3757,7 @@ retry_init:
 		mrioc->sas_transport_enabled = 1;
 		mrioc->scsi_device_channel = 1;
 		mrioc->shost->max_channel = 1;
+		mrioc->shost->transportt = mpi3mr_transport_template;
 	}
 
 	mrioc->reply_sz = mrioc->facts.reply_sz;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 3b20096..139c164 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -5168,18 +5168,33 @@ static int __init mpi3mr_init(void)
 	pr_info("Loading %s version %s\n", MPI3MR_DRIVER_NAME,
 	    MPI3MR_DRIVER_VERSION);
 
+	mpi3mr_transport_template =
+	    sas_attach_transport(&mpi3mr_transport_functions);
+	if (!mpi3mr_transport_template) {
+		pr_err("%s failed to load due to sas transport attach failure\n",
+		    MPI3MR_DRIVER_NAME);
+		return -ENODEV;
+	}
+
 	ret_val = pci_register_driver(&mpi3mr_pci_driver);
 	if (ret_val) {
 		pr_err("%s failed to load due to pci register driver failure\n",
 		    MPI3MR_DRIVER_NAME);
-		return ret_val;
+		goto err_pci_reg_fail;
 	}
 
 	ret_val = driver_create_file(&mpi3mr_pci_driver.driver,
 				     &driver_attr_event_counter);
 	if (ret_val)
-		pci_unregister_driver(&mpi3mr_pci_driver);
+		goto err_event_counter;
+
+	return ret_val;
+
+err_event_counter:
+	pci_unregister_driver(&mpi3mr_pci_driver);
 
+err_pci_reg_fail:
+	sas_release_transport(mpi3mr_transport_template);
 	return ret_val;
 }
 
@@ -5196,6 +5211,7 @@ static void __exit mpi3mr_exit(void)
 	driver_remove_file(&mpi3mr_pci_driver.driver,
 			   &driver_attr_event_counter);
 	pci_unregister_driver(&mpi3mr_pci_driver);
+	sas_release_transport(mpi3mr_transport_template);
 }
 
 module_init(mpi3mr_init);
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index 44a30d7..e8a9a76 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -2046,3 +2046,920 @@ void mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc *mrioc,
 	    hba_port);
 	tgtdev->host_exposed = 0;
 }
+
+/**
+ * mpi3mr_get_port_id_by_sas_phy -  Get port ID of the given phy
+ * @phy: SAS transport layer phy object
+ *
+ * Return: Port number for valid ID else 0xFFFF
+ */
+static inline u8 mpi3mr_get_port_id_by_sas_phy(struct sas_phy *phy)
+{
+	u8 port_id = 0xFF;
+	struct mpi3mr_hba_port *hba_port = phy->hostdata;
+
+	if (hba_port)
+		port_id = hba_port->port_id;
+
+	return port_id;
+}
+
+/**
+ * mpi3mr_get_port_id_by_rphy - Get Port number from SAS rphy
+ *
+ * @mrioc: Adapter instance reference
+ * @rphy: SAS transport layer remote phy object
+ *
+ * Retrieves HBA port number in which the device pointed by the
+ * rphy object is attached with.
+ *
+ * Return: Valid port number on success else OxFFFF.
+ */
+static u8 mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc *mrioc, struct sas_rphy *rphy)
+{
+	struct mpi3mr_sas_node *sas_expander;
+	struct mpi3mr_tgt_dev *tgtdev;
+	unsigned long flags;
+	u8 port_id = 0xFF;
+
+	if (!rphy)
+		return port_id;
+
+	if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
+	    rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) {
+		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
+		list_for_each_entry(sas_expander, &mrioc->sas_expander_list,
+		    list) {
+			if (sas_expander->rphy == rphy) {
+				port_id = sas_expander->hba_port->port_id;
+				break;
+			}
+		}
+		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
+	} else if (rphy->identify.device_type == SAS_END_DEVICE) {
+		spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+
+		tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
+			    rphy->identify.sas_address, rphy);
+		if (tgtdev) {
+			port_id =
+				tgtdev->dev_spec.sas_sata_inf.hba_port->port_id;
+			mpi3mr_tgtdev_put(tgtdev);
+		}
+		spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+	}
+	return port_id;
+}
+
+static inline struct mpi3mr_ioc *phy_to_mrioc(struct sas_phy *phy)
+{
+	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+
+	return shost_priv(shost);
+}
+
+static inline struct mpi3mr_ioc *rphy_to_mrioc(struct sas_rphy *rphy)
+{
+	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
+
+	return shost_priv(shost);
+}
+
+/* report phy error log structure */
+struct phy_error_log_request {
+	u8 smp_frame_type; /* 0x40 */
+	u8 function; /* 0x11 */
+	u8 allocated_response_length;
+	u8 request_length; /* 02 */
+	u8 reserved_1[5];
+	u8 phy_identifier;
+	u8 reserved_2[2];
+};
+
+/* report phy error log reply structure */
+struct phy_error_log_reply {
+	u8 smp_frame_type; /* 0x41 */
+	u8 function; /* 0x11 */
+	u8 function_result;
+	u8 response_length;
+	__be16 expander_change_count;
+	u8 reserved_1[3];
+	u8 phy_identifier;
+	u8 reserved_2[2];
+	__be32 invalid_dword;
+	__be32 running_disparity_error;
+	__be32 loss_of_dword_sync;
+	__be32 phy_reset_problem;
+};
+
+
+/**
+ * mpi3mr_get_expander_phy_error_log - return expander counters:
+ * @mrioc: Adapter instance reference
+ * @phy: The SAS transport layer phy object
+ *
+ * Return: 0 for success, non-zero for failure.
+ *
+ */
+static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,
+	struct sas_phy *phy)
+{
+	struct mpi3_smp_passthrough_request mpi_request;
+	struct mpi3_smp_passthrough_reply mpi_reply;
+	struct phy_error_log_request *phy_error_log_request;
+	struct phy_error_log_reply *phy_error_log_reply;
+	int rc;
+	void *psge;
+	void *data_out = NULL;
+	dma_addr_t data_out_dma, data_in_dma;
+	u32 data_out_sz, data_in_sz, sz;
+	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
+	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
+	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
+	u16 ioc_status;
+
+
+	if (mrioc->reset_in_progress) {
+		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
+		return -EFAULT;
+	}
+
+
+	data_out_sz = sizeof(struct phy_error_log_request);
+	data_in_sz = sizeof(struct phy_error_log_reply);
+	sz = data_out_sz + data_in_sz;
+	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
+	    GFP_KERNEL);
+	if (!data_out) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	data_in_dma = data_out_dma + data_out_sz;
+	phy_error_log_reply = data_out + data_out_sz;
+
+	rc = -EINVAL;
+	memset(data_out, 0, sz);
+	phy_error_log_request = data_out;
+	phy_error_log_request->smp_frame_type = 0x40;
+	phy_error_log_request->function = 0x11;
+	phy_error_log_request->request_length = 2;
+	phy_error_log_request->allocated_response_length = 0;
+	phy_error_log_request->phy_identifier = phy->number;
+
+	memset(&mpi_request, 0, request_sz);
+	memset(&mpi_reply, 0, reply_sz);
+	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
+	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
+	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
+	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
+
+	psge = &mpi_request.request_sge;
+	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
+
+	psge = &mpi_request.response_sge;
+	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
+
+	dprint_transport_info(mrioc,
+	    "sending phy error log SMP request to sas_address(0x%016llx), phy_id(%d)\n",
+	    (unsigned long long)phy->identify.sas_address, phy->number);
+
+	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
+	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
+		goto out;
+
+	dprint_transport_info(mrioc,
+	    "phy error log SMP request completed with ioc_status(0x%04x)\n",
+	    ioc_status);
+
+
+	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
+		dprint_transport_info(mrioc,
+		    "phy error log - reply data transfer size(%d)\n",
+		    le16_to_cpu(mpi_reply.response_data_length));
+
+		if (le16_to_cpu(mpi_reply.response_data_length) !=
+		    sizeof(struct phy_error_log_reply))
+			goto out;
+
+
+		dprint_transport_info(mrioc,
+		    "phy error log - function_result(%d)\n",
+		    phy_error_log_reply->function_result);
+
+		phy->invalid_dword_count =
+		    be32_to_cpu(phy_error_log_reply->invalid_dword);
+		phy->running_disparity_error_count =
+		    be32_to_cpu(phy_error_log_reply->running_disparity_error);
+		phy->loss_of_dword_sync_count =
+		    be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
+		phy->phy_reset_problem_count =
+		    be32_to_cpu(phy_error_log_reply->phy_reset_problem);
+		rc = 0;
+	}
+
+out:
+	if (data_out)
+		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
+		    data_out_dma);
+
+	return rc;
+}
+
+
+/**
+ * mpi3mr_transport_get_linkerrors - return phy error counters
+ * @phy: The SAS transport layer phy object
+ *
+ * This function retrieves the phy error log information of the
+ * HBA or expander for which the phy belongs to
+ *
+ * Return: 0 for success, non-zero for failure.
+ *
+ */
+static int mpi3mr_transport_get_linkerrors(struct sas_phy *phy)
+{
+	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
+	struct mpi3_sas_phy_page1 phy_pg1;
+	int rc = 0;
+	u16 ioc_status;
+
+	rc = mpi3mr_parent_present(mrioc, phy);
+	if (rc)
+		return rc;
+
+	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
+		return mpi3mr_get_expander_phy_error_log(mrioc, phy);
+
+	memset(&phy_pg1, 0, sizeof(struct mpi3_sas_phy_page1));
+	/* get hba phy error logs */
+	if ((mpi3mr_cfg_get_sas_phy_pg1(mrioc, &ioc_status, &phy_pg1,
+	    sizeof(struct mpi3_sas_phy_page1),
+	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number))) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		return -ENXIO;
+	}
+
+	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		return -ENXIO;
+	}
+	phy->invalid_dword_count = le32_to_cpu(phy_pg1.invalid_dword_count);
+	phy->running_disparity_error_count =
+		le32_to_cpu(phy_pg1.running_disparity_error_count);
+	phy->loss_of_dword_sync_count =
+		le32_to_cpu(phy_pg1.loss_dword_synch_count);
+	phy->phy_reset_problem_count =
+		le32_to_cpu(phy_pg1.phy_reset_problem_count);
+	return 0;
+}
+
+
+/**
+ * mpi3mr_transport_get_enclosure_identifier - Get Enclosure ID
+ * @rphy: The SAS transport layer remote phy object
+ * @identifier: Enclosure identifier to be returned
+ *
+ * Returns the enclosure id for the device pointed by the remote
+ * phy object.
+ *
+ * Return: 0 on success or -ENXIO
+ */
+static int
+mpi3mr_transport_get_enclosure_identifier(struct sas_rphy *rphy,
+	u64 *identifier)
+{
+	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
+	struct mpi3mr_tgt_dev *tgtdev = NULL;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
+	    rphy->identify.sas_address, rphy);
+	if (tgtdev) {
+		*identifier =
+			tgtdev->enclosure_logical_id;
+		rc = 0;
+		mpi3mr_tgtdev_put(tgtdev);
+	} else {
+		*identifier = 0;
+		rc = -ENXIO;
+	}
+	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+
+	return rc;
+}
+
+/**
+ * mpi3mr_transport_get_bay_identifier - Get bay ID
+ * @rphy: The SAS transport layer remote phy object
+ *
+ * Returns the slot id for the device pointed by the remote phy
+ * object.
+ *
+ * Return: Valid slot ID on success or -ENXIO
+ */
+static int
+mpi3mr_transport_get_bay_identifier(struct sas_rphy *rphy)
+{
+
+	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
+	struct mpi3mr_tgt_dev *tgtdev = NULL;
+	unsigned long flags;
+	int rc;
+
+	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
+	    rphy->identify.sas_address, rphy);
+	if (tgtdev) {
+		rc = tgtdev->slot;
+		mpi3mr_tgtdev_put(tgtdev);
+	} else
+		rc = -ENXIO;
+	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+
+	return rc;
+}
+
+/* phy control request structure */
+struct phy_control_request {
+	u8 smp_frame_type; /* 0x40 */
+	u8 function; /* 0x91 */
+	u8 allocated_response_length;
+	u8 request_length; /* 0x09 */
+	u16 expander_change_count;
+	u8 reserved_1[3];
+	u8 phy_identifier;
+	u8 phy_operation;
+	u8 reserved_2[13];
+	u64 attached_device_name;
+	u8 programmed_min_physical_link_rate;
+	u8 programmed_max_physical_link_rate;
+	u8 reserved_3[6];
+};
+
+/* phy control reply structure */
+struct phy_control_reply {
+	u8 smp_frame_type; /* 0x41 */
+	u8 function; /* 0x11 */
+	u8 function_result;
+	u8 response_length;
+};
+
+#define SMP_PHY_CONTROL_LINK_RESET	(0x01)
+#define SMP_PHY_CONTROL_HARD_RESET	(0x02)
+#define SMP_PHY_CONTROL_DISABLE		(0x03)
+
+/**
+ * mpi3mr_expander_phy_control - expander phy control
+ * @mrioc: Adapter instance reference
+ * @phy: The SAS transport layer phy object
+ * @phy_operation: The phy operation to be executed
+ *
+ * Issues SMP passthru phy control request to execute a specific
+ * phy operation for a given expander device.
+ *
+ * Return: 0 for success, non-zero for failure.
+ *
+ */
+static int
+mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,
+	struct sas_phy *phy, u8 phy_operation)
+{
+	struct mpi3_smp_passthrough_request mpi_request;
+	struct mpi3_smp_passthrough_reply mpi_reply;
+	struct phy_control_request *phy_control_request;
+	struct phy_control_reply *phy_control_reply;
+	int rc;
+	void *psge;
+	void *data_out = NULL;
+	dma_addr_t data_out_dma;
+	dma_addr_t data_in_dma;
+	size_t data_in_sz;
+	size_t data_out_sz;
+	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
+	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
+	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
+	u16 ioc_status;
+	u16 sz;
+
+	if (mrioc->reset_in_progress) {
+		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
+		return -EFAULT;
+	}
+
+
+	data_out_sz = sizeof(struct phy_control_request);
+	data_in_sz = sizeof(struct phy_control_reply);
+	sz = data_out_sz + data_in_sz;
+	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
+	    GFP_KERNEL);
+	if (!data_out) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	data_in_dma = data_out_dma + data_out_sz;
+	phy_control_reply = data_out + data_out_sz;
+
+	rc = -EINVAL;
+	memset(data_out, 0, sz);
+
+	phy_control_request = data_out;
+	phy_control_request->smp_frame_type = 0x40;
+	phy_control_request->function = 0x91;
+	phy_control_request->request_length = 9;
+	phy_control_request->allocated_response_length = 0;
+	phy_control_request->phy_identifier = phy->number;
+	phy_control_request->phy_operation = phy_operation;
+	phy_control_request->programmed_min_physical_link_rate =
+	    phy->minimum_linkrate << 4;
+	phy_control_request->programmed_max_physical_link_rate =
+	    phy->maximum_linkrate << 4;
+
+	memset(&mpi_request, 0, request_sz);
+	memset(&mpi_reply, 0, reply_sz);
+	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
+	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
+	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
+	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
+
+	psge = &mpi_request.request_sge;
+	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
+
+	psge = &mpi_request.response_sge;
+	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
+
+	dprint_transport_info(mrioc,
+	    "sending phy control SMP request to sas_address(0x%016llx), phy_id(%d) opcode(%d)\n",
+	    (unsigned long long)phy->identify.sas_address, phy->number,
+	    phy_operation);
+
+	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
+	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
+		goto out;
+
+	dprint_transport_info(mrioc,
+	    "phy control SMP request completed with ioc_status(0x%04x)\n",
+	    ioc_status);
+
+
+	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
+		dprint_transport_info(mrioc,
+		    "phy control - reply data transfer size(%d)\n",
+		    le16_to_cpu(mpi_reply.response_data_length));
+
+		if (le16_to_cpu(mpi_reply.response_data_length) !=
+		    sizeof(struct phy_control_reply))
+			goto out;
+		dprint_transport_info(mrioc,
+		    "phy control - function_result(%d)\n",
+		    phy_control_reply->function_result);
+		rc = 0;
+	}
+ out:
+	if (data_out)
+		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
+		    data_out_dma);
+
+	return rc;
+}
+
+/**
+ * mpi3mr_transport_phy_reset - Reset a given phy
+ * @phy: The SAS transport layer phy object
+ * @hard_reset: Flag to indicate the type of reset
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+static int
+mpi3mr_transport_phy_reset(struct sas_phy *phy, int hard_reset)
+{
+	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
+	struct mpi3_iounit_control_request mpi_request;
+	struct mpi3_iounit_control_reply mpi_reply;
+	u16 request_sz = sizeof(struct mpi3_iounit_control_request);
+	u16 reply_sz = sizeof(struct mpi3_iounit_control_reply);
+	int rc = 0;
+	u16 ioc_status;
+
+	rc = mpi3mr_parent_present(mrioc, phy);
+	if (rc)
+		return rc;
+
+	/* handle expander phys */
+	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
+		return mpi3mr_expander_phy_control(mrioc, phy,
+		    (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
+		    SMP_PHY_CONTROL_LINK_RESET);
+
+	/* handle hba phys */
+	memset(&mpi_request, 0, request_sz);
+	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
+	mpi_request.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
+	mpi_request.operation = MPI3_CTRL_OP_SAS_PHY_CONTROL;
+	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_ACTION_INDEX] =
+		(hard_reset ? MPI3_CTRL_ACTION_HARD_RESET :
+		 MPI3_CTRL_ACTION_LINK_RESET);
+	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_PHY_INDEX] =
+		phy->number;
+
+	dprint_transport_info(mrioc,
+	    "sending phy reset request to sas_address(0x%016llx), phy_id(%d) hard_reset(%d)\n",
+	    (unsigned long long)phy->identify.sas_address, phy->number,
+	    hard_reset);
+
+	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
+	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status)) {
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	dprint_transport_info(mrioc,
+	    "phy reset request completed with ioc_status(0x%04x)\n",
+	    ioc_status);
+out:
+	return rc;
+}
+
+/**
+ * mpi3mr_transport_phy_enable - enable/disable phys
+ * @phy: The SAS transport layer phy object
+ * @enable: flag to enable/disable, enable phy when true
+ *
+ * This function enables/disables a given by executing required
+ * configuration page changes or expander phy control command
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+static int
+mpi3mr_transport_phy_enable(struct sas_phy *phy, int enable)
+{
+	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
+	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
+	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
+	u16 sz;
+	int rc = 0;
+	int i, discovery_active;
+
+	rc = mpi3mr_parent_present(mrioc, phy);
+	if (rc)
+		return rc;
+
+	/* handle expander phys */
+	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
+		return mpi3mr_expander_phy_control(mrioc, phy,
+		    (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
+		    SMP_PHY_CONTROL_DISABLE);
+
+	/* handle hba phys */
+
+	/* read sas_iounit page 0 */
+	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) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	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__);
+		rc = -ENXIO;
+		goto out;
+	}
+
+	/* unable to enable/disable phys when discovery is active */
+	for (i = 0, discovery_active = 0; i < mrioc->sas_hba.num_phys ; i++) {
+		if (sas_io_unit_pg0->phy_data[i].port_flags &
+		    MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS) {
+			ioc_err(mrioc,
+			    "discovery is active on port = %d, phy = %d\n"
+			    "\tunable to enable/disable phys, try again later!\n",
+			    sas_io_unit_pg0->phy_data[i].io_unit_port, i);
+			discovery_active = 1;
+		}
+	}
+
+	if (discovery_active) {
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	if ((sas_io_unit_pg0->phy_data[phy->number].phy_flags &
+	     (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
+	      MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		rc = -ENXIO;
+		goto out;
+	}
+
+
+	/* read sas_iounit page 1 */
+	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
+		(mrioc->sas_hba.num_phys *
+		 sizeof(struct mpi3_sas_io_unit1_phy_data));
+	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
+	if (!sas_io_unit_pg1) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		rc = -ENXIO;
+		goto out;
+	}
+
+	if (enable)
+		sas_io_unit_pg1->phy_data[phy->number].phy_flags
+		    &= ~MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
+	else
+		sas_io_unit_pg1->phy_data[phy->number].phy_flags
+		    |= MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
+
+	mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz);
+
+	/* link reset */
+	if (enable)
+		mpi3mr_transport_phy_reset(phy, 0);
+
+ out:
+	kfree(sas_io_unit_pg1);
+	kfree(sas_io_unit_pg0);
+	return rc;
+}
+
+/**
+ * mpi3mr_transport_phy_speed - set phy min/max speed
+ * @phy: The SAS transport later phy object
+ * @rates: Rates defined as in sas_phy_linkrates
+ *
+ * This function sets the link rates given in the rates
+ * argument to the given phy by executing required configuration
+ * page changes or expander phy control command
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+static int
+mpi3mr_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
+{
+
+	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
+	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
+	struct mpi3_sas_phy_page0 phy_pg0;
+	u16 sz, ioc_status;
+	int rc = 0;
+
+	rc = mpi3mr_parent_present(mrioc, phy);
+	if (rc)
+		return rc;
+
+	if (!rates->minimum_linkrate)
+		rates->minimum_linkrate = phy->minimum_linkrate;
+	else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
+		rates->minimum_linkrate = phy->minimum_linkrate_hw;
+
+	if (!rates->maximum_linkrate)
+		rates->maximum_linkrate = phy->maximum_linkrate;
+	else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
+		rates->maximum_linkrate = phy->maximum_linkrate_hw;
+
+	/* handle expander phys */
+	if (phy->identify.sas_address != mrioc->sas_hba.sas_address) {
+		phy->minimum_linkrate = rates->minimum_linkrate;
+		phy->maximum_linkrate = rates->maximum_linkrate;
+		return mpi3mr_expander_phy_control(mrioc, phy,
+		    SMP_PHY_CONTROL_LINK_RESET);
+	}
+
+	/* handle hba phys */
+
+	/* sas_iounit page 1 */
+	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
+		(mrioc->sas_hba.num_phys *
+		 sizeof(struct mpi3_sas_io_unit1_phy_data));
+	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
+	if (!sas_io_unit_pg1) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		rc = -ENXIO;
+		goto out;
+	}
+
+	sas_io_unit_pg1->phy_data[phy->number].max_min_link_rate =
+		(rates->minimum_linkrate + (rates->maximum_linkrate << 4));
+
+	if (mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
+		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
+		    __FILE__, __LINE__, __func__);
+		rc = -ENXIO;
+		goto out;
+	}
+
+	/* link reset */
+	mpi3mr_transport_phy_reset(phy, 0);
+
+	/* read phy page 0, then update the rates in the sas transport phy */
+	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, phy->number) &&
+	    (ioc_status == MPI3_IOCSTATUS_SUCCESS)) {
+		phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
+		    phy_pg0.programmed_link_rate &
+		    MPI3_SAS_PRATE_MIN_RATE_MASK);
+		phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
+		    phy_pg0.programmed_link_rate >> 4);
+		phy->negotiated_linkrate =
+			mpi3mr_convert_phy_link_rate(
+			    (phy_pg0.negotiated_link_rate &
+			    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK)
+			    >> MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
+	}
+
+out:
+	kfree(sas_io_unit_pg1);
+	return rc;
+}
+
+
+/**
+ * mpi3mr_map_smp_buffer - map BSG dma buffer
+ * @dev: Generic device reference
+ * @buf: BSG buffer pointer
+ * @dma_addr: Physical address holder
+ * @dma_len: Mapped DMA buffer length.
+ * @p: Virtual address holder
+ *
+ * This function maps the DMAable buffer
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+
+static int
+mpi3mr_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,
+		dma_addr_t *dma_addr, size_t *dma_len, void **p)
+{
+	/* Check if the request is split across multiple segments */
+	if (buf->sg_cnt > 1) {
+		*p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,
+				GFP_KERNEL);
+		if (!*p)
+			return -ENOMEM;
+		*dma_len = buf->payload_len;
+	} else {
+		if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))
+			return -ENOMEM;
+		*dma_addr = sg_dma_address(buf->sg_list);
+		*dma_len = sg_dma_len(buf->sg_list);
+		*p = NULL;
+	}
+
+	return 0;
+}
+
+/**
+ * mpi3mr_unmap_smp_buffer - unmap BSG dma buffer
+ * @dev: Generic device reference
+ * @buf: BSG buffer pointer
+ * @dma_addr: Physical address to be unmapped
+ * @p: Virtual address
+ *
+ * This function unmaps the DMAable buffer
+ */
+
+static void
+mpi3mr_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,
+		dma_addr_t dma_addr, void *p)
+{
+	if (p)
+		dma_free_coherent(dev, buf->payload_len, p, dma_addr);
+	else
+		dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);
+}
+
+/**
+ * mpi3mr_transport_smp_handler - handler for smp passthru
+ * @job: BSG job reference
+ * @shost: SCSI host object reference
+ * @rphy: SAS transport rphy object pointing the expander
+ *
+ * This is used primarily by smp utils for sending the SMP
+ * commands to the expanders attached to the controller
+ */
+static void
+mpi3mr_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
+	struct sas_rphy *rphy)
+{
+
+	struct mpi3mr_ioc *mrioc = shost_priv(shost);
+	struct mpi3_smp_passthrough_request mpi_request;
+	struct mpi3_smp_passthrough_reply mpi_reply;
+	int rc;
+	void *psge;
+	dma_addr_t dma_addr_in;
+	dma_addr_t dma_addr_out;
+	void *addr_in = NULL;
+	void *addr_out = NULL;
+	size_t dma_len_in;
+	size_t dma_len_out;
+	unsigned int reslen = 0;
+	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
+	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
+	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
+	u16 ioc_status;
+
+
+	if (mrioc->reset_in_progress) {
+		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
+		rc = -EFAULT;
+		goto out;
+	}
+
+	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
+	    &dma_addr_out, &dma_len_out, &addr_out);
+	if (rc)
+		goto out;
+
+	if (addr_out)
+		sg_copy_to_buffer(job->request_payload.sg_list,
+		    job->request_payload.sg_cnt, addr_out,
+		    job->request_payload.payload_len);
+
+	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
+			&dma_addr_in, &dma_len_in, &addr_in);
+	if (rc)
+		goto unmap_out;
+
+	memset(&mpi_request, 0, request_sz);
+	memset(&mpi_reply, 0, reply_sz);
+	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
+	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
+	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_rphy(mrioc, rphy);
+	mpi_request.sas_address = ((rphy) ?
+	    cpu_to_le64(rphy->identify.sas_address) :
+	    cpu_to_le64(mrioc->sas_hba.sas_address));
+	psge = &mpi_request.request_sge;
+	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_out - 4, dma_addr_out);
+
+	psge = &mpi_request.response_sge;
+	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_in - 4, dma_addr_in);
+
+
+	dprint_transport_info(mrioc, "sending SMP request\n");
+
+	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
+	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
+		goto unmap_in;
+
+	dprint_transport_info(mrioc,
+	    "SMP request completed with ioc_status(0x%04x)\n", ioc_status);
+
+
+	dprint_transport_info(mrioc,
+		    "SMP request - reply data transfer size(%d)\n",
+		    le16_to_cpu(mpi_reply.response_data_length));
+
+	memcpy(job->reply, &mpi_reply, reply_sz);
+	job->reply_len = reply_sz;
+	reslen = le16_to_cpu(mpi_reply.response_data_length);
+
+	if (addr_in)
+		sg_copy_from_buffer(job->reply_payload.sg_list,
+				job->reply_payload.sg_cnt, addr_in,
+				job->reply_payload.payload_len);
+
+	rc = 0;
+unmap_in:
+	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
+			dma_addr_in, addr_in);
+unmap_out:
+	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
+			dma_addr_out, addr_out);
+out:
+	bsg_job_done(job, rc, reslen);
+
+}
+
+struct sas_function_template mpi3mr_transport_functions = {
+	.get_linkerrors		= mpi3mr_transport_get_linkerrors,
+	.get_enclosure_identifier = mpi3mr_transport_get_enclosure_identifier,
+	.get_bay_identifier	= mpi3mr_transport_get_bay_identifier,
+	.phy_reset		= mpi3mr_transport_phy_reset,
+	.phy_enable		= mpi3mr_transport_phy_enable,
+	.set_phy_speed		= mpi3mr_transport_phy_speed,
+	.smp_handler		= mpi3mr_transport_smp_handler,
+};
+
+struct scsi_transport_template *mpi3mr_transport_template;
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 14/15] mpi3mr: Refresh sas ports during soft reset
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (12 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 13/15] mpi3mr: Support sas transport class callbacks Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-08-02 21:00   ` Himanshu Madhani
  2022-07-29 13:16 ` [PATCH 15/15] mpi3mr: Block IOs while refreshing target dev objects Sreekanth Reddy
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 19755 bytes --]

- Update the Host's sas ports if there is change in port id
 or phys. If the port id is changed then the driver updates
 the same. If some phys are enabled/disabled during reset then
 driver updates the same in STL.

- Check for the responding expander devices and update the
 device handle if it got changed. Register the expander with
 STL if it got added during reset and unregister the
 expander device if it got removed during reset.

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr.h           |  11 +
 drivers/scsi/mpi3mr/mpi3mr_fw.c        |  10 +-
 drivers/scsi/mpi3mr/mpi3mr_os.c        |  50 ++++
 drivers/scsi/mpi3mr/mpi3mr_transport.c | 351 +++++++++++++++++++++++++
 4 files changed, 421 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index d203167..0f47b45 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -482,6 +482,9 @@ struct mpi3mr_hba_port {
  * struct mpi3mr_sas_port - Internal SAS port information
  * @port_list: List of ports belonging to a SAS node
  * @num_phys: Number of phys associated with port
+ * @marked_responding: used while refresing the sas ports
+ * @lowest_phy: lowest phy ID of current sas port
+ * @phy_mask: phy_mask of current sas port
  * @hba_port: HBA port entry
  * @remote_identify: Attached device identification
  * @rphy: SAS transport layer rphy object
@@ -491,6 +494,9 @@ struct mpi3mr_hba_port {
 struct mpi3mr_sas_port {
 	struct list_head port_list;
 	u8 num_phys;
+	u8 marked_responding;
+	int lowest_phy;
+	u32 phy_mask;
 	struct mpi3mr_hba_port *hba_port;
 	struct sas_identify remote_identify;
 	struct sas_rphy *rphy;
@@ -939,6 +945,7 @@ struct scmd_priv {
  * @scan_started: Async scan started
  * @scan_failed: Asycn scan failed
  * @stop_drv_processing: Stop all command processing
+ * @device_refresh_on: Don't process the events until devices are refreshed
  * @max_host_ios: Maximum host I/O count
  * @chain_buf_count: Chain buffer count
  * @chain_buf_pool: Chain buffer pool
@@ -1107,6 +1114,7 @@ struct mpi3mr_ioc {
 	u8 scan_started;
 	u16 scan_failed;
 	u8 stop_drv_processing;
+	u8 device_refresh_on;
 
 	u16 max_host_ios;
 	spinlock_t tgtdev_lock;
@@ -1378,4 +1386,7 @@ struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
 	struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy);
 void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc,
 	bool device_add);
+void mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc);
+void mpi3mr_refresh_expanders(struct mpi3mr_ioc *mrioc);
+void mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc);
 #endif /*MPI3MR_H_INCLUDED*/
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 59ef373..dfb7570 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -3977,6 +3977,11 @@ retry_init:
 		goto out_failed;
 	}
 
+	if (!is_resume) {
+		mrioc->device_refresh_on = 1;
+		mpi3mr_add_event_wait_for_device_refresh(mrioc);
+	}
+
 	ioc_info(mrioc, "sending port enable\n");
 	retval = mpi3mr_issue_port_enable(mrioc, 0);
 	if (retval) {
@@ -4733,6 +4738,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
 	ioc_info(mrioc, "controller reset is triggered by %s\n",
 	    mpi3mr_reset_rc_name(reset_reason));
 
+	mrioc->device_refresh_on = 0;
 	mrioc->reset_in_progress = 1;
 	mrioc->stop_bsgs = 1;
 	mrioc->prev_reset_result = -1;
@@ -4814,7 +4820,8 @@ out:
 			mpi3mr_pel_wait_post(mrioc, &mrioc->pel_cmds);
 		}
 
-		mpi3mr_rfresh_tgtdevs(mrioc);
+		mrioc->device_refresh_on = 0;
+
 		mrioc->ts_update_counter = 0;
 		spin_lock_irqsave(&mrioc->watchdog_lock, flags);
 		if (mrioc->watchdog_work_q)
@@ -4828,6 +4835,7 @@ out:
 	} else {
 		mpi3mr_issue_reset(mrioc,
 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
+		mrioc->device_refresh_on = 0;
 		mrioc->unrecoverable = 1;
 		mrioc->reset_in_progress = 0;
 		retval = -1;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index 139c164..d4f37b1 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -40,6 +40,8 @@ static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
 
 #define MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION	(0xFFFF)
 
+#define MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH	(0xFFFE)
+
 /**
  * mpi3mr_host_tag_for_scmd - Get host tag for a scmd
  * @mrioc: Adapter instance reference
@@ -1114,6 +1116,9 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
 		    MPI3_DEVICE0_FLAGS_ATT_METHOD_VIRTUAL)) ||
 		    (tgtdev->parent_handle == 0xFFFF))
 			tgtdev->non_stl = 1;
+		if (tgtdev->dev_spec.sas_sata_inf.hba_port)
+			tgtdev->dev_spec.sas_sata_inf.hba_port->port_id =
+			    dev_pg0->io_unit_port;
 		break;
 	}
 	case MPI3_DEVICE_DEVFORM_PCIE:
@@ -1886,6 +1891,22 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
 		}
 		break;
 	}
+	case MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH:
+	{
+		while (mrioc->device_refresh_on)
+			msleep(500);
+
+		dprint_event_bh(mrioc,
+		    "scan for non responding and newly added devices after soft reset started\n");
+		if (mrioc->sas_transport_enabled) {
+			mpi3mr_refresh_sas_ports(mrioc);
+			mpi3mr_refresh_expanders(mrioc);
+		}
+		mpi3mr_rfresh_tgtdevs(mrioc);
+		ioc_info(mrioc,
+		    "scan for non responding and newly added devices after soft reset completed\n");
+		break;
+	}
 	default:
 		break;
 	}
@@ -2655,6 +2676,35 @@ static void mpi3mr_cablemgmt_evt_th(struct mpi3mr_ioc *mrioc,
 	}
 }
 
+/**
+ * mpi3mr_add_event_wait_for_device_refresh - Add Wait for Device Refresh Event
+ * @mrioc: Adapter instance reference
+ *
+ * Add driver specific event to make sure that the driver won't process the
+ * events until all the devices are refreshed during soft reset.
+ *
+ * Return: Nothing
+ */
+void mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc)
+{
+	struct mpi3mr_fwevt *fwevt = NULL;
+
+	fwevt = mpi3mr_alloc_fwevt(0);
+	if (!fwevt) {
+		dprint_event_th(mrioc,
+		    "failed to schedule bottom half handler for event(0x%02x)\n",
+		    MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH);
+		return;
+	}
+	fwevt->mrioc = mrioc;
+	fwevt->event_id = MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH;
+	fwevt->send_ack = 0;
+	fwevt->process_evt = 1;
+	fwevt->evt_ctx = 0;
+	fwevt->event_data_size = 0;
+	mpi3mr_fwevt_add_to_list(mrioc, fwevt);
+}
+
 /**
  * mpi3mr_os_handle_events - Firmware event handler
  * @mrioc: Adapter instance reference
diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
index e8a9a76..c1ca97c 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
@@ -9,6 +9,9 @@
 
 #include "mpi3mr.h"
 
+static void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
+	struct mpi3mr_sas_node *sas_expander);
+
 /**
  * mpi3mr_post_transport_req - Issue transport requests and wait
  * @mrioc: Adapter instance reference
@@ -597,6 +600,9 @@ static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
 
 	list_del(&mr_sas_phy->port_siblings);
 	mr_sas_port->num_phys--;
+	mr_sas_port->phy_mask &= ~(1 << mr_sas_phy->phy_id);
+	if (mr_sas_port->lowest_phy == mr_sas_phy->phy_id)
+		mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
 	sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);
 	mr_sas_phy->phy_belongs_to_port = 0;
 }
@@ -621,6 +627,9 @@ static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
 
 	list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);
 	mr_sas_port->num_phys++;
+	mr_sas_port->phy_mask |= (1 << mr_sas_phy->phy_id);
+	if (mr_sas_phy->phy_id < mr_sas_port->lowest_phy)
+		mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
 	sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);
 	mr_sas_phy->phy_belongs_to_port = 1;
 }
@@ -1356,6 +1365,7 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
 		list_add_tail(&mr_sas_node->phy[i].port_siblings,
 		    &mr_sas_port->phy_list);
 		mr_sas_port->num_phys++;
+		mr_sas_port->phy_mask |= (1 << i);
 	}
 
 	if (!mr_sas_port->num_phys) {
@@ -1364,6 +1374,8 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
 		goto out_fail;
 	}
 
+	mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
+
 	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,
@@ -1565,6 +1577,345 @@ static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
 	kfree(mr_sas_port);
 }
 
+/**
+ * struct host_port - host port details
+ * @sas_address: SAS Address of the attached device
+ * @phy_mask: phy mask of host port
+ * @handle: Device Handle of attached device
+ * @iounit_port_id: port ID
+ * @used: host port is already matched with sas port from sas_port_list
+ * @lowest_phy: lowest phy ID of host port
+ */
+struct host_port {
+	u64	sas_address;
+	u32	phy_mask;
+	u16	handle;
+	u8	iounit_port_id;
+	u8	used;
+	u8	lowest_phy;
+};
+
+/**
+ * mpi3mr_update_mr_sas_port - update sas port objects during reset
+ * @mrioc: Adapter instance reference
+ * @h_port: host_port object
+ * @mr_sas_port: sas_port objects which needs to be updated
+ *
+ * Update the port ID of sas port object. Also add the phys if new phys got
+ * added to current sas port and remove the phys if some phys are moved
+ * out of the current sas port.
+ *
+ * Return: Nothing.
+ */
+static void
+mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port,
+	struct mpi3mr_sas_port *mr_sas_port)
+{
+	struct mpi3mr_sas_phy *mr_sas_phy;
+	u32 phy_mask_xor, phys_to_be_added, phys_to_be_removed;
+	int i;
+
+	h_port->used = 1;
+	mr_sas_port->marked_responding = 1;
+
+	dev_info(&mr_sas_port->port->dev,
+	    "sas_address(0x%016llx), old: port_id %d phy_mask 0x%x, new: port_id %d phy_mask:0x%x\n",
+	    mr_sas_port->remote_identify.sas_address,
+	    mr_sas_port->hba_port->port_id, mr_sas_port->phy_mask,
+	    h_port->iounit_port_id, h_port->phy_mask);
+
+	mr_sas_port->hba_port->port_id = h_port->iounit_port_id;
+	mr_sas_port->hba_port->flags &= ~MPI3MR_HBA_PORT_FLAG_DIRTY;
+
+	/* Get the newly added phys bit map & removed phys bit map */
+	phy_mask_xor = mr_sas_port->phy_mask ^ h_port->phy_mask;
+	phys_to_be_added = h_port->phy_mask & phy_mask_xor;
+	phys_to_be_removed = mr_sas_port->phy_mask & phy_mask_xor;
+
+	/*
+	 * Register these new phys to current mr_sas_port's port.
+	 * if these phys are previously registered with another port
+	 * then delete these phys from that port first.
+	 */
+	for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u32)) {
+		mr_sas_phy = &mrioc->sas_hba.phy[i];
+		if (mr_sas_phy->phy_belongs_to_port)
+			mpi3mr_del_phy_from_an_existing_port(mrioc,
+			    &mrioc->sas_hba, mr_sas_phy);
+		mpi3mr_add_phy_to_an_existing_port(mrioc,
+		    &mrioc->sas_hba, mr_sas_phy,
+		    mr_sas_port->remote_identify.sas_address,
+		    mr_sas_port->hba_port);
+	}
+
+	/* Delete the phys which are not part of current mr_sas_port's port. */
+	for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u32)) {
+		mr_sas_phy = &mrioc->sas_hba.phy[i];
+		if (mr_sas_phy->phy_belongs_to_port)
+			mpi3mr_del_phy_from_an_existing_port(mrioc,
+			    &mrioc->sas_hba, mr_sas_phy);
+	}
+}
+
+/**
+ * mpi3mr_refresh_sas_ports - update host's sas ports during reset
+ * @mrioc: Adapter instance reference
+ *
+ * Update the host's sas ports during reset by checking whether
+ * sas ports are still intact or not. Add/remove phys if any hba
+ * phys are (moved in)/(moved out) of sas port. Also update
+ * io_unit_port if it got changed during reset.
+ *
+ * Return: Nothing.
+ */
+void
+mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)
+{
+	struct host_port h_port[32];
+	int i, j, found, host_port_count = 0, port_idx;
+	u16 sz, attached_handle, ioc_status;
+	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
+	struct mpi3_device_page0 dev_pg0;
+	struct mpi3_device0_sas_sata_format *sasinf;
+	struct mpi3mr_sas_port *mr_sas_port;
+
+	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;
+	}
+
+	/* Create a new expander port table */
+	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
+		attached_handle = le16_to_cpu(
+		    sas_io_unit_pg0->phy_data[i].attached_dev_handle);
+		if (!attached_handle)
+			continue;
+		found = 0;
+		for (j = 0; j < host_port_count; j++) {
+			if (h_port[j].handle == attached_handle) {
+				h_port[j].phy_mask |= (1 << i);
+				found = 1;
+				break;
+			}
+		}
+		if (found)
+			continue;
+		if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
+		    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
+		    attached_handle))) {
+			dprint_reset(mrioc,
+			    "failed to read dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
+			    attached_handle, __FILE__, __LINE__, __func__);
+			continue;
+		}
+		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+			dprint_reset(mrioc,
+			    "ioc_status(0x%x) while reading dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
+			    ioc_status, attached_handle,
+			    __FILE__, __LINE__, __func__);
+			continue;
+		}
+		sasinf = &dev_pg0.device_specific.sas_sata_format;
+
+		port_idx = host_port_count;
+		h_port[port_idx].sas_address = le64_to_cpu(sasinf->sas_address);
+		h_port[port_idx].handle = attached_handle;
+		h_port[port_idx].phy_mask = (1 << i);
+		h_port[port_idx].iounit_port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
+		h_port[port_idx].lowest_phy = sasinf->phy_num;
+		h_port[port_idx].used = 0;
+		host_port_count++;
+	}
+
+	if (!host_port_count)
+		goto out;
+
+	if (mrioc->logging_level & MPI3_DEBUG_RESET) {
+		ioc_info(mrioc, "Host port details before reset\n");
+		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
+		    port_list) {
+			ioc_info(mrioc,
+			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%x), lowest phy id:%d\n",
+			    mr_sas_port->hba_port->port_id,
+			    mr_sas_port->remote_identify.sas_address,
+			    mr_sas_port->phy_mask, mr_sas_port->lowest_phy);
+		}
+		mr_sas_port = NULL;
+		ioc_info(mrioc, "Host port details after reset\n");
+		for (i = 0; i < host_port_count; i++) {
+			ioc_info(mrioc,
+			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%x), lowest phy id:%d\n",
+			    h_port[i].iounit_port_id, h_port[i].sas_address,
+			    h_port[i].phy_mask, h_port[i].lowest_phy);
+		}
+	}
+
+	/* mark all host sas port entries as dirty */
+	list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
+	    port_list) {
+		mr_sas_port->marked_responding = 0;
+		mr_sas_port->hba_port->flags |= MPI3MR_HBA_PORT_FLAG_DIRTY;
+	}
+
+	/* First check for matching lowest phy */
+	for (i = 0; i < host_port_count; i++) {
+		mr_sas_port = NULL;
+		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
+		    port_list) {
+			if (mr_sas_port->marked_responding)
+				continue;
+			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
+				continue;
+			if (h_port[i].lowest_phy == mr_sas_port->lowest_phy) {
+				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
+				break;
+			}
+		}
+	}
+
+	/* In case if lowest phy is got enabled or disabled during reset */
+	for (i = 0; i < host_port_count; i++) {
+		if (h_port[i].used)
+			continue;
+		mr_sas_port = NULL;
+		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
+		    port_list) {
+			if (mr_sas_port->marked_responding)
+				continue;
+			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
+				continue;
+			if (h_port[i].phy_mask & mr_sas_port->phy_mask) {
+				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
+				break;
+			}
+		}
+	}
+
+	/* In case if expander cable is removed & connected to another HBA port during reset */
+	for (i = 0; i < host_port_count; i++) {
+		if (h_port[i].used)
+			continue;
+		mr_sas_port = NULL;
+		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
+		    port_list) {
+			if (mr_sas_port->marked_responding)
+				continue;
+			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
+				continue;
+			mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
+			break;
+		}
+	}
+out:
+	kfree(sas_io_unit_pg0);
+}
+
+/**
+ * mpi3mr_refresh_expanders - Refresh expander device exposure
+ * @mrioc: Adapter instance reference
+ *
+ * This is executed post controller reset to identify any
+ * missing expander devices during reset and remove from the upper layers
+ * or expose any newly detected expander device to the upper layers.
+ *
+ * Return: Nothing.
+ */
+void
+mpi3mr_refresh_expanders(struct mpi3mr_ioc *mrioc)
+{
+	struct mpi3mr_sas_node *sas_expander, *sas_expander_next;
+	struct mpi3_sas_expander_page0 expander_pg0;
+	u16 ioc_status, handle;
+	u64 sas_address;
+	int i;
+	unsigned long flags;
+	struct mpi3mr_hba_port *hba_port;
+
+	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
+	list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
+		sas_expander->non_responding = 1;
+	}
+	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
+
+	sas_expander = NULL;
+
+	handle = 0xffff;
+
+	/* Search for responding expander devices and add them if they are newly got added */
+	while (true) {
+		if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
+		    sizeof(struct mpi3_sas_expander_page0),
+		    MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+			dprint_reset(mrioc,
+			    "failed to read exp pg0 for handle(0x%04x) at %s:%d/%s()!\n",
+			    handle, __FILE__, __LINE__, __func__);
+			break;
+		}
+
+		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
+			dprint_reset(mrioc,
+			   "ioc_status(0x%x) while reading exp pg0 for handle:(0x%04x), %s:%d/%s()!\n",
+			   ioc_status, handle, __FILE__, __LINE__, __func__);
+			break;
+		}
+
+		handle = le16_to_cpu(expander_pg0.dev_handle);
+		sas_address = le64_to_cpu(expander_pg0.sas_address);
+		hba_port = mpi3mr_get_hba_port_by_id(mrioc, expander_pg0.io_unit_port);
+
+		if (!hba_port) {
+			mpi3mr_sas_host_refresh(mrioc);
+			mpi3mr_expander_add(mrioc, handle);
+			continue;
+		}
+
+		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_sas_host_refresh(mrioc);
+			mpi3mr_expander_add(mrioc, handle);
+			continue;
+		}
+
+		sas_expander->non_responding = 0;
+		if (sas_expander->handle == handle)
+			continue;
+
+		sas_expander->handle = handle;
+		for (i = 0 ; i < sas_expander->num_phys ; i++)
+			sas_expander->phy[i].handle = handle;
+	}
+
+	/*
+	 * Delete non responding expander devices and the corresponding
+	 * hba_port if the non responding expander device's parent device
+	 * is a host node.
+	 */
+
+	sas_expander = NULL;
+	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
+	list_for_each_entry_safe_reverse(sas_expander, sas_expander_next,
+	    &mrioc->sas_expander_list, list) {
+		if (sas_expander->non_responding) {
+			spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
+			mpi3mr_expander_node_remove(mrioc, sas_expander);
+			spin_lock_irqsave(&mrioc->sas_node_lock, flags);
+		}
+	}
+	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
+}
+
 /**
  * mpi3mr_expander_node_add - insert an expander to the list.
  * @mrioc: Adapter instance reference
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH 15/15] mpi3mr: Block IOs while refreshing target dev objects
  2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
                   ` (13 preceding siblings ...)
  2022-07-29 13:16 ` [PATCH 14/15] mpi3mr: Refresh sas ports during soft reset Sreekanth Reddy
@ 2022-07-29 13:16 ` Sreekanth Reddy
  2022-08-02 21:12   ` Himanshu Madhani
  14 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-07-29 13:16 UTC (permalink / raw)
  To: linux-scsi; +Cc: martin.petersen, Sreekanth Reddy

[-- Attachment #1: Type: text/plain, Size: 2396 bytes --]

Block the IOs on the target devices until corresponding
target device's target dev objects are refreshed as part
of post controller reset operation.

Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
---
 drivers/scsi/mpi3mr/mpi3mr_os.c | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index d4f37b1..c7d9e46 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -424,6 +424,8 @@ void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc)
 			tgt_priv->io_throttle_enabled = 0;
 			tgt_priv->io_divert = 0;
 			tgt_priv->throttle_group = NULL;
+			if (tgtdev->host_exposed)
+				atomic_set(&tgt_priv->block_io, 1);
 		}
 	}
 }
@@ -835,6 +837,7 @@ void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
 	    __func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
 	if (tgtdev->starget && tgtdev->starget->hostdata) {
 		tgt_priv = tgtdev->starget->hostdata;
+		atomic_set(&tgt_priv->block_io, 0);
 		tgt_priv->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
 	}
 
@@ -1077,6 +1080,8 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
 		scsi_tgt_priv_data->dev_type = tgtdev->dev_type;
 		scsi_tgt_priv_data->io_throttle_enabled =
 		    tgtdev->io_throttle_enabled;
+		if (is_added == true)
+			atomic_set(&scsi_tgt_priv_data->block_io, 0);
 	}
 
 	switch (dev_pg0->access_status) {
@@ -4576,6 +4581,16 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
 
 	stgt_priv_data = sdev_priv_data->tgt_priv_data;
 
+	if (atomic_read(&stgt_priv_data->block_io)) {
+		if (mrioc->stop_drv_processing) {
+			scmd->result = DID_NO_CONNECT << 16;
+			scsi_done(scmd);
+			goto out;
+		}
+		retval = SCSI_MLQUEUE_DEVICE_BUSY;
+		goto out;
+	}
+
 	dev_handle = stgt_priv_data->dev_handle;
 	if (dev_handle == MPI3MR_INVALID_DEV_HANDLE) {
 		scmd->result = DID_NO_CONNECT << 16;
@@ -4588,16 +4603,6 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
 		goto out;
 	}
 
-	if (atomic_read(&stgt_priv_data->block_io)) {
-		if (mrioc->stop_drv_processing) {
-			scmd->result = DID_NO_CONNECT << 16;
-			scsi_done(scmd);
-			goto out;
-		}
-		retval = SCSI_MLQUEUE_DEVICE_BUSY;
-		goto out;
-	}
-
 	if (stgt_priv_data->dev_type == MPI3_DEVICE_DEVFORM_PCIE)
 		is_pcie_dev = 1;
 	if ((scmd->cmnd[0] == UNMAP) && is_pcie_dev &&
-- 
2.27.0


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [PATCH 01/15] mpi3mr: Add config and transport related debug flags
  2022-07-29 13:16 ` [PATCH 01/15] mpi3mr: Add config and transport related debug flags Sreekanth Reddy
@ 2022-07-29 16:59   ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-07-29 16:59 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Add config and transport request related error & info debug
> flags and functions.
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr_debug.h | 27 +++++++++++++++++++++++++++
> 1 file changed, 27 insertions(+)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_debug.h b/drivers/scsi/mpi3mr/mpi3mr_debug.h
> index 2464c40..ee6edd8 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_debug.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr_debug.h
> @@ -23,9 +23,13 @@
> #define MPI3_DEBUG_RESET		0x00000020
> #define MPI3_DEBUG_SCSI_ERROR		0x00000040
> #define MPI3_DEBUG_REPLY		0x00000080
> +#define MPI3_DEBUG_CFG_ERROR		0x00000100
> +#define MPI3_DEBUG_TRANSPORT_ERROR	0x00000200
> #define MPI3_DEBUG_BSG_ERROR		0x00008000
> #define MPI3_DEBUG_BSG_INFO		0x00010000
> #define MPI3_DEBUG_SCSI_INFO		0x00020000
> +#define MPI3_DEBUG_CFG_INFO		0x00040000
> +#define MPI3_DEBUG_TRANSPORT_INFO	0x00080000
> #define MPI3_DEBUG			0x01000000
> #define MPI3_DEBUG_SG			0x02000000
> 
> @@ -122,6 +126,29 @@
> 			pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
> 	} while (0)
> 
> +#define dprint_cfg_info(ioc, fmt, ...) \
> +	do { \
> +		if (ioc->logging_level & MPI3_DEBUG_CFG_INFO) \
> +			pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
> +	} while (0)
> +
> +#define dprint_cfg_err(ioc, fmt, ...) \
> +	do { \
> +		if (ioc->logging_level & MPI3_DEBUG_CFG_ERROR) \
> +			pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
> +	} while (0)
> +#define dprint_transport_info(ioc, fmt, ...) \
> +	do { \
> +		if (ioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO) \
> +			pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
> +	} while (0)
> +
> +#define dprint_transport_err(ioc, fmt, ...) \
> +	do { \
> +		if (ioc->logging_level & MPI3_DEBUG_TRANSPORT_ERROR) \
> +			pr_info("%s: " fmt, (ioc)->name, ##__VA_ARGS__); \
> +	} while (0)
> +
> #endif /* MPT3SAS_DEBUG_H_INCLUDED */
> 
> /**
> -- 
> 2.27.0
> 

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 02/15] mpi3mr: Add framework to issue cnfg requests
  2022-07-29 13:16 ` [PATCH 02/15] mpi3mr: Add framework to issue cnfg requests Sreekanth Reddy
@ 2022-07-29 17:00   ` Himanshu Madhani
  2022-08-01  7:40     ` Sreekanth Reddy
  0 siblings, 1 reply; 35+ messages in thread
From: Himanshu Madhani @ 2022-07-29 17:00 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Added framework to issue config requests commands to
> controller firmware.
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr.h    |  28 ++++
> drivers/scsi/mpi3mr/mpi3mr_fw.c | 256 ++++++++++++++++++++++++++++++++
> drivers/scsi/mpi3mr/mpi3mr_os.c |   1 +
> 3 files changed, 285 insertions(+)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index 0935b2e..e15ad0e 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -97,6 +97,7 @@ extern atomic64_t event_counter;
> #define MPI3MR_HOSTTAG_PEL_ABORT	3
> #define MPI3MR_HOSTTAG_PEL_WAIT		4
> #define MPI3MR_HOSTTAG_BLK_TMS		5
> +#define MPI3MR_HOSTTAG_CFG_CMDS		6
> 
> #define MPI3MR_NUM_DEVRMCMD		16
> #define MPI3MR_HOSTTAG_DEVRMCMD_MIN	(MPI3MR_HOSTTAG_BLK_TMS + 1)
> @@ -126,6 +127,8 @@ extern atomic64_t event_counter;
> 
> #define MPI3MR_WATCHDOG_INTERVAL		1000 /* in milli seconds */
> 
> +#define MPI3MR_DEFAULT_CFG_PAGE_SZ		1024 /* in bytes */
> +
> #define MPI3MR_SCMD_TIMEOUT    (60 * HZ)
> #define MPI3MR_EH_SCMD_TIMEOUT (60 * HZ)
> 
> @@ -274,6 +277,7 @@ enum mpi3mr_reset_reason {
> 	MPI3MR_RESET_FROM_SYSFS = 23,
> 	MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24,
> 	MPI3MR_RESET_FROM_FIRMWARE = 27,
> +	MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT = 29,
> };
> 
> /* Queue type definitions */
> @@ -679,6 +683,21 @@ struct mpi3mr_drv_cmd {
> 	    struct mpi3mr_drv_cmd *drv_cmd);
> };
> 
> +/**
> + * struct dma_memory_desc - memory descriptor structure to store
> + * virtual address, dma address and size for any generic dma
> + * memory allocations in the driver.
> + *
> + * @size: buffer size
> + * @addr: virtual address
> + * @dma_addr: dma address
> + */
> +struct dma_memory_desc {
> +	u32 size;
> +	void *addr;
> +	dma_addr_t dma_addr;
> +};
> +
> 
> /**
>  * struct chain_element - memory descriptor structure to store
> @@ -756,6 +775,7 @@ struct scmd_priv {
>  * @num_op_reply_q: Number of operational reply queues
>  * @op_reply_qinfo: Operational reply queue info pointer
>  * @init_cmds: Command tracker for initialization commands
> + * @cfg_cmds: Command tracker for configuration requests
>  * @facts: Cached IOC facts data
>  * @op_reply_desc_sz: Operational reply descriptor size
>  * @num_reply_bufs: Number of reply buffers allocated
> @@ -854,6 +874,9 @@ struct scmd_priv {
>  * @io_throttle_low: I/O size to stop throttle in 512b blocks
>  * @num_io_throttle_group: Maximum number of throttle groups
>  * @throttle_groups: Pointer to throttle group info structures
> + * @cfg_page: Default memory for configuration pages
> + * @cfg_page_dma: Configuration page DMA address
> + * @cfg_page_sz: Default configuration page memory size
>  */
> struct mpi3mr_ioc {
> 	struct list_head list;
> @@ -904,6 +927,7 @@ struct mpi3mr_ioc {
> 	struct op_reply_qinfo *op_reply_qinfo;
> 
> 	struct mpi3mr_drv_cmd init_cmds;
> +	struct mpi3mr_drv_cmd cfg_cmds;
> 	struct mpi3mr_ioc_facts facts;
> 	u16 op_reply_desc_sz;
> 
> @@ -1025,6 +1049,10 @@ struct mpi3mr_ioc {
> 	u32 io_throttle_low;
> 	u16 num_io_throttle_group;
> 	struct mpi3mr_throttle_group_info *throttle_groups;
> +
> +	void *cfg_page;
> +	dma_addr_t cfg_page_dma;
> +	u16 cfg_page_sz;
> };
> 
> /**
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index 0866dfd..da6eceb 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -299,6 +299,8 @@ mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
> 	switch (host_tag) {
> 	case MPI3MR_HOSTTAG_INITCMDS:
> 		return &mrioc->init_cmds;
> +	case MPI3MR_HOSTTAG_CFG_CMDS:
> +		return &mrioc->cfg_cmds;
> 	case MPI3MR_HOSTTAG_BSG_CMDS:
> 		return &mrioc->bsg_cmds;
> 	case MPI3MR_HOSTTAG_BLK_TMS:
> @@ -907,6 +909,7 @@ static const struct {
> 	{ MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
> 	{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
> 	{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronous reset" },
> +	{ MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout"},
> };
> 
> /**
> @@ -3738,6 +3741,14 @@ retry_init:
> 
> 	mpi3mr_print_ioc_info(mrioc);
> 
> +	dprint_init(mrioc, "allocating config page buffers\n");
> +	mrioc->cfg_page = dma_alloc_coherent(&mrioc->pdev->dev,
> +	    MPI3MR_DEFAULT_CFG_PAGE_SZ, &mrioc->cfg_page_dma, GFP_KERNEL);
> +	if (!mrioc->cfg_page)
> +		goto out_failed_noretry;
> +
> +	mrioc->cfg_page_sz = MPI3MR_DEFAULT_CFG_PAGE_SZ;
> +
> 	retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
> 	if (retval) {
> 		ioc_err(mrioc,
> @@ -4362,6 +4373,10 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
> 
> 	cmdptr = &mrioc->init_cmds;
> 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
> +
> +	cmdptr = &mrioc->cfg_cmds;
> +	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
> +
> 	cmdptr = &mrioc->bsg_cmds;
> 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
> 	cmdptr = &mrioc->host_tm_cmds;
> @@ -4786,3 +4801,244 @@ out:
> 	    ((retval == 0) ? "successful" : "failed"));
> 	return retval;
> }
> +
> +
> +/**
> + * mpi3mr_free_config_dma_memory - free memory for config page
> + * @mrioc: Adapter instance reference
> + * @mem_desc: memory descriptor structure
> + *
> + * Check whether the size of the buffer specified by the memory
> + * descriptor is greater than the default page size if so then
> + * free the memory pointed by the descriptor.
> + *
> + * Return: 0 on success, non-zero on failure.

Nit: the above comment is incorrect. This function returns nothing.
 
> + */
> +static void mpi3mr_free_config_dma_memory(struct mpi3mr_ioc *mrioc,
> +	struct dma_memory_desc *mem_desc)
> +{
> +	if ((mem_desc->size > mrioc->cfg_page_sz) && mem_desc->addr) {
> +		dma_free_coherent(&mrioc->pdev->dev, mem_desc->size,
> +		    mem_desc->addr, mem_desc->dma_addr);
> +		mem_desc->addr = NULL;
> +	}
> +}
> +
> +
> +

Remove extra newline

> +/**
> + * mpi3mr_alloc_config_dma_memory - Alloc memory for config page
> + * @mrioc: Adapter instance reference
> + * @mem_desc: Memory descriptor to hold dma memory info
> + *
> + * This function allocates new dmaable memory or provides the
> + * default config page dmaable memory based on the memory size
> + * described by the descriptor.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +static int mpi3mr_alloc_config_dma_memory(struct mpi3mr_ioc *mrioc,
> +	struct dma_memory_desc *mem_desc)
> +{
> +	if (mem_desc->size > mrioc->cfg_page_sz) {
> +		mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev,
> +		    mem_desc->size, &mem_desc->dma_addr, GFP_KERNEL);
> +		if (!mem_desc->addr)
> +			return -ENOMEM;
> +	} else {
> +		mem_desc->addr = mrioc->cfg_page;
> +		mem_desc->dma_addr = mrioc->cfg_page_dma;
> +		memset(mem_desc->addr, 0, mrioc->cfg_page_sz);
> +	}
> +	return 0;
> +}
> +
> +
> +/**
> + * mpi3mr_post_cfg_req - Issue config requests and wait
> + * @mrioc: Adapter instance reference
> + * @cfg_req: Configuration request
> + * @timeout: Timeout in seconds
> + * @ioc_status: Pointer to return ioc status
> + *
> + * A generic function for posting MPI3 configuration request to
> + * the firmware. This blocks for the completion of request for
> + * timeout seconds and if the request times out this function
> + * faults the controller with proper reason code.
> + *
> + * On successful completion of the request this function returns
> + * appropriate ioc status from the firmware back to the caller.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +static int mpi3mr_post_cfg_req(struct mpi3mr_ioc *mrioc,
> +	struct mpi3_config_request *cfg_req, int timeout, u16 *ioc_status)
> +{
> +	int retval = 0;
> +
> +	mutex_lock(&mrioc->cfg_cmds.mutex);
> +	if (mrioc->cfg_cmds.state & MPI3MR_CMD_PENDING) {
> +		retval = -1;
> +		ioc_err(mrioc, "sending config request failed due to command in use\n");
> +		mutex_unlock(&mrioc->cfg_cmds.mutex);
> +		goto out;
> +	}
> +	mrioc->cfg_cmds.state = MPI3MR_CMD_PENDING;
> +	mrioc->cfg_cmds.is_waiting = 1;

You are setting is_waiting here, but I don’t see this being cleared anywhere. 

> +	mrioc->cfg_cmds.callback = NULL;
> +	mrioc->cfg_cmds.ioc_status = 0;
> +	mrioc->cfg_cmds.ioc_loginfo = 0;
> +
> +	cfg_req->host_tag = cpu_to_le16(MPI3MR_HOSTTAG_CFG_CMDS);
> +	cfg_req->function = MPI3_FUNCTION_CONFIG;
> +
> +	init_completion(&mrioc->cfg_cmds.done);
> +	dprint_cfg_info(mrioc, "posting config request\n");
> +	if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
> +		dprint_dump(cfg_req, sizeof(struct mpi3_config_request),
> +		    "mpi3_cfg_req");
> +	retval = mpi3mr_admin_request_post(mrioc, cfg_req, sizeof(*cfg_req), 1);
> +	if (retval) {
> +		ioc_err(mrioc, "posting config request failed\n");
> +		goto out_unlock;
> +	}
> +	wait_for_completion_timeout(&mrioc->cfg_cmds.done, (timeout * HZ));
> +	if (!(mrioc->cfg_cmds.state & MPI3MR_CMD_COMPLETE)) {
> +		mpi3mr_check_rh_fault_ioc(mrioc,
> +		    MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT);
> +		ioc_err(mrioc, "config request timed out\n");
> +		retval = -1;
> +		goto out_unlock;
> +	}
> +	*ioc_status = mrioc->cfg_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
> +	if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS)
> +		dprint_cfg_err(mrioc,
> +		    "cfg_page request returned with ioc_status(0x%04x), log_info(0x%08x)\n",
> +		    *ioc_status, mrioc->cfg_cmds.ioc_loginfo);
> +
> +out_unlock:
> +	mrioc->cfg_cmds.state = MPI3MR_CMD_NOTUSED;

Should you not set mrioc->cfg_cmds.is_waiting = 0 here? Or am I missing something?

> +	mutex_unlock(&mrioc->cfg_cmds.mutex);
> +
> +out:
> +	return retval;
> +}
> +
> +/**
> + * mpi3mr_process_cfg_req - config page request processor
> + * @mrioc: Adapter instance reference
> + * @cfg_req: Configuration request
> + * @cfg_hdr: Configuration page header
> + * @timeout: Timeout in seconds
> + * @ioc_status: Pointer to return ioc status
> + * @cfg_buf: Memory pointer to copy config page or header
> + * @cfg_buf_sz: Size of the memory to get config page or header
> + *
> + * This is handler for config page read, write and config page
> + * header read operations.
> + *
> + * This function expects the cfg_req to be populated with page
> + * type, page number, action for the header read and with page
> + * address for all other operations.
> + *
> + * The cfg_hdr can be passed as null for reading required header
> + * details for read/write pages the cfg_hdr should point valid
> + * configuration page header.
> + *
> + * This allocates dmaable memory based on the size of the config
> + * buffer and set the SGE of the cfg_req.
> + *
> + * For write actions, the config page data has to be passed in
> + * the cfg_buf and size of the data has to be mentioned in the
> + * cfg_buf_sz.
> + *
> + * For read/header actions, on successful completion of the
> + * request with successful ioc_status the data will be copied
> + * into the cfg_buf limited to a minimum of actual page size and
> + * cfg_buf_sz
> + *
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc,
> +	struct mpi3_config_request *cfg_req,
> +	struct mpi3_config_page_header *cfg_hdr, int timeout, u16 *ioc_status,
> +	void *cfg_buf, u32 cfg_buf_sz)
> +{
> +	struct dma_memory_desc mem_desc;
> +	int retval = -1;
> +	u8 invalid_action = 0;
> +	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
> +
> +	memset(&mem_desc, 0, sizeof(struct dma_memory_desc));
> +
> +	if (cfg_req->action == MPI3_CONFIG_ACTION_PAGE_HEADER)
> +		mem_desc.size = sizeof(struct mpi3_config_page_header);
> +	else {
> +		if (!cfg_hdr) {
> +			ioc_err(mrioc, "null config header passed for config action(%d), page_type(0x%02x), page_num(%d)\n",
> +			    cfg_req->action, cfg_req->page_type,
> +			    cfg_req->page_number);
> +			goto out;
> +		}
> +		switch (cfg_hdr->page_attribute & MPI3_CONFIG_PAGEATTR_MASK) {
> +		case MPI3_CONFIG_PAGEATTR_READ_ONLY:
> +			if (cfg_req->action
> +			    != MPI3_CONFIG_ACTION_READ_CURRENT)
> +				invalid_action = 1;
> +			break;
> +		case MPI3_CONFIG_PAGEATTR_CHANGEABLE:
> +			if ((cfg_req->action ==
> +			     MPI3_CONFIG_ACTION_READ_PERSISTENT) ||
> +			    (cfg_req->action ==
> +			     MPI3_CONFIG_ACTION_WRITE_PERSISTENT))
> +				invalid_action = 1;
> +			break;
> +		case MPI3_CONFIG_PAGEATTR_PERSISTENT:
> +		default:
> +			break;
> +		}
> +		if (invalid_action) {
> +			ioc_err(mrioc,
> +			    "config action(%d) is not allowed for page_type(0x%02x), page_num(%d) with page_attribute(0x%02x)\n",
> +			    cfg_req->action, cfg_req->page_type,
> +			    cfg_req->page_number, cfg_hdr->page_attribute);
> +			goto out;
> +		}
> +		mem_desc.size = le16_to_cpu(cfg_hdr->page_length) * 4;
> +		cfg_req->page_length = cfg_hdr->page_length;
> +		cfg_req->page_version = cfg_hdr->page_version;
> +	}
> +	if (mpi3mr_alloc_config_dma_memory(mrioc, &mem_desc))
> +		goto out;
> +
> +	mpi3mr_add_sg_single(&cfg_req->sgl, sgl_flags, mem_desc.size,
> +	    mem_desc.dma_addr);
> +
> +	if ((cfg_req->action == MPI3_CONFIG_ACTION_WRITE_PERSISTENT) ||
> +	    (cfg_req->action == MPI3_CONFIG_ACTION_WRITE_CURRENT)) {
> +		memcpy(mem_desc.addr, cfg_buf, min_t(u16, mem_desc.size,
> +		    cfg_buf_sz));
> +		dprint_cfg_info(mrioc, "config buffer to be written\n");
> +		if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
> +			dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf");
> +	}
> +
> +	if (mpi3mr_post_cfg_req(mrioc, cfg_req, timeout, ioc_status))
> +		goto out;
> +
> +	retval = 0;
> +	if ((*ioc_status == MPI3_IOCSTATUS_SUCCESS) &&
> +	    (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_PERSISTENT) &&
> +	    (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_CURRENT)) {
> +		memcpy(cfg_buf, mem_desc.addr, min_t(u16, mem_desc.size,
> +		    cfg_buf_sz));
> +		dprint_cfg_info(mrioc, "config buffer read\n");
> +		if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
> +			dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf");
> +	}
> +
> +out:
> +	mpi3mr_free_config_dma_memory(mrioc, &mem_desc);
> +	return retval;
> +}
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index 8bdf927..40bed22 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -4574,6 +4574,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> 	mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
> 	mpi3mr_init_drv_cmd(&mrioc->host_tm_cmds, MPI3MR_HOSTTAG_BLK_TMS);
> 	mpi3mr_init_drv_cmd(&mrioc->bsg_cmds, MPI3MR_HOSTTAG_BSG_CMDS);
> +	mpi3mr_init_drv_cmd(&mrioc->cfg_cmds, MPI3MR_HOSTTAG_CFG_CMDS);
> 
> 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
> 		mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i],
> -- 
> 2.27.0
> 

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 11/15] mpi3mr: Add SAS SATA end devices to STL
  2022-07-29 13:16 ` [PATCH 11/15] mpi3mr: Add SAS SATA end devices to STL Sreekanth Reddy
@ 2022-07-29 17:32   ` kernel test robot
  0 siblings, 0 replies; 35+ messages in thread
From: kernel test robot @ 2022-07-29 17:32 UTC (permalink / raw)
  To: Sreekanth Reddy, linux-scsi
  Cc: llvm, kbuild-all, martin.petersen, Sreekanth Reddy

Hi Sreekanth,

I love your patch! Perhaps something to improve:

[auto build test WARNING on mkp-scsi/for-next]
[also build test WARNING on next-20220728]
[cannot apply to jejb-scsi/for-next linus/master v5.19-rc8]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Sreekanth-Reddy/mpi3mr-Added-Support-for-SAS-Transport/20220729-210902
base:   https://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next
config: i386-randconfig-a013 (https://download.01.org/0day-ci/archive/20220730/202207300127.y29B3Vbe-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 8dfaecc4c24494337933aff9d9166486ca0949f1)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/e4b268bf60cc339de06db43ad3da7450cf59e9c2
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Sreekanth-Reddy/mpi3mr-Added-Support-for-SAS-Transport/20220729-210902
        git checkout e4b268bf60cc339de06db43ad3da7450cf59e9c2
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=i386 SHELL=/bin/bash drivers/scsi/mpi3mr/

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/scsi/mpi3mr/mpi3mr_os.c:1573:3: warning: unannotated fall-through between switch labels [-Wimplicit-fallthrough]
                   default:
                   ^
   drivers/scsi/mpi3mr/mpi3mr_os.c:1573:3: note: insert 'break;' to avoid fall-through
                   default:
                   ^
                   break; 
   1 warning generated.


vim +1573 drivers/scsi/mpi3mr/mpi3mr_os.c

9fc4abfe5a5fc9f Kashyap Desai   2021-05-20  1491  
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1492  /**
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1493   * mpi3mr_sastopochg_evt_bh - SASTopologyChange evt bottomhalf
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1494   * @mrioc: Adapter instance reference
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1495   * @fwevt: Firmware event reference
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1496   *
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1497   * Prints information about the SAS topology change event and
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1498   * for "not responding" event code, removes the device from the
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1499   * upper layers.
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1500   *
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1501   * Return: Nothing.
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1502   */
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1503  static void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc,
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1504  	struct mpi3mr_fwevt *fwevt)
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1505  {
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1506  	struct mpi3_event_data_sas_topology_change_list *event_data =
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1507  	    (struct mpi3_event_data_sas_topology_change_list *)fwevt->event_data;
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1508  	int i;
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1509  	u16 handle;
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1510  	u8 reason_code;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1511  	u64 exp_sas_address = 0, parent_sas_address = 0;
eaf398d9cf51b23 Sreekanth Reddy 2022-07-29  1512  	struct mpi3mr_hba_port *hba_port = NULL;
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1513  	struct mpi3mr_tgt_dev *tgtdev = NULL;
eaf398d9cf51b23 Sreekanth Reddy 2022-07-29  1514  	struct mpi3mr_sas_node *sas_expander = NULL;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1515  	unsigned long flags;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1516  	u8 link_rate, prev_link_rate, parent_phy_number;
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1517  
9fc4abfe5a5fc9f Kashyap Desai   2021-05-20  1518  	mpi3mr_sastopochg_evt_debug(mrioc, event_data);
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1519  	if (mrioc->sas_transport_enabled) {
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1520  		hba_port = mpi3mr_get_hba_port_by_id(mrioc,
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1521  		    event_data->io_unit_port);
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1522  		if (le16_to_cpu(event_data->expander_dev_handle)) {
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1523  			spin_lock_irqsave(&mrioc->sas_node_lock, flags);
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1524  			sas_expander = __mpi3mr_expander_find_by_handle(mrioc,
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1525  			    le16_to_cpu(event_data->expander_dev_handle));
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1526  			if (sas_expander) {
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1527  				exp_sas_address = sas_expander->sas_address;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1528  				hba_port = sas_expander->hba_port;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1529  			}
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1530  			spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1531  			parent_sas_address = exp_sas_address;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1532  		} else
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1533  			parent_sas_address = mrioc->sas_hba.sas_address;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1534  	}
9fc4abfe5a5fc9f Kashyap Desai   2021-05-20  1535  
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1536  	for (i = 0; i < event_data->num_entries; i++) {
580e6742205efe6 Sreekanth Reddy 2022-02-10  1537  		if (fwevt->discard)
580e6742205efe6 Sreekanth Reddy 2022-02-10  1538  			return;
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1539  		handle = le16_to_cpu(event_data->phy_entry[i].attached_dev_handle);
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1540  		if (!handle)
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1541  			continue;
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1542  		tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, handle);
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1543  		if (!tgtdev)
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1544  			continue;
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1545  
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1546  		reason_code = event_data->phy_entry[i].status &
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1547  		    MPI3_EVENT_SAS_TOPO_PHY_RC_MASK;
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1548  
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1549  		switch (reason_code) {
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1550  		case MPI3_EVENT_SAS_TOPO_PHY_RC_TARG_NOT_RESPONDING:
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1551  			if (tgtdev->host_exposed)
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1552  				mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1553  			mpi3mr_tgtdev_del_from_list(mrioc, tgtdev);
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1554  			mpi3mr_tgtdev_put(tgtdev);
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1555  			break;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1556  		case MPI3_EVENT_SAS_TOPO_PHY_RC_RESPONDING:
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1557  		case MPI3_EVENT_SAS_TOPO_PHY_RC_PHY_CHANGED:
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1558  		case MPI3_EVENT_SAS_TOPO_PHY_RC_NO_CHANGE:
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1559  		{
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1560  			if (!mrioc->sas_transport_enabled || tgtdev->non_stl
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1561  			    || tgtdev->is_hidden)
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1562  				break;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1563  			link_rate = event_data->phy_entry[i].link_rate >> 4;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1564  			prev_link_rate = event_data->phy_entry[i].link_rate & 0xF;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1565  			if (link_rate == prev_link_rate)
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1566  				break;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1567  			if (!parent_sas_address)
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1568  				break;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1569  			parent_phy_number = event_data->start_phy_num + i;
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1570  			mpi3mr_update_links(mrioc, parent_sas_address, handle,
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1571  			    parent_phy_number, link_rate, hba_port);
e4b268bf60cc339 Sreekanth Reddy 2022-07-29  1572  		}
13ef29ea4aa0655 Kashyap Desai   2021-05-20 @1573  		default:
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1574  			break;
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1575  		}
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1576  		if (tgtdev)
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1577  			mpi3mr_tgtdev_put(tgtdev);
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1578  	}
eaf398d9cf51b23 Sreekanth Reddy 2022-07-29  1579  
eaf398d9cf51b23 Sreekanth Reddy 2022-07-29  1580  	if (mrioc->sas_transport_enabled && (event_data->exp_status ==
eaf398d9cf51b23 Sreekanth Reddy 2022-07-29  1581  	    MPI3_EVENT_SAS_TOPO_ES_NOT_RESPONDING)) {
eaf398d9cf51b23 Sreekanth Reddy 2022-07-29  1582  		if (sas_expander)
eaf398d9cf51b23 Sreekanth Reddy 2022-07-29  1583  			mpi3mr_expander_remove(mrioc, exp_sas_address,
eaf398d9cf51b23 Sreekanth Reddy 2022-07-29  1584  			    hba_port);
eaf398d9cf51b23 Sreekanth Reddy 2022-07-29  1585  	}
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1586  }
13ef29ea4aa0655 Kashyap Desai   2021-05-20  1587  

-- 
0-DAY CI Kernel Test Service
https://01.org/lkp

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 03/15] mpi3mr: Added helper functions to retrieve cnfg pages
  2022-07-29 13:16 ` [PATCH 03/15] mpi3mr: Added helper functions to retrieve cnfg pages Sreekanth Reddy
@ 2022-07-29 18:13   ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-07-29 18:13 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Added helper functions to retrieve below controller's
> config pages,
> - SAS IOUnit Page0
> - SAS IOUnit Page1
> - Driver Page1
> - Device Page0
> - SAS Phy Page0
> - SAS Phy Page1
> - SAS Expander Page0
> - SAS Expander Page1
> - Enclosure Page0
> 
> Also added the helper function to set the SAS IOUnit Page1.
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr.h    |  26 ++
> drivers/scsi/mpi3mr/mpi3mr_fw.c | 595 ++++++++++++++++++++++++++++++++
> 2 files changed, 621 insertions(+)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index e15ad0e..8af94d3 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -1179,4 +1179,30 @@ void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data,
> 	u16 event_data_size);
> extern const struct attribute_group *mpi3mr_host_groups[];
> extern const struct attribute_group *mpi3mr_dev_groups[];
> +
> +int mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_device_page0 *dev_pg0, u16 pg_sz, u32 form, u32 form_spec);
> +int mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_sas_phy_page0 *phy_pg0, u16 pg_sz, u32 form,
> +	u32 form_spec);
> +int mpi3mr_cfg_get_sas_phy_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_sas_phy_page1 *phy_pg1, u16 pg_sz, u32 form,
> +	u32 form_spec);
> +int mpi3mr_cfg_get_sas_exp_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_sas_expander_page0 *exp_pg0, u16 pg_sz, u32 form,
> +	u32 form_spec);
> +int mpi3mr_cfg_get_sas_exp_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_sas_expander_page1 *exp_pg1, u16 pg_sz, u32 form,
> +	u32 form_spec);
> +int mpi3mr_cfg_get_enclosure_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_enclosure_page0 *encl_pg0, u16 pg_sz, u32 form,
> +	u32 form_spec);
> +int mpi3mr_cfg_get_sas_io_unit_pg0(struct mpi3mr_ioc *mrioc,
> +	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0, u16 pg_sz);
> +int mpi3mr_cfg_get_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
> +	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz);
> +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);
> #endif /*MPI3MR_H_INCLUDED*/
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index da6eceb..50e88d4 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -5042,3 +5042,598 @@ out:
> 	mpi3mr_free_config_dma_memory(mrioc, &mem_desc);
> 	return retval;
> }
> +
> +/**
> + * mpi3mr_cfg_get_dev_pg0 - Read current device page0
> + * @mrioc: Adapter instance reference
> + * @ioc_status: Pointer to return ioc status
> + * @dev_pg0: Pointer to return device page 0
> + * @pg_sz: Size of the memory allocated to the page pointer
> + * @form: The form to be used for addressing the page
> + * @form_spec: Form specific information like device handle
> + *
> + * This is handler for config page read for a specific device
> + * page0. The ioc_status has the controller returned ioc_status.
> + * This routine doesn't check ioc_status to decide whether the
> + * page read is success or not and it is the callers
> + * responsibility.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +int mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_device_page0 *dev_pg0, u16 pg_sz, u32 form, u32 form_spec)
> +{
> +	struct mpi3_config_page_header cfg_hdr;
> +	struct mpi3_config_request cfg_req;
> +	u32 page_address;
> +
> +	memset(dev_pg0, 0, pg_sz);
> +	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
> +	memset(&cfg_req, 0, sizeof(cfg_req));
> +
> +	cfg_req.function = MPI3_FUNCTION_CONFIG;
> +	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
> +	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DEVICE;
> +	cfg_req.page_number = 0;
> +	cfg_req.page_address = 0;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
> +		ioc_err(mrioc, "device page0 header read failed\n");
> +		goto out_failed;
> +	}
> +	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "device page0 header read failed with ioc_status(0x%04x)\n",
> +		    *ioc_status);
> +		goto out_failed;
> +	}
> +	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
> +	page_address = ((form & MPI3_DEVICE_PGAD_FORM_MASK) |
> +	    (form_spec & MPI3_DEVICE_PGAD_HANDLE_MASK));
> +	cfg_req.page_address = cpu_to_le32(page_address);
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, dev_pg0, pg_sz)) {
> +		ioc_err(mrioc, "device page0 read failed\n");
> +		goto out_failed;
> +	}
> +	return 0;
> +out_failed:
> +	return -1;
> +}
> +
> +
> +/**
> + * mpi3mr_cfg_get_sas_phy_pg0 - Read current SAS Phy page0
> + * @mrioc: Adapter instance reference
> + * @ioc_status: Pointer to return ioc status
> + * @phy_pg0: Pointer to return SAS Phy page 0
> + * @pg_sz: Size of the memory allocated to the page pointer
> + * @form: The form to be used for addressing the page
> + * @form_spec: Form specific information like phy number
> + *
> + * This is handler for config page read for a specific SAS Phy
> + * page0. The ioc_status has the controller returned ioc_status.
> + * This routine doesn't check ioc_status to decide whether the
> + * page read is success or not and it is the callers
> + * responsibility.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +int mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_sas_phy_page0 *phy_pg0, u16 pg_sz, u32 form,
> +	u32 form_spec)
> +{
> +	struct mpi3_config_page_header cfg_hdr;
> +	struct mpi3_config_request cfg_req;
> +	u32 page_address;
> +
> +	memset(phy_pg0, 0, pg_sz);
> +	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
> +	memset(&cfg_req, 0, sizeof(cfg_req));
> +
> +	cfg_req.function = MPI3_FUNCTION_CONFIG;
> +	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
> +	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_PHY;
> +	cfg_req.page_number = 0;
> +	cfg_req.page_address = 0;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
> +		ioc_err(mrioc, "sas phy page0 header read failed\n");
> +		goto out_failed;
> +	}
> +	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "sas phy page0 header read failed with ioc_status(0x%04x)\n",
> +		    *ioc_status);
> +		goto out_failed;
> +	}
> +	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
> +	page_address = ((form & MPI3_SAS_PHY_PGAD_FORM_MASK) |
> +	    (form_spec & MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK));
> +	cfg_req.page_address = cpu_to_le32(page_address);
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, phy_pg0, pg_sz)) {
> +		ioc_err(mrioc, "sas phy page0 read failed\n");
> +		goto out_failed;
> +	}
> +	return 0;
> +out_failed:
> +	return -1;
> +}
> +
> +/**
> + * mpi3mr_cfg_get_sas_phy_pg1 - Read current SAS Phy page1
> + * @mrioc: Adapter instance reference
> + * @ioc_status: Pointer to return ioc status
> + * @phy_pg1: Pointer to return SAS Phy page 1
> + * @pg_sz: Size of the memory allocated to the page pointer
> + * @form: The form to be used for addressing the page
> + * @form_spec: Form specific information like phy number
> + *
> + * This is handler for config page read for a specific SAS Phy
> + * page1. The ioc_status has the controller returned ioc_status.
> + * This routine doesn't check ioc_status to decide whether the
> + * page read is success or not and it is the callers
> + * responsibility.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +int mpi3mr_cfg_get_sas_phy_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_sas_phy_page1 *phy_pg1, u16 pg_sz, u32 form,
> +	u32 form_spec)
> +{
> +	struct mpi3_config_page_header cfg_hdr;
> +	struct mpi3_config_request cfg_req;
> +	u32 page_address;
> +
> +	memset(phy_pg1, 0, pg_sz);
> +	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
> +	memset(&cfg_req, 0, sizeof(cfg_req));
> +
> +	cfg_req.function = MPI3_FUNCTION_CONFIG;
> +	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
> +	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_PHY;
> +	cfg_req.page_number = 1;
> +	cfg_req.page_address = 0;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
> +		ioc_err(mrioc, "sas phy page1 header read failed\n");
> +		goto out_failed;
> +	}
> +	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "sas phy page1 header read failed with ioc_status(0x%04x)\n",
> +		    *ioc_status);
> +		goto out_failed;
> +	}
> +	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
> +	page_address = ((form & MPI3_SAS_PHY_PGAD_FORM_MASK) |
> +	    (form_spec & MPI3_SAS_PHY_PGAD_PHY_NUMBER_MASK));
> +	cfg_req.page_address = cpu_to_le32(page_address);
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, phy_pg1, pg_sz)) {
> +		ioc_err(mrioc, "sas phy page1 read failed\n");
> +		goto out_failed;
> +	}
> +	return 0;
> +out_failed:
> +	return -1;
> +}
> +
> +
> +/**
> + * mpi3mr_cfg_get_sas_exp_pg0 - Read current SAS Expander page0
> + * @mrioc: Adapter instance reference
> + * @ioc_status: Pointer to return ioc status
> + * @exp_pg0: Pointer to return SAS Expander page 0
> + * @pg_sz: Size of the memory allocated to the page pointer
> + * @form: The form to be used for addressing the page
> + * @form_spec: Form specific information like device handle
> + *
> + * This is handler for config page read for a specific SAS
> + * Expander page0. The ioc_status has the controller returned
> + * ioc_status. This routine doesn't check ioc_status to decide
> + * whether the page read is success or not and it is the callers
> + * responsibility.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +int mpi3mr_cfg_get_sas_exp_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_sas_expander_page0 *exp_pg0, u16 pg_sz, u32 form,
> +	u32 form_spec)
> +{
> +	struct mpi3_config_page_header cfg_hdr;
> +	struct mpi3_config_request cfg_req;
> +	u32 page_address;
> +
> +	memset(exp_pg0, 0, pg_sz);
> +	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
> +	memset(&cfg_req, 0, sizeof(cfg_req));
> +
> +	cfg_req.function = MPI3_FUNCTION_CONFIG;
> +	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
> +	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_EXPANDER;
> +	cfg_req.page_number = 0;
> +	cfg_req.page_address = 0;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
> +		ioc_err(mrioc, "expander page0 header read failed\n");
> +		goto out_failed;
> +	}
> +	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "expander page0 header read failed with ioc_status(0x%04x)\n",
> +		    *ioc_status);
> +		goto out_failed;
> +	}
> +	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
> +	page_address = ((form & MPI3_SAS_EXPAND_PGAD_FORM_MASK) |
> +	    (form_spec & (MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK |
> +	    MPI3_SAS_EXPAND_PGAD_HANDLE_MASK)));
> +	cfg_req.page_address = cpu_to_le32(page_address);
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, exp_pg0, pg_sz)) {
> +		ioc_err(mrioc, "expander page0 read failed\n");
> +		goto out_failed;
> +	}
> +	return 0;
> +out_failed:
> +	return -1;
> +}
> +
> +/**
> + * mpi3mr_cfg_get_sas_exp_pg1 - Read current SAS Expander page1
> + * @mrioc: Adapter instance reference
> + * @ioc_status: Pointer to return ioc status
> + * @exp_pg1: Pointer to return SAS Expander page 1
> + * @pg_sz: Size of the memory allocated to the page pointer
> + * @form: The form to be used for addressing the page
> + * @form_spec: Form specific information like phy number
> + *
> + * This is handler for config page read for a specific SAS
> + * Expander page1. The ioc_status has the controller returned
> + * ioc_status. This routine doesn't check ioc_status to decide
> + * whether the page read is success or not and it is the callers
> + * responsibility.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +int mpi3mr_cfg_get_sas_exp_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_sas_expander_page1 *exp_pg1, u16 pg_sz, u32 form,
> +	u32 form_spec)
> +{
> +	struct mpi3_config_page_header cfg_hdr;
> +	struct mpi3_config_request cfg_req;
> +	u32 page_address;
> +
> +	memset(exp_pg1, 0, pg_sz);
> +	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
> +	memset(&cfg_req, 0, sizeof(cfg_req));
> +
> +	cfg_req.function = MPI3_FUNCTION_CONFIG;
> +	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
> +	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_EXPANDER;
> +	cfg_req.page_number = 1;
> +	cfg_req.page_address = 0;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
> +		ioc_err(mrioc, "expander page1 header read failed\n");
> +		goto out_failed;
> +	}
> +	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "expander page1 header read failed with ioc_status(0x%04x)\n",
> +		    *ioc_status);
> +		goto out_failed;
> +	}
> +	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
> +	page_address = ((form & MPI3_SAS_EXPAND_PGAD_FORM_MASK) |
> +	    (form_spec & (MPI3_SAS_EXPAND_PGAD_PHYNUM_MASK |
> +	    MPI3_SAS_EXPAND_PGAD_HANDLE_MASK)));
> +	cfg_req.page_address = cpu_to_le32(page_address);
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, exp_pg1, pg_sz)) {
> +		ioc_err(mrioc, "expander page1 read failed\n");
> +		goto out_failed;
> +	}
> +	return 0;
> +out_failed:
> +	return -1;
> +}
> +
> +/**
> + * mpi3mr_cfg_get_enclosure_pg0 - Read current Enclosure page0
> + * @mrioc: Adapter instance reference
> + * @ioc_status: Pointer to return ioc status
> + * @encl_pg0: Pointer to return Enclosure page 0
> + * @pg_sz: Size of the memory allocated to the page pointer
> + * @form: The form to be used for addressing the page
> + * @form_spec: Form specific information like device handle
> + *
> + * This is handler for config page read for a specific Enclosure
> + * page0. The ioc_status has the controller returned ioc_status.
> + * This routine doesn't check ioc_status to decide whether the
> + * page read is success or not and it is the callers
> + * responsibility.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +int mpi3mr_cfg_get_enclosure_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> +	struct mpi3_enclosure_page0 *encl_pg0, u16 pg_sz, u32 form,
> +	u32 form_spec)
> +{
> +	struct mpi3_config_page_header cfg_hdr;
> +	struct mpi3_config_request cfg_req;
> +	u32 page_address;
> +
> +	memset(encl_pg0, 0, pg_sz);
> +	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
> +	memset(&cfg_req, 0, sizeof(cfg_req));
> +
> +	cfg_req.function = MPI3_FUNCTION_CONFIG;
> +	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
> +	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_ENCLOSURE;
> +	cfg_req.page_number = 0;
> +	cfg_req.page_address = 0;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
> +		ioc_err(mrioc, "enclosure page0 header read failed\n");
> +		goto out_failed;
> +	}
> +	if (*ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "enclosure page0 header read failed with ioc_status(0x%04x)\n",
> +		    *ioc_status);
> +		goto out_failed;
> +	}
> +	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
> +	page_address = ((form & MPI3_ENCLOS_PGAD_FORM_MASK) |
> +	    (form_spec & MPI3_ENCLOS_PGAD_HANDLE_MASK));
> +	cfg_req.page_address = cpu_to_le32(page_address);
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
> +	    MPI3MR_INTADMCMD_TIMEOUT, ioc_status, encl_pg0, pg_sz)) {
> +		ioc_err(mrioc, "enclosure page0 read failed\n");
> +		goto out_failed;
> +	}
> +	return 0;
> +out_failed:
> +	return -1;
> +}
> +
> +
> +/**
> + * mpi3mr_cfg_get_sas_io_unit_pg0 - Read current SASIOUnit page0
> + * @mrioc: Adapter instance reference
> + * @sas_io_unit_pg0: Pointer to return SAS IO Unit page 0
> + * @pg_sz: Size of the memory allocated to the page pointer
> + *
> + * This is handler for config page read for the SAS IO Unit
> + * page0. This routine checks ioc_status to decide whether the
> + * page read is success or not.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +int mpi3mr_cfg_get_sas_io_unit_pg0(struct mpi3mr_ioc *mrioc,
> +	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0, u16 pg_sz)
> +{
> +	struct mpi3_config_page_header cfg_hdr;
> +	struct mpi3_config_request cfg_req;
> +	u16 ioc_status = 0;
> +
> +	memset(sas_io_unit_pg0, 0, pg_sz);
> +	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
> +	memset(&cfg_req, 0, sizeof(cfg_req));
> +
> +	cfg_req.function = MPI3_FUNCTION_CONFIG;
> +	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
> +	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
> +	cfg_req.page_number = 0;
> +	cfg_req.page_address = 0;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
> +	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
> +		ioc_err(mrioc, "sas io unit page0 header read failed\n");
> +		goto out_failed;
> +	}
> +	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "sas io unit page0 header read failed with ioc_status(0x%04x)\n",
> +		    ioc_status);
> +		goto out_failed;
> +	}
> +	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
> +	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg0, pg_sz)) {
> +		ioc_err(mrioc, "sas io unit page0 read failed\n");
> +		goto out_failed;
> +	}
> +	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "sas io unit page0 read failed with ioc_status(0x%04x)\n",
> +		    ioc_status);
> +		goto out_failed;
> +	}
> +	return 0;
> +out_failed:
> +	return -1;
> +}
> +
> +/**
> + * mpi3mr_cfg_get_sas_io_unit_pg1 - Read current SASIOUnit page1
> + * @mrioc: Adapter instance reference
> + * @sas_io_unit_pg1: Pointer to return SAS IO Unit page 1
> + * @pg_sz: Size of the memory allocated to the page pointer
> + *
> + * This is handler for config page read for the SAS IO Unit
> + * page1. This routine checks ioc_status to decide whether the
> + * page read is success or not.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +int mpi3mr_cfg_get_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
> +	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz)
> +{
> +	struct mpi3_config_page_header cfg_hdr;
> +	struct mpi3_config_request cfg_req;
> +	u16 ioc_status = 0;
> +
> +	memset(sas_io_unit_pg1, 0, pg_sz);
> +	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
> +	memset(&cfg_req, 0, sizeof(cfg_req));
> +
> +	cfg_req.function = MPI3_FUNCTION_CONFIG;
> +	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
> +	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
> +	cfg_req.page_number = 1;
> +	cfg_req.page_address = 0;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
> +	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
> +		ioc_err(mrioc, "sas io unit page1 header read failed\n");
> +		goto out_failed;
> +	}
> +	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "sas io unit page1 header read failed with ioc_status(0x%04x)\n",
> +		    ioc_status);
> +		goto out_failed;
> +	}
> +	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
> +	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
> +		ioc_err(mrioc, "sas io unit page1 read failed\n");
> +		goto out_failed;
> +	}
> +	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "sas io unit page1 read failed with ioc_status(0x%04x)\n",
> +		    ioc_status);
> +		goto out_failed;
> +	}
> +	return 0;
> +out_failed:
> +	return -1;
> +}
> +
> +/**
> + * mpi3mr_cfg_set_sas_io_unit_pg1 - Write SASIOUnit page1
> + * @mrioc: Adapter instance reference
> + * @sas_io_unit_pg1: Pointer to the SAS IO Unit page 1 to write
> + * @pg_sz: Size of the memory allocated to the page pointer
> + *
> + * This is handler for config page write for the SAS IO Unit
> + * page1. This routine checks ioc_status to decide whether the
> + * page read is success or not. This will modify both current
> + * and persistent page.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +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)
> +{
> +	struct mpi3_config_page_header cfg_hdr;
> +	struct mpi3_config_request cfg_req;
> +	u16 ioc_status = 0;
> +
> +	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
> +	memset(&cfg_req, 0, sizeof(cfg_req));
> +
> +	cfg_req.function = MPI3_FUNCTION_CONFIG;
> +	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
> +	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_SAS_IO_UNIT;
> +	cfg_req.page_number = 1;
> +	cfg_req.page_address = 0;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
> +	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
> +		ioc_err(mrioc, "sas io unit page1 header read failed\n");
> +		goto out_failed;
> +	}
> +	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "sas io unit page1 header read failed with ioc_status(0x%04x)\n",
> +		    ioc_status);
> +		goto out_failed;
> +	}
> +	cfg_req.action = MPI3_CONFIG_ACTION_WRITE_CURRENT;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
> +	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
> +		ioc_err(mrioc, "sas io unit page1 write current failed\n");
> +		goto out_failed;
> +	}
> +	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "sas io unit page1 write current failed with ioc_status(0x%04x)\n",
> +		    ioc_status);
> +		goto out_failed;
> +	}
> +
> +	cfg_req.action = MPI3_CONFIG_ACTION_WRITE_PERSISTENT;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
> +	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
> +		ioc_err(mrioc, "sas io unit page1 write persistent failed\n");
> +		goto out_failed;
> +	}
> +	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "sas io unit page1 write persistent failed with ioc_status(0x%04x)\n",
> +		    ioc_status);
> +		goto out_failed;
> +	}
> +	return 0;
> +out_failed:
> +	return -1;
> +}
> +
> +/**
> + * mpi3mr_cfg_get_driver_pg1 - Read current Driver page1
> + * @mrioc: Adapter instance reference
> + * @driver_pg1: Pointer to return Driver page 1
> + * @pg_sz: Size of the memory allocated to the page pointer
> + *
> + * This is handler for config page read for the Driver page1.
> + * This routine checks ioc_status to decide whether the page
> + * read is success or not.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc,
> +	struct mpi3_driver_page1 *driver_pg1, u16 pg_sz)
> +{
> +	struct mpi3_config_page_header cfg_hdr;
> +	struct mpi3_config_request cfg_req;
> +	u16 ioc_status = 0;
> +
> +	memset(driver_pg1, 0, pg_sz);
> +	memset(&cfg_hdr, 0, sizeof(cfg_hdr));
> +	memset(&cfg_req, 0, sizeof(cfg_req));
> +
> +	cfg_req.function = MPI3_FUNCTION_CONFIG;
> +	cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
> +	cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DRIVER;
> +	cfg_req.page_number = 1;
> +	cfg_req.page_address = 0;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
> +	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
> +		ioc_err(mrioc, "driver page1 header read failed\n");
> +		goto out_failed;
> +	}
> +	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "driver page1 header read failed with ioc_status(0x%04x)\n",
> +		    ioc_status);
> +		goto out_failed;
> +	}
> +	cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
> +
> +	if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
> +	    MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, driver_pg1, pg_sz)) {
> +		ioc_err(mrioc, "driver page1 read failed\n");
> +		goto out_failed;
> +	}
> +	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "driver page1 read failed with ioc_status(0x%04x)\n",
> +		    ioc_status);
> +		goto out_failed;
> +	}
> +	return 0;
> +out_failed:
> +	return -1;
> +}
> -- 
> 2.27.0
> 

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 04/15] mpi3mr: Enable Enclosure device add event
  2022-07-29 13:16 ` [PATCH 04/15] mpi3mr: Enable Enclosure device add event Sreekanth Reddy
@ 2022-07-29 18:33   ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-07-29 18:33 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Enable and process the Enclosure device add event.
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr.h    |  19 +++++
> drivers/scsi/mpi3mr/mpi3mr_fw.c |   4 +
> drivers/scsi/mpi3mr/mpi3mr_os.c | 133 +++++++++++++++++++++++++++++++-
> 3 files changed, 154 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index 8af94d3..542b462 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -461,6 +461,16 @@ struct mpi3mr_throttle_group_info {
> 	atomic_t pend_large_data_sz;
> };
> 
> +/**
> + * struct mpi3mr_enclosure_node - enclosure information
> + * @list: List of enclosures
> + * @pg0: Enclosure page 0;
> + */
> +struct mpi3mr_enclosure_node {
> +	struct list_head list;
> +	struct mpi3_enclosure_page0 pg0;
> +};
> +
> /**
>  * struct tgt_dev_sas_sata - SAS/SATA device specific
>  * information cached from firmware given data
> @@ -535,12 +545,14 @@ union _form_spec_inf {
>  * @slot: Slot number
>  * @encl_handle: FW enclosure handle
>  * @perst_id: FW assigned Persistent ID
> + * @devpg0_flag: Device Page0 flag
>  * @dev_type: SAS/SATA/PCIE device type
>  * @is_hidden: Should be exposed to upper layers or not
>  * @host_exposed: Already exposed to host or not
>  * @io_throttle_enabled: I/O throttling needed or not
>  * @q_depth: Device specific Queue Depth
>  * @wwid: World wide ID
> + * @enclosure_logical_id: Enclosure logical identifier
>  * @dev_spec: Device type specific information
>  * @ref_count: Reference count
>  */
> @@ -552,12 +564,14 @@ struct mpi3mr_tgt_dev {
> 	u16 slot;
> 	u16 encl_handle;
> 	u16 perst_id;
> +	u16 devpg0_flag;
> 	u8 dev_type;
> 	u8 is_hidden;
> 	u8 host_exposed;
> 	u8 io_throttle_enabled;
> 	u16 q_depth;
> 	u64 wwid;
> +	u64 enclosure_logical_id;
> 	union _form_spec_inf dev_spec;
> 	struct kref ref_count;
> };
> @@ -877,6 +891,7 @@ 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
> + * @enclosure_list: List of Enclosure objects
>  */
> struct mpi3mr_ioc {
> 	struct list_head list;
> @@ -1053,6 +1068,8 @@ struct mpi3mr_ioc {
> 	void *cfg_page;
> 	dma_addr_t cfg_page_dma;
> 	u16 cfg_page_sz;
> +
> +	struct list_head enclosure_list;
> };
> 
> /**
> @@ -1177,6 +1194,8 @@ int mpi3mr_pel_get_seqnum_post(struct mpi3mr_ioc *mrioc,
> 	struct mpi3mr_drv_cmd *drv_cmd);
> void mpi3mr_app_save_logdata(struct mpi3mr_ioc *mrioc, char *event_data,
> 	u16 event_data_size);
> +struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
> +	struct mpi3mr_ioc *mrioc, u16 handle);
> extern const struct attribute_group *mpi3mr_host_groups[];
> extern const struct attribute_group *mpi3mr_dev_groups[];
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index 50e88d4..9c36f52 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -244,6 +244,9 @@ static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
> 	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
> 		desc = "Enclosure Device Status Change";
> 		break;
> +	case MPI3_EVENT_ENCL_DEVICE_ADDED:
> +		desc = "Enclosure Added";
> +		break;
> 	case MPI3_EVENT_HARD_RESET_RECEIVED:
> 		desc = "Hard Reset Received";
> 		break;
> @@ -3660,6 +3663,7 @@ static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc)
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_INFO_CHANGED);
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_DEVICE_STATUS_CHANGE);
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE);
> +	mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENCL_DEVICE_ADDED);
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DISCOVERY);
> 	mpi3mr_unmask_events(mrioc, MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR);
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index 40bed22..ca718cb 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -1026,6 +1026,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
> {
> 	u16 flags = 0;
> 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data = NULL;
> +	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
> 	u8 prot_mask = 0;
> 
> 	tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id);
> @@ -1036,8 +1037,17 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
> 	tgtdev->slot = le16_to_cpu(dev_pg0->slot);
> 	tgtdev->q_depth = le16_to_cpu(dev_pg0->queue_depth);
> 	tgtdev->wwid = le64_to_cpu(dev_pg0->wwid);
> +	tgtdev->devpg0_flag = le16_to_cpu(dev_pg0->flags);
> +
> +	if (tgtdev->encl_handle)
> +		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
> +		    tgtdev->encl_handle);
> +	if (enclosure_dev)
> +		tgtdev->enclosure_logical_id = le64_to_cpu(
> +		    enclosure_dev->pg0.enclosure_logical_id);
> +
> +	flags = tgtdev->devpg0_flag;
> 
> -	flags = le16_to_cpu(dev_pg0->flags);
> 	tgtdev->is_hidden = (flags & MPI3_DEVICE0_FLAGS_HIDDEN);
> 
> 	if (is_added == true)
> @@ -1265,6 +1275,116 @@ out:
> 		mpi3mr_tgtdev_put(tgtdev);
> }
> 
> +/**
> + * mpi3mr_enclosure_find_by_handle - enclosure search by handle
> + * @mrioc: Adapter instance reference
> + * @handle: Firmware device handle of the enclosure
> + *
> + * This searches for enclosure device based on handle, then returns the
> + * enclosure object.
> + *
> + * Return: Enclosure object reference or NULL
> + */
> +struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
> +	struct mpi3mr_ioc *mrioc, u16 handle)
> +{
> +	struct mpi3mr_enclosure_node *enclosure_dev, *r = NULL;
> +
> +	list_for_each_entry(enclosure_dev, &mrioc->enclosure_list, list) {
> +		if (le16_to_cpu(enclosure_dev->pg0.enclosure_handle) != handle)
> +			continue;
> +		r = enclosure_dev;
> +		goto out;
> +	}
> +out:
> +	return r;
> +}
> +
> +/**
> + * mpi3mr_encldev_add_chg_evt_debug - debug for enclosure event
> + * @mrioc: Adapter instance reference
> + * @encl_pg0: Enclosure page 0.
> + * @is_added: Added event or not
> + *
> + * Return nothing.
> + */
> +static void mpi3mr_encldev_add_chg_evt_debug(struct mpi3mr_ioc *mrioc,
> +	struct mpi3_enclosure_page0 *encl_pg0, u8 is_added)
> +{
> +	char *reason_str = NULL;
> +
> +	if (!(mrioc->logging_level & MPI3_DEBUG_EVENT_WORK_TASK))
> +		return;
> +
> +	if (is_added)
> +		reason_str = "enclosure added";
> +	else
> +		reason_str = "enclosure dev status changed";
> +
> +	ioc_info(mrioc,
> +	    "%s: handle(0x%04x), enclosure logical id(0x%016llx)\n",
> +	    reason_str, le16_to_cpu(encl_pg0->enclosure_handle),
> +	    (unsigned long long)le64_to_cpu(encl_pg0->enclosure_logical_id));
> +	ioc_info(mrioc,
> +	    "number of slots(%d), port(%d), flags(0x%04x), present(%d)\n",
> +	    le16_to_cpu(encl_pg0->num_slots), encl_pg0->io_unit_port,
> +	    le16_to_cpu(encl_pg0->flags),
> +	    ((le16_to_cpu(encl_pg0->flags) &
> +	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4));
> +}
> +
> +/**
> + * mpi3mr_encldev_add_chg_evt_bh - Enclosure evt bottomhalf
> + * @mrioc: Adapter instance reference
> + * @fwevt: Firmware event reference
> + *
> + * Prints information about the Enclosure device status or
> + * Enclosure add events if logging is enabled and add or remove
> + * the enclosure from the controller's internal list of
> + * enclosures.
> + *
> + * Return: Nothing.
> + */
> +static void mpi3mr_encldev_add_chg_evt_bh(struct mpi3mr_ioc *mrioc,
> +	struct mpi3mr_fwevt *fwevt)
> +{
> +	struct mpi3mr_enclosure_node *enclosure_dev = NULL;
> +	struct mpi3_enclosure_page0 *encl_pg0;
> +	u16 encl_handle;
> +	u8 added, present;
> +
> +	encl_pg0 = (struct mpi3_enclosure_page0 *) fwevt->event_data;
> +	added = (fwevt->event_id == MPI3_EVENT_ENCL_DEVICE_ADDED) ? 1 : 0;
> +	mpi3mr_encldev_add_chg_evt_debug(mrioc, encl_pg0, added);
> +
> +
> +	encl_handle = le16_to_cpu(encl_pg0->enclosure_handle);
> +	present = ((le16_to_cpu(encl_pg0->flags) &
> +	      MPI3_ENCLS0_FLAGS_ENCL_DEV_PRESENT_MASK) >> 4);
> +
> +	if (encl_handle)
> +		enclosure_dev = mpi3mr_enclosure_find_by_handle(mrioc,
> +		    encl_handle);
> +	if (!enclosure_dev && present) {
> +		enclosure_dev =
> +			kzalloc(sizeof(struct mpi3mr_enclosure_node),
> +			    GFP_KERNEL);
> +		if (!enclosure_dev)
> +			return;
> +		list_add_tail(&enclosure_dev->list,
> +		    &mrioc->enclosure_list);
> +	}
> +	if (enclosure_dev) {
> +		if (!present) {
> +			list_del(&enclosure_dev->list);
> +			kfree(enclosure_dev);
> +		} else
> +			memcpy(&enclosure_dev->pg0, encl_pg0,
> +			    sizeof(enclosure_dev->pg0));
> +
> +	}
> +}
> +
> /**
>  * mpi3mr_sastopochg_evt_debug - SASTopoChange details
>  * @mrioc: Adapter instance reference
> @@ -1641,6 +1761,13 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
> 		mpi3mr_devstatuschg_evt_bh(mrioc, fwevt);
> 		break;
> 	}
> +	case MPI3_EVENT_ENCL_DEVICE_ADDED:
> +	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
> +	{
> +		mpi3mr_encldev_add_chg_evt_bh(mrioc, fwevt);
> +		break;
> +	}
> +
> 	case MPI3_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
> 	{
> 		mpi3mr_sastopochg_evt_bh(mrioc, fwevt);
> @@ -2502,6 +2629,8 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
> 	}
> 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
> 	case MPI3_EVENT_LOG_DATA:
> +	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
> +	case MPI3_EVENT_ENCL_DEVICE_ADDED:
> 	{
> 		process_evt_bh = 1;
> 		break;
> @@ -2516,7 +2645,6 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
> 		mpi3mr_cablemgmt_evt_th(mrioc, event_reply);
> 		break;
> 	}
> -	case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
> 	case MPI3_EVENT_SAS_DISCOVERY:
> 	case MPI3_EVENT_SAS_DEVICE_DISCOVERY_ERROR:
> 	case MPI3_EVENT_SAS_BROADCAST_PRIMITIVE:
> @@ -4569,6 +4697,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> 	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->enclosure_list);
> 
> 	mutex_init(&mrioc->reset_mutex);
> 	mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
> -- 
> 2.27.0
> 

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 05/15] mpi3mr: Add framework to add phys to STL
  2022-07-29 13:16 ` [PATCH 05/15] mpi3mr: Add framework to add phys to STL Sreekanth Reddy
@ 2022-07-29 19:42   ` Himanshu Madhani
  2022-08-01  7:46     ` Sreekanth Reddy
  0 siblings, 1 reply; 35+ messages in thread
From: Himanshu Madhani @ 2022-07-29 19:42 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Added framework to register and unregister the
> host and expander phys with SCSI Transport Layer (STL).
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/Makefile           |   1 +
> drivers/scsi/mpi3mr/mpi3mr.h           |  93 ++++++
> drivers/scsi/mpi3mr/mpi3mr_transport.c | 430 +++++++++++++++++++++++++
> 3 files changed, 524 insertions(+)
> create mode 100644 drivers/scsi/mpi3mr/mpi3mr_transport.c
> 
> diff --git a/drivers/scsi/mpi3mr/Makefile b/drivers/scsi/mpi3mr/Makefile
> index f5cdbe4..ef86ca4 100644
> --- a/drivers/scsi/mpi3mr/Makefile
> +++ b/drivers/scsi/mpi3mr/Makefile
> @@ -3,3 +3,4 @@ obj-m += mpi3mr.o
> mpi3mr-y +=  mpi3mr_os.o     \
> 		mpi3mr_fw.o \
> 		mpi3mr_app.o \
> +		mpi3mr_transport.o
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index 542b462..006bc5d 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -39,6 +39,7 @@
> #include <scsi/scsi_host.h>
> #include <scsi/scsi_tcq.h>
> #include <uapi/scsi/scsi_bsg_mpi3mr.h>
> +#include <scsi/scsi_transport_sas.h>
> 
> #include "mpi/mpi30_transport.h"
> #include "mpi/mpi30_cnfg.h"
> @@ -461,6 +462,98 @@ struct mpi3mr_throttle_group_info {
> 	atomic_t pend_large_data_sz;
> };
> 
> +/* HBA port flags */
> +#define MPI3MR_HBA_PORT_FLAG_DIRTY	0x01
> +
> +/**
> + * struct mpi3mr_hba_port - HBA's port information
> + * @port_id: Port number
> + * @flags: HBA port flags
> + */
> +struct mpi3mr_hba_port {
> +	struct list_head list;
> +	u8 port_id;
> +	u8 flags;
> +};
> +
> +/**
> + * struct mpi3mr_sas_port - Internal SAS port information
> + * @port_list: List of ports belonging to a SAS node
> + * @num_phys: Number of phys associated with port
> + * @hba_port: HBA port entry
> + * @remote_identify: Attached device identification
> + * @rphy: SAS transport layer rphy object
> + * @port: SAS transport layer port object
> + * @phy_list: mpi3mr_sas_phy objects belonging to this port
> + */
> +struct mpi3mr_sas_port {
> +	struct list_head port_list;
> +	u8 num_phys;
> +	struct mpi3mr_hba_port *hba_port;
> +	struct sas_identify remote_identify;
> +	struct sas_rphy *rphy;
> +	struct sas_port *port;
> +	struct list_head phy_list;
> +};
> +
> +/**
> + * struct mpi3mr_sas_phy - Internal SAS Phy information
> + * @port_siblings: List of phys belonging to a port
> + * @identify: Phy identification
> + * @remote_identify: Attached device identification
> + * @phy: SAS transport layer Phy object
> + * @phy_id: Unique phy id within a port
> + * @handle: Firmware device handle for this phy
> + * @attached_handle: Firmware device handle for attached device
> + * @phy_belongs_to_port: Flag to indicate phy belongs to port
> +   @hba_port: HBA port entry
> + */
> +struct mpi3mr_sas_phy {
> +	struct list_head port_siblings;
> +	struct sas_identify identify;
> +	struct sas_identify remote_identify;
> +	struct sas_phy *phy;
> +	u8 phy_id;
> +	u16 handle;
> +	u16 attached_handle;
> +	u8 phy_belongs_to_port;
> +	struct mpi3mr_hba_port *hba_port;
> +};
> +
> +/**
> + * struct mpi3mr_sas_node - SAS host/expander information
> + * @list: List of sas nodes in a controller
> + * @parent_dev: Parent device class
> + * @num_phys: Number phys belonging to sas_node
> + * @sas_address: SAS address of sas_node
> + * @handle: Firmware device handle for this sas_host/expander
> + * @sas_address_parent: SAS address of parent expander or host
> + * @enclosure_handle: Firmware handle of enclosure of this node
> + * @device_info: Capabilities of this sas_host/expander
> + * @non_responding: used to refresh the expander devices during reset
> + * @host_node: Flag to indicate this is a host_node
> + * @hba_port: HBA port entry
> + * @phy: A list of phys that make up this sas_host/expander
> + * @sas_port_list: List of internal ports of this node
> + * @rphy: sas_rphy object of this expander node
> + */
> +struct mpi3mr_sas_node {
> +	struct list_head list;
> +	struct device *parent_dev;
> +	u8 num_phys;
> +	u64 sas_address;
> +	u16 handle;
> +	u64 sas_address_parent;
> +	u16 enclosure_handle;
> +	u64 enclosure_logical_id;
> +	u8 non_responding;
> +	u8 host_node;
> +	struct mpi3mr_hba_port *hba_port;
> +	struct mpi3mr_sas_phy *phy;
> +	struct list_head sas_port_list;
> +	struct sas_rphy *rphy;
> +};
> +
> /**
>  * struct mpi3mr_enclosure_node - enclosure information
>  * @list: List of enclosures
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> new file mode 100644
> index 0000000..989bf63
> --- /dev/null
> +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> @@ -0,0 +1,430 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Driver for Broadcom MPI3 Storage Controllers
> + *
> + * Copyright (C) 2017-2022 Broadcom Inc.
> + *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
> + *
> + */
> +
> +#include "mpi3mr.h"
> +
> +/**
> + * mpi3mr_convert_phy_link_rate -
> + * @link_rate: link rate as defined in the MPI header
> + *
> + * Convert link_rate from mpi format into sas_transport layer
> + * form.
> + *
> + * Return: A valid SAS transport layer defined link rate
> + */
> +static enum sas_linkrate mpi3mr_convert_phy_link_rate(u8 link_rate)
> +{
> +	enum sas_linkrate rc;
> +
> +	switch (link_rate) {
> +	case MPI3_SAS_NEG_LINK_RATE_1_5:
> +		rc = SAS_LINK_RATE_1_5_GBPS;
> +		break;
> +	case MPI3_SAS_NEG_LINK_RATE_3_0:
> +		rc = SAS_LINK_RATE_3_0_GBPS;
> +		break;
> +	case MPI3_SAS_NEG_LINK_RATE_6_0:
> +		rc = SAS_LINK_RATE_6_0_GBPS;
> +		break;
> +	case MPI3_SAS_NEG_LINK_RATE_12_0:
> +		rc = SAS_LINK_RATE_12_0_GBPS;
> +		break;
> +	case MPI3_SAS_NEG_LINK_RATE_22_5:
> +		rc = SAS_LINK_RATE_12_0_GBPS;

This should be SAS_LINK_RATE_22_5_GBPS

> +		break;
> +	case MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED:
> +		rc = SAS_PHY_DISABLED;
> +		break;
> +	case MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
> +		rc = SAS_LINK_RATE_FAILED;
> +		break;
> +	case MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR:
> +		rc = SAS_SATA_PORT_SELECTOR;
> +		break;
> +	case MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
> +		rc = SAS_PHY_RESET_IN_PROGRESS;
> +		break;
> +	case MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
> +	case MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
> +	default:
> +		rc = SAS_LINK_RATE_UNKNOWN;
> +		break;
> +	}
> +	return rc;
> +}
> +
> +/**
> + * mpi3mr_delete_sas_phy - Remove a single phy from port
> + * @mrioc: Adapter instance reference
> + * @mr_sas_port: Internal Port object
> + * @mr_sas_phy: Internal Phy object
> + *
> + * Return: None.
> + */
> +static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
> +	struct mpi3mr_sas_port *mr_sas_port,
> +	struct mpi3mr_sas_phy *mr_sas_phy)
> +{
> +	u64 sas_address = mr_sas_port->remote_identify.sas_address;
> +
> +	dev_info(&mr_sas_phy->phy->dev,
> +	    "remove: sas_address(0x%016llx), phy(%d)\n",
> +	    (unsigned long long) sas_address, mr_sas_phy->phy_id);
> +
> +	list_del(&mr_sas_phy->port_siblings);
> +	mr_sas_port->num_phys--;
> +	sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);
> +	mr_sas_phy->phy_belongs_to_port = 0;
> +}
> +
> +/**
> + * mpi3mr_add_sas_phy - Adding a single phy to a port
> + * @mrioc: Adapter instance reference
> + * @mr_sas_port: Internal Port object
> + * @mr_sas_phy: Internal Phy object
> + *
> + * Return: None.
> + */
> +static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
> +	struct mpi3mr_sas_port *mr_sas_port,
> +	struct mpi3mr_sas_phy *mr_sas_phy)
> +{
> +	u64 sas_address = mr_sas_port->remote_identify.sas_address;
> +
> +	dev_info(&mr_sas_phy->phy->dev,
> +	    "add: sas_address(0x%016llx), phy(%d)\n", (unsigned long long)
> +	    sas_address, mr_sas_phy->phy_id);
> +
> +	list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);
> +	mr_sas_port->num_phys++;
> +	sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);
> +	mr_sas_phy->phy_belongs_to_port = 1;
> +}
> +
> +/**
> + * mpi3mr_add_phy_to_an_existing_port - add phy to existing port
> + * @mrioc: Adapter instance reference
> + * @mr_sas_node: Internal sas node object (expander or host)
> + * @mr_sas_phy: Internal Phy object *
> + * @sas_address: SAS address of device/expander were phy needs
> + *             to be added to
> + * @hba_port: HBA port entry
> + *
> + * Return: None.
> + */
> +static void mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc *mrioc,
> +	struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy,
> +	u64 sas_address, struct mpi3mr_hba_port *hba_port)
> +{
> +	struct mpi3mr_sas_port *mr_sas_port;
> +	struct mpi3mr_sas_phy *srch_phy;
> +
> +	if (mr_sas_phy->phy_belongs_to_port == 1)
> +		return;
> +
> +	if (!hba_port)
> +		return;
> +
> +	list_for_each_entry(mr_sas_port, &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;
> +		list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
> +		    port_siblings) {
> +			if (srch_phy == mr_sas_phy)
> +				return;
> +		}
> +		mpi3mr_add_sas_phy(mrioc, mr_sas_port, mr_sas_phy);
> +		return;
> +	}
> +}
> +
> +/**
> + * mpi3mr_del_phy_from_an_existing_port - del phy from a port
> + * @mrioc: Adapter instance reference
> + * @mr_sas_node: Internal sas node object (expander or host)
> + * @mr_sas_phy: Internal Phy object
> + *
> + * Return: None.
> + */
> +static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,
> +	struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy)
> +{
> +	struct mpi3mr_sas_port *mr_sas_port, *next;
> +	struct mpi3mr_sas_phy *srch_phy;
> +
> +	if (mr_sas_phy->phy_belongs_to_port == 0)
> +		return;
> +
> +	list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
> +	    port_list) {
> +		list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
> +		    port_siblings) {
> +			if (srch_phy != mr_sas_phy)
> +				continue;
> +			mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
> +			    mr_sas_phy);
> +			return;
> +		}
> +	}
> +}
> +
> +/**
> + * mpi3mr_sas_port_sanity_check - sanity check while adding port
> + * @mrioc: Adapter instance reference
> + * @mr_sas_node: Internal sas node object (expander or host)
> + * @sas_address: SAS address of device/expander
> + * @hba_port: HBA port entry
> + *
> + * Verifies whether the Phys attached to a device with the given
> + * SAS address already belongs to an existing sas port if so
> + * will remove those phys from the sas port
> + *
> + * Return: None.
> + */
> +static void mpi3mr_sas_port_sanity_check(struct mpi3mr_ioc *mrioc,
> +	struct mpi3mr_sas_node *mr_sas_node, u64 sas_address,
> +	struct mpi3mr_hba_port *hba_port)
> +{
> +	int i;
> +
> +	for (i = 0; i < mr_sas_node->num_phys; i++) {
> +		if ((mr_sas_node->phy[i].remote_identify.sas_address !=
> +		    sas_address) || (mr_sas_node->phy[i].hba_port != hba_port))
> +			continue;
> +		if (mr_sas_node->phy[i].phy_belongs_to_port == 1)
> +			mpi3mr_del_phy_from_an_existing_port(mrioc,
> +			    mr_sas_node, &mr_sas_node->phy[i]);
> +	}
> +}
> +
> +/**
> + * mpi3mr_set_identify - set identify for phys and end devices
> + * @mrioc: Adapter instance reference
> + * @handle: Firmware device handle
> + * @identify: SAS transport layer's identify info
> + *
> + * Populates sas identify info for a specific device.
> + *
> + * Return: 0 for success, non-zero for failure.
> + */
> +static int mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle,
> +	struct sas_identify *identify)
> +{
> +
> +	struct mpi3_device_page0 device_pg0;
> +	struct mpi3_device0_sas_sata_format *sasinf;
> +	u16 device_info;
> +	u16 ioc_status;
> +
> +	if (mrioc->reset_in_progress) {
> +		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
> +		return -EFAULT;
> +	}
> +
> +	if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,
> +	    sizeof(device_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 -EIO;
> +	}
> +
> +	memset(identify, 0, sizeof(struct sas_identify));
> +	sasinf = &device_pg0.device_specific.sas_sata_format;
> +	device_info = le16_to_cpu(sasinf->device_info);
> +
> +	/* sas_address */
> +	identify->sas_address = le64_to_cpu(sasinf->sas_address);
> +
> +	/* phy number of the parent device this device is linked to */
> +	identify->phy_identifier = sasinf->phy_num;
> +
> +	/* device_type */
> +	switch (device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) {
> +	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE:
> +		identify->device_type = SAS_PHY_UNUSED;
> +		break;
> +	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE:
> +		identify->device_type = SAS_END_DEVICE;
> +		break;
> +	case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER:
> +		identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
> +		break;
> +	}
> +
> +	/* initiator_port_protocols */
> +	if (device_info & MPI3_SAS_DEVICE_INFO_SSP_INITIATOR)
> +		identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
> +	/* MPI3.0 doesn't have define for SATA INIT so setting both here*/
> +	if (device_info & MPI3_SAS_DEVICE_INFO_STP_INITIATOR)
> +		identify->initiator_port_protocols |= (SAS_PROTOCOL_STP |
> +		    SAS_PROTOCOL_SATA);
> +	if (device_info & MPI3_SAS_DEVICE_INFO_SMP_INITIATOR)
> +		identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
> +
> +	/* target_port_protocols */
> +	if (device_info & MPI3_SAS_DEVICE_INFO_SSP_TARGET)
> +		identify->target_port_protocols |= SAS_PROTOCOL_SSP;
> +	/* MPI3.0 doesn't have define for STP Target so setting both here*/
> +	if (device_info & MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET)
> +		identify->target_port_protocols |= (SAS_PROTOCOL_STP |
> +		    SAS_PROTOCOL_SATA);
> +	if (device_info & MPI3_SAS_DEVICE_INFO_SMP_TARGET)
> +		identify->target_port_protocols |= SAS_PROTOCOL_SMP;
> +	return 0;
> +}
> +
> +/**
> + * mpi3mr_add_host_phy - report sas_host phy to SAS transport
> + * @mrioc: Adapter instance reference
> + * @mr_sas_phy: Internal Phy object
> + * @phy_pg0: SAS phy page 0
> + * @parent_dev: Prent device class object
> + *
> + * Return: 0 for success, non-zero for failure.
> + */
> +static int mpi3mr_add_host_phy(struct mpi3mr_ioc *mrioc,
> +	struct mpi3mr_sas_phy *mr_sas_phy, struct mpi3_sas_phy_page0 phy_pg0,
> +	struct device *parent_dev)
> +{
> +	struct sas_phy *phy;
> +	int phy_index = mr_sas_phy->phy_id;
> +
> +
> +	INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
> +	phy = sas_phy_alloc(parent_dev, phy_index);
> +	if (!phy) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		return -1;
> +	}
> +	if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
> +	    &mr_sas_phy->identify))) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		sas_phy_free(phy);
> +		return -1;
> +	}
> +	phy->identify = mr_sas_phy->identify;
> +	mr_sas_phy->attached_handle = le16_to_cpu(phy_pg0.attached_dev_handle);
> +	if (mr_sas_phy->attached_handle)
> +		mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
> +		    &mr_sas_phy->remote_identify);
> +	phy->identify.phy_identifier = mr_sas_phy->phy_id;
> +	phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
> +	    (phy_pg0.negotiated_link_rate &
> +	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
> +	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
> +	phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
> +	    phy_pg0.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
> +	phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
> +	    phy_pg0.hw_link_rate >> 4);
> +	phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
> +	    phy_pg0.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
> +	phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
> +	    phy_pg0.programmed_link_rate >> 4);
> +	phy->hostdata = mr_sas_phy->hba_port;
> +
> +	if ((sas_phy_add(phy))) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		sas_phy_free(phy);
> +		return -1;
> +	}
> +	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
> +		dev_info(&phy->dev,
> +		    "add: handle(0x%04x), sas_address(0x%016llx)\n"
> +		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
> +		    mr_sas_phy->handle, (unsigned long long)
> +		    mr_sas_phy->identify.sas_address,
> +		    mr_sas_phy->attached_handle,
> +		    (unsigned long long)
> +		    mr_sas_phy->remote_identify.sas_address);
> +	mr_sas_phy->phy = phy;
> +	return 0;
> +}
> +
> +/**
> + * mpi3mr_add_expander_phy - report expander phy to transport
> + * @mrioc: Adapter instance reference
> + * @mr_sas_phy: Internal Phy object
> + * @expander_pg1: SAS Expander page 1
> + * @parent_dev: Parent device class object
> + *
> + * Return: 0 for success, non-zero for failure.
> + */
> +static int mpi3mr_add_expander_phy(struct mpi3mr_ioc *mrioc,
> +	struct mpi3mr_sas_phy *mr_sas_phy,
> +	struct mpi3_sas_expander_page1 expander_pg1,
> +	struct device *parent_dev)
> +{
> +	struct sas_phy *phy;
> +	int phy_index = mr_sas_phy->phy_id;
> +
> +	INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
> +	phy = sas_phy_alloc(parent_dev, phy_index);
> +	if (!phy) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		return -1;
> +	}
> +	if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
> +	    &mr_sas_phy->identify))) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		sas_phy_free(phy);
> +		return -1;
> +	}
> +	phy->identify = mr_sas_phy->identify;
> +	mr_sas_phy->attached_handle =
> +	    le16_to_cpu(expander_pg1.attached_dev_handle);
> +	if (mr_sas_phy->attached_handle)
> +		mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
> +		    &mr_sas_phy->remote_identify);
> +	phy->identify.phy_identifier = mr_sas_phy->phy_id;
> +	phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
> +	    (expander_pg1.negotiated_link_rate &
> +	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
> +	    MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
> +	phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
> +	    expander_pg1.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
> +	phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
> +	    expander_pg1.hw_link_rate >> 4);
> +	phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
> +	    expander_pg1.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
> +	phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
> +	    expander_pg1.programmed_link_rate >> 4);
> +	phy->hostdata = mr_sas_phy->hba_port;
> +
> +	if ((sas_phy_add(phy))) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		sas_phy_free(phy);
> +		return -1;
> +	}
> +	if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
> +		dev_info(&phy->dev,
> +		    "add: handle(0x%04x), sas_address(0x%016llx)\n"
> +		    "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
> +		    mr_sas_phy->handle, (unsigned long long)
> +		    mr_sas_phy->identify.sas_address,
> +		    mr_sas_phy->attached_handle,
> +		    (unsigned long long)
> +		    mr_sas_phy->remote_identify.sas_address);
> +	mr_sas_phy->phy = phy;
> +	return 0;
> +}
> -- 
> 2.27.0
> 

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 06/15] mpi3mr: Add helper functions to retrieve device objects
  2022-07-29 13:16 ` [PATCH 06/15] mpi3mr: Add helper functions to retrieve device objects Sreekanth Reddy
@ 2022-07-29 20:11   ` Himanshu Madhani
  2022-08-01  7:48     ` Sreekanth Reddy
  0 siblings, 1 reply; 35+ messages in thread
From: Himanshu Madhani @ 2022-07-29 20:11 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 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 | 280 +++++++++++++++++++++++++
> 3 files changed, 297 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 989bf63..fea3aae 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> @@ -9,6 +9,237 @@
> 
> #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)
> +{
> +
Remove new line here
> +	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)
> +{
> +
remove new line 
> +	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 +659,52 @@ 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)
> +{
> +
Ditto remove newline
> +	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
> 

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 02/15] mpi3mr: Add framework to issue cnfg requests
  2022-07-29 17:00   ` Himanshu Madhani
@ 2022-08-01  7:40     ` Sreekanth Reddy
  2022-08-01 16:37       ` Himanshu Madhani
  0 siblings, 1 reply; 35+ messages in thread
From: Sreekanth Reddy @ 2022-08-01  7:40 UTC (permalink / raw)
  To: Himanshu Madhani; +Cc: linux-scsi, Martin Petersen

[-- Attachment #1: Type: text/plain, Size: 18210 bytes --]

On Fri, Jul 29, 2022 at 10:30 PM Himanshu Madhani
<himanshu.madhani@oracle.com> wrote:
>
>
>
> > On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> >
> > Added framework to issue config requests commands to
> > controller firmware.
> >
> > Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> > ---
> > drivers/scsi/mpi3mr/mpi3mr.h    |  28 ++++
> > drivers/scsi/mpi3mr/mpi3mr_fw.c | 256 ++++++++++++++++++++++++++++++++
> > drivers/scsi/mpi3mr/mpi3mr_os.c |   1 +
> > 3 files changed, 285 insertions(+)
> >
> > diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> > index 0935b2e..e15ad0e 100644
> > --- a/drivers/scsi/mpi3mr/mpi3mr.h
> > +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> > @@ -97,6 +97,7 @@ extern atomic64_t event_counter;
> > #define MPI3MR_HOSTTAG_PEL_ABORT      3
> > #define MPI3MR_HOSTTAG_PEL_WAIT               4
> > #define MPI3MR_HOSTTAG_BLK_TMS                5
> > +#define MPI3MR_HOSTTAG_CFG_CMDS              6
> >
> > #define MPI3MR_NUM_DEVRMCMD           16
> > #define MPI3MR_HOSTTAG_DEVRMCMD_MIN   (MPI3MR_HOSTTAG_BLK_TMS + 1)
> > @@ -126,6 +127,8 @@ extern atomic64_t event_counter;
> >
> > #define MPI3MR_WATCHDOG_INTERVAL              1000 /* in milli seconds */
> >
> > +#define MPI3MR_DEFAULT_CFG_PAGE_SZ           1024 /* in bytes */
> > +
> > #define MPI3MR_SCMD_TIMEOUT    (60 * HZ)
> > #define MPI3MR_EH_SCMD_TIMEOUT (60 * HZ)
> >
> > @@ -274,6 +277,7 @@ enum mpi3mr_reset_reason {
> >       MPI3MR_RESET_FROM_SYSFS = 23,
> >       MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24,
> >       MPI3MR_RESET_FROM_FIRMWARE = 27,
> > +     MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT = 29,
> > };
> >
> > /* Queue type definitions */
> > @@ -679,6 +683,21 @@ struct mpi3mr_drv_cmd {
> >           struct mpi3mr_drv_cmd *drv_cmd);
> > };
> >
> > +/**
> > + * struct dma_memory_desc - memory descriptor structure to store
> > + * virtual address, dma address and size for any generic dma
> > + * memory allocations in the driver.
> > + *
> > + * @size: buffer size
> > + * @addr: virtual address
> > + * @dma_addr: dma address
> > + */
> > +struct dma_memory_desc {
> > +     u32 size;
> > +     void *addr;
> > +     dma_addr_t dma_addr;
> > +};
> > +
> >
> > /**
> >  * struct chain_element - memory descriptor structure to store
> > @@ -756,6 +775,7 @@ struct scmd_priv {
> >  * @num_op_reply_q: Number of operational reply queues
> >  * @op_reply_qinfo: Operational reply queue info pointer
> >  * @init_cmds: Command tracker for initialization commands
> > + * @cfg_cmds: Command tracker for configuration requests
> >  * @facts: Cached IOC facts data
> >  * @op_reply_desc_sz: Operational reply descriptor size
> >  * @num_reply_bufs: Number of reply buffers allocated
> > @@ -854,6 +874,9 @@ struct scmd_priv {
> >  * @io_throttle_low: I/O size to stop throttle in 512b blocks
> >  * @num_io_throttle_group: Maximum number of throttle groups
> >  * @throttle_groups: Pointer to throttle group info structures
> > + * @cfg_page: Default memory for configuration pages
> > + * @cfg_page_dma: Configuration page DMA address
> > + * @cfg_page_sz: Default configuration page memory size
> >  */
> > struct mpi3mr_ioc {
> >       struct list_head list;
> > @@ -904,6 +927,7 @@ struct mpi3mr_ioc {
> >       struct op_reply_qinfo *op_reply_qinfo;
> >
> >       struct mpi3mr_drv_cmd init_cmds;
> > +     struct mpi3mr_drv_cmd cfg_cmds;
> >       struct mpi3mr_ioc_facts facts;
> >       u16 op_reply_desc_sz;
> >
> > @@ -1025,6 +1049,10 @@ struct mpi3mr_ioc {
> >       u32 io_throttle_low;
> >       u16 num_io_throttle_group;
> >       struct mpi3mr_throttle_group_info *throttle_groups;
> > +
> > +     void *cfg_page;
> > +     dma_addr_t cfg_page_dma;
> > +     u16 cfg_page_sz;
> > };
> >
> > /**
> > diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> > index 0866dfd..da6eceb 100644
> > --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> > +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> > @@ -299,6 +299,8 @@ mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
> >       switch (host_tag) {
> >       case MPI3MR_HOSTTAG_INITCMDS:
> >               return &mrioc->init_cmds;
> > +     case MPI3MR_HOSTTAG_CFG_CMDS:
> > +             return &mrioc->cfg_cmds;
> >       case MPI3MR_HOSTTAG_BSG_CMDS:
> >               return &mrioc->bsg_cmds;
> >       case MPI3MR_HOSTTAG_BLK_TMS:
> > @@ -907,6 +909,7 @@ static const struct {
> >       { MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
> >       { MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
> >       { MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronous reset" },
> > +     { MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout"},
> > };
> >
> > /**
> > @@ -3738,6 +3741,14 @@ retry_init:
> >
> >       mpi3mr_print_ioc_info(mrioc);
> >
> > +     dprint_init(mrioc, "allocating config page buffers\n");
> > +     mrioc->cfg_page = dma_alloc_coherent(&mrioc->pdev->dev,
> > +         MPI3MR_DEFAULT_CFG_PAGE_SZ, &mrioc->cfg_page_dma, GFP_KERNEL);
> > +     if (!mrioc->cfg_page)
> > +             goto out_failed_noretry;
> > +
> > +     mrioc->cfg_page_sz = MPI3MR_DEFAULT_CFG_PAGE_SZ;
> > +
> >       retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
> >       if (retval) {
> >               ioc_err(mrioc,
> > @@ -4362,6 +4373,10 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
> >
> >       cmdptr = &mrioc->init_cmds;
> >       mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
> > +
> > +     cmdptr = &mrioc->cfg_cmds;
> > +     mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
> > +
> >       cmdptr = &mrioc->bsg_cmds;
> >       mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
> >       cmdptr = &mrioc->host_tm_cmds;
> > @@ -4786,3 +4801,244 @@ out:
> >           ((retval == 0) ? "successful" : "failed"));
> >       return retval;
> > }
> > +
> > +
> > +/**
> > + * mpi3mr_free_config_dma_memory - free memory for config page
> > + * @mrioc: Adapter instance reference
> > + * @mem_desc: memory descriptor structure
> > + *
> > + * Check whether the size of the buffer specified by the memory
> > + * descriptor is greater than the default page size if so then
> > + * free the memory pointed by the descriptor.
> > + *
> > + * Return: 0 on success, non-zero on failure.
>
> Nit: the above comment is incorrect. This function returns nothing.

Agree. Will update in the next patch version set.

>
> > + */
> > +static void mpi3mr_free_config_dma_memory(struct mpi3mr_ioc *mrioc,
> > +     struct dma_memory_desc *mem_desc)
> > +{
> > +     if ((mem_desc->size > mrioc->cfg_page_sz) && mem_desc->addr) {
> > +             dma_free_coherent(&mrioc->pdev->dev, mem_desc->size,
> > +                 mem_desc->addr, mem_desc->dma_addr);
> > +             mem_desc->addr = NULL;
> > +     }
> > +}
> > +
> > +
> > +
>
> Remove extra newline

Agree. Will remove it next patch version set.
>
> > +/**
> > + * mpi3mr_alloc_config_dma_memory - Alloc memory for config page
> > + * @mrioc: Adapter instance reference
> > + * @mem_desc: Memory descriptor to hold dma memory info
> > + *
> > + * This function allocates new dmaable memory or provides the
> > + * default config page dmaable memory based on the memory size
> > + * described by the descriptor.
> > + *
> > + * Return: 0 on success, non-zero on failure.
> > + */
> > +static int mpi3mr_alloc_config_dma_memory(struct mpi3mr_ioc *mrioc,
> > +     struct dma_memory_desc *mem_desc)
> > +{
> > +     if (mem_desc->size > mrioc->cfg_page_sz) {
> > +             mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev,
> > +                 mem_desc->size, &mem_desc->dma_addr, GFP_KERNEL);
> > +             if (!mem_desc->addr)
> > +                     return -ENOMEM;
> > +     } else {
> > +             mem_desc->addr = mrioc->cfg_page;
> > +             mem_desc->dma_addr = mrioc->cfg_page_dma;
> > +             memset(mem_desc->addr, 0, mrioc->cfg_page_sz);
> > +     }
> > +     return 0;
> > +}
> > +
> > +
> > +/**
> > + * mpi3mr_post_cfg_req - Issue config requests and wait
> > + * @mrioc: Adapter instance reference
> > + * @cfg_req: Configuration request
> > + * @timeout: Timeout in seconds
> > + * @ioc_status: Pointer to return ioc status
> > + *
> > + * A generic function for posting MPI3 configuration request to
> > + * the firmware. This blocks for the completion of request for
> > + * timeout seconds and if the request times out this function
> > + * faults the controller with proper reason code.
> > + *
> > + * On successful completion of the request this function returns
> > + * appropriate ioc status from the firmware back to the caller.
> > + *
> > + * Return: 0 on success, non-zero on failure.
> > + */
> > +static int mpi3mr_post_cfg_req(struct mpi3mr_ioc *mrioc,
> > +     struct mpi3_config_request *cfg_req, int timeout, u16 *ioc_status)
> > +{
> > +     int retval = 0;
> > +
> > +     mutex_lock(&mrioc->cfg_cmds.mutex);
> > +     if (mrioc->cfg_cmds.state & MPI3MR_CMD_PENDING) {
> > +             retval = -1;
> > +             ioc_err(mrioc, "sending config request failed due to command in use\n");
> > +             mutex_unlock(&mrioc->cfg_cmds.mutex);
> > +             goto out;
> > +     }
> > +     mrioc->cfg_cmds.state = MPI3MR_CMD_PENDING;
> > +     mrioc->cfg_cmds.is_waiting = 1;
>
> You are setting is_waiting here, but I don’t see this being cleared anywhere.

It is getting cleared in mpi3mr_process_admin_reply_desc() with below lines,

                        if (cmdptr->is_waiting) {
                                complete(&cmdptr->done);
                                cmdptr->is_waiting = 0;
                        } else if (cmdptr->callback)
                                cmdptr->callback(mrioc, cmdptr);

>
> > +     mrioc->cfg_cmds.callback = NULL;
> > +     mrioc->cfg_cmds.ioc_status = 0;
> > +     mrioc->cfg_cmds.ioc_loginfo = 0;
> > +
> > +     cfg_req->host_tag = cpu_to_le16(MPI3MR_HOSTTAG_CFG_CMDS);
> > +     cfg_req->function = MPI3_FUNCTION_CONFIG;
> > +
> > +     init_completion(&mrioc->cfg_cmds.done);
> > +     dprint_cfg_info(mrioc, "posting config request\n");
> > +     if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
> > +             dprint_dump(cfg_req, sizeof(struct mpi3_config_request),
> > +                 "mpi3_cfg_req");
> > +     retval = mpi3mr_admin_request_post(mrioc, cfg_req, sizeof(*cfg_req), 1);
> > +     if (retval) {
> > +             ioc_err(mrioc, "posting config request failed\n");
> > +             goto out_unlock;
> > +     }
> > +     wait_for_completion_timeout(&mrioc->cfg_cmds.done, (timeout * HZ));
> > +     if (!(mrioc->cfg_cmds.state & MPI3MR_CMD_COMPLETE)) {
> > +             mpi3mr_check_rh_fault_ioc(mrioc,
> > +                 MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT);
> > +             ioc_err(mrioc, "config request timed out\n");
> > +             retval = -1;
> > +             goto out_unlock;
> > +     }
> > +     *ioc_status = mrioc->cfg_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK;
> > +     if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS)
> > +             dprint_cfg_err(mrioc,
> > +                 "cfg_page request returned with ioc_status(0x%04x), log_info(0x%08x)\n",
> > +                 *ioc_status, mrioc->cfg_cmds.ioc_loginfo);
> > +
> > +out_unlock:
> > +     mrioc->cfg_cmds.state = MPI3MR_CMD_NOTUSED;
>
> Should you not set mrioc->cfg_cmds.is_waiting = 0 here? Or am I missing something?

cfg_cmds's is_waiting is cleared in mpi3mr_process_admin_reply_desc().

>
> > +     mutex_unlock(&mrioc->cfg_cmds.mutex);
> > +
> > +out:
> > +     return retval;
> > +}
> > +
> > +/**
> > + * mpi3mr_process_cfg_req - config page request processor
> > + * @mrioc: Adapter instance reference
> > + * @cfg_req: Configuration request
> > + * @cfg_hdr: Configuration page header
> > + * @timeout: Timeout in seconds
> > + * @ioc_status: Pointer to return ioc status
> > + * @cfg_buf: Memory pointer to copy config page or header
> > + * @cfg_buf_sz: Size of the memory to get config page or header
> > + *
> > + * This is handler for config page read, write and config page
> > + * header read operations.
> > + *
> > + * This function expects the cfg_req to be populated with page
> > + * type, page number, action for the header read and with page
> > + * address for all other operations.
> > + *
> > + * The cfg_hdr can be passed as null for reading required header
> > + * details for read/write pages the cfg_hdr should point valid
> > + * configuration page header.
> > + *
> > + * This allocates dmaable memory based on the size of the config
> > + * buffer and set the SGE of the cfg_req.
> > + *
> > + * For write actions, the config page data has to be passed in
> > + * the cfg_buf and size of the data has to be mentioned in the
> > + * cfg_buf_sz.
> > + *
> > + * For read/header actions, on successful completion of the
> > + * request with successful ioc_status the data will be copied
> > + * into the cfg_buf limited to a minimum of actual page size and
> > + * cfg_buf_sz
> > + *
> > + *
> > + * Return: 0 on success, non-zero on failure.
> > + */
> > +static int mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc,
> > +     struct mpi3_config_request *cfg_req,
> > +     struct mpi3_config_page_header *cfg_hdr, int timeout, u16 *ioc_status,
> > +     void *cfg_buf, u32 cfg_buf_sz)
> > +{
> > +     struct dma_memory_desc mem_desc;
> > +     int retval = -1;
> > +     u8 invalid_action = 0;
> > +     u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
> > +
> > +     memset(&mem_desc, 0, sizeof(struct dma_memory_desc));
> > +
> > +     if (cfg_req->action == MPI3_CONFIG_ACTION_PAGE_HEADER)
> > +             mem_desc.size = sizeof(struct mpi3_config_page_header);
> > +     else {
> > +             if (!cfg_hdr) {
> > +                     ioc_err(mrioc, "null config header passed for config action(%d), page_type(0x%02x), page_num(%d)\n",
> > +                         cfg_req->action, cfg_req->page_type,
> > +                         cfg_req->page_number);
> > +                     goto out;
> > +             }
> > +             switch (cfg_hdr->page_attribute & MPI3_CONFIG_PAGEATTR_MASK) {
> > +             case MPI3_CONFIG_PAGEATTR_READ_ONLY:
> > +                     if (cfg_req->action
> > +                         != MPI3_CONFIG_ACTION_READ_CURRENT)
> > +                             invalid_action = 1;
> > +                     break;
> > +             case MPI3_CONFIG_PAGEATTR_CHANGEABLE:
> > +                     if ((cfg_req->action ==
> > +                          MPI3_CONFIG_ACTION_READ_PERSISTENT) ||
> > +                         (cfg_req->action ==
> > +                          MPI3_CONFIG_ACTION_WRITE_PERSISTENT))
> > +                             invalid_action = 1;
> > +                     break;
> > +             case MPI3_CONFIG_PAGEATTR_PERSISTENT:
> > +             default:
> > +                     break;
> > +             }
> > +             if (invalid_action) {
> > +                     ioc_err(mrioc,
> > +                         "config action(%d) is not allowed for page_type(0x%02x), page_num(%d) with page_attribute(0x%02x)\n",
> > +                         cfg_req->action, cfg_req->page_type,
> > +                         cfg_req->page_number, cfg_hdr->page_attribute);
> > +                     goto out;
> > +             }
> > +             mem_desc.size = le16_to_cpu(cfg_hdr->page_length) * 4;
> > +             cfg_req->page_length = cfg_hdr->page_length;
> > +             cfg_req->page_version = cfg_hdr->page_version;
> > +     }
> > +     if (mpi3mr_alloc_config_dma_memory(mrioc, &mem_desc))
> > +             goto out;
> > +
> > +     mpi3mr_add_sg_single(&cfg_req->sgl, sgl_flags, mem_desc.size,
> > +         mem_desc.dma_addr);
> > +
> > +     if ((cfg_req->action == MPI3_CONFIG_ACTION_WRITE_PERSISTENT) ||
> > +         (cfg_req->action == MPI3_CONFIG_ACTION_WRITE_CURRENT)) {
> > +             memcpy(mem_desc.addr, cfg_buf, min_t(u16, mem_desc.size,
> > +                 cfg_buf_sz));
> > +             dprint_cfg_info(mrioc, "config buffer to be written\n");
> > +             if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
> > +                     dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf");
> > +     }
> > +
> > +     if (mpi3mr_post_cfg_req(mrioc, cfg_req, timeout, ioc_status))
> > +             goto out;
> > +
> > +     retval = 0;
> > +     if ((*ioc_status == MPI3_IOCSTATUS_SUCCESS) &&
> > +         (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_PERSISTENT) &&
> > +         (cfg_req->action != MPI3_CONFIG_ACTION_WRITE_CURRENT)) {
> > +             memcpy(cfg_buf, mem_desc.addr, min_t(u16, mem_desc.size,
> > +                 cfg_buf_sz));
> > +             dprint_cfg_info(mrioc, "config buffer read\n");
> > +             if (mrioc->logging_level & MPI3_DEBUG_CFG_INFO)
> > +                     dprint_dump(mem_desc.addr, mem_desc.size, "cfg_buf");
> > +     }
> > +
> > +out:
> > +     mpi3mr_free_config_dma_memory(mrioc, &mem_desc);
> > +     return retval;
> > +}
> > diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> > index 8bdf927..40bed22 100644
> > --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> > +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> > @@ -4574,6 +4574,7 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> >       mpi3mr_init_drv_cmd(&mrioc->init_cmds, MPI3MR_HOSTTAG_INITCMDS);
> >       mpi3mr_init_drv_cmd(&mrioc->host_tm_cmds, MPI3MR_HOSTTAG_BLK_TMS);
> >       mpi3mr_init_drv_cmd(&mrioc->bsg_cmds, MPI3MR_HOSTTAG_BSG_CMDS);
> > +     mpi3mr_init_drv_cmd(&mrioc->cfg_cmds, MPI3MR_HOSTTAG_CFG_CMDS);
> >
> >       for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
> >               mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i],
> > --
> > 2.27.0
> >
>
> --
> Himanshu Madhani        Oracle Linux Engineering
>

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 05/15] mpi3mr: Add framework to add phys to STL
  2022-07-29 19:42   ` Himanshu Madhani
@ 2022-08-01  7:46     ` Sreekanth Reddy
  0 siblings, 0 replies; 35+ messages in thread
From: Sreekanth Reddy @ 2022-08-01  7:46 UTC (permalink / raw)
  To: Himanshu Madhani; +Cc: linux-scsi, Martin Petersen

[-- Attachment #1: Type: text/plain, Size: 22935 bytes --]

On Sat, Jul 30, 2022 at 1:12 AM Himanshu Madhani
<himanshu.madhani@oracle.com> wrote:
>
>
>
> > On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> >
> > Added framework to register and unregister the
> > host and expander phys with SCSI Transport Layer (STL).
> >
> > Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> > ---
> > drivers/scsi/mpi3mr/Makefile           |   1 +
> > drivers/scsi/mpi3mr/mpi3mr.h           |  93 ++++++
> > drivers/scsi/mpi3mr/mpi3mr_transport.c | 430 +++++++++++++++++++++++++
> > 3 files changed, 524 insertions(+)
> > create mode 100644 drivers/scsi/mpi3mr/mpi3mr_transport.c
> >
> > diff --git a/drivers/scsi/mpi3mr/Makefile b/drivers/scsi/mpi3mr/Makefile
> > index f5cdbe4..ef86ca4 100644
> > --- a/drivers/scsi/mpi3mr/Makefile
> > +++ b/drivers/scsi/mpi3mr/Makefile
> > @@ -3,3 +3,4 @@ obj-m += mpi3mr.o
> > mpi3mr-y +=  mpi3mr_os.o     \
> >               mpi3mr_fw.o \
> >               mpi3mr_app.o \
> > +             mpi3mr_transport.o
> > diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> > index 542b462..006bc5d 100644
> > --- a/drivers/scsi/mpi3mr/mpi3mr.h
> > +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> > @@ -39,6 +39,7 @@
> > #include <scsi/scsi_host.h>
> > #include <scsi/scsi_tcq.h>
> > #include <uapi/scsi/scsi_bsg_mpi3mr.h>
> > +#include <scsi/scsi_transport_sas.h>
> >
> > #include "mpi/mpi30_transport.h"
> > #include "mpi/mpi30_cnfg.h"
> > @@ -461,6 +462,98 @@ struct mpi3mr_throttle_group_info {
> >       atomic_t pend_large_data_sz;
> > };
> >
> > +/* HBA port flags */
> > +#define MPI3MR_HBA_PORT_FLAG_DIRTY   0x01
> > +
> > +/**
> > + * struct mpi3mr_hba_port - HBA's port information
> > + * @port_id: Port number
> > + * @flags: HBA port flags
> > + */
> > +struct mpi3mr_hba_port {
> > +     struct list_head list;
> > +     u8 port_id;
> > +     u8 flags;
> > +};
> > +
> > +/**
> > + * struct mpi3mr_sas_port - Internal SAS port information
> > + * @port_list: List of ports belonging to a SAS node
> > + * @num_phys: Number of phys associated with port
> > + * @hba_port: HBA port entry
> > + * @remote_identify: Attached device identification
> > + * @rphy: SAS transport layer rphy object
> > + * @port: SAS transport layer port object
> > + * @phy_list: mpi3mr_sas_phy objects belonging to this port
> > + */
> > +struct mpi3mr_sas_port {
> > +     struct list_head port_list;
> > +     u8 num_phys;
> > +     struct mpi3mr_hba_port *hba_port;
> > +     struct sas_identify remote_identify;
> > +     struct sas_rphy *rphy;
> > +     struct sas_port *port;
> > +     struct list_head phy_list;
> > +};
> > +
> > +/**
> > + * struct mpi3mr_sas_phy - Internal SAS Phy information
> > + * @port_siblings: List of phys belonging to a port
> > + * @identify: Phy identification
> > + * @remote_identify: Attached device identification
> > + * @phy: SAS transport layer Phy object
> > + * @phy_id: Unique phy id within a port
> > + * @handle: Firmware device handle for this phy
> > + * @attached_handle: Firmware device handle for attached device
> > + * @phy_belongs_to_port: Flag to indicate phy belongs to port
> > +   @hba_port: HBA port entry
> > + */
> > +struct mpi3mr_sas_phy {
> > +     struct list_head port_siblings;
> > +     struct sas_identify identify;
> > +     struct sas_identify remote_identify;
> > +     struct sas_phy *phy;
> > +     u8 phy_id;
> > +     u16 handle;
> > +     u16 attached_handle;
> > +     u8 phy_belongs_to_port;
> > +     struct mpi3mr_hba_port *hba_port;
> > +};
> > +
> > +/**
> > + * struct mpi3mr_sas_node - SAS host/expander information
> > + * @list: List of sas nodes in a controller
> > + * @parent_dev: Parent device class
> > + * @num_phys: Number phys belonging to sas_node
> > + * @sas_address: SAS address of sas_node
> > + * @handle: Firmware device handle for this sas_host/expander
> > + * @sas_address_parent: SAS address of parent expander or host
> > + * @enclosure_handle: Firmware handle of enclosure of this node
> > + * @device_info: Capabilities of this sas_host/expander
> > + * @non_responding: used to refresh the expander devices during reset
> > + * @host_node: Flag to indicate this is a host_node
> > + * @hba_port: HBA port entry
> > + * @phy: A list of phys that make up this sas_host/expander
> > + * @sas_port_list: List of internal ports of this node
> > + * @rphy: sas_rphy object of this expander node
> > + */
> > +struct mpi3mr_sas_node {
> > +     struct list_head list;
> > +     struct device *parent_dev;
> > +     u8 num_phys;
> > +     u64 sas_address;
> > +     u16 handle;
> > +     u64 sas_address_parent;
> > +     u16 enclosure_handle;
> > +     u64 enclosure_logical_id;
> > +     u8 non_responding;
> > +     u8 host_node;
> > +     struct mpi3mr_hba_port *hba_port;
> > +     struct mpi3mr_sas_phy *phy;
> > +     struct list_head sas_port_list;
> > +     struct sas_rphy *rphy;
> > +};
> > +
> > /**
> >  * struct mpi3mr_enclosure_node - enclosure information
> >  * @list: List of enclosures
> > diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> > new file mode 100644
> > index 0000000..989bf63
> > --- /dev/null
> > +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> > @@ -0,0 +1,430 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Driver for Broadcom MPI3 Storage Controllers
> > + *
> > + * Copyright (C) 2017-2022 Broadcom Inc.
> > + *  (mailto: mpi3mr-linuxdrv.pdl@broadcom.com)
> > + *
> > + */
> > +
> > +#include "mpi3mr.h"
> > +
> > +/**
> > + * mpi3mr_convert_phy_link_rate -
> > + * @link_rate: link rate as defined in the MPI header
> > + *
> > + * Convert link_rate from mpi format into sas_transport layer
> > + * form.
> > + *
> > + * Return: A valid SAS transport layer defined link rate
> > + */
> > +static enum sas_linkrate mpi3mr_convert_phy_link_rate(u8 link_rate)
> > +{
> > +     enum sas_linkrate rc;
> > +
> > +     switch (link_rate) {
> > +     case MPI3_SAS_NEG_LINK_RATE_1_5:
> > +             rc = SAS_LINK_RATE_1_5_GBPS;
> > +             break;
> > +     case MPI3_SAS_NEG_LINK_RATE_3_0:
> > +             rc = SAS_LINK_RATE_3_0_GBPS;
> > +             break;
> > +     case MPI3_SAS_NEG_LINK_RATE_6_0:
> > +             rc = SAS_LINK_RATE_6_0_GBPS;
> > +             break;
> > +     case MPI3_SAS_NEG_LINK_RATE_12_0:
> > +             rc = SAS_LINK_RATE_12_0_GBPS;
> > +             break;
> > +     case MPI3_SAS_NEG_LINK_RATE_22_5:
> > +             rc = SAS_LINK_RATE_12_0_GBPS;
>
> This should be SAS_LINK_RATE_22_5_GBPS

Agree. Will update in next version patch set.

>
> > +             break;
> > +     case MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED:
> > +             rc = SAS_PHY_DISABLED;
> > +             break;
> > +     case MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
> > +             rc = SAS_LINK_RATE_FAILED;
> > +             break;
> > +     case MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR:
> > +             rc = SAS_SATA_PORT_SELECTOR;
> > +             break;
> > +     case MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
> > +             rc = SAS_PHY_RESET_IN_PROGRESS;
> > +             break;
> > +     case MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
> > +     case MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
> > +     default:
> > +             rc = SAS_LINK_RATE_UNKNOWN;
> > +             break;
> > +     }
> > +     return rc;
> > +}
> > +
> > +/**
> > + * mpi3mr_delete_sas_phy - Remove a single phy from port
> > + * @mrioc: Adapter instance reference
> > + * @mr_sas_port: Internal Port object
> > + * @mr_sas_phy: Internal Phy object
> > + *
> > + * Return: None.
> > + */
> > +static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
> > +     struct mpi3mr_sas_port *mr_sas_port,
> > +     struct mpi3mr_sas_phy *mr_sas_phy)
> > +{
> > +     u64 sas_address = mr_sas_port->remote_identify.sas_address;
> > +
> > +     dev_info(&mr_sas_phy->phy->dev,
> > +         "remove: sas_address(0x%016llx), phy(%d)\n",
> > +         (unsigned long long) sas_address, mr_sas_phy->phy_id);
> > +
> > +     list_del(&mr_sas_phy->port_siblings);
> > +     mr_sas_port->num_phys--;
> > +     sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);
> > +     mr_sas_phy->phy_belongs_to_port = 0;
> > +}
> > +
> > +/**
> > + * mpi3mr_add_sas_phy - Adding a single phy to a port
> > + * @mrioc: Adapter instance reference
> > + * @mr_sas_port: Internal Port object
> > + * @mr_sas_phy: Internal Phy object
> > + *
> > + * Return: None.
> > + */
> > +static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
> > +     struct mpi3mr_sas_port *mr_sas_port,
> > +     struct mpi3mr_sas_phy *mr_sas_phy)
> > +{
> > +     u64 sas_address = mr_sas_port->remote_identify.sas_address;
> > +
> > +     dev_info(&mr_sas_phy->phy->dev,
> > +         "add: sas_address(0x%016llx), phy(%d)\n", (unsigned long long)
> > +         sas_address, mr_sas_phy->phy_id);
> > +
> > +     list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);
> > +     mr_sas_port->num_phys++;
> > +     sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);
> > +     mr_sas_phy->phy_belongs_to_port = 1;
> > +}
> > +
> > +/**
> > + * mpi3mr_add_phy_to_an_existing_port - add phy to existing port
> > + * @mrioc: Adapter instance reference
> > + * @mr_sas_node: Internal sas node object (expander or host)
> > + * @mr_sas_phy: Internal Phy object *
> > + * @sas_address: SAS address of device/expander were phy needs
> > + *             to be added to
> > + * @hba_port: HBA port entry
> > + *
> > + * Return: None.
> > + */
> > +static void mpi3mr_add_phy_to_an_existing_port(struct mpi3mr_ioc *mrioc,
> > +     struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy,
> > +     u64 sas_address, struct mpi3mr_hba_port *hba_port)
> > +{
> > +     struct mpi3mr_sas_port *mr_sas_port;
> > +     struct mpi3mr_sas_phy *srch_phy;
> > +
> > +     if (mr_sas_phy->phy_belongs_to_port == 1)
> > +             return;
> > +
> > +     if (!hba_port)
> > +             return;
> > +
> > +     list_for_each_entry(mr_sas_port, &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;
> > +             list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
> > +                 port_siblings) {
> > +                     if (srch_phy == mr_sas_phy)
> > +                             return;
> > +             }
> > +             mpi3mr_add_sas_phy(mrioc, mr_sas_port, mr_sas_phy);
> > +             return;
> > +     }
> > +}
> > +
> > +/**
> > + * mpi3mr_del_phy_from_an_existing_port - del phy from a port
> > + * @mrioc: Adapter instance reference
> > + * @mr_sas_node: Internal sas node object (expander or host)
> > + * @mr_sas_phy: Internal Phy object
> > + *
> > + * Return: None.
> > + */
> > +static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,
> > +     struct mpi3mr_sas_node *mr_sas_node, struct mpi3mr_sas_phy *mr_sas_phy)
> > +{
> > +     struct mpi3mr_sas_port *mr_sas_port, *next;
> > +     struct mpi3mr_sas_phy *srch_phy;
> > +
> > +     if (mr_sas_phy->phy_belongs_to_port == 0)
> > +             return;
> > +
> > +     list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
> > +         port_list) {
> > +             list_for_each_entry(srch_phy, &mr_sas_port->phy_list,
> > +                 port_siblings) {
> > +                     if (srch_phy != mr_sas_phy)
> > +                             continue;
> > +                     mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
> > +                         mr_sas_phy);
> > +                     return;
> > +             }
> > +     }
> > +}
> > +
> > +/**
> > + * mpi3mr_sas_port_sanity_check - sanity check while adding port
> > + * @mrioc: Adapter instance reference
> > + * @mr_sas_node: Internal sas node object (expander or host)
> > + * @sas_address: SAS address of device/expander
> > + * @hba_port: HBA port entry
> > + *
> > + * Verifies whether the Phys attached to a device with the given
> > + * SAS address already belongs to an existing sas port if so
> > + * will remove those phys from the sas port
> > + *
> > + * Return: None.
> > + */
> > +static void mpi3mr_sas_port_sanity_check(struct mpi3mr_ioc *mrioc,
> > +     struct mpi3mr_sas_node *mr_sas_node, u64 sas_address,
> > +     struct mpi3mr_hba_port *hba_port)
> > +{
> > +     int i;
> > +
> > +     for (i = 0; i < mr_sas_node->num_phys; i++) {
> > +             if ((mr_sas_node->phy[i].remote_identify.sas_address !=
> > +                 sas_address) || (mr_sas_node->phy[i].hba_port != hba_port))
> > +                     continue;
> > +             if (mr_sas_node->phy[i].phy_belongs_to_port == 1)
> > +                     mpi3mr_del_phy_from_an_existing_port(mrioc,
> > +                         mr_sas_node, &mr_sas_node->phy[i]);
> > +     }
> > +}
> > +
> > +/**
> > + * mpi3mr_set_identify - set identify for phys and end devices
> > + * @mrioc: Adapter instance reference
> > + * @handle: Firmware device handle
> > + * @identify: SAS transport layer's identify info
> > + *
> > + * Populates sas identify info for a specific device.
> > + *
> > + * Return: 0 for success, non-zero for failure.
> > + */
> > +static int mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle,
> > +     struct sas_identify *identify)
> > +{
> > +
> > +     struct mpi3_device_page0 device_pg0;
> > +     struct mpi3_device0_sas_sata_format *sasinf;
> > +     u16 device_info;
> > +     u16 ioc_status;
> > +
> > +     if (mrioc->reset_in_progress) {
> > +             ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
> > +             return -EFAULT;
> > +     }
> > +
> > +     if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &device_pg0,
> > +         sizeof(device_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 -EIO;
> > +     }
> > +
> > +     memset(identify, 0, sizeof(struct sas_identify));
> > +     sasinf = &device_pg0.device_specific.sas_sata_format;
> > +     device_info = le16_to_cpu(sasinf->device_info);
> > +
> > +     /* sas_address */
> > +     identify->sas_address = le64_to_cpu(sasinf->sas_address);
> > +
> > +     /* phy number of the parent device this device is linked to */
> > +     identify->phy_identifier = sasinf->phy_num;
> > +
> > +     /* device_type */
> > +     switch (device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) {
> > +     case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE:
> > +             identify->device_type = SAS_PHY_UNUSED;
> > +             break;
> > +     case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE:
> > +             identify->device_type = SAS_END_DEVICE;
> > +             break;
> > +     case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER:
> > +             identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
> > +             break;
> > +     }
> > +
> > +     /* initiator_port_protocols */
> > +     if (device_info & MPI3_SAS_DEVICE_INFO_SSP_INITIATOR)
> > +             identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
> > +     /* MPI3.0 doesn't have define for SATA INIT so setting both here*/
> > +     if (device_info & MPI3_SAS_DEVICE_INFO_STP_INITIATOR)
> > +             identify->initiator_port_protocols |= (SAS_PROTOCOL_STP |
> > +                 SAS_PROTOCOL_SATA);
> > +     if (device_info & MPI3_SAS_DEVICE_INFO_SMP_INITIATOR)
> > +             identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
> > +
> > +     /* target_port_protocols */
> > +     if (device_info & MPI3_SAS_DEVICE_INFO_SSP_TARGET)
> > +             identify->target_port_protocols |= SAS_PROTOCOL_SSP;
> > +     /* MPI3.0 doesn't have define for STP Target so setting both here*/
> > +     if (device_info & MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET)
> > +             identify->target_port_protocols |= (SAS_PROTOCOL_STP |
> > +                 SAS_PROTOCOL_SATA);
> > +     if (device_info & MPI3_SAS_DEVICE_INFO_SMP_TARGET)
> > +             identify->target_port_protocols |= SAS_PROTOCOL_SMP;
> > +     return 0;
> > +}
> > +
> > +/**
> > + * mpi3mr_add_host_phy - report sas_host phy to SAS transport
> > + * @mrioc: Adapter instance reference
> > + * @mr_sas_phy: Internal Phy object
> > + * @phy_pg0: SAS phy page 0
> > + * @parent_dev: Prent device class object
> > + *
> > + * Return: 0 for success, non-zero for failure.
> > + */
> > +static int mpi3mr_add_host_phy(struct mpi3mr_ioc *mrioc,
> > +     struct mpi3mr_sas_phy *mr_sas_phy, struct mpi3_sas_phy_page0 phy_pg0,
> > +     struct device *parent_dev)
> > +{
> > +     struct sas_phy *phy;
> > +     int phy_index = mr_sas_phy->phy_id;
> > +
> > +
> > +     INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
> > +     phy = sas_phy_alloc(parent_dev, phy_index);
> > +     if (!phy) {
> > +             ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> > +                 __FILE__, __LINE__, __func__);
> > +             return -1;
> > +     }
> > +     if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
> > +         &mr_sas_phy->identify))) {
> > +             ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> > +                 __FILE__, __LINE__, __func__);
> > +             sas_phy_free(phy);
> > +             return -1;
> > +     }
> > +     phy->identify = mr_sas_phy->identify;
> > +     mr_sas_phy->attached_handle = le16_to_cpu(phy_pg0.attached_dev_handle);
> > +     if (mr_sas_phy->attached_handle)
> > +             mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
> > +                 &mr_sas_phy->remote_identify);
> > +     phy->identify.phy_identifier = mr_sas_phy->phy_id;
> > +     phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
> > +         (phy_pg0.negotiated_link_rate &
> > +         MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
> > +         MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
> > +     phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
> > +         phy_pg0.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
> > +     phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
> > +         phy_pg0.hw_link_rate >> 4);
> > +     phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
> > +         phy_pg0.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
> > +     phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
> > +         phy_pg0.programmed_link_rate >> 4);
> > +     phy->hostdata = mr_sas_phy->hba_port;
> > +
> > +     if ((sas_phy_add(phy))) {
> > +             ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> > +                 __FILE__, __LINE__, __func__);
> > +             sas_phy_free(phy);
> > +             return -1;
> > +     }
> > +     if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
> > +             dev_info(&phy->dev,
> > +                 "add: handle(0x%04x), sas_address(0x%016llx)\n"
> > +                 "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
> > +                 mr_sas_phy->handle, (unsigned long long)
> > +                 mr_sas_phy->identify.sas_address,
> > +                 mr_sas_phy->attached_handle,
> > +                 (unsigned long long)
> > +                 mr_sas_phy->remote_identify.sas_address);
> > +     mr_sas_phy->phy = phy;
> > +     return 0;
> > +}
> > +
> > +/**
> > + * mpi3mr_add_expander_phy - report expander phy to transport
> > + * @mrioc: Adapter instance reference
> > + * @mr_sas_phy: Internal Phy object
> > + * @expander_pg1: SAS Expander page 1
> > + * @parent_dev: Parent device class object
> > + *
> > + * Return: 0 for success, non-zero for failure.
> > + */
> > +static int mpi3mr_add_expander_phy(struct mpi3mr_ioc *mrioc,
> > +     struct mpi3mr_sas_phy *mr_sas_phy,
> > +     struct mpi3_sas_expander_page1 expander_pg1,
> > +     struct device *parent_dev)
> > +{
> > +     struct sas_phy *phy;
> > +     int phy_index = mr_sas_phy->phy_id;
> > +
> > +     INIT_LIST_HEAD(&mr_sas_phy->port_siblings);
> > +     phy = sas_phy_alloc(parent_dev, phy_index);
> > +     if (!phy) {
> > +             ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> > +                 __FILE__, __LINE__, __func__);
> > +             return -1;
> > +     }
> > +     if ((mpi3mr_set_identify(mrioc, mr_sas_phy->handle,
> > +         &mr_sas_phy->identify))) {
> > +             ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> > +                 __FILE__, __LINE__, __func__);
> > +             sas_phy_free(phy);
> > +             return -1;
> > +     }
> > +     phy->identify = mr_sas_phy->identify;
> > +     mr_sas_phy->attached_handle =
> > +         le16_to_cpu(expander_pg1.attached_dev_handle);
> > +     if (mr_sas_phy->attached_handle)
> > +             mpi3mr_set_identify(mrioc, mr_sas_phy->attached_handle,
> > +                 &mr_sas_phy->remote_identify);
> > +     phy->identify.phy_identifier = mr_sas_phy->phy_id;
> > +     phy->negotiated_linkrate = mpi3mr_convert_phy_link_rate(
> > +         (expander_pg1.negotiated_link_rate &
> > +         MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK) >>
> > +         MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
> > +     phy->minimum_linkrate_hw = mpi3mr_convert_phy_link_rate(
> > +         expander_pg1.hw_link_rate & MPI3_SAS_HWRATE_MIN_RATE_MASK);
> > +     phy->maximum_linkrate_hw = mpi3mr_convert_phy_link_rate(
> > +         expander_pg1.hw_link_rate >> 4);
> > +     phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
> > +         expander_pg1.programmed_link_rate & MPI3_SAS_PRATE_MIN_RATE_MASK);
> > +     phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
> > +         expander_pg1.programmed_link_rate >> 4);
> > +     phy->hostdata = mr_sas_phy->hba_port;
> > +
> > +     if ((sas_phy_add(phy))) {
> > +             ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> > +                 __FILE__, __LINE__, __func__);
> > +             sas_phy_free(phy);
> > +             return -1;
> > +     }
> > +     if ((mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO))
> > +             dev_info(&phy->dev,
> > +                 "add: handle(0x%04x), sas_address(0x%016llx)\n"
> > +                 "\tattached_handle(0x%04x), sas_address(0x%016llx)\n",
> > +                 mr_sas_phy->handle, (unsigned long long)
> > +                 mr_sas_phy->identify.sas_address,
> > +                 mr_sas_phy->attached_handle,
> > +                 (unsigned long long)
> > +                 mr_sas_phy->remote_identify.sas_address);
> > +     mr_sas_phy->phy = phy;
> > +     return 0;
> > +}
> > --
> > 2.27.0
> >
>
> --
> Himanshu Madhani        Oracle Linux Engineering
>

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 06/15] mpi3mr: Add helper functions to retrieve device objects
  2022-07-29 20:11   ` Himanshu Madhani
@ 2022-08-01  7:48     ` Sreekanth Reddy
  0 siblings, 0 replies; 35+ messages in thread
From: Sreekanth Reddy @ 2022-08-01  7:48 UTC (permalink / raw)
  To: Himanshu Madhani; +Cc: linux-scsi, Martin Petersen

[-- Attachment #1: Type: text/plain, Size: 14373 bytes --]

On Sat, Jul 30, 2022 at 1:41 AM Himanshu Madhani
<himanshu.madhani@oracle.com> wrote:
>
>
>
> > On Jul 29, 2022, at 6:16 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 | 280 +++++++++++++++++++++++++
> > 3 files changed, 297 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 989bf63..fea3aae 100644
> > --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
> > +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> > @@ -9,6 +9,237 @@
> >
> > #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)
> > +{
> > +
> Remove new line here
> > +     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)
> > +{
> > +
> remove new line

Agree. Will remove it next version patch set.

> > +     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 +659,52 @@ 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)
> > +{
> > +
> Ditto remove newline

Agree. Will remove it next version patch set.

> > +     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
> >
>
> --
> Himanshu Madhani        Oracle Linux Engineering
>

[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4218 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 02/15] mpi3mr: Add framework to issue cnfg requests
  2022-08-01  7:40     ` Sreekanth Reddy
@ 2022-08-01 16:37       ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-08-01 16:37 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Aug 1, 2022, at 12:40 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> It is getting cleared in mpi3mr_process_admin_reply_desc() with below lines,
> 
> if (cmdptr->is_waiting) {
> complete(&cmdptr->done);
> cmdptr->is_waiting = 0;
> } else if (cmdptr->callback)
> cmdptr->callback(mrioc, cmdptr);

Ah.. I see that now. 

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 07/15] mpi3mr: Add helper functions to manage device's port
  2022-07-29 13:16 ` [PATCH 07/15] mpi3mr: Add helper functions to manage device's port Sreekanth Reddy
@ 2022-08-01 19:07   ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-08-01 19:07 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Added below helper functions,
> - Add, update the host phys with STL
> - Add, remove the device's sas port with STL
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr.h           |  13 +
> drivers/scsi/mpi3mr/mpi3mr_os.c        |   2 +-
> drivers/scsi/mpi3mr/mpi3mr_transport.c | 527 +++++++++++++++++++++++++
> 3 files changed, 541 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index 742caf5..8ab843a 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -570,12 +570,18 @@ struct mpi3mr_enclosure_node {
>  *
>  * @sas_address: World wide unique SAS address
>  * @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
> + * @rphy: SAS transport layer rphy object
>  */
> struct tgt_dev_sas_sata {
> 	u64 sas_address;
> 	u16 dev_info;
> +	u8 sas_transport_attached;
> +	u8 pend_sas_rphy_add;
> 	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);
> struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc,
> 	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*/
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index b75ce73..905b434 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -804,7 +804,7 @@ static void mpi3mr_set_io_divert_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc,
>  *
>  * 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)
> {
> 	ioc_notice(mrioc, "Device %s was in progress before the reset and\n",
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> index fea3aae..b85d60f 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> @@ -708,3 +708,530 @@ struct mpi3mr_hba_port *mpi3mr_get_hba_port_by_id(struct mpi3mr_ioc *mrioc,
> 
> 	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;
> +
> +

remove extra newline

> +	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)
> +{
> +

remove newline

> +	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);
> +}
> -- 
> 2.27.0
> 

Looks good. When you fix the small nit above, you can add

Reviewed-by: Himanshu Madhani <himanshu.madani@oracle.com>

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 08/15] mpi3mr: Enable STL on HBAs where multipath is disabled
  2022-07-29 13:16 ` [PATCH 08/15] mpi3mr: Enable STL on HBAs where multipath is disabled Sreekanth Reddy
@ 2022-08-01 19:12   ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-08-01 19:12 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Register the SAS, SATA devices to SCSI Transport Layer (STL)
> only if multipath capability is disabled on the controller's
> firmware.
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr.h    |  6 ++++++
> drivers/scsi/mpi3mr/mpi3mr_fw.c | 13 +++++++++++++
> drivers/scsi/mpi3mr/mpi3mr_os.c | 31 +++++++++++++++++++++++++++----
> 3 files changed, 46 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index 8ab843a..8c8703e 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -650,6 +650,8 @@ union _form_spec_inf {
>  * @dev_type: SAS/SATA/PCIE device type
>  * @is_hidden: Should be exposed to upper layers or not
>  * @host_exposed: Already exposed to host or not
> + * @io_unit_port: IO Unit port ID
> + * @non_stl: Is this device not to be attached with SAS TL
>  * @io_throttle_enabled: I/O throttling needed or not
>  * @q_depth: Device specific Queue Depth
>  * @wwid: World wide ID
> @@ -669,6 +671,8 @@ struct mpi3mr_tgt_dev {
> 	u8 dev_type;
> 	u8 is_hidden;
> 	u8 host_exposed;
> +	u8 io_unit_port;
> +	u8 non_stl;
> 	u8 io_throttle_enabled;
> 	u16 q_depth;
> 	u64 wwid;
> @@ -992,6 +996,7 @@ 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_transport_enabled: SAS transport enabled or not
>  * @sas_hba: SAS node for the controller
>  * @sas_expander_list: SAS node list of expanders
>  * @sas_node_lock: Lock to protect SAS node list
> @@ -1174,6 +1179,7 @@ struct mpi3mr_ioc {
> 	dma_addr_t cfg_page_dma;
> 	u16 cfg_page_sz;
> 
> +	u8 sas_transport_enabled;
> 	struct mpi3mr_sas_node sas_hba;
> 	struct list_head sas_expander_list;
> 	spinlock_t sas_node_lock;
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index 9c36f52..0659d3f 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -1136,6 +1136,13 @@ mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
> 		return -EPERM;
> 	}
> 
> +	if ((mrioc->sas_transport_enabled) && (mrioc->facts.ioc_capabilities &
> +	    MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED))
> +		ioc_err(mrioc,
> +		    "critical error: multipath capability is enabled at the\n"
> +		    "\tcontroller while sas transport support is enabled at the\n"
> +		    "\tdriver, please reboot the system or reload the driver\n");
> +
> 	dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8;
> 	if (mrioc->facts.max_devhandle % 8)
> 		dev_handle_bitmap_sz++;
> @@ -3453,6 +3460,7 @@ static const struct {
> 	char *name;
> } mpi3mr_capabilities[] = {
> 	{ MPI3_IOCFACTS_CAPABILITY_RAID_CAPABLE, "RAID" },
> +	{ MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED, "MultiPath" },
> };
> 
> /**
> @@ -3734,6 +3742,11 @@ retry_init:
> 		mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
> 		    MPI3MR_HOST_IOS_KDUMP);
> 
> +	if (!(mrioc->facts.ioc_capabilities &
> +	    MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED)) {
> +		mrioc->sas_transport_enabled = 1;
> +	}
> +
> 	mrioc->reply_sz = mrioc->facts.reply_sz;
> 
> 	retval = mpi3mr_check_reset_dma_mask(mrioc);
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index 905b434..ae77422 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -1032,6 +1032,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
> 	tgtdev->perst_id = le16_to_cpu(dev_pg0->persistent_id);
> 	tgtdev->dev_handle = le16_to_cpu(dev_pg0->dev_handle);
> 	tgtdev->dev_type = dev_pg0->device_form;
> +	tgtdev->io_unit_port = dev_pg0->io_unit_port;
> 	tgtdev->encl_handle = le16_to_cpu(dev_pg0->enclosure_handle);
> 	tgtdev->parent_handle = le16_to_cpu(dev_pg0->parent_dev_handle);
> 	tgtdev->slot = le16_to_cpu(dev_pg0->slot);
> @@ -1092,6 +1093,13 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
> 		else if (!(dev_info & (MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET |
> 		    MPI3_SAS_DEVICE_INFO_SSP_TARGET)))
> 			tgtdev->is_hidden = 1;
> +
> +		if (((tgtdev->devpg0_flag &
> +		    MPI3_DEVICE0_FLAGS_ATT_METHOD_DIR_ATTACHED)
> +		    && (tgtdev->devpg0_flag &
> +		    MPI3_DEVICE0_FLAGS_ATT_METHOD_VIRTUAL)) ||
> +		    (tgtdev->parent_handle == 0xFFFF))
> +			tgtdev->non_stl = 1;
> 		break;
> 	}
> 	case MPI3_DEVICE_DEVFORM_PCIE:
> @@ -1124,6 +1132,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
> 		    ((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
> 		    MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_SCSI_DEVICE))
> 			tgtdev->is_hidden = 1;
> +		tgtdev->non_stl = 1;
> 		if (!mrioc->shost)
> 			break;
> 		prot_mask = scsi_host_get_prot(mrioc->shost);
> @@ -1147,6 +1156,7 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
> 		tgtdev->dev_spec.vd_inf.state = vdinf->vd_state;
> 		if (vdinf->vd_state == MPI3_DEVICE0_VD_STATE_OFFLINE)
> 			tgtdev->is_hidden = 1;
> +		tgtdev->non_stl = 1;
> 		tgtdev->dev_spec.vd_inf.tg_id = vdinf_io_throttle_group;
> 		tgtdev->dev_spec.vd_inf.tg_high =
> 		    le16_to_cpu(vdinf->io_throttle_group_high) * 2048;
> @@ -1424,8 +1434,9 @@ mpi3mr_sastopochg_evt_debug(struct mpi3mr_ioc *mrioc,
> 	ioc_info(mrioc, "%s :sas topology change: (%s)\n",
> 	    __func__, status_str);
> 	ioc_info(mrioc,
> -	    "%s :\texpander_handle(0x%04x), enclosure_handle(0x%04x) start_phy(%02d), num_entries(%d)\n",
> +	    "%s :\texpander_handle(0x%04x), port(%d), enclosure_handle(0x%04x) start_phy(%02d), num_entries(%d)\n",
> 	    __func__, le16_to_cpu(event_data->expander_dev_handle),
> +	    event_data->io_unit_port,
> 	    le16_to_cpu(event_data->enclosure_handle),
> 	    event_data->start_phy_num, event_data->num_entries);
> 	for (i = 0; i < event_data->num_entries; i++) {
> @@ -1732,6 +1743,9 @@ static void mpi3mr_set_qd_for_all_vd_in_tg(struct mpi3mr_ioc *mrioc,
> static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
> 	struct mpi3mr_fwevt *fwevt)
> {
> +	struct mpi3_device_page0 *dev_pg0 = NULL;
> +	u16 perst_id;
> +
> 	mpi3mr_fwevt_del_from_list(mrioc, fwevt);
> 	mrioc->current_event = fwevt;
> 
> @@ -1752,8 +1766,10 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
> 	}
> 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
> 	{
> -		mpi3mr_devinfochg_evt_bh(mrioc,
> -		    (struct mpi3_device_page0 *)fwevt->event_data);
> +		dev_pg0 = (struct mpi3_device_page0 *)fwevt->event_data;
> +		perst_id = le16_to_cpu(dev_pg0->persistent_id);
> +		if (perst_id != MPI3_DEVICE0_PERSISTENTID_INVALID)
> +			mpi3mr_devinfochg_evt_bh(mrioc, dev_pg0);
> 		break;
> 	}
> 	case MPI3_EVENT_DEVICE_STATUS_CHANGE:
> @@ -1851,6 +1867,9 @@ static int mpi3mr_create_tgtdev(struct mpi3mr_ioc *mrioc,
> 	u16 perst_id = 0;
> 
> 	perst_id = le16_to_cpu(dev_pg0->persistent_id);
> +	if (perst_id == MPI3_DEVICE0_PERSISTENTID_INVALID)
> +		return retval;
> +
> 	tgtdev = mpi3mr_get_tgtdev_by_perst_id(mrioc, perst_id);
> 	if (tgtdev) {
> 		mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, true);
> @@ -4850,7 +4869,11 @@ static void mpi3mr_remove(struct pci_dev *pdev)
> 	spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
> 	if (wq)
> 		destroy_workqueue(wq);
> -	scsi_remove_host(shost);
> +
> +	if (mrioc->sas_transport_enabled)
> +		sas_remove_host(shost);
> +	else
> +		scsi_remove_host(shost);
> 
> 	list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list,
> 	    list) {
> -- 
> 2.27.0
> 

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 09/15] mpi3mr: Add expander devices to STL
  2022-07-29 13:16 ` [PATCH 09/15] mpi3mr: Add expander devices to STL Sreekanth Reddy
@ 2022-08-01 20:50   ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-08-01 20:50 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Register/unregister the expander devices to
> SCSI Transport Layer(STL) whenever the corresponding expander
> is added/removed from topology.
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr.h           |   7 +
> drivers/scsi/mpi3mr/mpi3mr_os.c        |  36 ++-
> drivers/scsi/mpi3mr/mpi3mr_transport.c | 402 ++++++++++++++++++++++++-
> 3 files changed, 436 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index 8c8703e..9cd5f88 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -1341,6 +1341,11 @@ 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);
> +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,
> 	u8 port_id);
> 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,
> 	u64 sas_address_parent, u16 handle, u8 phy_number, u8 link_rate,
> 	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,
> 	bool device_add);
> #endif /*MPI3MR_H_INCLUDED*/
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index ae77422..9a32dc6 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -824,7 +824,7 @@ void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc,
>  *
>  * 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_stgt_priv_data *tgt_priv;
> @@ -1494,7 +1494,10 @@ static void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc,
> 	int i;
> 	u16 handle;
> 	u8 reason_code;
> +	u64 exp_sas_address = 0;
> +	struct mpi3mr_hba_port *hba_port = NULL;
> 	struct mpi3mr_tgt_dev *tgtdev = NULL;
> +	struct mpi3mr_sas_node *sas_expander = NULL;
> 
> 	mpi3mr_sastopochg_evt_debug(mrioc, event_data);
> 
> @@ -1524,6 +1527,13 @@ static void mpi3mr_sastopochg_evt_bh(struct mpi3mr_ioc *mrioc,
> 		if (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);
> +	}
> }
> 
> /**
> @@ -1744,7 +1754,8 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
> 	struct mpi3mr_fwevt *fwevt)
> {
> 	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);
> 	mrioc->current_event = fwevt;
> @@ -1758,10 +1769,23 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
> 	switch (fwevt->event_id) {
> 	case MPI3_EVENT_DEVICE_ADDED:
> 	{
> -		struct mpi3_device_page0 *dev_pg0 =
> -		    (struct mpi3_device_page0 *)fwevt->event_data;
> -		mpi3mr_report_tgtdev_to_host(mrioc,
> -		    le16_to_cpu(dev_pg0->persistent_id));
> +		dev_pg0 = (struct mpi3_device_page0 *)fwevt->event_data;
> +		perst_id = le16_to_cpu(dev_pg0->persistent_id);
> +		handle = le16_to_cpu(dev_pg0->dev_handle);
> +		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;
> 	}
> 	case MPI3_EVENT_DEVICE_INFO_CHANGED:
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> index b85d60f..1d6ae9d 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> @@ -21,7 +21,7 @@
>  *
>  * 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)
> {
> 	struct mpi3mr_sas_node *sas_expander, *r;
> @@ -159,6 +159,45 @@ out:
> 	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
>  * @mrioc: Adapter instance reference
> @@ -379,6 +418,35 @@ 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)
> +{
> +

Delete extra newline

> +	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
>  * @mrioc: Adapter instance reference
> @@ -402,8 +470,12 @@ static void mpi3mr_del_phy_from_an_existing_port(struct mpi3mr_ioc *mrioc,
> 		    port_siblings) {
> 			if (srch_phy != mr_sas_phy)
> 				continue;
> -			mpi3mr_delete_sas_phy(mrioc, mr_sas_port,
> -			    mr_sas_phy);
> +			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,
> +				    mr_sas_phy);
> 			return;
> 		}
> 	}
> @@ -1235,3 +1307,327 @@ static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
> 
> 	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;
> +
Remove newline here

> +	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;
> +
> +
remove extra newline

> +	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);
> +}
> +
> +
remove new line

> +/**
> + * 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);
> +
> +}
> -- 
> 2.27.0
> 

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 10/15] mpi3mr: Get target object based on rphy
  2022-07-29 13:16 ` [PATCH 10/15] mpi3mr: Get target object based on rphy Sreekanth Reddy
@ 2022-08-01 21:27   ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-08-01 21:27 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> When device is registered with the STL then
> get the corresponding device's target object
> using the rphy in below callback functions,
> 
> - mpi3mr_target_alloc,
> - mpi3mr_slave_alloc,
> - mpi3mr_slave_configure,
> - mpi3mr_slave_destroy
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr.h           |  4 ++
> drivers/scsi/mpi3mr/mpi3mr_fw.c        |  2 +
> drivers/scsi/mpi3mr/mpi3mr_os.c        | 61 +++++++++++++++++++++-----
> drivers/scsi/mpi3mr/mpi3mr_transport.c | 29 ++++++++++++
> 4 files changed, 86 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index 9cd5f88..a91a57b 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -997,6 +997,7 @@ struct scmd_priv {
>  * @cfg_page_dma: Configuration page DMA address
>  * @cfg_page_sz: Default configuration page memory size
>  * @sas_transport_enabled: SAS transport enabled or not
> + * @scsi_device_channel: Channel ID for SCSI devices
>  * @sas_hba: SAS node for the controller
>  * @sas_expander_list: SAS node list of expanders
>  * @sas_node_lock: Lock to protect SAS node list
> @@ -1180,6 +1181,7 @@ struct mpi3mr_ioc {
> 	u16 cfg_page_sz;
> 
> 	u8 sas_transport_enabled;
> +	u8 scsi_device_channel;
> 	struct mpi3mr_sas_node sas_hba;
> 	struct list_head sas_expander_list;
> 	spinlock_t sas_node_lock;
> @@ -1355,6 +1357,8 @@ void mpi3mr_update_links(struct mpi3mr_ioc *mrioc,
> 	struct mpi3mr_hba_port *hba_port);
> void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
> 	struct mpi3mr_tgt_dev *tgtdev);
> +struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
> +	struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy);
> void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc,
> 	bool device_add);
> #endif /*MPI3MR_H_INCLUDED*/
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index 0659d3f..9155434 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -3745,6 +3745,8 @@ retry_init:
> 	if (!(mrioc->facts.ioc_capabilities &
> 	    MPI3_IOCFACTS_CAPABILITY_MULTIPATH_ENABLED)) {
> 		mrioc->sas_transport_enabled = 1;
> +		mrioc->scsi_device_channel = 1;
> +		mrioc->shost->max_channel = 1;
> 	}
> 
> 	mrioc->reply_sz = mrioc->facts.reply_sz;
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index 9a32dc6..aed9b60 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -4031,9 +4031,10 @@ static void mpi3mr_slave_destroy(struct scsi_device *sdev)
> 	struct Scsi_Host *shost;
> 	struct mpi3mr_ioc *mrioc;
> 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
> -	struct mpi3mr_tgt_dev *tgt_dev;
> +	struct mpi3mr_tgt_dev *tgt_dev = NULL;
> 	unsigned long flags;
> 	struct scsi_target *starget;
> +	struct sas_rphy *rphy = NULL;
> 
> 	if (!sdev->hostdata)
> 		return;
> @@ -4046,7 +4047,14 @@ static void mpi3mr_slave_destroy(struct scsi_device *sdev)
> 	scsi_tgt_priv_data->num_luns--;
> 
> 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
> -	tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
> +	if (starget->channel == mrioc->scsi_device_channel)
> +		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
> +	else if (mrioc->sas_transport_enabled && !starget->channel) {
> +		rphy = dev_to_rphy(starget->dev.parent);
> +		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
> +		    rphy->identify.sas_address, rphy);
> +	}
> +
> 	if (tgt_dev && (!scsi_tgt_priv_data->num_luns))
> 		tgt_dev->starget = NULL;
> 	if (tgt_dev)
> @@ -4111,16 +4119,23 @@ static int mpi3mr_slave_configure(struct scsi_device *sdev)
> 	struct scsi_target *starget;
> 	struct Scsi_Host *shost;
> 	struct mpi3mr_ioc *mrioc;
> -	struct mpi3mr_tgt_dev *tgt_dev;
> +	struct mpi3mr_tgt_dev *tgt_dev = NULL;
> 	unsigned long flags;
> 	int retval = 0;
> +	struct sas_rphy *rphy = NULL;
> 
> 	starget = scsi_target(sdev);
> 	shost = dev_to_shost(&starget->dev);
> 	mrioc = shost_priv(shost);
> 
> 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
> -	tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
> +	if (starget->channel == mrioc->scsi_device_channel)
> +		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
> +	else if (mrioc->sas_transport_enabled && !starget->channel) {
> +		rphy = dev_to_rphy(starget->dev.parent);
> +		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
> +		    rphy->identify.sas_address, rphy);
> +	}
> 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
> 	if (!tgt_dev)
> 		return -ENXIO;
> @@ -4168,11 +4183,12 @@ static int mpi3mr_slave_alloc(struct scsi_device *sdev)
> 	struct Scsi_Host *shost;
> 	struct mpi3mr_ioc *mrioc;
> 	struct mpi3mr_stgt_priv_data *scsi_tgt_priv_data;
> -	struct mpi3mr_tgt_dev *tgt_dev;
> +	struct mpi3mr_tgt_dev *tgt_dev = NULL;
> 	struct mpi3mr_sdev_priv_data *scsi_dev_priv_data;
> 	unsigned long flags;
> 	struct scsi_target *starget;
> 	int retval = 0;
> +	struct sas_rphy *rphy = NULL;
> 
> 	starget = scsi_target(sdev);
> 	shost = dev_to_shost(&starget->dev);
> @@ -4180,7 +4196,14 @@ static int mpi3mr_slave_alloc(struct scsi_device *sdev)
> 	scsi_tgt_priv_data = starget->hostdata;
> 
> 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
> -	tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
> +
> +	if (starget->channel == mrioc->scsi_device_channel)
> +		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
> +	else if (mrioc->sas_transport_enabled && !starget->channel) {
> +		rphy = dev_to_rphy(starget->dev.parent);
> +		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
> +		    rphy->identify.sas_address, rphy);
> +	}
> 
> 	if (tgt_dev) {
> 		if (tgt_dev->starget == NULL)
> @@ -4223,6 +4246,8 @@ static int mpi3mr_target_alloc(struct scsi_target *starget)
> 	struct mpi3mr_tgt_dev *tgt_dev;
> 	unsigned long flags;
> 	int retval = 0;
> +	struct sas_rphy *rphy = NULL;
> +	bool update_stgt_priv_data = false;
> 
> 	scsi_tgt_priv_data = kzalloc(sizeof(*scsi_tgt_priv_data), GFP_KERNEL);
> 	if (!scsi_tgt_priv_data)
> @@ -4231,8 +4256,25 @@ static int mpi3mr_target_alloc(struct scsi_target *starget)
> 	starget->hostdata = scsi_tgt_priv_data;
> 
> 	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
> -	tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
> -	if (tgt_dev && !tgt_dev->is_hidden) {
> +
> +	if (starget->channel == mrioc->scsi_device_channel) {
> +		tgt_dev = __mpi3mr_get_tgtdev_by_perst_id(mrioc, starget->id);
> +		if (tgt_dev && !tgt_dev->is_hidden)
> +			update_stgt_priv_data = true;
> +		else
> +			retval = -ENXIO;
> +	} else if (mrioc->sas_transport_enabled && !starget->channel) {
> +		rphy = dev_to_rphy(starget->dev.parent);
> +		tgt_dev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
> +		    rphy->identify.sas_address, rphy);
> +		if (tgt_dev && !tgt_dev->is_hidden && !tgt_dev->non_stl &&
> +		    (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_SAS_SATA))
> +			update_stgt_priv_data = true;
> +		else
> +			retval = -ENXIO;
> +	}
> +
> +	if (update_stgt_priv_data) {
> 		scsi_tgt_priv_data->starget = starget;
> 		scsi_tgt_priv_data->dev_handle = tgt_dev->dev_handle;
> 		scsi_tgt_priv_data->perst_id = tgt_dev->perst_id;
> @@ -4246,8 +4288,7 @@ static int mpi3mr_target_alloc(struct scsi_target *starget)
> 		if (tgt_dev->dev_type == MPI3_DEVICE_DEVFORM_VD)
> 			scsi_tgt_priv_data->throttle_group =
> 			    tgt_dev->dev_spec.vd_inf.tg;
> -	} else
> -		retval = -ENXIO;
> +	}
> 	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
> 
> 	return retval;
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> index 1d6ae9d..f7faf6e 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> @@ -198,6 +198,35 @@ static void mpi3mr_remove_device_by_sas_address(struct mpi3mr_ioc *mrioc,
> 	}
> }
> 
> +/**
> + * __mpi3mr_get_tgtdev_by_addr_and_rphy - target device search
> + * @mrioc: Adapter instance reference
> + * @sas_address: SAS address of the device
> + * @rphy: SAS transport layer rphy object
> + *
> + * This searches for target device from sas address and rphy
> + * pointer then return mpi3mr_tgt_dev object.
> + *
> + * Return: Valid tget_dev or NULL
> + */
> +struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
> +	struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy)
> +{
> +	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.rphy == rphy))
> +			goto found_device;
> +	return NULL;
> +found_device:
> +	mpi3mr_tgtdev_get(tgtdev);
> +	return tgtdev;
> +}
> +
> /**
>  * mpi3mr_expander_find_by_sas_address - sas expander search
>  * @mrioc: Adapter instance reference
> -- 
> 2.27.0
> 

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 12/15] mpi3mr: Add framework to issue MPT transport cmds
  2022-07-29 13:16 ` [PATCH 12/15] mpi3mr: Add framework to issue MPT transport cmds Sreekanth Reddy
@ 2022-08-02  0:13   ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-08-02  0:13 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Added framework to issue MPT transport commands to
> controllers.
> Also issued the MPT transport commands to get the
> manufacturing info of sas expander device.
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr.h           |   6 +-
> drivers/scsi/mpi3mr/mpi3mr_fw.c        |  17 ++
> drivers/scsi/mpi3mr/mpi3mr_os.c        |   2 +
> drivers/scsi/mpi3mr/mpi3mr_transport.c | 228 +++++++++++++++++++++++++
> 4 files changed, 252 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index 21ea021..a6c880c 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -99,9 +99,10 @@ extern atomic64_t event_counter;
> #define MPI3MR_HOSTTAG_PEL_WAIT		4
> #define MPI3MR_HOSTTAG_BLK_TMS		5
> #define MPI3MR_HOSTTAG_CFG_CMDS		6
> +#define MPI3MR_HOSTTAG_TRANSPORT_CMDS	7
> 
> #define MPI3MR_NUM_DEVRMCMD		16
> -#define MPI3MR_HOSTTAG_DEVRMCMD_MIN	(MPI3MR_HOSTTAG_BLK_TMS + 1)
> +#define MPI3MR_HOSTTAG_DEVRMCMD_MIN	(MPI3MR_HOSTTAG_TRANSPORT_CMDS + 1)
> #define MPI3MR_HOSTTAG_DEVRMCMD_MAX	(MPI3MR_HOSTTAG_DEVRMCMD_MIN + \
> 						MPI3MR_NUM_DEVRMCMD - 1)
> 
> @@ -279,6 +280,7 @@ enum mpi3mr_reset_reason {
> 	MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24,
> 	MPI3MR_RESET_FROM_FIRMWARE = 27,
> 	MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT = 29,
> +	MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT = 30,
> };
> 
> /* Queue type definitions */
> @@ -1004,6 +1006,7 @@ struct scmd_priv {
>  * @cfg_page_sz: Default configuration page memory size
>  * @sas_transport_enabled: SAS transport enabled or not
>  * @scsi_device_channel: Channel ID for SCSI devices
> + * @transport_cmds: Command tracker for SAS transport commands
>  * @sas_hba: SAS node for the controller
>  * @sas_expander_list: SAS node list of expanders
>  * @sas_node_lock: Lock to protect SAS node list
> @@ -1188,6 +1191,7 @@ struct mpi3mr_ioc {
> 
> 	u8 sas_transport_enabled;
> 	u8 scsi_device_channel;
> +	struct mpi3mr_drv_cmd transport_cmds;
> 	struct mpi3mr_sas_node sas_hba;
> 	struct list_head sas_expander_list;
> 	spinlock_t sas_node_lock;
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index 9155434..1bf3cae 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -312,6 +312,8 @@ mpi3mr_get_drv_cmd(struct mpi3mr_ioc *mrioc, u16 host_tag,
> 		return &mrioc->pel_abort_cmd;
> 	case MPI3MR_HOSTTAG_PEL_WAIT:
> 		return &mrioc->pel_cmds;
> +	case MPI3MR_HOSTTAG_TRANSPORT_CMDS:
> +		return &mrioc->transport_cmds;
> 	case MPI3MR_HOSTTAG_INVALID:
> 		if (def_reply && def_reply->function ==
> 		    MPI3_FUNCTION_EVENT_NOTIFICATION)
> @@ -913,6 +915,10 @@ static const struct {
> 	{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
> 	{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronous reset" },
> 	{ MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout"},
> +	{
> +		MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT,
> +		"timeout of a SAS transport layer request"
> +	},
Fix coding style mismatch here

> };
> 
> /**
> @@ -2866,6 +2872,10 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
> 	if (!mrioc->bsg_cmds.reply)
> 		goto out_failed;
> 
> +	mrioc->transport_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
> +	if (!mrioc->transport_cmds.reply)
> +		goto out_failed;
> +
> 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
> 		mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz,
> 		    GFP_KERNEL);
> @@ -4072,6 +4082,8 @@ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
> 		    sizeof(*mrioc->pel_cmds.reply));
> 		memset(mrioc->pel_abort_cmd.reply, 0,
> 		    sizeof(*mrioc->pel_abort_cmd.reply));
> +		memset(mrioc->transport_cmds.reply, 0,
> +		    sizeof(*mrioc->transport_cmds.reply));
> 		for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
> 			memset(mrioc->dev_rmhs_cmds[i].reply, 0,
> 			    sizeof(*mrioc->dev_rmhs_cmds[i].reply));
> @@ -4217,6 +4229,9 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
> 	kfree(mrioc->chain_bitmap);
> 	mrioc->chain_bitmap = NULL;
> 
> +	kfree(mrioc->transport_cmds.reply);
> +	mrioc->transport_cmds.reply = NULL;
> +
> 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
> 		kfree(mrioc->dev_rmhs_cmds[i].reply);
> 		mrioc->dev_rmhs_cmds[i].reply = NULL;
> @@ -4417,6 +4432,8 @@ static void mpi3mr_flush_drv_cmds(struct mpi3mr_ioc *mrioc)
> 	cmdptr = &mrioc->pel_abort_cmd;
> 	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
> 
> +	cmdptr = &mrioc->transport_cmds;
> +	mpi3mr_drv_cmd_comp_reset(mrioc, cmdptr);
> }
> 
> /**
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index a486fe3..3b20096 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -4840,6 +4840,8 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> 	mpi3mr_init_drv_cmd(&mrioc->host_tm_cmds, MPI3MR_HOSTTAG_BLK_TMS);
> 	mpi3mr_init_drv_cmd(&mrioc->bsg_cmds, MPI3MR_HOSTTAG_BSG_CMDS);
> 	mpi3mr_init_drv_cmd(&mrioc->cfg_cmds, MPI3MR_HOSTTAG_CFG_CMDS);
> +	mpi3mr_init_drv_cmd(&mrioc->transport_cmds,
> +	    MPI3MR_HOSTTAG_TRANSPORT_CMDS);
> 
> 	for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++)
> 		mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i],
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> index c449820..44a30d7 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> @@ -9,6 +9,225 @@
> 
> #include "mpi3mr.h"
> 
> +/**
> + * mpi3mr_post_transport_req - Issue transport requests and wait
> + * @mrioc: Adapter instance reference
> + * @request: Properly populated MPI3 request
> + * @request_sz: Size of the MPI3 request
> + * @reply: Pointer to return MPI3 reply
> + * @reply_sz: Size of the MPI3 reply buffer
> + * @timeout: Timeout in seconds
> + * @ioc_status: Pointer to return ioc status
> + *
> + * A generic function for posting MPI3 requests from the SAS
> + * transport layer that uses transport command infrastructure.
> + * This blocks for the completion of request for timeout seconds
> + * and if the request times out this function faults the
> + * controller with proper reason code.
> + *
> + * On successful completion of the request this function returns
> + * appropriate ioc status from the firmware back to the caller.
> + *
> + * Return: 0 on success, non-zero on failure.
> + */
> +static int mpi3mr_post_transport_req(struct mpi3mr_ioc *mrioc, void *request,
> +	u16 request_sz, void *reply, u16 reply_sz, int timeout,
> +	u16 *ioc_status)
> +{
> +	int retval = 0;
> +
> +	mutex_lock(&mrioc->transport_cmds.mutex);
> +	if (mrioc->transport_cmds.state & MPI3MR_CMD_PENDING) {
> +		retval = -1;
> +		ioc_err(mrioc, "sending transport request failed due to command in use\n");
> +		mutex_unlock(&mrioc->transport_cmds.mutex);
> +		goto out;
> +	}
> +	mrioc->transport_cmds.state = MPI3MR_CMD_PENDING;
> +	mrioc->transport_cmds.is_waiting = 1;
> +	mrioc->transport_cmds.callback = NULL;
> +	mrioc->transport_cmds.ioc_status = 0;
> +	mrioc->transport_cmds.ioc_loginfo = 0;
> +
> +	init_completion(&mrioc->transport_cmds.done);
> +	dprint_cfg_info(mrioc, "posting transport request\n");
> +	if (mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO)
> +		dprint_dump(request, request_sz, "transport_req");
> +	retval = mpi3mr_admin_request_post(mrioc, request, request_sz, 1);
> +	if (retval) {
> +		ioc_err(mrioc, "posting transport request failed\n");
> +		goto out_unlock;
> +	}
> +	wait_for_completion_timeout(&mrioc->transport_cmds.done,
> +	    (timeout * HZ));
> +	if (!(mrioc->transport_cmds.state & MPI3MR_CMD_COMPLETE)) {
> +		mpi3mr_check_rh_fault_ioc(mrioc,
> +		    MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT);
> +		ioc_err(mrioc, "transport request timed out\n");
> +		retval = -1;
> +		goto out_unlock;
> +	}
> +	*ioc_status = mrioc->transport_cmds.ioc_status &
> +		MPI3_IOCSTATUS_STATUS_MASK;
> +	if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS)
> +		dprint_transport_err(mrioc,
> +		    "transport request returned with ioc_status(0x%04x), log_info(0x%08x)\n",
> +		    *ioc_status, mrioc->transport_cmds.ioc_loginfo);
> +
> +	if ((reply) && (mrioc->transport_cmds.state & MPI3MR_CMD_REPLY_VALID))
> +		memcpy((u8 *)reply, mrioc->transport_cmds.reply, reply_sz);
> +
> +out_unlock:
> +	mrioc->transport_cmds.state = MPI3MR_CMD_NOTUSED;
> +	mutex_unlock(&mrioc->transport_cmds.mutex);
> +
> +out:
> +	return retval;
> +}
> +
> +/* report manufacture request structure */
> +struct rep_manu_request {
> +	u8 smp_frame_type;
> +	u8 function;
> +	u8 reserved;
> +	u8 request_length;
> +};
> +
> +/* report manufacture reply structure */
> +struct rep_manu_reply {
> +	u8 smp_frame_type; /* 0x41 */
> +	u8 function; /* 0x01 */
> +	u8 function_result;
> +	u8 response_length;
> +	u16 expander_change_count;
> +	u8 reserved0[2];
> +	u8 sas_format;
> +	u8 reserved2[3];
> +	u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
> +	u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
> +	u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
> +	u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
> +	u16 component_id;
> +	u8 component_revision_id;
> +	u8 reserved3;
> +	u8 vendor_specific[8];
> +};
> +
> +/**
> + * mpi3mr_report_manufacture - obtain SMP report_manufacture
> + * @mrioc: Adapter instance reference
> + * @sas_address: SAS address of the expander device
> + * @edev: SAS transport layer sas_expander_device object
> + * @port_id: ID of the HBA port
> + *
> + * Fills in the sas_expander_device with manufacturing info.
> + *
> + * Return: 0 for success, non-zero for failure.
> + */
> +static int mpi3mr_report_manufacture(struct mpi3mr_ioc *mrioc,
> +	u64 sas_address, struct sas_expander_device *edev, u8 port_id)
> +{
> +	struct mpi3_smp_passthrough_request mpi_request;
> +	struct mpi3_smp_passthrough_reply mpi_reply;
> +	struct rep_manu_reply *manufacture_reply;
> +	struct rep_manu_request *manufacture_request;
> +	int rc = 0;
> +	void *psge;
> +	void *data_out = NULL;
> +	dma_addr_t data_out_dma;
> +	dma_addr_t data_in_dma;
> +	size_t data_in_sz;
> +	size_t data_out_sz;
> +	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
> +	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
> +	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
> +	u16 ioc_status;
> +
> +	if (mrioc->reset_in_progress) {
> +		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
> +		return -EFAULT;
> +	}
> +
> +	data_out_sz = sizeof(struct rep_manu_request);
> +	data_in_sz = sizeof(struct rep_manu_reply);
> +	data_out = dma_alloc_coherent(&mrioc->pdev->dev,
> +	    data_out_sz + data_in_sz, &data_out_dma, GFP_KERNEL);
> +	if (!data_out) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
> +	data_in_dma = data_out_dma + data_out_sz;
> +	manufacture_reply = data_out + data_out_sz;
> +
> +	manufacture_request = data_out;
> +	manufacture_request->smp_frame_type = 0x40;
> +	manufacture_request->function = 1;
> +	manufacture_request->reserved = 0;
> +	manufacture_request->request_length = 0;
> +
> +	memset(&mpi_request, 0, request_sz);
> +	memset(&mpi_reply, 0, reply_sz);
> +	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
> +	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
> +	mpi_request.io_unit_port = (u8) port_id;
> +	mpi_request.sas_address = cpu_to_le64(sas_address);
> +
> +	psge = &mpi_request.request_sge;
> +	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
> +
> +	psge = &mpi_request.response_sge;
> +	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
> +
> +	dprint_transport_info(mrioc,
> +	    "sending report manufacturer SMP request to sas_address(0x%016llx), port(%d)\n",
> +	    (unsigned long long)sas_address, port_id);
> +
> +	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
> +	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
> +		goto out;
> +
> +	dprint_transport_info(mrioc,
> +	    "report manufacturer SMP request completed with ioc_status(0x%04x)\n",
> +	    ioc_status);
> +
> +	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
> +		u8 *tmp;
> +
> +		dprint_transport_info(mrioc,
> +		    "report manufacturer - reply data transfer size(%d)\n",
> +		    le16_to_cpu(mpi_reply.response_data_length));
> +
> +		if (le16_to_cpu(mpi_reply.response_data_length) !=
> +		    sizeof(struct rep_manu_reply))
> +			goto out;
> +
> +		strscpy(edev->vendor_id, manufacture_reply->vendor_id,
> +		     SAS_EXPANDER_VENDOR_ID_LEN);
> +		strscpy(edev->product_id, manufacture_reply->product_id,
> +		     SAS_EXPANDER_PRODUCT_ID_LEN);
> +		strscpy(edev->product_rev, manufacture_reply->product_rev,
> +		     SAS_EXPANDER_PRODUCT_REV_LEN);
> +		edev->level = manufacture_reply->sas_format & 1;
> +		if (edev->level) {
> +			strscpy(edev->component_vendor_id,
> +			    manufacture_reply->component_vendor_id,
> +			     SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
> +			tmp = (u8 *)&manufacture_reply->component_id;
> +			edev->component_id = tmp[0] << 8 | tmp[1];
> +			edev->component_revision_id =
> +			    manufacture_reply->component_revision_id;
> +		}
> +	}
> +
> +out:
> +	if (data_out)
> +		dma_free_coherent(&mrioc->pdev->dev, data_out_sz + data_in_sz,
> +		    data_out, data_out_dma);
> +
> +	return rc;
> +}
> +
> /**
>  * __mpi3mr_expander_find_by_handle - expander search by handle
>  * @mrioc: Adapter instance reference
> @@ -1223,6 +1442,15 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
> 			mpi3mr_print_device_event_notice(mrioc, true);
> 	}
> 
> +	/* fill in report manufacture */
> +	if (mr_sas_port->remote_identify.device_type ==
> +	    SAS_EDGE_EXPANDER_DEVICE ||
> +	    mr_sas_port->remote_identify.device_type ==
> +	    SAS_FANOUT_EXPANDER_DEVICE)
> +		mpi3mr_report_manufacture(mrioc,
> +		    mr_sas_port->remote_identify.sas_address,
> +		    rphy_to_expander_device(rphy), hba_port->port_id);
> +
> 	return mr_sas_port;
> 
>  out_fail:
> -- 
> 2.27.0
> 

With small nit fixed, You can add

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 13/15] mpi3mr: Support sas transport class callbacks
  2022-07-29 13:16 ` [PATCH 13/15] mpi3mr: Support sas transport class callbacks Sreekanth Reddy
@ 2022-08-02 18:11   ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-08-02 18:11 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Added support for below sas transport class callbacks,
> - get_linkerrors
> - get_enclosure_identifier
> - get_bay_identifier
> - phy_reset
> - phy_enable
> - set_phy_speed
> - smp_handler
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr.h           |   3 +
> drivers/scsi/mpi3mr/mpi3mr_fw.c        |   1 +
> drivers/scsi/mpi3mr/mpi3mr_os.c        |  20 +-
> drivers/scsi/mpi3mr/mpi3mr_transport.c | 917 +++++++++++++++++++++++++
> 4 files changed, 939 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index a6c880c..d203167 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -1326,6 +1326,9 @@ struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
> extern const struct attribute_group *mpi3mr_host_groups[];
> extern const struct attribute_group *mpi3mr_dev_groups[];
> 
> +extern struct sas_function_template mpi3mr_transport_functions;
> +extern struct scsi_transport_template *mpi3mr_transport_template;
> +
> int mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> 	struct mpi3_device_page0 *dev_pg0, u16 pg_sz, u32 form, u32 form_spec);
> int mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status,
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index 1bf3cae..59ef373 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -3757,6 +3757,7 @@ retry_init:
> 		mrioc->sas_transport_enabled = 1;
> 		mrioc->scsi_device_channel = 1;
> 		mrioc->shost->max_channel = 1;
> +		mrioc->shost->transportt = mpi3mr_transport_template;
> 	}
> 
> 	mrioc->reply_sz = mrioc->facts.reply_sz;
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index 3b20096..139c164 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -5168,18 +5168,33 @@ static int __init mpi3mr_init(void)
> 	pr_info("Loading %s version %s\n", MPI3MR_DRIVER_NAME,
> 	    MPI3MR_DRIVER_VERSION);
> 
> +	mpi3mr_transport_template =
> +	    sas_attach_transport(&mpi3mr_transport_functions);
> +	if (!mpi3mr_transport_template) {
> +		pr_err("%s failed to load due to sas transport attach failure\n",
> +		    MPI3MR_DRIVER_NAME);
> +		return -ENODEV;
> +	}
> +
> 	ret_val = pci_register_driver(&mpi3mr_pci_driver);
> 	if (ret_val) {
> 		pr_err("%s failed to load due to pci register driver failure\n",
> 		    MPI3MR_DRIVER_NAME);
> -		return ret_val;
> +		goto err_pci_reg_fail;
> 	}
> 
> 	ret_val = driver_create_file(&mpi3mr_pci_driver.driver,
> 				     &driver_attr_event_counter);
> 	if (ret_val)
> -		pci_unregister_driver(&mpi3mr_pci_driver);
> +		goto err_event_counter;
> +
> +	return ret_val;
> +
> +err_event_counter:
> +	pci_unregister_driver(&mpi3mr_pci_driver);
> 
> +err_pci_reg_fail:
> +	sas_release_transport(mpi3mr_transport_template);
> 	return ret_val;
> }
> 
> @@ -5196,6 +5211,7 @@ static void __exit mpi3mr_exit(void)
> 	driver_remove_file(&mpi3mr_pci_driver.driver,
> 			   &driver_attr_event_counter);
> 	pci_unregister_driver(&mpi3mr_pci_driver);
> +	sas_release_transport(mpi3mr_transport_template);
> }
> 
> module_init(mpi3mr_init);
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> index 44a30d7..e8a9a76 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> @@ -2046,3 +2046,920 @@ void mpi3mr_remove_tgtdev_from_sas_transport(struct mpi3mr_ioc *mrioc,
> 	    hba_port);
> 	tgtdev->host_exposed = 0;
> }
> +
> +/**
> + * mpi3mr_get_port_id_by_sas_phy -  Get port ID of the given phy
> + * @phy: SAS transport layer phy object
> + *
> + * Return: Port number for valid ID else 0xFFFF
> + */
> +static inline u8 mpi3mr_get_port_id_by_sas_phy(struct sas_phy *phy)
> +{
> +	u8 port_id = 0xFF;
> +	struct mpi3mr_hba_port *hba_port = phy->hostdata;
> +
> +	if (hba_port)
> +		port_id = hba_port->port_id;
> +
> +	return port_id;
> +}
> +
> +/**
> + * mpi3mr_get_port_id_by_rphy - Get Port number from SAS rphy
> + *
> + * @mrioc: Adapter instance reference
> + * @rphy: SAS transport layer remote phy object
> + *
> + * Retrieves HBA port number in which the device pointed by the
> + * rphy object is attached with.
> + *
> + * Return: Valid port number on success else OxFFFF.
> + */
> +static u8 mpi3mr_get_port_id_by_rphy(struct mpi3mr_ioc *mrioc, struct sas_rphy *rphy)
> +{
> +	struct mpi3mr_sas_node *sas_expander;
> +	struct mpi3mr_tgt_dev *tgtdev;
> +	unsigned long flags;
> +	u8 port_id = 0xFF;
> +
> +	if (!rphy)
> +		return port_id;
> +
> +	if (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
> +	    rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE) {
> +		spin_lock_irqsave(&mrioc->sas_node_lock, flags);
> +		list_for_each_entry(sas_expander, &mrioc->sas_expander_list,
> +		    list) {
> +			if (sas_expander->rphy == rphy) {
> +				port_id = sas_expander->hba_port->port_id;
> +				break;
> +			}
> +		}
> +		spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
> +	} else if (rphy->identify.device_type == SAS_END_DEVICE) {
> +		spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
> +
> +		tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
> +			    rphy->identify.sas_address, rphy);
> +		if (tgtdev) {
> +			port_id =
> +				tgtdev->dev_spec.sas_sata_inf.hba_port->port_id;
> +			mpi3mr_tgtdev_put(tgtdev);
> +		}
> +		spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
> +	}
> +	return port_id;
> +}
> +
> +static inline struct mpi3mr_ioc *phy_to_mrioc(struct sas_phy *phy)
> +{
> +	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
> +
> +	return shost_priv(shost);
> +}
> +
> +static inline struct mpi3mr_ioc *rphy_to_mrioc(struct sas_rphy *rphy)
> +{
> +	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
> +
> +	return shost_priv(shost);
> +}
> +
> +/* report phy error log structure */
> +struct phy_error_log_request {
> +	u8 smp_frame_type; /* 0x40 */
> +	u8 function; /* 0x11 */
> +	u8 allocated_response_length;
> +	u8 request_length; /* 02 */
> +	u8 reserved_1[5];
> +	u8 phy_identifier;
> +	u8 reserved_2[2];
> +};
> +
> +/* report phy error log reply structure */
> +struct phy_error_log_reply {
> +	u8 smp_frame_type; /* 0x41 */
> +	u8 function; /* 0x11 */
> +	u8 function_result;
> +	u8 response_length;
> +	__be16 expander_change_count;
> +	u8 reserved_1[3];
> +	u8 phy_identifier;
> +	u8 reserved_2[2];
> +	__be32 invalid_dword;
> +	__be32 running_disparity_error;
> +	__be32 loss_of_dword_sync;
> +	__be32 phy_reset_problem;
> +};
> +
> +
> +/**
> + * mpi3mr_get_expander_phy_error_log - return expander counters:
> + * @mrioc: Adapter instance reference
> + * @phy: The SAS transport layer phy object
> + *
> + * Return: 0 for success, non-zero for failure.
> + *
> + */
> +static int mpi3mr_get_expander_phy_error_log(struct mpi3mr_ioc *mrioc,
> +	struct sas_phy *phy)
> +{
> +	struct mpi3_smp_passthrough_request mpi_request;
> +	struct mpi3_smp_passthrough_reply mpi_reply;
> +	struct phy_error_log_request *phy_error_log_request;
> +	struct phy_error_log_reply *phy_error_log_reply;
> +	int rc;
> +	void *psge;
> +	void *data_out = NULL;
> +	dma_addr_t data_out_dma, data_in_dma;
> +	u32 data_out_sz, data_in_sz, sz;
> +	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
> +	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
> +	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
> +	u16 ioc_status;
> +
> +
> +	if (mrioc->reset_in_progress) {
> +		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
> +		return -EFAULT;
> +	}
> +
> +
Remove extra newline

> +	data_out_sz = sizeof(struct phy_error_log_request);
> +	data_in_sz = sizeof(struct phy_error_log_reply);
> +	sz = data_out_sz + data_in_sz;
> +	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
> +	    GFP_KERNEL);
> +	if (!data_out) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
> +	data_in_dma = data_out_dma + data_out_sz;
> +	phy_error_log_reply = data_out + data_out_sz;
> +
> +	rc = -EINVAL;
> +	memset(data_out, 0, sz);
> +	phy_error_log_request = data_out;
> +	phy_error_log_request->smp_frame_type = 0x40;
> +	phy_error_log_request->function = 0x11;
> +	phy_error_log_request->request_length = 2;
> +	phy_error_log_request->allocated_response_length = 0;
> +	phy_error_log_request->phy_identifier = phy->number;
> +
> +	memset(&mpi_request, 0, request_sz);
> +	memset(&mpi_reply, 0, reply_sz);
> +	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
> +	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
> +	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
> +	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
> +
> +	psge = &mpi_request.request_sge;
> +	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
> +
> +	psge = &mpi_request.response_sge;
> +	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
> +
> +	dprint_transport_info(mrioc,
> +	    "sending phy error log SMP request to sas_address(0x%016llx), phy_id(%d)\n",
> +	    (unsigned long long)phy->identify.sas_address, phy->number);
> +
> +	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
> +	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
> +		goto out;
> +
> +	dprint_transport_info(mrioc,
> +	    "phy error log SMP request completed with ioc_status(0x%04x)\n",
> +	    ioc_status);
> +
> +
Ditto here remove extra newline

> +	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
> +		dprint_transport_info(mrioc,
> +		    "phy error log - reply data transfer size(%d)\n",
> +		    le16_to_cpu(mpi_reply.response_data_length));
> +
> +		if (le16_to_cpu(mpi_reply.response_data_length) !=
> +		    sizeof(struct phy_error_log_reply))
> +			goto out;
> +
> +
Same here remove extra newline

> +		dprint_transport_info(mrioc,
> +		    "phy error log - function_result(%d)\n",
> +		    phy_error_log_reply->function_result);
> +
> +		phy->invalid_dword_count =
> +		    be32_to_cpu(phy_error_log_reply->invalid_dword);
> +		phy->running_disparity_error_count =
> +		    be32_to_cpu(phy_error_log_reply->running_disparity_error);
> +		phy->loss_of_dword_sync_count =
> +		    be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
> +		phy->phy_reset_problem_count =
> +		    be32_to_cpu(phy_error_log_reply->phy_reset_problem);
> +		rc = 0;
> +	}
> +
> +out:
> +	if (data_out)
> +		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
> +		    data_out_dma);
> +
> +	return rc;
> +}
> +
> +
Remove extra newline
> +/**
> + * mpi3mr_transport_get_linkerrors - return phy error counters
> + * @phy: The SAS transport layer phy object
> + *
> + * This function retrieves the phy error log information of the
> + * HBA or expander for which the phy belongs to
> + *
> + * Return: 0 for success, non-zero for failure.
> + *
remove extra newline in comment.
> + */
> +static int mpi3mr_transport_get_linkerrors(struct sas_phy *phy)
> +{
> +	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
> +	struct mpi3_sas_phy_page1 phy_pg1;
> +	int rc = 0;
> +	u16 ioc_status;
> +
> +	rc = mpi3mr_parent_present(mrioc, phy);
> +	if (rc)
> +		return rc;
> +
> +	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
> +		return mpi3mr_get_expander_phy_error_log(mrioc, phy);
> +
> +	memset(&phy_pg1, 0, sizeof(struct mpi3_sas_phy_page1));
> +	/* get hba phy error logs */
> +	if ((mpi3mr_cfg_get_sas_phy_pg1(mrioc, &ioc_status, &phy_pg1,
> +	    sizeof(struct mpi3_sas_phy_page1),
> +	    MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, phy->number))) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		return -ENXIO;
> +	}
> +
> +	if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		return -ENXIO;
> +	}
> +	phy->invalid_dword_count = le32_to_cpu(phy_pg1.invalid_dword_count);
> +	phy->running_disparity_error_count =
> +		le32_to_cpu(phy_pg1.running_disparity_error_count);
> +	phy->loss_of_dword_sync_count =
> +		le32_to_cpu(phy_pg1.loss_dword_synch_count);
> +	phy->phy_reset_problem_count =
> +		le32_to_cpu(phy_pg1.phy_reset_problem_count);
> +	return 0;
> +}
> +
> +
Another one, remove extra newline
> +/**
> + * mpi3mr_transport_get_enclosure_identifier - Get Enclosure ID
> + * @rphy: The SAS transport layer remote phy object
> + * @identifier: Enclosure identifier to be returned
> + *
> + * Returns the enclosure id for the device pointed by the remote
> + * phy object.
> + *
> + * Return: 0 on success or -ENXIO
> + */
> +static int
> +mpi3mr_transport_get_enclosure_identifier(struct sas_rphy *rphy,
> +	u64 *identifier)
> +{
> +	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
> +	struct mpi3mr_tgt_dev *tgtdev = NULL;
> +	unsigned long flags;
> +	int rc;
> +
> +	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
> +	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
> +	    rphy->identify.sas_address, rphy);
> +	if (tgtdev) {
> +		*identifier =
> +			tgtdev->enclosure_logical_id;
> +		rc = 0;
> +		mpi3mr_tgtdev_put(tgtdev);
> +	} else {
> +		*identifier = 0;
> +		rc = -ENXIO;
> +	}
> +	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
> +
> +	return rc;
> +}
> +
> +/**
> + * mpi3mr_transport_get_bay_identifier - Get bay ID
> + * @rphy: The SAS transport layer remote phy object
> + *
> + * Returns the slot id for the device pointed by the remote phy
> + * object.
> + *
> + * Return: Valid slot ID on success or -ENXIO
> + */
> +static int
> +mpi3mr_transport_get_bay_identifier(struct sas_rphy *rphy)
> +{
> +
Remove newline here

> +	struct mpi3mr_ioc *mrioc = rphy_to_mrioc(rphy);
> +	struct mpi3mr_tgt_dev *tgtdev = NULL;
> +	unsigned long flags;
> +	int rc;
> +
> +	spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
> +	tgtdev = __mpi3mr_get_tgtdev_by_addr_and_rphy(mrioc,
> +	    rphy->identify.sas_address, rphy);
> +	if (tgtdev) {
> +		rc = tgtdev->slot;
> +		mpi3mr_tgtdev_put(tgtdev);
> +	} else
> +		rc = -ENXIO;
> +	spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
> +
> +	return rc;
> +}
> +
> +/* phy control request structure */
> +struct phy_control_request {
> +	u8 smp_frame_type; /* 0x40 */
> +	u8 function; /* 0x91 */
> +	u8 allocated_response_length;
> +	u8 request_length; /* 0x09 */
> +	u16 expander_change_count;
> +	u8 reserved_1[3];
> +	u8 phy_identifier;
> +	u8 phy_operation;
> +	u8 reserved_2[13];
> +	u64 attached_device_name;
> +	u8 programmed_min_physical_link_rate;
> +	u8 programmed_max_physical_link_rate;
> +	u8 reserved_3[6];
> +};
> +
> +/* phy control reply structure */
> +struct phy_control_reply {
> +	u8 smp_frame_type; /* 0x41 */
> +	u8 function; /* 0x11 */
> +	u8 function_result;
> +	u8 response_length;
> +};
> +
> +#define SMP_PHY_CONTROL_LINK_RESET	(0x01)
> +#define SMP_PHY_CONTROL_HARD_RESET	(0x02)
> +#define SMP_PHY_CONTROL_DISABLE		(0x03)
> +
> +/**
> + * mpi3mr_expander_phy_control - expander phy control
> + * @mrioc: Adapter instance reference
> + * @phy: The SAS transport layer phy object
> + * @phy_operation: The phy operation to be executed
> + *
> + * Issues SMP passthru phy control request to execute a specific
> + * phy operation for a given expander device.
> + *
> + * Return: 0 for success, non-zero for failure.
> + *
remove extra newline in comment. 

> + */
> +static int
> +mpi3mr_expander_phy_control(struct mpi3mr_ioc *mrioc,
> +	struct sas_phy *phy, u8 phy_operation)
> +{
> +	struct mpi3_smp_passthrough_request mpi_request;
> +	struct mpi3_smp_passthrough_reply mpi_reply;
> +	struct phy_control_request *phy_control_request;
> +	struct phy_control_reply *phy_control_reply;
> +	int rc;
> +	void *psge;
> +	void *data_out = NULL;
> +	dma_addr_t data_out_dma;
> +	dma_addr_t data_in_dma;
> +	size_t data_in_sz;
> +	size_t data_out_sz;
> +	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
> +	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
> +	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
> +	u16 ioc_status;
> +	u16 sz;
> +
> +	if (mrioc->reset_in_progress) {
> +		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
> +		return -EFAULT;
> +	}
> +
> +
Remove extra newline

> +	data_out_sz = sizeof(struct phy_control_request);
> +	data_in_sz = sizeof(struct phy_control_reply);
> +	sz = data_out_sz + data_in_sz;
> +	data_out = dma_alloc_coherent(&mrioc->pdev->dev, sz, &data_out_dma,
> +	    GFP_KERNEL);
> +	if (!data_out) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
> +	data_in_dma = data_out_dma + data_out_sz;
> +	phy_control_reply = data_out + data_out_sz;
> +
> +	rc = -EINVAL;
> +	memset(data_out, 0, sz);
> +
> +	phy_control_request = data_out;
> +	phy_control_request->smp_frame_type = 0x40;
> +	phy_control_request->function = 0x91;
> +	phy_control_request->request_length = 9;
> +	phy_control_request->allocated_response_length = 0;
> +	phy_control_request->phy_identifier = phy->number;
> +	phy_control_request->phy_operation = phy_operation;
> +	phy_control_request->programmed_min_physical_link_rate =
> +	    phy->minimum_linkrate << 4;
> +	phy_control_request->programmed_max_physical_link_rate =
> +	    phy->maximum_linkrate << 4;
> +
> +	memset(&mpi_request, 0, request_sz);
> +	memset(&mpi_reply, 0, reply_sz);
> +	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
> +	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
> +	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_sas_phy(phy);
> +	mpi_request.sas_address = cpu_to_le64(phy->identify.sas_address);
> +
> +	psge = &mpi_request.request_sge;
> +	mpi3mr_add_sg_single(psge, sgl_flags, data_out_sz, data_out_dma);
> +
> +	psge = &mpi_request.response_sge;
> +	mpi3mr_add_sg_single(psge, sgl_flags, data_in_sz, data_in_dma);
> +
> +	dprint_transport_info(mrioc,
> +	    "sending phy control SMP request to sas_address(0x%016llx), phy_id(%d) opcode(%d)\n",
> +	    (unsigned long long)phy->identify.sas_address, phy->number,
> +	    phy_operation);
> +
> +	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
> +	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
> +		goto out;
> +
> +	dprint_transport_info(mrioc,
> +	    "phy control SMP request completed with ioc_status(0x%04x)\n",
> +	    ioc_status);
> +
> +
Remove extra newline

> +	if (ioc_status == MPI3_IOCSTATUS_SUCCESS) {
> +		dprint_transport_info(mrioc,
> +		    "phy control - reply data transfer size(%d)\n",
> +		    le16_to_cpu(mpi_reply.response_data_length));
> +
> +		if (le16_to_cpu(mpi_reply.response_data_length) !=
> +		    sizeof(struct phy_control_reply))
> +			goto out;
> +		dprint_transport_info(mrioc,
> +		    "phy control - function_result(%d)\n",
> +		    phy_control_reply->function_result);
> +		rc = 0;
> +	}
> + out:
> +	if (data_out)
> +		dma_free_coherent(&mrioc->pdev->dev, sz, data_out,
> +		    data_out_dma);
> +
> +	return rc;
> +}
> +
> +/**
> + * mpi3mr_transport_phy_reset - Reset a given phy
> + * @phy: The SAS transport layer phy object
> + * @hard_reset: Flag to indicate the type of reset
> + *
> + * Return: 0 for success, non-zero for failure.
> + */
> +static int
> +mpi3mr_transport_phy_reset(struct sas_phy *phy, int hard_reset)
> +{
> +	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
> +	struct mpi3_iounit_control_request mpi_request;
> +	struct mpi3_iounit_control_reply mpi_reply;
> +	u16 request_sz = sizeof(struct mpi3_iounit_control_request);
> +	u16 reply_sz = sizeof(struct mpi3_iounit_control_reply);
> +	int rc = 0;
> +	u16 ioc_status;
> +
> +	rc = mpi3mr_parent_present(mrioc, phy);
> +	if (rc)
> +		return rc;
> +
> +	/* handle expander phys */
> +	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
> +		return mpi3mr_expander_phy_control(mrioc, phy,
> +		    (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
> +		    SMP_PHY_CONTROL_LINK_RESET);
> +
> +	/* handle hba phys */
> +	memset(&mpi_request, 0, request_sz);
> +	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
> +	mpi_request.function = MPI3_FUNCTION_IO_UNIT_CONTROL;
> +	mpi_request.operation = MPI3_CTRL_OP_SAS_PHY_CONTROL;
> +	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_ACTION_INDEX] =
> +		(hard_reset ? MPI3_CTRL_ACTION_HARD_RESET :
> +		 MPI3_CTRL_ACTION_LINK_RESET);
> +	mpi_request.param8[MPI3_CTRL_OP_SAS_PHY_CONTROL_PARAM8_PHY_INDEX] =
> +		phy->number;
> +
> +	dprint_transport_info(mrioc,
> +	    "sending phy reset request to sas_address(0x%016llx), phy_id(%d) hard_reset(%d)\n",
> +	    (unsigned long long)phy->identify.sas_address, phy->number,
> +	    hard_reset);
> +
> +	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
> +	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status)) {
> +		rc = -EAGAIN;
> +		goto out;
> +	}
> +
> +	dprint_transport_info(mrioc,
> +	    "phy reset request completed with ioc_status(0x%04x)\n",
> +	    ioc_status);
> +out:
> +	return rc;
> +}
> +
> +/**
> + * mpi3mr_transport_phy_enable - enable/disable phys
> + * @phy: The SAS transport layer phy object
> + * @enable: flag to enable/disable, enable phy when true
> + *
> + * This function enables/disables a given by executing required
> + * configuration page changes or expander phy control command
> + *
> + * Return: 0 for success, non-zero for failure.
> + */
> +static int
> +mpi3mr_transport_phy_enable(struct sas_phy *phy, int enable)
> +{
> +	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
> +	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
> +	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
> +	u16 sz;
> +	int rc = 0;
> +	int i, discovery_active;
> +
> +	rc = mpi3mr_parent_present(mrioc, phy);
> +	if (rc)
> +		return rc;
> +
> +	/* handle expander phys */
> +	if (phy->identify.sas_address != mrioc->sas_hba.sas_address)
> +		return mpi3mr_expander_phy_control(mrioc, phy,
> +		    (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
> +		    SMP_PHY_CONTROL_DISABLE);
> +
> +	/* handle hba phys */
> +
> +	/* read sas_iounit page 0 */
> +	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) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +	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__);
> +		rc = -ENXIO;
> +		goto out;
> +	}
> +
> +	/* unable to enable/disable phys when discovery is active */
> +	for (i = 0, discovery_active = 0; i < mrioc->sas_hba.num_phys ; i++) {
> +		if (sas_io_unit_pg0->phy_data[i].port_flags &
> +		    MPI3_SASIOUNIT0_PORTFLAGS_DISC_IN_PROGRESS) {
> +			ioc_err(mrioc,
> +			    "discovery is active on port = %d, phy = %d\n"
> +			    "\tunable to enable/disable phys, try again later!\n",
> +			    sas_io_unit_pg0->phy_data[i].io_unit_port, i);
> +			discovery_active = 1;
> +		}
> +	}
> +
> +	if (discovery_active) {
> +		rc = -EAGAIN;
> +		goto out;
> +	}
> +
> +	if ((sas_io_unit_pg0->phy_data[phy->number].phy_flags &
> +	     (MPI3_SASIOUNIT0_PHYFLAGS_HOST_PHY |
> +	      MPI3_SASIOUNIT0_PHYFLAGS_VIRTUAL_PHY))) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		rc = -ENXIO;
> +		goto out;
> +	}
> +
> +
Remove newline

> +	/* read sas_iounit page 1 */
> +	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
> +		(mrioc->sas_hba.num_phys *
> +		 sizeof(struct mpi3_sas_io_unit1_phy_data));
> +	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
> +	if (!sas_io_unit_pg1) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
> +	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		rc = -ENXIO;
> +		goto out;
> +	}
> +
> +	if (enable)
> +		sas_io_unit_pg1->phy_data[phy->number].phy_flags
> +		    &= ~MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
> +	else
> +		sas_io_unit_pg1->phy_data[phy->number].phy_flags
> +		    |= MPI3_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
> +
> +	mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz);
> +
> +	/* link reset */
> +	if (enable)
> +		mpi3mr_transport_phy_reset(phy, 0);
> +
> + out:
> +	kfree(sas_io_unit_pg1);
> +	kfree(sas_io_unit_pg0);
> +	return rc;
> +}
> +
> +/**
> + * mpi3mr_transport_phy_speed - set phy min/max speed
> + * @phy: The SAS transport later phy object
> + * @rates: Rates defined as in sas_phy_linkrates
> + *
> + * This function sets the link rates given in the rates
> + * argument to the given phy by executing required configuration
> + * page changes or expander phy control command
> + *
> + * Return: 0 for success, non-zero for failure.
> + */
> +static int
> +mpi3mr_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
> +{
> +
Remove newline here 
 
> +	struct mpi3mr_ioc *mrioc = phy_to_mrioc(phy);
> +	struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1 = NULL;
> +	struct mpi3_sas_phy_page0 phy_pg0;
> +	u16 sz, ioc_status;
> +	int rc = 0;
> +
> +	rc = mpi3mr_parent_present(mrioc, phy);
> +	if (rc)
> +		return rc;
> +
> +	if (!rates->minimum_linkrate)
> +		rates->minimum_linkrate = phy->minimum_linkrate;
> +	else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
> +		rates->minimum_linkrate = phy->minimum_linkrate_hw;
> +
> +	if (!rates->maximum_linkrate)
> +		rates->maximum_linkrate = phy->maximum_linkrate;
> +	else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
> +		rates->maximum_linkrate = phy->maximum_linkrate_hw;
> +
> +	/* handle expander phys */
> +	if (phy->identify.sas_address != mrioc->sas_hba.sas_address) {
> +		phy->minimum_linkrate = rates->minimum_linkrate;
> +		phy->maximum_linkrate = rates->maximum_linkrate;
> +		return mpi3mr_expander_phy_control(mrioc, phy,
> +		    SMP_PHY_CONTROL_LINK_RESET);
> +	}
> +
> +	/* handle hba phys */
> +
Looks like missing code chunk or stray comment. 

> +	/* sas_iounit page 1 */
> +	sz = offsetof(struct mpi3_sas_io_unit_page1, phy_data) +
> +		(mrioc->sas_hba.num_phys *
> +		 sizeof(struct mpi3_sas_io_unit1_phy_data));
> +	sas_io_unit_pg1 = kzalloc(sz, GFP_KERNEL);
> +	if (!sas_io_unit_pg1) {
> +		rc = -ENOMEM;
> +		goto out;
> +	}
> +
> +	if (mpi3mr_cfg_get_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		rc = -ENXIO;
> +		goto out;
> +	}
> +
> +	sas_io_unit_pg1->phy_data[phy->number].max_min_link_rate =
> +		(rates->minimum_linkrate + (rates->maximum_linkrate << 4));
> +
> +	if (mpi3mr_cfg_set_sas_io_unit_pg1(mrioc, sas_io_unit_pg1, sz)) {
> +		ioc_err(mrioc, "failure at %s:%d/%s()!\n",
> +		    __FILE__, __LINE__, __func__);
> +		rc = -ENXIO;
> +		goto out;
> +	}
> +
> +	/* link reset */
> +	mpi3mr_transport_phy_reset(phy, 0);
> +
> +	/* read phy page 0, then update the rates in the sas transport phy */
> +	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, phy->number) &&
> +	    (ioc_status == MPI3_IOCSTATUS_SUCCESS)) {
> +		phy->minimum_linkrate = mpi3mr_convert_phy_link_rate(
> +		    phy_pg0.programmed_link_rate &
> +		    MPI3_SAS_PRATE_MIN_RATE_MASK);
> +		phy->maximum_linkrate = mpi3mr_convert_phy_link_rate(
> +		    phy_pg0.programmed_link_rate >> 4);
> +		phy->negotiated_linkrate =
> +			mpi3mr_convert_phy_link_rate(
> +			    (phy_pg0.negotiated_link_rate &
> +			    MPI3_SAS_NEG_LINK_RATE_LOGICAL_MASK)
> +			    >> MPI3_SAS_NEG_LINK_RATE_LOGICAL_SHIFT);
> +	}
> +
> +out:
> +	kfree(sas_io_unit_pg1);
> +	return rc;
> +}
> +
> +
remove extra newline
> +/**
> + * mpi3mr_map_smp_buffer - map BSG dma buffer
> + * @dev: Generic device reference
> + * @buf: BSG buffer pointer
> + * @dma_addr: Physical address holder
> + * @dma_len: Mapped DMA buffer length.
> + * @p: Virtual address holder
> + *
> + * This function maps the DMAable buffer
> + *
> + * Return: 0 on success, non-zero on failure
> + */
> +
remove extra newline
> +static int
> +mpi3mr_map_smp_buffer(struct device *dev, struct bsg_buffer *buf,
> +		dma_addr_t *dma_addr, size_t *dma_len, void **p)
> +{
> +	/* Check if the request is split across multiple segments */
> +	if (buf->sg_cnt > 1) {
> +		*p = dma_alloc_coherent(dev, buf->payload_len, dma_addr,
> +				GFP_KERNEL);
> +		if (!*p)
> +			return -ENOMEM;
> +		*dma_len = buf->payload_len;
> +	} else {
> +		if (!dma_map_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL))
> +			return -ENOMEM;
> +		*dma_addr = sg_dma_address(buf->sg_list);
> +		*dma_len = sg_dma_len(buf->sg_list);
> +		*p = NULL;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * mpi3mr_unmap_smp_buffer - unmap BSG dma buffer
> + * @dev: Generic device reference
> + * @buf: BSG buffer pointer
> + * @dma_addr: Physical address to be unmapped
> + * @p: Virtual address
> + *
> + * This function unmaps the DMAable buffer
> + */
> +
> +static void
> +mpi3mr_unmap_smp_buffer(struct device *dev, struct bsg_buffer *buf,
> +		dma_addr_t dma_addr, void *p)
> +{
> +	if (p)
> +		dma_free_coherent(dev, buf->payload_len, p, dma_addr);
> +	else
> +		dma_unmap_sg(dev, buf->sg_list, 1, DMA_BIDIRECTIONAL);
> +}
> +
> +/**
> + * mpi3mr_transport_smp_handler - handler for smp passthru
> + * @job: BSG job reference
> + * @shost: SCSI host object reference
> + * @rphy: SAS transport rphy object pointing the expander
> + *
> + * This is used primarily by smp utils for sending the SMP
> + * commands to the expanders attached to the controller
> + */
> +static void
> +mpi3mr_transport_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
> +	struct sas_rphy *rphy)
> +{
> +
Remove extra newline

> +	struct mpi3mr_ioc *mrioc = shost_priv(shost);
> +	struct mpi3_smp_passthrough_request mpi_request;
> +	struct mpi3_smp_passthrough_reply mpi_reply;
> +	int rc;
> +	void *psge;
> +	dma_addr_t dma_addr_in;
> +	dma_addr_t dma_addr_out;
> +	void *addr_in = NULL;
> +	void *addr_out = NULL;
> +	size_t dma_len_in;
> +	size_t dma_len_out;
> +	unsigned int reslen = 0;
> +	u16 request_sz = sizeof(struct mpi3_smp_passthrough_request);
> +	u16 reply_sz = sizeof(struct mpi3_smp_passthrough_reply);
> +	u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
> +	u16 ioc_status;
> +
> +
Ditto remove extra newline

> +	if (mrioc->reset_in_progress) {
> +		ioc_err(mrioc, "%s: host reset in progress!\n", __func__);
> +		rc = -EFAULT;
> +		goto out;
> +	}
> +
> +	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
> +	    &dma_addr_out, &dma_len_out, &addr_out);
> +	if (rc)

> +		goto out;
> +
> +	if (addr_out)
> +		sg_copy_to_buffer(job->request_payload.sg_list,
> +		    job->request_payload.sg_cnt, addr_out,
> +		    job->request_payload.payload_len);
> +
> +	rc = mpi3mr_map_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
> +			&dma_addr_in, &dma_len_in, &addr_in);
> +	if (rc)
> +		goto unmap_out;
> +
> +	memset(&mpi_request, 0, request_sz);
> +	memset(&mpi_reply, 0, reply_sz);
> +	mpi_request.host_tag = cpu_to_le16(MPI3MR_HOSTTAG_TRANSPORT_CMDS);
> +	mpi_request.function = MPI3_FUNCTION_SMP_PASSTHROUGH;
> +	mpi_request.io_unit_port = (u8) mpi3mr_get_port_id_by_rphy(mrioc, rphy);
> +	mpi_request.sas_address = ((rphy) ?
> +	    cpu_to_le64(rphy->identify.sas_address) :
> +	    cpu_to_le64(mrioc->sas_hba.sas_address));
> +	psge = &mpi_request.request_sge;
> +	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_out - 4, dma_addr_out);
> +
> +	psge = &mpi_request.response_sge;
> +	mpi3mr_add_sg_single(psge, sgl_flags, dma_len_in - 4, dma_addr_in);
> +
> +
remove newline

> +	dprint_transport_info(mrioc, "sending SMP request\n");
> +
> +	if (mpi3mr_post_transport_req(mrioc, &mpi_request, request_sz,
> +	    &mpi_reply, reply_sz, MPI3MR_INTADMCMD_TIMEOUT, &ioc_status))
> +		goto unmap_in;
> +
> +	dprint_transport_info(mrioc,
> +	    "SMP request completed with ioc_status(0x%04x)\n", ioc_status);
> +
> +
Ditto same here ... remove newline

> +	dprint_transport_info(mrioc,
> +		    "SMP request - reply data transfer size(%d)\n",
> +		    le16_to_cpu(mpi_reply.response_data_length));
> +
> +	memcpy(job->reply, &mpi_reply, reply_sz);
> +	job->reply_len = reply_sz;
> +	reslen = le16_to_cpu(mpi_reply.response_data_length);
> +
> +	if (addr_in)
> +		sg_copy_from_buffer(job->reply_payload.sg_list,
> +				job->reply_payload.sg_cnt, addr_in,
> +				job->reply_payload.payload_len);
> +
> +	rc = 0;
> +unmap_in:
> +	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->reply_payload,
> +			dma_addr_in, addr_in);
> +unmap_out:
> +	mpi3mr_unmap_smp_buffer(&mrioc->pdev->dev, &job->request_payload,
> +			dma_addr_out, addr_out);
> +out:
> +	bsg_job_done(job, rc, reslen);
> +
remove newline

> +}
> +
> +struct sas_function_template mpi3mr_transport_functions = {
> +	.get_linkerrors		= mpi3mr_transport_get_linkerrors,
> +	.get_enclosure_identifier = mpi3mr_transport_get_enclosure_identifier,
> +	.get_bay_identifier	= mpi3mr_transport_get_bay_identifier,
> +	.phy_reset		= mpi3mr_transport_phy_reset,
> +	.phy_enable		= mpi3mr_transport_phy_enable,
> +	.set_phy_speed		= mpi3mr_transport_phy_speed,
> +	.smp_handler		= mpi3mr_transport_smp_handler,
> +};
> +
> +struct scsi_transport_template *mpi3mr_transport_template;
> -- 
> 2.27.0
> 

After fixing all nits of formatting, you can add 

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 14/15] mpi3mr: Refresh sas ports during soft reset
  2022-07-29 13:16 ` [PATCH 14/15] mpi3mr: Refresh sas ports during soft reset Sreekanth Reddy
@ 2022-08-02 21:00   ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-08-02 21:00 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> - Update the Host's sas ports if there is change in port id
> or phys. If the port id is changed then the driver updates
> the same. If some phys are enabled/disabled during reset then
> driver updates the same in STL.
> 
> - Check for the responding expander devices and update the
> device handle if it got changed. Register the expander with
> STL if it got added during reset and unregister the
> expander device if it got removed during reset.
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr.h           |  11 +
> drivers/scsi/mpi3mr/mpi3mr_fw.c        |  10 +-
> drivers/scsi/mpi3mr/mpi3mr_os.c        |  50 ++++
> drivers/scsi/mpi3mr/mpi3mr_transport.c | 351 +++++++++++++++++++++++++
> 4 files changed, 421 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
> index d203167..0f47b45 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr.h
> +++ b/drivers/scsi/mpi3mr/mpi3mr.h
> @@ -482,6 +482,9 @@ struct mpi3mr_hba_port {
>  * struct mpi3mr_sas_port - Internal SAS port information
>  * @port_list: List of ports belonging to a SAS node
>  * @num_phys: Number of phys associated with port
> + * @marked_responding: used while refresing the sas ports
> + * @lowest_phy: lowest phy ID of current sas port
> + * @phy_mask: phy_mask of current sas port
>  * @hba_port: HBA port entry
>  * @remote_identify: Attached device identification
>  * @rphy: SAS transport layer rphy object
> @@ -491,6 +494,9 @@ struct mpi3mr_hba_port {
> struct mpi3mr_sas_port {
> 	struct list_head port_list;
> 	u8 num_phys;
> +	u8 marked_responding;
> +	int lowest_phy;
> +	u32 phy_mask;
> 	struct mpi3mr_hba_port *hba_port;
> 	struct sas_identify remote_identify;
> 	struct sas_rphy *rphy;
> @@ -939,6 +945,7 @@ struct scmd_priv {
>  * @scan_started: Async scan started
>  * @scan_failed: Asycn scan failed
>  * @stop_drv_processing: Stop all command processing
> + * @device_refresh_on: Don't process the events until devices are refreshed
>  * @max_host_ios: Maximum host I/O count
>  * @chain_buf_count: Chain buffer count
>  * @chain_buf_pool: Chain buffer pool
> @@ -1107,6 +1114,7 @@ struct mpi3mr_ioc {
> 	u8 scan_started;
> 	u16 scan_failed;
> 	u8 stop_drv_processing;
> +	u8 device_refresh_on;
> 
> 	u16 max_host_ios;
> 	spinlock_t tgtdev_lock;
> @@ -1378,4 +1386,7 @@ struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy(
> 	struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy);
> void mpi3mr_print_device_event_notice(struct mpi3mr_ioc *mrioc,
> 	bool device_add);
> +void mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc);
> +void mpi3mr_refresh_expanders(struct mpi3mr_ioc *mrioc);
> +void mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc);
> #endif /*MPI3MR_H_INCLUDED*/
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> index 59ef373..dfb7570 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
> @@ -3977,6 +3977,11 @@ retry_init:
> 		goto out_failed;
> 	}
> 
> +	if (!is_resume) {
> +		mrioc->device_refresh_on = 1;
> +		mpi3mr_add_event_wait_for_device_refresh(mrioc);
> +	}
> +
> 	ioc_info(mrioc, "sending port enable\n");
> 	retval = mpi3mr_issue_port_enable(mrioc, 0);
> 	if (retval) {
> @@ -4733,6 +4738,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
> 	ioc_info(mrioc, "controller reset is triggered by %s\n",
> 	    mpi3mr_reset_rc_name(reset_reason));
> 
> +	mrioc->device_refresh_on = 0;
> 	mrioc->reset_in_progress = 1;
> 	mrioc->stop_bsgs = 1;
> 	mrioc->prev_reset_result = -1;
> @@ -4814,7 +4820,8 @@ out:
> 			mpi3mr_pel_wait_post(mrioc, &mrioc->pel_cmds);
> 		}
> 
> -		mpi3mr_rfresh_tgtdevs(mrioc);
> +		mrioc->device_refresh_on = 0;
> +
> 		mrioc->ts_update_counter = 0;
> 		spin_lock_irqsave(&mrioc->watchdog_lock, flags);
> 		if (mrioc->watchdog_work_q)
> @@ -4828,6 +4835,7 @@ out:
> 	} else {
> 		mpi3mr_issue_reset(mrioc,
> 		    MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
> +		mrioc->device_refresh_on = 0;
> 		mrioc->unrecoverable = 1;
> 		mrioc->reset_in_progress = 0;
> 		retval = -1;
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index 139c164..d4f37b1 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -40,6 +40,8 @@ static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
> 
> #define MPI3MR_DRIVER_EVENT_TG_QD_REDUCTION	(0xFFFF)
> 
> +#define MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH	(0xFFFE)
> +
> /**
>  * mpi3mr_host_tag_for_scmd - Get host tag for a scmd
>  * @mrioc: Adapter instance reference
> @@ -1114,6 +1116,9 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
> 		    MPI3_DEVICE0_FLAGS_ATT_METHOD_VIRTUAL)) ||
> 		    (tgtdev->parent_handle == 0xFFFF))
> 			tgtdev->non_stl = 1;
> +		if (tgtdev->dev_spec.sas_sata_inf.hba_port)
> +			tgtdev->dev_spec.sas_sata_inf.hba_port->port_id =
> +			    dev_pg0->io_unit_port;
> 		break;
> 	}
> 	case MPI3_DEVICE_DEVFORM_PCIE:
> @@ -1886,6 +1891,22 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
> 		}
> 		break;
> 	}
> +	case MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH:
> +	{
> +		while (mrioc->device_refresh_on)
> +			msleep(500);
> +
> +		dprint_event_bh(mrioc,
> +		    "scan for non responding and newly added devices after soft reset started\n");
> +		if (mrioc->sas_transport_enabled) {
> +			mpi3mr_refresh_sas_ports(mrioc);
> +			mpi3mr_refresh_expanders(mrioc);
> +		}
> +		mpi3mr_rfresh_tgtdevs(mrioc);
> +		ioc_info(mrioc,
> +		    "scan for non responding and newly added devices after soft reset completed\n");
> +		break;
> +	}
> 	default:
> 		break;
> 	}
> @@ -2655,6 +2676,35 @@ static void mpi3mr_cablemgmt_evt_th(struct mpi3mr_ioc *mrioc,
> 	}
> }
> 
> +/**
> + * mpi3mr_add_event_wait_for_device_refresh - Add Wait for Device Refresh Event
> + * @mrioc: Adapter instance reference
> + *
> + * Add driver specific event to make sure that the driver won't process the
> + * events until all the devices are refreshed during soft reset.
> + *
> + * Return: Nothing
> + */
> +void mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc)
> +{
> +	struct mpi3mr_fwevt *fwevt = NULL;
> +
> +	fwevt = mpi3mr_alloc_fwevt(0);
> +	if (!fwevt) {
> +		dprint_event_th(mrioc,
> +		    "failed to schedule bottom half handler for event(0x%02x)\n",
> +		    MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH);
> +		return;
> +	}
> +	fwevt->mrioc = mrioc;
> +	fwevt->event_id = MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH;
> +	fwevt->send_ack = 0;
> +	fwevt->process_evt = 1;
> +	fwevt->evt_ctx = 0;
> +	fwevt->event_data_size = 0;
> +	mpi3mr_fwevt_add_to_list(mrioc, fwevt);
> +}
> +
> /**
>  * mpi3mr_os_handle_events - Firmware event handler
>  * @mrioc: Adapter instance reference
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> index e8a9a76..c1ca97c 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c
> @@ -9,6 +9,9 @@
> 
> #include "mpi3mr.h"
> 
> +static void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
> +	struct mpi3mr_sas_node *sas_expander);
> +
> /**
>  * mpi3mr_post_transport_req - Issue transport requests and wait
>  * @mrioc: Adapter instance reference
> @@ -597,6 +600,9 @@ static void mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc,
> 
> 	list_del(&mr_sas_phy->port_siblings);
> 	mr_sas_port->num_phys--;
> +	mr_sas_port->phy_mask &= ~(1 << mr_sas_phy->phy_id);
> +	if (mr_sas_port->lowest_phy == mr_sas_phy->phy_id)
> +		mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
> 	sas_port_delete_phy(mr_sas_port->port, mr_sas_phy->phy);
> 	mr_sas_phy->phy_belongs_to_port = 0;
> }
> @@ -621,6 +627,9 @@ static void mpi3mr_add_sas_phy(struct mpi3mr_ioc *mrioc,
> 
> 	list_add_tail(&mr_sas_phy->port_siblings, &mr_sas_port->phy_list);
> 	mr_sas_port->num_phys++;
> +	mr_sas_port->phy_mask |= (1 << mr_sas_phy->phy_id);
> +	if (mr_sas_phy->phy_id < mr_sas_port->lowest_phy)
> +		mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
> 	sas_port_add_phy(mr_sas_port->port, mr_sas_phy->phy);
> 	mr_sas_phy->phy_belongs_to_port = 1;
> }
> @@ -1356,6 +1365,7 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
> 		list_add_tail(&mr_sas_node->phy[i].port_siblings,
> 		    &mr_sas_port->phy_list);
> 		mr_sas_port->num_phys++;
> +		mr_sas_port->phy_mask |= (1 << i);
> 	}
> 
> 	if (!mr_sas_port->num_phys) {
> @@ -1364,6 +1374,8 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
> 		goto out_fail;
> 	}
> 
> +	mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
> +
> 	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,
> @@ -1565,6 +1577,345 @@ static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
> 	kfree(mr_sas_port);
> }
> 
> +/**
> + * struct host_port - host port details
> + * @sas_address: SAS Address of the attached device
> + * @phy_mask: phy mask of host port
> + * @handle: Device Handle of attached device
> + * @iounit_port_id: port ID
> + * @used: host port is already matched with sas port from sas_port_list
> + * @lowest_phy: lowest phy ID of host port
> + */
> +struct host_port {
> +	u64	sas_address;
> +	u32	phy_mask;
> +	u16	handle;
> +	u8	iounit_port_id;
> +	u8	used;
> +	u8	lowest_phy;
> +};
> +
> +/**
> + * mpi3mr_update_mr_sas_port - update sas port objects during reset
> + * @mrioc: Adapter instance reference
> + * @h_port: host_port object
> + * @mr_sas_port: sas_port objects which needs to be updated
> + *
> + * Update the port ID of sas port object. Also add the phys if new phys got
> + * added to current sas port and remove the phys if some phys are moved
> + * out of the current sas port.
> + *
> + * Return: Nothing.
> + */
> +static void
> +mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port,
> +	struct mpi3mr_sas_port *mr_sas_port)
> +{
> +	struct mpi3mr_sas_phy *mr_sas_phy;
> +	u32 phy_mask_xor, phys_to_be_added, phys_to_be_removed;
> +	int i;
> +
> +	h_port->used = 1;
> +	mr_sas_port->marked_responding = 1;
> +
> +	dev_info(&mr_sas_port->port->dev,
> +	    "sas_address(0x%016llx), old: port_id %d phy_mask 0x%x, new: port_id %d phy_mask:0x%x\n",
> +	    mr_sas_port->remote_identify.sas_address,
> +	    mr_sas_port->hba_port->port_id, mr_sas_port->phy_mask,
> +	    h_port->iounit_port_id, h_port->phy_mask);
> +
> +	mr_sas_port->hba_port->port_id = h_port->iounit_port_id;
> +	mr_sas_port->hba_port->flags &= ~MPI3MR_HBA_PORT_FLAG_DIRTY;
> +
> +	/* Get the newly added phys bit map & removed phys bit map */
> +	phy_mask_xor = mr_sas_port->phy_mask ^ h_port->phy_mask;
> +	phys_to_be_added = h_port->phy_mask & phy_mask_xor;
> +	phys_to_be_removed = mr_sas_port->phy_mask & phy_mask_xor;
> +
> +	/*
> +	 * Register these new phys to current mr_sas_port's port.
> +	 * if these phys are previously registered with another port
> +	 * then delete these phys from that port first.
> +	 */
> +	for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u32)) {
> +		mr_sas_phy = &mrioc->sas_hba.phy[i];
> +		if (mr_sas_phy->phy_belongs_to_port)
> +			mpi3mr_del_phy_from_an_existing_port(mrioc,
> +			    &mrioc->sas_hba, mr_sas_phy);
> +		mpi3mr_add_phy_to_an_existing_port(mrioc,
> +		    &mrioc->sas_hba, mr_sas_phy,
> +		    mr_sas_port->remote_identify.sas_address,
> +		    mr_sas_port->hba_port);
> +	}
> +
> +	/* Delete the phys which are not part of current mr_sas_port's port. */
> +	for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u32)) {
> +		mr_sas_phy = &mrioc->sas_hba.phy[i];
> +		if (mr_sas_phy->phy_belongs_to_port)
> +			mpi3mr_del_phy_from_an_existing_port(mrioc,
> +			    &mrioc->sas_hba, mr_sas_phy);
> +	}
> +}
> +
> +/**
> + * mpi3mr_refresh_sas_ports - update host's sas ports during reset
> + * @mrioc: Adapter instance reference
> + *
> + * Update the host's sas ports during reset by checking whether
> + * sas ports are still intact or not. Add/remove phys if any hba
> + * phys are (moved in)/(moved out) of sas port. Also update
> + * io_unit_port if it got changed during reset.
> + *
> + * Return: Nothing.
> + */
> +void
> +mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)
> +{
> +	struct host_port h_port[32];
> +	int i, j, found, host_port_count = 0, port_idx;
> +	u16 sz, attached_handle, ioc_status;
> +	struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
> +	struct mpi3_device_page0 dev_pg0;
> +	struct mpi3_device0_sas_sata_format *sasinf;
> +	struct mpi3mr_sas_port *mr_sas_port;
> +
> +	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;
> +	}
> +
> +	/* Create a new expander port table */
> +	for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
> +		attached_handle = le16_to_cpu(
> +		    sas_io_unit_pg0->phy_data[i].attached_dev_handle);
> +		if (!attached_handle)
> +			continue;
> +		found = 0;
> +		for (j = 0; j < host_port_count; j++) {
> +			if (h_port[j].handle == attached_handle) {
> +				h_port[j].phy_mask |= (1 << i);
> +				found = 1;
> +				break;
> +			}
> +		}
> +		if (found)
> +			continue;
> +		if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
> +		    sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
> +		    attached_handle))) {
> +			dprint_reset(mrioc,
> +			    "failed to read dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
> +			    attached_handle, __FILE__, __LINE__, __func__);
> +			continue;
> +		}
> +		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +			dprint_reset(mrioc,
> +			    "ioc_status(0x%x) while reading dev_pg0 for handle(0x%04x) at %s:%d/%s()!\n",
> +			    ioc_status, attached_handle,
> +			    __FILE__, __LINE__, __func__);
> +			continue;
> +		}
> +		sasinf = &dev_pg0.device_specific.sas_sata_format;
> +
> +		port_idx = host_port_count;
> +		h_port[port_idx].sas_address = le64_to_cpu(sasinf->sas_address);
> +		h_port[port_idx].handle = attached_handle;
> +		h_port[port_idx].phy_mask = (1 << i);
> +		h_port[port_idx].iounit_port_id = sas_io_unit_pg0->phy_data[i].io_unit_port;
> +		h_port[port_idx].lowest_phy = sasinf->phy_num;
> +		h_port[port_idx].used = 0;
> +		host_port_count++;
> +	}
> +
> +	if (!host_port_count)
> +		goto out;
> +
> +	if (mrioc->logging_level & MPI3_DEBUG_RESET) {
> +		ioc_info(mrioc, "Host port details before reset\n");
> +		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
> +		    port_list) {
> +			ioc_info(mrioc,
> +			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%x), lowest phy id:%d\n",
> +			    mr_sas_port->hba_port->port_id,
> +			    mr_sas_port->remote_identify.sas_address,
> +			    mr_sas_port->phy_mask, mr_sas_port->lowest_phy);
> +		}
> +		mr_sas_port = NULL;
> +		ioc_info(mrioc, "Host port details after reset\n");
> +		for (i = 0; i < host_port_count; i++) {
> +			ioc_info(mrioc,
> +			    "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%x), lowest phy id:%d\n",
> +			    h_port[i].iounit_port_id, h_port[i].sas_address,
> +			    h_port[i].phy_mask, h_port[i].lowest_phy);
> +		}
> +	}
> +
> +	/* mark all host sas port entries as dirty */
> +	list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
> +	    port_list) {
> +		mr_sas_port->marked_responding = 0;
> +		mr_sas_port->hba_port->flags |= MPI3MR_HBA_PORT_FLAG_DIRTY;
> +	}
> +
> +	/* First check for matching lowest phy */
> +	for (i = 0; i < host_port_count; i++) {
> +		mr_sas_port = NULL;
> +		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
> +		    port_list) {
> +			if (mr_sas_port->marked_responding)
> +				continue;
> +			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
> +				continue;
> +			if (h_port[i].lowest_phy == mr_sas_port->lowest_phy) {
> +				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
> +				break;
> +			}
> +		}
> +	}
> +
> +	/* In case if lowest phy is got enabled or disabled during reset */
> +	for (i = 0; i < host_port_count; i++) {
> +		if (h_port[i].used)
> +			continue;
> +		mr_sas_port = NULL;
> +		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
> +		    port_list) {
> +			if (mr_sas_port->marked_responding)
> +				continue;
> +			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
> +				continue;
> +			if (h_port[i].phy_mask & mr_sas_port->phy_mask) {
> +				mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
> +				break;
> +			}
> +		}
> +	}
> +
> +	/* In case if expander cable is removed & connected to another HBA port during reset */
> +	for (i = 0; i < host_port_count; i++) {
> +		if (h_port[i].used)
> +			continue;
> +		mr_sas_port = NULL;
> +		list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
> +		    port_list) {
> +			if (mr_sas_port->marked_responding)
> +				continue;
> +			if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address)
> +				continue;
> +			mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port);
> +			break;
> +		}
> +	}
> +out:
> +	kfree(sas_io_unit_pg0);
> +}
> +
> +/**
> + * mpi3mr_refresh_expanders - Refresh expander device exposure
> + * @mrioc: Adapter instance reference
> + *
> + * This is executed post controller reset to identify any
> + * missing expander devices during reset and remove from the upper layers
> + * or expose any newly detected expander device to the upper layers.
> + *
> + * Return: Nothing.
> + */
> +void
> +mpi3mr_refresh_expanders(struct mpi3mr_ioc *mrioc)
> +{
> +	struct mpi3mr_sas_node *sas_expander, *sas_expander_next;
> +	struct mpi3_sas_expander_page0 expander_pg0;
> +	u16 ioc_status, handle;
> +	u64 sas_address;
> +	int i;
> +	unsigned long flags;
> +	struct mpi3mr_hba_port *hba_port;
> +
> +	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
> +	list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) {
> +		sas_expander->non_responding = 1;
> +	}
> +	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
> +
> +	sas_expander = NULL;
> +
> +	handle = 0xffff;
> +
> +	/* Search for responding expander devices and add them if they are newly got added */
> +	while (true) {
> +		if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0,
> +		    sizeof(struct mpi3_sas_expander_page0),
> +		    MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
> +			dprint_reset(mrioc,
> +			    "failed to read exp pg0 for handle(0x%04x) at %s:%d/%s()!\n",
> +			    handle, __FILE__, __LINE__, __func__);
> +			break;
> +		}
> +
> +		if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
> +			dprint_reset(mrioc,
> +			   "ioc_status(0x%x) while reading exp pg0 for handle:(0x%04x), %s:%d/%s()!\n",
> +			   ioc_status, handle, __FILE__, __LINE__, __func__);
> +			break;
> +		}
> +
> +		handle = le16_to_cpu(expander_pg0.dev_handle);
> +		sas_address = le64_to_cpu(expander_pg0.sas_address);
> +		hba_port = mpi3mr_get_hba_port_by_id(mrioc, expander_pg0.io_unit_port);
> +
> +		if (!hba_port) {
> +			mpi3mr_sas_host_refresh(mrioc);
> +			mpi3mr_expander_add(mrioc, handle);
> +			continue;
> +		}
> +
> +		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_sas_host_refresh(mrioc);
> +			mpi3mr_expander_add(mrioc, handle);
> +			continue;
> +		}
> +
> +		sas_expander->non_responding = 0;
> +		if (sas_expander->handle == handle)
> +			continue;
> +
> +		sas_expander->handle = handle;
> +		for (i = 0 ; i < sas_expander->num_phys ; i++)
> +			sas_expander->phy[i].handle = handle;
> +	}
> +
> +	/*
> +	 * Delete non responding expander devices and the corresponding
> +	 * hba_port if the non responding expander device's parent device
> +	 * is a host node.
> +	 */
> +
Remove newline here

> +	sas_expander = NULL;
> +	spin_lock_irqsave(&mrioc->sas_node_lock, flags);
> +	list_for_each_entry_safe_reverse(sas_expander, sas_expander_next,
> +	    &mrioc->sas_expander_list, list) {
> +		if (sas_expander->non_responding) {
> +			spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
> +			mpi3mr_expander_node_remove(mrioc, sas_expander);
> +			spin_lock_irqsave(&mrioc->sas_node_lock, flags);
> +		}
> +	}
> +	spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
> +}
> +
> /**
>  * mpi3mr_expander_node_add - insert an expander to the list.
>  * @mrioc: Adapter instance reference
> -- 
> 2.27.0
> 

With the small nits fixed, you can add

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH 15/15] mpi3mr: Block IOs while refreshing target dev objects
  2022-07-29 13:16 ` [PATCH 15/15] mpi3mr: Block IOs while refreshing target dev objects Sreekanth Reddy
@ 2022-08-02 21:12   ` Himanshu Madhani
  0 siblings, 0 replies; 35+ messages in thread
From: Himanshu Madhani @ 2022-08-02 21:12 UTC (permalink / raw)
  To: Sreekanth Reddy; +Cc: linux-scsi, Martin Petersen



> On Jul 29, 2022, at 6:16 AM, Sreekanth Reddy <sreekanth.reddy@broadcom.com> wrote:
> 
> Block the IOs on the target devices until corresponding
> target device's target dev objects are refreshed as part
> of post controller reset operation.
> 
> Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
> ---
> drivers/scsi/mpi3mr/mpi3mr_os.c | 25 +++++++++++++++----------
> 1 file changed, 15 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
> index d4f37b1..c7d9e46 100644
> --- a/drivers/scsi/mpi3mr/mpi3mr_os.c
> +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
> @@ -424,6 +424,8 @@ void mpi3mr_invalidate_devhandles(struct mpi3mr_ioc *mrioc)
> 			tgt_priv->io_throttle_enabled = 0;
> 			tgt_priv->io_divert = 0;
> 			tgt_priv->throttle_group = NULL;
> +			if (tgtdev->host_exposed)
> +				atomic_set(&tgt_priv->block_io, 1);
> 		}
> 	}
> }
> @@ -835,6 +837,7 @@ void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
> 	    __func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
> 	if (tgtdev->starget && tgtdev->starget->hostdata) {
> 		tgt_priv = tgtdev->starget->hostdata;
> +		atomic_set(&tgt_priv->block_io, 0);
> 		tgt_priv->dev_handle = MPI3MR_INVALID_DEV_HANDLE;
> 	}
> 
> @@ -1077,6 +1080,8 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
> 		scsi_tgt_priv_data->dev_type = tgtdev->dev_type;
> 		scsi_tgt_priv_data->io_throttle_enabled =
> 		    tgtdev->io_throttle_enabled;
> +		if (is_added == true)
> +			atomic_set(&scsi_tgt_priv_data->block_io, 0);
> 	}
> 
> 	switch (dev_pg0->access_status) {
> @@ -4576,6 +4581,16 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
> 
> 	stgt_priv_data = sdev_priv_data->tgt_priv_data;
> 
> +	if (atomic_read(&stgt_priv_data->block_io)) {
> +		if (mrioc->stop_drv_processing) {
> +			scmd->result = DID_NO_CONNECT << 16;
> +			scsi_done(scmd);
> +			goto out;
> +		}
> +		retval = SCSI_MLQUEUE_DEVICE_BUSY;
> +		goto out;
> +	}
> +
> 	dev_handle = stgt_priv_data->dev_handle;
> 	if (dev_handle == MPI3MR_INVALID_DEV_HANDLE) {
> 		scmd->result = DID_NO_CONNECT << 16;
> @@ -4588,16 +4603,6 @@ static int mpi3mr_qcmd(struct Scsi_Host *shost,
> 		goto out;
> 	}
> 
> -	if (atomic_read(&stgt_priv_data->block_io)) {
> -		if (mrioc->stop_drv_processing) {
> -			scmd->result = DID_NO_CONNECT << 16;
> -			scsi_done(scmd);
> -			goto out;
> -		}
> -		retval = SCSI_MLQUEUE_DEVICE_BUSY;
> -		goto out;
> -	}
> -
> 	if (stgt_priv_data->dev_type == MPI3_DEVICE_DEVFORM_PCIE)
> 		is_pcie_dev = 1;
> 	if ((scmd->cmnd[0] == UNMAP) && is_pcie_dev &&
> -- 
> 2.27.0
> 

Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>

--
Himanshu Madhani	Oracle Linux Engineering


^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2022-08-02 21:12 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-29 13:16 [PATCH 00/15] mpi3mr: Added Support for SAS Transport Sreekanth Reddy
2022-07-29 13:16 ` [PATCH 01/15] mpi3mr: Add config and transport related debug flags Sreekanth Reddy
2022-07-29 16:59   ` Himanshu Madhani
2022-07-29 13:16 ` [PATCH 02/15] mpi3mr: Add framework to issue cnfg requests Sreekanth Reddy
2022-07-29 17:00   ` Himanshu Madhani
2022-08-01  7:40     ` Sreekanth Reddy
2022-08-01 16:37       ` Himanshu Madhani
2022-07-29 13:16 ` [PATCH 03/15] mpi3mr: Added helper functions to retrieve cnfg pages Sreekanth Reddy
2022-07-29 18:13   ` Himanshu Madhani
2022-07-29 13:16 ` [PATCH 04/15] mpi3mr: Enable Enclosure device add event Sreekanth Reddy
2022-07-29 18:33   ` Himanshu Madhani
2022-07-29 13:16 ` [PATCH 05/15] mpi3mr: Add framework to add phys to STL Sreekanth Reddy
2022-07-29 19:42   ` Himanshu Madhani
2022-08-01  7:46     ` Sreekanth Reddy
2022-07-29 13:16 ` [PATCH 06/15] mpi3mr: Add helper functions to retrieve device objects Sreekanth Reddy
2022-07-29 20:11   ` Himanshu Madhani
2022-08-01  7:48     ` Sreekanth Reddy
2022-07-29 13:16 ` [PATCH 07/15] mpi3mr: Add helper functions to manage device's port Sreekanth Reddy
2022-08-01 19:07   ` Himanshu Madhani
2022-07-29 13:16 ` [PATCH 08/15] mpi3mr: Enable STL on HBAs where multipath is disabled Sreekanth Reddy
2022-08-01 19:12   ` Himanshu Madhani
2022-07-29 13:16 ` [PATCH 09/15] mpi3mr: Add expander devices to STL Sreekanth Reddy
2022-08-01 20:50   ` Himanshu Madhani
2022-07-29 13:16 ` [PATCH 10/15] mpi3mr: Get target object based on rphy Sreekanth Reddy
2022-08-01 21:27   ` Himanshu Madhani
2022-07-29 13:16 ` [PATCH 11/15] mpi3mr: Add SAS SATA end devices to STL Sreekanth Reddy
2022-07-29 17:32   ` kernel test robot
2022-07-29 13:16 ` [PATCH 12/15] mpi3mr: Add framework to issue MPT transport cmds Sreekanth Reddy
2022-08-02  0:13   ` Himanshu Madhani
2022-07-29 13:16 ` [PATCH 13/15] mpi3mr: Support sas transport class callbacks Sreekanth Reddy
2022-08-02 18:11   ` Himanshu Madhani
2022-07-29 13:16 ` [PATCH 14/15] mpi3mr: Refresh sas ports during soft reset Sreekanth Reddy
2022-08-02 21:00   ` Himanshu Madhani
2022-07-29 13:16 ` [PATCH 15/15] mpi3mr: Block IOs while refreshing target dev objects Sreekanth Reddy
2022-08-02 21:12   ` Himanshu Madhani

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.