linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
@ 2014-06-25 10:34 Reddy, Sreekanth
  2014-07-22  3:10 ` Martin K. Petersen
  0 siblings, 1 reply; 20+ messages in thread
From: Reddy, Sreekanth @ 2014-06-25 10:34 UTC (permalink / raw)
  To: jejb, JBottomley, martin.petersen
  Cc: linux-scsi, Sathya.Prakash, Nagalakshmi.Nandigama,
	sreekanth.reddy, linux-kernel, hch

Up to now, Driver allocates a single contiguous block of memory
pool for all reply queues and passes down a single address in the
ReplyDescriptorPostQueueAddress field of the IOC Init Request
Message to the firmware.

When firmware receives this address, it will program each of the
Reply Descriptor Post Queue registers, as each reply queue has its
own register. Thus the firmware, starting from a base address it
determines the starting address of the subsequent reply queues
through some simple arithmetic calculations.

The size of this contiguous block of memory pool is directly proportional
to number of MSI-X vectors and the HBA queue depth. For example higher
MSIX vectors requires larger contiguous block of memory pool.

But some of the OS kernels are unable to allocate this larger
contiguous block of memory pool.

So, the proposal is to allocate memory independently for each
Reply Queue and pass down all of the addresses to the firmware.
Then the firmware will just take each address and program the value
into the correct register.

When HBAs with older firmware(i.e. without RDPQ capability) is used
with this new driver then the max_msix_vectors value would be set
to 8 by default.

Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
---
 drivers/scsi/mpt2sas/mpt2sas_base.c |  923 +++++++++++++++++++++--------------
 drivers/scsi/mpt2sas/mpt2sas_base.h |   18 +-
 2 files changed, 558 insertions(+), 383 deletions(-)

diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 774720f..81f1d58 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -1427,6 +1427,9 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
 	ioc->reply_queue_count = min_t(int, ioc->cpu_count,
 	    ioc->msix_vector_count);
 
+	if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
+		max_msix_vectors = 8;
+
 	if (max_msix_vectors > 0) {
 		ioc->reply_queue_count = min_t(int, max_msix_vectors,
 		    ioc->reply_queue_count);
@@ -1480,6 +1483,335 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
 }
 
 /**
+ * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
+ * a write to the doorbell)
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
+ */
+static int
+_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
+	int sleep_flag)
+{
+	u32 cntdn, count;
+	u32 int_status;
+
+	count = 0;
+	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+	do {
+		int_status = readl(&ioc->chip->HostInterruptStatus);
+		if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
+			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT
+			    "%s: successful count(%d), timeout(%d)\n",
+			    ioc->name, __func__, count, timeout));
+			return 0;
+		}
+		if (sleep_flag == CAN_SLEEP)
+			msleep(1);
+		else
+			udelay(500);
+		count++;
+	} while (--cntdn);
+
+	printk(MPT2SAS_ERR_FMT
+	    "%s: failed due to timeout count(%d), int_status(%x)!\n",
+	    ioc->name, __func__, count, int_status);
+	return -EFAULT;
+}
+
+/**
+ * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to
+ * doorbell.
+ */
+static int
+_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
+	int sleep_flag)
+{
+	u32 cntdn, count;
+	u32 int_status;
+	u32 doorbell;
+
+	count = 0;
+	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+	do {
+		int_status = readl(&ioc->chip->HostInterruptStatus);
+		if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
+			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT
+			    "%s: successful count(%d), timeout(%d)\n",
+			    ioc->name, __func__, count, timeout));
+			return 0;
+		} else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
+			doorbell = readl(&ioc->chip->Doorbell);
+			if ((doorbell & MPI2_IOC_STATE_MASK) ==
+			    MPI2_IOC_STATE_FAULT) {
+				mpt2sas_base_fault_info(ioc , doorbell);
+				return -EFAULT;
+			}
+		} else if (int_status == 0xFFFFFFFF)
+			goto out;
+
+		if (sleep_flag == CAN_SLEEP)
+			msleep(1);
+		else
+			udelay(500);
+		count++;
+	} while (--cntdn);
+
+ out:
+	printk(MPT2SAS_ERR_FMT
+	    "%s: failed due to timeout count(%d), int_status(%x)!\n",
+	    ioc->name, __func__, count, int_status);
+	return -EFAULT;
+}
+
+/**
+ * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ */
+static int
+_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,
+	int sleep_flag)
+{
+	u32 cntdn, count;
+	u32 doorbell_reg;
+
+	count = 0;
+	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+	do {
+		doorbell_reg = readl(&ioc->chip->Doorbell);
+		if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
+			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT
+			    "%s: successful count(%d), timeout(%d)\n",
+			    ioc->name, __func__, count, timeout));
+			return 0;
+		}
+		if (sleep_flag == CAN_SLEEP)
+			msleep(1);
+		else
+			udelay(500);
+		count++;
+	} while (--cntdn);
+
+	printk(MPT2SAS_ERR_FMT
+	    "%s: failed due to timeout count(%d), doorbell_reg(%x)!\n",
+	    ioc->name, __func__, count, doorbell_reg);
+	return -EFAULT;
+}
+
+/**
+ * _base_handshake_req_reply_wait - send request thru doorbell interface
+ * @ioc: per adapter object
+ * @request_bytes: request length
+ * @request: pointer having request payload
+ * @reply_bytes: reply length
+ * @reply: pointer to reply payload
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
+	u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
+{
+	MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
+	int i;
+	u8 failed;
+	u16 dummy;
+	__le32 *mfp;
+
+	/* make sure doorbell is not in use */
+	if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
+		printk(MPT2SAS_ERR_FMT "doorbell is in use (line=%d)\n",
+		    ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* clear pending doorbell interrupts from previous state changes */
+	if (readl(&ioc->chip->HostInterruptStatus) &
+	    MPI2_HIS_IOC2SYS_DB_STATUS)
+		writel(0, &ioc->chip->HostInterruptStatus);
+
+	/* send message to ioc */
+	writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
+	    ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
+	    &ioc->chip->Doorbell);
+
+	if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {
+		printk(MPT2SAS_ERR_FMT
+		   "doorbell handshake int failed (line=%d)\n",
+		   ioc->name, __LINE__);
+		return -EFAULT;
+	}
+	writel(0, &ioc->chip->HostInterruptStatus);
+
+	if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
+		printk(MPT2SAS_ERR_FMT
+		    "doorbell handshake ack failed (line=%d)\n",
+		    ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* send message 32-bits at a time */
+	for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
+		writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
+		if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
+			failed = 1;
+	}
+
+	if (failed) {
+		printk(MPT2SAS_ERR_FMT
+		   "doorbell handshake sending request failed (line=%d)\n",
+		   ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* now wait for the reply */
+	if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
+		printk(MPT2SAS_ERR_FMT
+		   "doorbell handshake int failed (line=%d)\n",
+		   ioc->name, __LINE__);
+		return -EFAULT;
+	}
+
+	/* read the first two 16-bits, it gives the total length of the reply */
+	reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+	    & MPI2_DOORBELL_DATA_MASK);
+	writel(0, &ioc->chip->HostInterruptStatus);
+	if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+		printk(MPT2SAS_ERR_FMT
+		   "doorbell handshake int failed (line=%d)\n",
+		   ioc->name, __LINE__);
+		return -EFAULT;
+	}
+	reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+	    & MPI2_DOORBELL_DATA_MASK);
+	writel(0, &ioc->chip->HostInterruptStatus);
+
+	for (i = 2; i < default_reply->MsgLength * 2; i++)  {
+		if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+			printk(MPT2SAS_ERR_FMT
+			    "doorbell handshake int failed (line=%d)\n",
+			    ioc->name, __LINE__);
+			return -EFAULT;
+		}
+		if (i >=  reply_bytes/2) /* overflow case */
+			dummy = readl(&ioc->chip->Doorbell);
+		else
+			reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+			    & MPI2_DOORBELL_DATA_MASK);
+		writel(0, &ioc->chip->HostInterruptStatus);
+	}
+
+	_base_wait_for_doorbell_int(ioc, 5, sleep_flag);
+	if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) {
+		dhsprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "doorbell is in use (line=%d)\n", ioc->name, __LINE__));
+	}
+	writel(0, &ioc->chip->HostInterruptStatus);
+
+	if (ioc->logging_level & MPT_DEBUG_INIT) {
+		mfp = (__le32 *)reply;
+		pr_info("\toffset:data\n");
+		for (i = 0; i < reply_bytes/4; i++)
+			pr_info("\t[0x%02x]:%08x\n", i*4,
+			    le32_to_cpu(mfp[i]));
+	}
+	return 0;
+}
+
+/**
+ * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
+{
+	Mpi2IOCFactsRequest_t mpi_request;
+	Mpi2IOCFactsReply_t mpi_reply;
+	struct mpt2sas_facts *facts;
+	int mpi_reply_sz, mpi_request_sz, r;
+
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
+	    __func__));
+
+	mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
+	mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
+	memset(&mpi_request, 0, mpi_request_sz);
+	mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
+	r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
+	    (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
+
+	if (r != 0) {
+		printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
+		    ioc->name, __func__, r);
+		return r;
+	}
+
+	facts = &ioc->facts;
+	memset(facts, 0, sizeof(struct mpt2sas_facts));
+	facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
+	facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
+	facts->VP_ID = mpi_reply.VP_ID;
+	facts->VF_ID = mpi_reply.VF_ID;
+	facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
+	facts->MaxChainDepth = mpi_reply.MaxChainDepth;
+	facts->WhoInit = mpi_reply.WhoInit;
+	facts->NumberOfPorts = mpi_reply.NumberOfPorts;
+	facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;
+	facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
+	facts->MaxReplyDescriptorPostQueueDepth =
+	    le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
+	facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
+	facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
+	if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
+		ioc->ir_firmware = 1;
+	if ((facts->IOCCapabilities &
+	      MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE))
+		ioc->rdpq_array_capable = 1;
+	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
+	facts->IOCRequestFrameSize =
+	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
+	facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
+	facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
+	ioc->shost->max_id = -1;
+	facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
+	facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
+	facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
+	facts->HighPriorityCredit =
+	    le16_to_cpu(mpi_reply.HighPriorityCredit);
+	facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
+	facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
+
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+	    "hba queue depth(%d), max chains per io(%d)\n", ioc->name,
+	    facts->RequestCredit, facts->MaxChainDepth));
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+	    "request frame size(%d), reply frame size(%d)\n", ioc->name,
+	    facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
+	return 0;
+}
+
+/**
  * mpt2sas_base_map_resources - map in controller resources (io/irq/memap)
  * @ioc: per adapter object
  *
@@ -1555,6 +1887,16 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
 	}
 
 	_base_mask_interrupts(ioc);
+
+	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+	if (r)
+		goto out_fail;
+
+	if (!ioc->rdpq_array_enable_assigned) {
+		ioc->rdpq_array_enable = ioc->rdpq_array_capable;
+		ioc->rdpq_array_enable_assigned = 1;
+	}
+
 	r = _base_enable_msix(ioc);
 	if (r)
 		goto out_fail;
@@ -2393,15 +2735,39 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 		ioc->reply_free = NULL;
 	}
 
-	if (ioc->reply_post_free) {
-		pci_pool_free(ioc->reply_post_free_dma_pool,
-		    ioc->reply_post_free, ioc->reply_post_free_dma);
+	if (ioc->reply_post) {
+		if (ioc->rdpq_array_enable) {
+			for (i = 0; i < ioc->reply_queue_count; i++) {
+				if (ioc->reply_post[i].reply_post_free) {
+					pci_pool_free(
+					    ioc->reply_post_free_dma_pool,
+					    ioc->reply_post[i].reply_post_free,
+					    ioc->
+					    reply_post[i].reply_post_free_dma);
+					dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+					   "reply_post_free_pool(0x%p): free\n",
+					    ioc->name,
+					    ioc->reply_post[i].reply_post_free)
+					     );
+					ioc->reply_post[i].reply_post_free =
+					  NULL;
+				}
+			}
+		} else {
+			if (ioc->reply_post[0].reply_post_free) {
+				pci_pool_free(ioc->reply_post_free_dma_pool,
+				    ioc->reply_post[0].reply_post_free,
+				    ioc->reply_post[0].reply_post_free_dma);
+				dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+				    "reply_post_free_pool(0x%p): free\n",
+				    ioc->name,
+				    ioc->reply_post[0].reply_post_free));
+				ioc->reply_post[0].reply_post_free = NULL;
+			}
+		}
 		if (ioc->reply_post_free_dma_pool)
 			pci_pool_destroy(ioc->reply_post_free_dma_pool);
-		dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
-		    "reply_post_free_pool(0x%p): free\n", ioc->name,
-		    ioc->reply_post_free));
-		ioc->reply_post_free = NULL;
+		kfree(ioc->reply_post);
 	}
 
 	if (ioc->config_page) {
@@ -2755,36 +3121,84 @@ chain_done:
 	    "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
 	total_sz += sz;
 
-	/* reply post queue, 16 byte align */
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
-	if (_base_is_controller_msix_enabled(ioc))
-		sz = reply_post_free_sz * ioc->reply_queue_count;
-	else
+	if (ioc->rdpq_array_enable) {
+		ioc->reply_post = kcalloc(ioc->reply_queue_count,
+		    sizeof(struct reply_post_struct), GFP_KERNEL);
+		/* reply post queue, 16 byte align */
+		reply_post_free_sz = ioc->reply_post_queue_depth *
+		    sizeof(Mpi2DefaultReplyDescriptor_t);
 		sz = reply_post_free_sz;
-	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
-	    ioc->pdev, sz, 16, 0);
-	if (!ioc->reply_post_free_dma_pool) {
-		printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create "
-		    "failed\n", ioc->name);
-		goto out;
-	}
-	ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
-	    GFP_KERNEL, &ioc->reply_post_free_dma);
-	if (!ioc->reply_post_free) {
-		printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc "
-		    "failed\n", ioc->name);
-		goto out;
+		ioc->reply_post_free_dma_pool =
+		    pci_pool_create("reply_post_free pool", ioc->pdev, sz,
+		    16, 2147483648);
+		if (!ioc->reply_post_free_dma_pool) {
+			printk(MPT2SAS_ERR_FMT
+			 "reply_post_free pool: pci_pool_create failed\n",
+			 ioc->name);
+			goto out;
+		}
+		for (i = 0; i < ioc->reply_queue_count; i++) {
+			ioc->reply_post[i].reply_post_free =
+			    pci_pool_alloc(ioc->reply_post_free_dma_pool,
+			    GFP_KERNEL,
+			    &ioc->reply_post[i].reply_post_free_dma);
+			if (!ioc->reply_post[i].reply_post_free) {
+				printk(MPT2SAS_ERR_FMT
+				"reply_post_free pool: pci_pool_alloc failed\n"
+				, ioc->name);
+				goto out;
+			}
+			memset(ioc->reply_post[i].reply_post_free, 0, sz);
+			dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+			    "reply post free pool (0x%p): depth(%d),"
+			    "element_size(%d), pool_size(%d kB)\n", ioc->name,
+			    ioc->reply_post[i].reply_post_free,
+			    ioc->reply_post_queue_depth, 8, sz/1024));
+			dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+			    "reply_post_free_dma = (0x%llx)\n", ioc->name,
+			    (unsigned long long)
+			    ioc->reply_post[i].reply_post_free_dma));
+			total_sz += sz;
+		}
+	} else {
+		ioc->reply_post = kzalloc(sizeof(struct reply_post_struct),
+		    GFP_KERNEL);
+		/* reply post queue, 16 byte align */
+		reply_post_free_sz = ioc->reply_post_queue_depth *
+		    sizeof(Mpi2DefaultReplyDescriptor_t);
+		if (_base_is_controller_msix_enabled(ioc))
+			sz = reply_post_free_sz * ioc->reply_queue_count;
+		else
+			sz = reply_post_free_sz;
+		ioc->reply_post_free_dma_pool =
+		    pci_pool_create("reply_post_free pool",
+		    ioc->pdev, sz, 16, 0);
+		if (!ioc->reply_post_free_dma_pool) {
+			printk(MPT2SAS_ERR_FMT
+			    "reply_post_free pool: pci_pool_create failed\n",
+			    ioc->name);
+			goto out;
+		}
+		ioc->reply_post[0].reply_post_free =
+		    pci_pool_alloc(ioc->reply_post_free_dma_pool,
+		    GFP_KERNEL, &ioc->reply_post[0].reply_post_free_dma);
+		if (!ioc->reply_post[0].reply_post_free) {
+			printk(MPT2SAS_ERR_FMT
+			    "reply_post_free pool: pci_pool_alloc failed\n",
+			    ioc->name);
+			goto out;
+		}
+		memset(ioc->reply_post[0].reply_post_free, 0, sz);
+		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
+		    "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
+		    ioc->name, ioc->reply_post[0].reply_post_free,
+		    ioc->reply_post_queue_depth, 8, sz/1024));
+		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "reply_post_free_dma = (0x%llx)\n", ioc->name,
+		    (unsigned long long)
+		    ioc->reply_post[0].reply_post_free_dma));
+		total_sz += sz;
 	}
-	memset(ioc->reply_post_free, 0, sz);
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
-	    "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
-	    ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
-	    sz/1024));
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = "
-	    "(0x%llx)\n", ioc->name, (unsigned long long)
-	    ioc->reply_post_free_dma));
-	total_sz += sz;
 
 	ioc->config_page_sz = 512;
 	ioc->config_page = pci_alloc_consistent(ioc->pdev,
@@ -2796,15 +3210,15 @@ chain_done:
 	}
 	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size"
 	    "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz));
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma"
-	    "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma));
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma (0x%llx)\n",
+	    ioc->name, (unsigned long long)ioc->config_page_dma));
 	total_sz += ioc->config_page_sz;
 
 	printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n",
 	    ioc->name, total_sz/1024);
-	printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), "
-	    "Max Controller Queue Depth(%d)\n",
-	    ioc->name, ioc->shost->can_queue, facts->RequestCredit);
+	printk(MPT2SAS_INFO_FMT
+	"Current Controller Queue Depth(%d), Max Controller Queue Depth(%d)\n",
+	 ioc->name, ioc->shost->can_queue, facts->RequestCredit);
 	printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n",
 	    ioc->name, ioc->shost->sg_tablesize);
 	return 0;
@@ -2813,7 +3227,6 @@ chain_done:
 	return -ENOMEM;
 }
 
-
 /**
  * mpt2sas_base_get_iocstate - Get the current state of a MPT adapter.
  * @ioc: Pointer to MPT_ADAPTER structure
@@ -2866,135 +3279,6 @@ _base_wait_on_iocstate(struct MPT2SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
 }
 
 /**
- * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
- * a write to the doorbell)
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
- */
-static int
-_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
-    int sleep_flag)
-{
-	u32 cntdn, count;
-	u32 int_status;
-
-	count = 0;
-	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
-	do {
-		int_status = readl(&ioc->chip->HostInterruptStatus);
-		if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
-			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
-			    "successful count(%d), timeout(%d)\n", ioc->name,
-			    __func__, count, timeout));
-			return 0;
-		}
-		if (sleep_flag == CAN_SLEEP)
-			msleep(1);
-		else
-			udelay(500);
-		count++;
-	} while (--cntdn);
-
-	printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
-	    "int_status(%x)!\n", ioc->name, __func__, count, int_status);
-	return -EFAULT;
-}
-
-/**
- * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to
- * doorbell.
- */
-static int
-_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
-    int sleep_flag)
-{
-	u32 cntdn, count;
-	u32 int_status;
-	u32 doorbell;
-
-	count = 0;
-	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
-	do {
-		int_status = readl(&ioc->chip->HostInterruptStatus);
-		if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
-			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
-			    "successful count(%d), timeout(%d)\n", ioc->name,
-			    __func__, count, timeout));
-			return 0;
-		} else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
-			doorbell = readl(&ioc->chip->Doorbell);
-			if ((doorbell & MPI2_IOC_STATE_MASK) ==
-			    MPI2_IOC_STATE_FAULT) {
-				mpt2sas_base_fault_info(ioc , doorbell);
-				return -EFAULT;
-			}
-		} else if (int_status == 0xFFFFFFFF)
-			goto out;
-
-		if (sleep_flag == CAN_SLEEP)
-			msleep(1);
-		else
-			udelay(500);
-		count++;
-	} while (--cntdn);
-
- out:
-	printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
-	    "int_status(%x)!\n", ioc->name, __func__, count, int_status);
-	return -EFAULT;
-}
-
-/**
- * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- */
-static int
-_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,
-    int sleep_flag)
-{
-	u32 cntdn, count;
-	u32 doorbell_reg;
-
-	count = 0;
-	cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
-	do {
-		doorbell_reg = readl(&ioc->chip->Doorbell);
-		if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
-			dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
-			    "successful count(%d), timeout(%d)\n", ioc->name,
-			    __func__, count, timeout));
-			return 0;
-		}
-		if (sleep_flag == CAN_SLEEP)
-			msleep(1);
-		else
-			udelay(500);
-		count++;
-	} while (--cntdn);
-
-	printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
-	    "doorbell_reg(%x)!\n", ioc->name, __func__, count, doorbell_reg);
-	return -EFAULT;
-}
-
-/**
  * _base_send_ioc_reset - send doorbell reset
  * @ioc: per adapter object
  * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET
@@ -3043,123 +3327,6 @@ _base_send_ioc_reset(struct MPT2SAS_ADAPTER *ioc, u8 reset_type, int timeout,
 }
 
 /**
- * _base_handshake_req_reply_wait - send request thru doorbell interface
- * @ioc: per adapter object
- * @request_bytes: request length
- * @request: pointer having request payload
- * @reply_bytes: reply length
- * @reply: pointer to reply payload
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
-    u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
-{
-	MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
-	int i;
-	u8 failed;
-	u16 dummy;
-	__le32 *mfp;
-
-	/* make sure doorbell is not in use */
-	if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
-		printk(MPT2SAS_ERR_FMT "doorbell is in use "
-		    " (line=%d)\n", ioc->name, __LINE__);
-		return -EFAULT;
-	}
-
-	/* clear pending doorbell interrupts from previous state changes */
-	if (readl(&ioc->chip->HostInterruptStatus) &
-	    MPI2_HIS_IOC2SYS_DB_STATUS)
-		writel(0, &ioc->chip->HostInterruptStatus);
-
-	/* send message to ioc */
-	writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
-	    ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
-	    &ioc->chip->Doorbell);
-
-	if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {
-		printk(MPT2SAS_ERR_FMT "doorbell handshake "
-		   "int failed (line=%d)\n", ioc->name, __LINE__);
-		return -EFAULT;
-	}
-	writel(0, &ioc->chip->HostInterruptStatus);
-
-	if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
-		printk(MPT2SAS_ERR_FMT "doorbell handshake "
-		    "ack failed (line=%d)\n", ioc->name, __LINE__);
-		return -EFAULT;
-	}
-
-	/* send message 32-bits at a time */
-	for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
-		writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
-		if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
-			failed = 1;
-	}
-
-	if (failed) {
-		printk(MPT2SAS_ERR_FMT "doorbell handshake "
-		    "sending request failed (line=%d)\n", ioc->name, __LINE__);
-		return -EFAULT;
-	}
-
-	/* now wait for the reply */
-	if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
-		printk(MPT2SAS_ERR_FMT "doorbell handshake "
-		   "int failed (line=%d)\n", ioc->name, __LINE__);
-		return -EFAULT;
-	}
-
-	/* read the first two 16-bits, it gives the total length of the reply */
-	reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
-	    & MPI2_DOORBELL_DATA_MASK);
-	writel(0, &ioc->chip->HostInterruptStatus);
-	if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
-		printk(MPT2SAS_ERR_FMT "doorbell handshake "
-		   "int failed (line=%d)\n", ioc->name, __LINE__);
-		return -EFAULT;
-	}
-	reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
-	    & MPI2_DOORBELL_DATA_MASK);
-	writel(0, &ioc->chip->HostInterruptStatus);
-
-	for (i = 2; i < default_reply->MsgLength * 2; i++)  {
-		if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
-			printk(MPT2SAS_ERR_FMT "doorbell "
-			    "handshake int failed (line=%d)\n", ioc->name,
-			    __LINE__);
-			return -EFAULT;
-		}
-		if (i >=  reply_bytes/2) /* overflow case */
-			dummy = readl(&ioc->chip->Doorbell);
-		else
-			reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
-			    & MPI2_DOORBELL_DATA_MASK);
-		writel(0, &ioc->chip->HostInterruptStatus);
-	}
-
-	_base_wait_for_doorbell_int(ioc, 5, sleep_flag);
-	if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) {
-		dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "doorbell is in use "
-		    " (line=%d)\n", ioc->name, __LINE__));
-	}
-	writel(0, &ioc->chip->HostInterruptStatus);
-
-	if (ioc->logging_level & MPT_DEBUG_INIT) {
-		mfp = (__le32 *)reply;
-		printk(KERN_INFO "\toffset:data\n");
-		for (i = 0; i < reply_bytes/4; i++)
-			printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
-			    le32_to_cpu(mfp[i]));
-	}
-	return 0;
-}
-
-/**
  * mpt2sas_base_sas_iounit_control - send sas iounit control to FW
  * @ioc: per adapter object
  * @mpi_reply: the reply payload from FW
@@ -3409,78 +3576,6 @@ _base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)
 }
 
 /**
- * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
-	Mpi2IOCFactsRequest_t mpi_request;
-	Mpi2IOCFactsReply_t mpi_reply;
-	struct mpt2sas_facts *facts;
-	int mpi_reply_sz, mpi_request_sz, r;
-
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
-	    __func__));
-
-	mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
-	mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
-	memset(&mpi_request, 0, mpi_request_sz);
-	mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
-	r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
-	    (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
-
-	if (r != 0) {
-		printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
-		    ioc->name, __func__, r);
-		return r;
-	}
-
-	facts = &ioc->facts;
-	memset(facts, 0, sizeof(struct mpt2sas_facts));
-	facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
-	facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
-	facts->VP_ID = mpi_reply.VP_ID;
-	facts->VF_ID = mpi_reply.VF_ID;
-	facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
-	facts->MaxChainDepth = mpi_reply.MaxChainDepth;
-	facts->WhoInit = mpi_reply.WhoInit;
-	facts->NumberOfPorts = mpi_reply.NumberOfPorts;
-	facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;
-	facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
-	facts->MaxReplyDescriptorPostQueueDepth =
-	    le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
-	facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
-	facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
-	if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
-		ioc->ir_firmware = 1;
-	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
-	facts->IOCRequestFrameSize =
-	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
-	facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
-	facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
-	ioc->shost->max_id = -1;
-	facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
-	facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
-	facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
-	facts->HighPriorityCredit =
-	    le16_to_cpu(mpi_reply.HighPriorityCredit);
-	facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
-	facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
-
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hba queue depth(%d), "
-	    "max chains per io(%d)\n", ioc->name, facts->RequestCredit,
-	    facts->MaxChainDepth));
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request frame size(%d), "
-	    "reply frame size(%d)\n", ioc->name,
-	    facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
-	return 0;
-}
-
-/**
  * _base_send_ioc_init - send ioc_init to firmware
  * @ioc: per adapter object
  * @sleep_flag: CAN_SLEEP or NO_SLEEP
@@ -3492,9 +3587,13 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 {
 	Mpi2IOCInitRequest_t mpi_request;
 	Mpi2IOCInitReply_t mpi_reply;
-	int r;
+	int i, r = 0;
 	struct timeval current_time;
 	u16 ioc_status;
+	u32 reply_post_free_array_sz;
+	Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
+	dma_addr_t reply_post_free_array_dma;
+	struct dma_pool *reply_post_free_array_dma_pool = NULL;
 
 	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
@@ -3523,9 +3622,41 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	    cpu_to_le64((u64)ioc->request_dma);
 	mpi_request.ReplyFreeQueueAddress =
 	    cpu_to_le64((u64)ioc->reply_free_dma);
-	mpi_request.ReplyDescriptorPostQueueAddress =
-	    cpu_to_le64((u64)ioc->reply_post_free_dma);
-
+	if (ioc->rdpq_array_enable) {
+		reply_post_free_array_sz = ioc->reply_queue_count *
+		    sizeof(Mpi2IOCInitRDPQArrayEntry);
+		reply_post_free_array_dma_pool =
+		    pci_pool_create("reply_post_free_array pool",
+		    ioc->pdev, reply_post_free_array_sz, 16, 0);
+		if (!reply_post_free_array_dma_pool) {
+			printk(MPT2SAS_ERR_FMT
+			"reply_post_free_array pool: pci_pool_create failed\n",
+			ioc->name);
+			r = -ENOMEM;
+			goto out;
+		}
+		reply_post_free_array =
+		    pci_pool_alloc(reply_post_free_array_dma_pool,
+		    GFP_KERNEL, &reply_post_free_array_dma);
+		if (!reply_post_free_array) {
+			printk(MPT2SAS_ERR_FMT
+			 "reply_post_free_array pool: pci_pool_alloc failed\n",
+			 ioc->name);
+			r = -ENOMEM;
+			goto out;
+		}
+		memset(reply_post_free_array, 0, reply_post_free_array_sz);
+		for (i = 0; i < ioc->reply_queue_count; i++)
+			reply_post_free_array[i].RDPQBaseAddress =
+			    cpu_to_le64(
+				(u64)ioc->reply_post[i].reply_post_free_dma);
+		mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64((u64)reply_post_free_array_dma);
+	} else {
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
+	}
 
 	/* This time stamp specifies number of milliseconds
 	 * since epoch ~ midnight January 1, 1970.
@@ -3553,7 +3684,7 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	if (r != 0) {
 		printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
 		    ioc->name, __func__, r);
-		return r;
+		goto out;
 	}
 
 	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
@@ -3563,7 +3694,17 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 		r = -EIO;
 	}
 
-	return 0;
+ out:
+	if (ioc->rdpq_array_enable) {
+		if (reply_post_free_array) {
+			pci_pool_free(reply_post_free_array_dma_pool,
+			    reply_post_free_array, reply_post_free_array_dma);
+			reply_post_free_array = NULL;
+		}
+		if (reply_post_free_array_dma_pool)
+			pci_pool_destroy(reply_post_free_array_dma_pool);
+	}
+	return r;
 }
 
 /**
@@ -4088,7 +4229,7 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
 static int
 _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 {
-	int r, i;
+	int r, i, j = 0;
 	unsigned long	flags;
 	u32 reply_address;
 	u16 smid;
@@ -4167,19 +4308,32 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 		_base_assign_reply_queues(ioc);
 
 	/* initialize Reply Post Free Queue */
-	reply_post_free = (long)ioc->reply_post_free;
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
-	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
-		reply_q->reply_post_host_index = 0;
-		reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
-		    reply_post_free;
-		for (i = 0; i < ioc->reply_post_queue_depth; i++)
-			reply_q->reply_post_free[i].Words =
-							cpu_to_le64(ULLONG_MAX);
-		if (!_base_is_controller_msix_enabled(ioc))
-			goto skip_init_reply_post_free_queue;
-		reply_post_free += reply_post_free_sz;
+	if (ioc->rdpq_array_enable) {
+		list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
+			reply_q->reply_post_host_index = 0;
+			reply_q->reply_post_free =
+			    ioc->reply_post[j++].reply_post_free;
+			for (i = 0; i < ioc->reply_post_queue_depth; i++)
+				reply_q->reply_post_free[i].Words =
+				    cpu_to_le64(ULLONG_MAX);
+			if (!_base_is_controller_msix_enabled(ioc))
+				goto skip_init_reply_post_free_queue;
+		}
+	} else {
+		reply_post_free = (long)ioc->reply_post[0].reply_post_free;
+		reply_post_free_sz = ioc->reply_post_queue_depth *
+		    sizeof(Mpi2DefaultReplyDescriptor_t);
+		list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
+			reply_q->reply_post_host_index = 0;
+			reply_q->reply_post_free =
+			    (Mpi2ReplyDescriptorsUnion_t *)reply_post_free;
+			for (i = 0; i < ioc->reply_post_queue_depth; i++)
+				reply_q->reply_post_free[i].Words =
+				    cpu_to_le64(ULLONG_MAX);
+			if (!_base_is_controller_msix_enabled(ioc))
+				goto skip_init_reply_post_free_queue;
+			reply_post_free += reply_post_free_sz;
+		}
 	}
  skip_init_reply_post_free_queue:
 
@@ -4307,6 +4461,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
 		}
 	}
 
+	ioc->rdpq_array_enable_assigned = 0;
 	r = mpt2sas_base_map_resources(ioc);
 	if (r)
 		goto out_free_resources;
@@ -4667,6 +4822,16 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
 		r = -EFAULT;
 		goto out;
 	}
+
+	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+	if (r)
+		goto out;
+
+	if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
+		panic("%s: Issue occurred with flashing controller firmware."
+		      "Please reboot the system and ensure that the correct"
+		      "firmware version is running\n", ioc->name);
+
 	r = _base_make_ioc_operational(ioc, sleep_flag);
 	if (!r)
 		_base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 0a6747a..32181a6 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -636,6 +636,11 @@ struct mpt2sas_port_facts {
 	u16			MaxPostedCmdBuffers;
 };
 
+struct reply_post_struct {
+	Mpi2ReplyDescriptorsUnion_t	*reply_post_free;
+	dma_addr_t			reply_post_free_dma;
+};
+
 /**
  * enum mutex_type - task management mutex type
  * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it
@@ -779,8 +784,11 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
  * @reply_free_dma_pool:
  * @reply_free_host_index: tail index in pool to insert free replys
  * @reply_post_queue_depth: reply post queue depth
- * @reply_post_free: pool for reply post (64bit descriptor)
- * @reply_post_free_dma:
+ * @reply_post_struct: struct for reply_post_free physical & virt address
+ * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
+ * @rdpq_array_enable: rdpq_array support is enabled in the driver
+ * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
+ *				is assigned only ones
  * @reply_queue_count: number of reply queue's
  * @reply_queue_list: link list contaning the reply queue info
  * @reply_post_host_index: head index in the pool where FW completes IO
@@ -973,11 +981,13 @@ struct MPT2SAS_ADAPTER {
 
 	/* reply post queue */
 	u16 		reply_post_queue_depth;
-	Mpi2ReplyDescriptorsUnion_t *reply_post_free;
-	dma_addr_t	reply_post_free_dma;
+	struct reply_post_struct *reply_post;
 	struct dma_pool *reply_post_free_dma_pool;
 	u8		reply_queue_count;
 	struct list_head reply_queue_list;
+	u8              rdpq_array_capable;
+	u8              rdpq_array_enable;
+	u8              rdpq_array_enable_assigned;
 
 	struct list_head delayed_tr_list;
 	struct list_head delayed_tr_volume_list;
-- 
1.7.1


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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-06-25 10:34 [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support Reddy, Sreekanth
@ 2014-07-22  3:10 ` Martin K. Petersen
       [not found]   ` <CAK=zhgoQt5J=jh4jShAy5rBXNz34sN-tqf=uZDkY4zQJ9XhM5g@mail.gmail.com>
  0 siblings, 1 reply; 20+ messages in thread
From: Martin K. Petersen @ 2014-07-22  3:10 UTC (permalink / raw)
  To: Reddy, Sreekanth
  Cc: jejb, JBottomley, martin.petersen, linux-scsi, Sathya.Prakash,
	Nagalakshmi.Nandigama, linux-kernel, hch

>>>>> "Sreekanth" == Reddy, Sreekanth <Sreekanth.Reddy@avagotech.com> writes:

Sreekanth,

@@ -2393,15 +2735,39 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 		ioc->reply_free = NULL;
 	}
 
-	if (ioc->reply_post_free) {
-		pci_pool_free(ioc->reply_post_free_dma_pool,
-		    ioc->reply_post_free, ioc->reply_post_free_dma);
+	if (ioc->reply_post) {
+		if (ioc->rdpq_array_enable) {
+			for (i = 0; i < ioc->reply_queue_count; i++) {
+				if (ioc->reply_post[i].reply_post_free) {
+					pci_pool_free(
+					    ioc->reply_post_free_dma_pool,
+					    ioc->reply_post[i].reply_post_free,
+					    ioc->
+					    reply_post[i].reply_post_free_dma);
+					dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+					   "reply_post_free_pool(0x%p): free\n",
+					    ioc->name,
+					    ioc->reply_post[i].reply_post_free)
+					     );
+					ioc->reply_post[i].reply_post_free =
+					  NULL;
+				}
+			}
+		} else {
+			if (ioc->reply_post[0].reply_post_free) {
+				pci_pool_free(ioc->reply_post_free_dma_pool,
+				    ioc->reply_post[0].reply_post_free,
+				    ioc->reply_post[0].reply_post_free_dma);
+				dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+				    "reply_post_free_pool(0x%p): free\n",
+				    ioc->name,
+				    ioc->reply_post[0].reply_post_free));
+				ioc->reply_post[0].reply_post_free = NULL;
+			}
+		}

Why do you need to special case !rdpq? Isn't reply_queue_count = 1 in
that case?

@@ -2755,36 +3121,84 @@ chain_done:
 	    "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
 	total_sz += sz;
 
-	/* reply post queue, 16 byte align */
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
-	if (_base_is_controller_msix_enabled(ioc))
-		sz = reply_post_free_sz * ioc->reply_queue_count;
-	else
+	if (ioc->rdpq_array_enable) {
+		ioc->reply_post = kcalloc(ioc->reply_queue_count,
+		    sizeof(struct reply_post_struct), GFP_KERNEL);
+		/* reply post queue, 16 byte align */
+		reply_post_free_sz = ioc->reply_post_queue_depth *
+		    sizeof(Mpi2DefaultReplyDescriptor_t);

This is done in both the rdpq and !rdpq cases. Please avoid code
duplication.

+		ioc->reply_post_free_dma_pool =
+		    pci_pool_create("reply_post_free pool", ioc->pdev, sz,
+		    16, 2147483648);

Magic number?           ^^^^^^^^^^

Why do you create pools for something that's not frequently allocated
and deallocated? These queues are set up once when a controller is
configured.

+		reply_post_free_sz = ioc->reply_post_queue_depth *
+		    sizeof(Mpi2DefaultReplyDescriptor_t);

What's all this reply_post_free business? I don't see the "_free" suffix
in the MPI spec and find it confusing.

@@ -3523,9 +3622,41 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	    cpu_to_le64((u64)ioc->request_dma);
 	mpi_request.ReplyFreeQueueAddress =
 	    cpu_to_le64((u64)ioc->reply_free_dma);
-	mpi_request.ReplyDescriptorPostQueueAddress =
-	    cpu_to_le64((u64)ioc->reply_post_free_dma);
-
+	if (ioc->rdpq_array_enable) {
+		reply_post_free_array_sz = ioc->reply_queue_count *
+		    sizeof(Mpi2IOCInitRDPQArrayEntry);
+		reply_post_free_array_dma_pool =
+		    pci_pool_create("reply_post_free_array pool",
+		    ioc->pdev, reply_post_free_array_sz, 16, 0);

This time with no magic number.                             ^^^

Another pool. This time short lived. Only does a single allocation and
then it's torn down.

+ * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
+ * @rdpq_array_enable: rdpq_array support is enabled in the driver
+ * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
+ *				is assigned only ones

I understand why array_capable is important. enable and enable_assigned
not so much.

In general, I think this could be made much simpler if you treated the
single reply_queue region as a subset of the multi region ditto. It
would avoid a lot of code duplication throughout. You should really only
need to make the distinction when you calculate the number of reply
queues and when you init the chip.

-- 
Martin K. Petersen	Oracle Linux Engineering

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
       [not found]   ` <CAK=zhgoQt5J=jh4jShAy5rBXNz34sN-tqf=uZDkY4zQJ9XhM5g@mail.gmail.com>
@ 2014-07-23  1:25     ` Martin K. Petersen
  2014-07-23 17:37       ` Sreekanth Reddy
  0 siblings, 1 reply; 20+ messages in thread
From: Martin K. Petersen @ 2014-07-23  1:25 UTC (permalink / raw)
  To: Sreekanth Reddy
  Cc: Martin K. Petersen, jejb, James E.J. Bottomley, linux-scsi,
	Sathya Prakash, Nagalakshmi Nandigama, linux-kernel,
	Christoph Hellwig

>>>>> "Sreekanth" == Sreekanth Reddy <sreekanth.reddy@avagotech.com> writes:

Sreekanth,

>> Why do you need to special case !rdpq? Isn't reply_queue_count = 1 in
>> that case?

Sreekanth> [Sreekanth] we have added this RDPQ support in phase18. So,
Sreekanth> the firmware from less than phase18 doesn't have this RDPQ
Sreekanth> support.

Yes, but a single allocation is a subset of multiple allocations. That
has nothing to do with firmware phase and whether RDPQ is available or
not.

I have attached a simplified patch below. I probably messed something up
but you get the idea.

When a new feature is introduced you guys generally go:

	if (new_feature) {
		/* Huge block of code */
	} else {
		/* Almost identical huge block of original code */
	}

I assume that's done to leave the original code paths unchanged. But
that approach doesn't fly around here. You'll have to come up with a
generic approach that reduces code duplication and which minimizes the
differences between the new feature and the old one.

As an example:

Original patch:
 mpt2sas_base.c |  923 +++++++++++++++++++++++++++++++++------------------------
 mpt2sas_base.h |   18 -
 2 files changed, 558 insertions(+), 383 deletions(-)

My patch:
 mpt2sas_base.c |  207 +++++++++++++++++++++++++++++++++++++++++----------------
 mpt2sas_base.h |   18 +++-
 2 files changed, 166 insertions(+), 59 deletions(-)


commit ef510bd8dc0e43f8c58012ba9f54213b26381464
Author: Martin K. Petersen <martin.petersen@oracle.com>
Date:   Tue Jul 22 20:56:27 2014 -0400

    Up to now, driver allocates a single contiguous block of memory pool for
    all reply queues and passes down a single address in the
    ReplyDescriptorPostQueueAddress field of the IOC Init Request Message to
    the firmware.
    
    When firmware receives this address, it will program each of the Reply
    Descriptor Post Queue registers, as each reply queue has its own
    register. Thus the firmware, starting from a base address it determines
    the starting address of the subsequent reply queues through some simple
    arithmetic calculations.
    
    The size of this contiguous block of memory pool is directly
    proportional to number of MSI-X vectors and the HBA queue depth. For
    example higher MSI-X vectors requires larger contiguous block of memory
    pool.
    
    But some of the OS kernels are unable to allocate this larger
    contiguous block of memory pool.
    
    So, the proposal is to allocate memory independently for each Reply
    Queue and pass down all of the addresses to the firmware.  Then the
    firmware will just take each address and program the value into the
    correct register.
    
    When HBAs with older firmware(i.e. without RDPQ capability) is used with
    this new driver then the max_msix_vectors value would be set to 8 by
    default.
    
    Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
    Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 22c4575241fc..2d39d5196788 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -92,6 +92,8 @@ static int disable_discovery = -1;
 module_param(disable_discovery, int, 0);
 MODULE_PARM_DESC(disable_discovery, " disable discovery ");
 
+static int _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag);
+
 /**
  * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
  *
@@ -1424,6 +1426,9 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
 	ioc->reply_queue_count = min_t(int, ioc->cpu_count,
 	    ioc->msix_vector_count);
 
+	if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
+		max_msix_vectors = 8;
+
 	if (max_msix_vectors > 0) {
 		ioc->reply_queue_count = min_t(int, max_msix_vectors,
 		    ioc->reply_queue_count);
@@ -1552,6 +1557,16 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
 	}
 
 	_base_mask_interrupts(ioc);
+
+	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+	if (r)
+		goto out_fail;
+
+	if (!ioc->rdpq_array_enable_assigned) {
+		ioc->rdpq_array_enable = ioc->rdpq_array_capable;
+		ioc->rdpq_array_enable_assigned = 1;
+	}
+
 	r = _base_enable_msix(ioc);
 	if (r)
 		goto out_fail;
@@ -2390,15 +2405,25 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 		ioc->reply_free = NULL;
 	}
 
-	if (ioc->reply_post_free) {
-		pci_pool_free(ioc->reply_post_free_dma_pool,
-		    ioc->reply_post_free, ioc->reply_post_free_dma);
+	if (ioc->reply_post) {
+		for (i = 0; i < ioc->reply_queue_count ; i++) {
+			struct reply_post_struct *rps = &ioc->reply_post[i];
+
+			if (rps->reply_post_free) {
+				pci_pool_free(ioc->reply_post_free_dma_pool,
+					      rps->reply_post_free,
+					      rps->reply_post_free_dma);
+				dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+					"reply_post_free_pool(0x%p): free\n",
+					ioc->name, rps->reply_post_free));
+				rps->reply_post_free = NULL;
+			}
+		}
+
 		if (ioc->reply_post_free_dma_pool)
 			pci_pool_destroy(ioc->reply_post_free_dma_pool);
-		dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
-		    "reply_post_free_pool(0x%p): free\n", ioc->name,
-		    ioc->reply_post_free));
-		ioc->reply_post_free = NULL;
+
+		kfree(ioc->reply_post);
 	}
 
 	if (ioc->config_page) {
@@ -2443,7 +2468,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
 	struct mpt2sas_facts *facts;
 	u16 max_sge_elements;
 	u16 chains_needed_per_io;
-	u32 sz, total_sz, reply_post_free_sz;
+	u32 sz, total_sz;
 	u32 retry_sz;
 	u16 max_request_credit;
 	int i;
@@ -2752,36 +2777,52 @@ chain_done:
 	    "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
 	total_sz += sz;
 
-	/* reply post queue, 16 byte align */
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
-	if (_base_is_controller_msix_enabled(ioc))
-		sz = reply_post_free_sz * ioc->reply_queue_count;
-	else
-		sz = reply_post_free_sz;
-	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
-	    ioc->pdev, sz, 16, 0);
-	if (!ioc->reply_post_free_dma_pool) {
-		printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create "
-		    "failed\n", ioc->name);
+	/* reply post queue, 16-byte alignment, do not cross 2GB boundary */
+	sz = ioc->reply_post_queue_depth * sizeof(Mpi2DefaultReplyDescriptor_t);
+
+	ioc->reply_post = kcalloc(ioc->reply_queue_count,
+				  sizeof(struct reply_post_struct), GFP_KERNEL);
+	if (!ioc->reply_post) {
+		printk(MPT2SAS_ERR_FMT "reply_post_free pool: kcalloc failed\n",
+		       ioc->name);
 		goto out;
 	}
-	ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
-	    GFP_KERNEL, &ioc->reply_post_free_dma);
-	if (!ioc->reply_post_free) {
-		printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc "
-		    "failed\n", ioc->name);
+
+	ioc->reply_post_free_dma_pool =
+		pci_pool_create("reply_post_free pool", ioc->pdev, sz, 16,
+				2L * 1024 * 1024 * 1024);
+	if (!ioc->reply_post_free_dma_pool) {
+		printk(MPT2SAS_ERR_FMT
+		       "reply_post_free pool: pci_pool_create failed\n",
+		       ioc->name);
 		goto out;
 	}
-	memset(ioc->reply_post_free, 0, sz);
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
-	    "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
-	    ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
-	    sz/1024));
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = "
-	    "(0x%llx)\n", ioc->name, (unsigned long long)
-	    ioc->reply_post_free_dma));
-	total_sz += sz;
+
+	for (i = 0; i < ioc->reply_queue_count ; i++) {
+		ioc->reply_post[i].reply_post_free =
+			pci_pool_alloc(ioc->reply_post_free_dma_pool,
+				       GFP_KERNEL,
+				       &ioc->reply_post[i].reply_post_free_dma);
+		if (!ioc->reply_post[i].reply_post_free) {
+			printk(MPT2SAS_ERR_FMT
+			       "reply_post_free pool: pci_pool_alloc failed\n"
+			       , ioc->name);
+			goto out;
+		}
+
+		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+					"reply post free pool (0x%p): depth(%d),"
+					"element_size(%d), pool_size(%d kB)\n",
+					ioc->name,
+					ioc->reply_post[i].reply_post_free,
+					ioc->reply_post_queue_depth, 8,
+					sz/1024));
+		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+					"reply_post_free_dma = (0x%llx)\n",
+					ioc->name, (unsigned long long)
+					ioc->reply_post[i].reply_post_free_dma));
+	}
+	total_sz += sz * ioc->reply_queue_count;
 
 	ioc->config_page_sz = 512;
 	ioc->config_page = pci_alloc_consistent(ioc->pdev,
@@ -2793,15 +2834,15 @@ chain_done:
 	}
 	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size"
 	    "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz));
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma"
-	    "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma));
+	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma (0x%llx)\n",
+	    ioc->name, (unsigned long long)ioc->config_page_dma));
 	total_sz += ioc->config_page_sz;
 
 	printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n",
 	    ioc->name, total_sz/1024);
-	printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), "
-	    "Max Controller Queue Depth(%d)\n",
-	    ioc->name, ioc->shost->can_queue, facts->RequestCredit);
+	printk(MPT2SAS_INFO_FMT
+	"Current Controller Queue Depth(%d), Max Controller Queue Depth(%d)\n",
+	 ioc->name, ioc->shost->can_queue, facts->RequestCredit);
 	printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n",
 	    ioc->name, ioc->shost->sg_tablesize);
 	return 0;
@@ -3489,9 +3530,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 {
 	Mpi2IOCInitRequest_t mpi_request;
 	Mpi2IOCInitReply_t mpi_reply;
-	int r;
+	int i, r = 0;
 	struct timeval current_time;
 	u16 ioc_status;
+	u32 reply_post_free_array_sz = 0;
+	Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
+	dma_addr_t reply_post_free_array_dma;
 
 	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
@@ -3520,9 +3564,35 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	    cpu_to_le64((u64)ioc->request_dma);
 	mpi_request.ReplyFreeQueueAddress =
 	    cpu_to_le64((u64)ioc->reply_free_dma);
-	mpi_request.ReplyDescriptorPostQueueAddress =
-	    cpu_to_le64((u64)ioc->reply_post_free_dma);
 
+	if (ioc->rdpq_array_enable) {
+		reply_post_free_array_sz = ioc->reply_queue_count *
+		    sizeof(Mpi2IOCInitRDPQArrayEntry);
+
+		reply_post_free_array = pci_alloc_consistent(ioc->pdev,
+				reply_post_free_array_sz,
+				&reply_post_free_array_dma);
+
+		if (!reply_post_free_array) {
+			printk(MPT2SAS_ERR_FMT
+			       "reply_post_free_array: pci_alloc_consistent failed\n",
+			       ioc->name);
+			r = -ENOMEM;
+			goto out;
+		}
+
+		memset(reply_post_free_array, 0, reply_post_free_array_sz);
+
+		for (i = 0; i < ioc->reply_queue_count; i++)
+			reply_post_free_array[i].RDPQBaseAddress =
+			    cpu_to_le64(ioc->reply_post[i].reply_post_free_dma);
+
+		mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64(reply_post_free_array_dma);
+	} else
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64(ioc->reply_post[0].reply_post_free_dma);
 
 	/* This time stamp specifies number of milliseconds
 	 * since epoch ~ midnight January 1, 1970.
@@ -3550,7 +3620,7 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	if (r != 0) {
 		printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
 		    ioc->name, __func__, r);
-		return r;
+		goto out;
 	}
 
 	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
@@ -3560,7 +3630,13 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 		r = -EIO;
 	}
 
-	return 0;
+ out:
+	if (reply_post_free_array)
+		pci_free_consistent(ioc->pdev, reply_post_free_array_sz,
+				    reply_post_free_array,
+				    reply_post_free_array_dma);
+
+	return r;
 }
 
 /**
@@ -4092,8 +4168,6 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	struct _tr_list *delayed_tr, *delayed_tr_next;
 	u8 hide_flag;
 	struct adapter_reply_queue *reply_q;
-	long reply_post_free;
-	u32 reply_post_free_sz;
 
 	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
@@ -4164,20 +4238,32 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 		_base_assign_reply_queues(ioc);
 
 	/* initialize Reply Post Free Queue */
-	reply_post_free = (long)ioc->reply_post_free;
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
 	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
+		Mpi2ReplyDescriptorsUnion_t *reply_post_free;
+		unsigned int reply_post_free_sz, index = 0;
+
+		reply_post_free_sz = ioc->reply_post_queue_depth *
+			sizeof(Mpi2DefaultReplyDescriptor_t);
+		reply_post_free = ioc->reply_post[index].reply_post_free;
+
+		reply_q->reply_post_free = reply_post_free;
 		reply_q->reply_post_host_index = 0;
-		reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
-		    reply_post_free;
-		for (i = 0; i < ioc->reply_post_queue_depth; i++)
-			reply_q->reply_post_free[i].Words =
-							cpu_to_le64(ULLONG_MAX);
+
+		memset(reply_post_free, 0xff, reply_post_free_sz);
+
 		if (!_base_is_controller_msix_enabled(ioc))
 			goto skip_init_reply_post_free_queue;
-		reply_post_free += reply_post_free_sz;
+
+		/*
+		 * If RDPQ is enabled, switch to the next allocation.
+		 * Otherwise advance within the contiguous region.
+		 */
+		if (ioc->rdpq_array_enable)
+			index++;
+		else
+			reply_post_free += reply_post_free_sz;
 	}
+
  skip_init_reply_post_free_queue:
 
 	r = _base_send_ioc_init(ioc, sleep_flag);
@@ -4304,6 +4390,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
 		}
 	}
 
+	ioc->rdpq_array_enable_assigned = 0;
 	r = mpt2sas_base_map_resources(ioc);
 	if (r)
 		goto out_free_resources;
@@ -4664,6 +4751,16 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
 		r = -EFAULT;
 		goto out;
 	}
+
+	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+	if (r)
+		goto out;
+
+	if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
+		panic("%s: Issue occurred with flashing controller firmware."
+		      "Please reboot the system and ensure that the correct"
+		      "firmware version is running\n", ioc->name);
+
 	r = _base_make_ioc_operational(ioc, sleep_flag);
 	if (!r)
 		_base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index fd3b998c75b1..e9749cb7c044 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -634,6 +634,11 @@ struct mpt2sas_port_facts {
 	u16			MaxPostedCmdBuffers;
 };
 
+struct reply_post_struct {
+	Mpi2ReplyDescriptorsUnion_t	*reply_post_free;
+	dma_addr_t			reply_post_free_dma;
+};
+
 /**
  * enum mutex_type - task management mutex type
  * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it
@@ -777,8 +782,11 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
  * @reply_free_dma_pool:
  * @reply_free_host_index: tail index in pool to insert free replys
  * @reply_post_queue_depth: reply post queue depth
- * @reply_post_free: pool for reply post (64bit descriptor)
- * @reply_post_free_dma:
+ * @reply_post_struct: struct for reply_post_free physical & virt address
+ * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
+ * @rdpq_array_enable: rdpq_array support is enabled in the driver
+ * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
+ *				is assigned only ones
  * @reply_queue_count: number of reply queue's
  * @reply_queue_list: link list contaning the reply queue info
  * @reply_post_host_index: head index in the pool where FW completes IO
@@ -970,11 +978,13 @@ struct MPT2SAS_ADAPTER {
 
 	/* reply post queue */
 	u16 		reply_post_queue_depth;
-	Mpi2ReplyDescriptorsUnion_t *reply_post_free;
-	dma_addr_t	reply_post_free_dma;
+	struct reply_post_struct *reply_post;
 	struct dma_pool *reply_post_free_dma_pool;
 	u8		reply_queue_count;
 	struct list_head reply_queue_list;
+	u8              rdpq_array_capable;
+	u8              rdpq_array_enable;
+	u8              rdpq_array_enable_assigned;
 
 	struct list_head delayed_tr_list;
 	struct list_head delayed_tr_volume_list;

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-07-23  1:25     ` Martin K. Petersen
@ 2014-07-23 17:37       ` Sreekanth Reddy
  2014-07-23 19:46         ` Martin K. Petersen
  0 siblings, 1 reply; 20+ messages in thread
From: Sreekanth Reddy @ 2014-07-23 17:37 UTC (permalink / raw)
  To: Martin K. Petersen
  Cc: jejb, James E.J. Bottomley, linux-scsi, Sathya Prakash,
	Nagalakshmi Nandigama, linux-kernel, Christoph Hellwig

Hi Martin,

Following are the changes that I have done in this patch over the
first RDPQ support patch,

1. As per your suggestion reduced the redundancy in the function
_base_release_memory_pools(), _base_allocate_memory_pools().
2. As per MPI Spec, each set of 8 reply descriptor post queues must
have the same value for the upper 32-bits of their memory address. So
allocated set of eight queues in a single pool and added a new
function is_MSB_are_same() to check whether higher 32 bits of this
pool memory address are same or not. If this functions returns zero
then we are saving these pools in the bad_reply_post_pool list. then
releasing these pools once we get the required memory pools.

Still some unit testing is needed for this patch. So I will post this
patch once again tomorrow.

Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>

diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c
b/drivers/scsi/mpt2sas/mpt2sas_base.c
index f5b8583..a319bd0 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -2681,6 +2681,34 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
 }

 /**
+ * release_bad_memory_pools - release bad reply post queue pools
+ * @ioc: per adapter object
+ *
+ * Free bad reply post queue pools.
+ *
+ * Return nothing.
+ */
+void
+release_bad_memory_pools(struct MPT2SAS_ADAPTER *ioc)
+{
+    struct bad_reply_post_pools *bad_reply_post_pool, *next;
+
+    list_for_each_entry_safe(bad_reply_post_pool, next,
+         &ioc->bad_reply_post_pool_list, list) {
+        pci_pool_free(ioc->reply_post_free_dma_pool,
+                  bad_reply_post_pool->reply_post_free,
+                  bad_reply_post_pool->reply_post_free_dma);
+        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+            "bad reply post free pool (0x%p): free\n",
+            ioc->name, bad_reply_post_pool->reply_post_free));
+        bad_reply_post_pool->reply_post_free = NULL;
+
+        list_del(&bad_reply_post_pool->list);
+        kfree(bad_reply_post_pool);
+    }
+}
+
+/**
  * _base_release_memory_pools - release memory
  * @ioc: per adapter object
  *
@@ -2692,6 +2720,7 @@ static void
 _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 {
     int i;
+    struct reply_post_struct *rps;

     dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
         __func__));
@@ -2733,18 +2762,24 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
     }

     if (ioc->reply_post) {
-        for (i = 0; i < ioc->reply_queue_count; i++) {
-            struct reply_post_struct *rps = &ioc->reply_post[i];
-            if (rps->reply_post_free) {
-                pci_pool_free(
-                    ioc->reply_post_free_dma_pool,
-                    rps->reply_post_free,
-                    rps->reply_post_free_dma);
-                dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
-                   "reply_post_free_pool(0x%p): free\n",
-                    ioc->name, rps->reply_post_free));
-                rps->reply_post_free = NULL;
-            }
+        i=0;
+        do {
+            if (i%8 == 0) {
+                rps = &ioc->reply_post[i];
+                if (rps->reply_post_free) {
+                    pci_pool_free(
+                        ioc->reply_post_free_dma_pool,
+                        rps->reply_post_free, rps->reply_post_free_dma);
+                    dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+                       "reply_post_free_pool(0x%p): free\n",
+                        ioc->name,rps->reply_post_free));
+                    rps->reply_post_free = NULL;
+                }
+            } else
+                ioc->reply_post[i].reply_post_free = NULL;
+            i++;
+        } while (ioc->rdpq_array_enable && i < ioc->reply_queue_count);
+
         if (ioc->reply_post_free_dma_pool)
             pci_pool_destroy(ioc->reply_post_free_dma_pool);
         kfree(ioc->reply_post);
@@ -2778,6 +2813,30 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
     }
 }

+/*
+ * is_MSB_are_same - checks whether all reply queues in a set are
+ *                   having same upper 32bits in their base memory address.
+ * @reply_pool_start_address: Base address of a reply queue set
+ * @pool_sz: Size of single Reply Descriptor Post Queues pool size
+ *
+ * Returns 1 if reply queues in a set have a same upper 32bits in
their base memory address,
+ * else 0
+ */
+
+static int
+is_MSB_are_same(long reply_pool_start_address, u32 pool_sz)
+{
+        long reply_pool_end_address;
+        unsigned long bit_divisor_16 = 0x10000;
+
+        reply_pool_end_address = reply_pool_start_address + pool_sz;
+
+        if (((reply_pool_start_address / bit_divisor_16) / (bit_divisor_16)) ==
+                ((reply_pool_end_address / bit_divisor_16) / bit_divisor_16))
+                return 1;
+        else
+                return 0;
+}

 /**
  * _base_allocate_memory_pools - allocate start of day memory pools
@@ -2796,6 +2855,7 @@ _base_allocate_memory_pools(struct
MPT2SAS_ADAPTER *ioc,  int sleep_flag)
     u32 retry_sz;
     u16 max_request_credit;
     int i;
+    struct bad_reply_post_pools *bad_reply_post_pool;

     dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
         __func__));
@@ -3101,84 +3161,88 @@ chain_done:
         "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
     total_sz += sz;

+    reply_post_free_sz = ioc->reply_post_queue_depth *
+        sizeof(Mpi2DefaultReplyDescriptor_t);
     if (ioc->rdpq_array_enable) {
-        ioc->reply_post = kcalloc(ioc->reply_queue_count,
-            sizeof(struct reply_post_struct), GFP_KERNEL);
-        /* reply post queue, 16 byte align */
-        reply_post_free_sz = ioc->reply_post_queue_depth *
-            sizeof(Mpi2DefaultReplyDescriptor_t);
-        sz = reply_post_free_sz;
-        ioc->reply_post_free_dma_pool =
-            pci_pool_create("reply_post_free pool", ioc->pdev, sz,
-            16, 2147483648);
-        if (!ioc->reply_post_free_dma_pool) {
-            printk(MPT2SAS_ERR_FMT
-             "reply_post_free pool: pci_pool_create failed\n",
-             ioc->name);
-            goto out;
-        }
-        for (i = 0; i < ioc->reply_queue_count; i++) {
+        sz = reply_post_free_sz * 8;
+        INIT_LIST_HEAD(&ioc->bad_reply_post_pool_list);
+    } else
+        sz = reply_post_free_sz * ioc->reply_queue_count;
+
+    ioc->reply_post = kcalloc((ioc->rdpq_array_enable)?
+        (ioc->reply_queue_count/8):1,
+        sizeof(struct reply_post_struct), GFP_KERNEL);
+
+    if (!ioc->reply_post) {
+        printk(MPT2SAS_ERR_FMT "reply_post_free pool: kcalloc failed\n",
+            ioc->name);
+        goto out;
+    }
+
+    ioc->reply_post_free_dma_pool =
+        pci_pool_create("reply_post_free pool", ioc->pdev, sz,
+            16, 0);
+    if (!ioc->reply_post_free_dma_pool) {
+        printk(MPT2SAS_ERR_FMT
+         "reply_post_free pool: pci_pool_create failed\n",
+         ioc->name);
+        goto out;
+    }
+
+    i = 0;
+    do {
+        if (i%8 == 0) {
             ioc->reply_post[i].reply_post_free =
                 pci_pool_alloc(ioc->reply_post_free_dma_pool,
                 GFP_KERNEL,
                 &ioc->reply_post[i].reply_post_free_dma);
             if (!ioc->reply_post[i].reply_post_free) {
                 printk(MPT2SAS_ERR_FMT
-                "reply_post_free pool: pci_pool_alloc failed\n"
-                , ioc->name);
+                "reply_post_free pool: pci_pool_alloc failed\n",
+                ioc->name);
+                release_bad_memory_pools(ioc);
                 goto out;
             }
+            if (ioc->rdpq_array_enable && !is_MSB_are_same(
+                 (long)ioc->reply_post[i].reply_post_free, sz)) {
+                bad_reply_post_pool = kzalloc(
+                    sizeof(struct bad_reply_post_pools),
+                    GFP_KERNEL);
+                bad_reply_post_pool->reply_post_free =
+                    ioc->reply_post[i].reply_post_free;
+                bad_reply_post_pool->reply_post_free_dma =
+                     ioc->reply_post[i].reply_post_free_dma;
+                list_add_tail(&bad_reply_post_pool->list,
+                    &ioc->bad_reply_post_pool_list);
+                ioc->reply_post[i].reply_post_free = NULL;
+                ioc->reply_post[i].reply_post_free_dma = 0;
+                continue;
+            }
             memset(ioc->reply_post[i].reply_post_free, 0, sz);
-            dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
-                "reply post free pool (0x%p): depth(%d),"
-                "element_size(%d), pool_size(%d kB)\n", ioc->name,
-                ioc->reply_post[i].reply_post_free,
-                ioc->reply_post_queue_depth, 8, sz/1024));
-            dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
-                "reply_post_free_dma = (0x%llx)\n", ioc->name,
-                (unsigned long long)
-                ioc->reply_post[i].reply_post_free_dma));
-            total_sz += sz;
-        }
-    } else {
-        ioc->reply_post = kzalloc(sizeof(struct reply_post_struct),
-            GFP_KERNEL);
-        /* reply post queue, 16 byte align */
-        reply_post_free_sz = ioc->reply_post_queue_depth *
-            sizeof(Mpi2DefaultReplyDescriptor_t);
-        if (_base_is_controller_msix_enabled(ioc))
-            sz = reply_post_free_sz * ioc->reply_queue_count;
-        else
-            sz = reply_post_free_sz;
-        ioc->reply_post_free_dma_pool =
-            pci_pool_create("reply_post_free pool",
-            ioc->pdev, sz, 16, 0);
-        if (!ioc->reply_post_free_dma_pool) {
-            printk(MPT2SAS_ERR_FMT
-                "reply_post_free pool: pci_pool_create failed\n",
-                ioc->name);
-            goto out;
-        }
-        ioc->reply_post[0].reply_post_free =
-            pci_pool_alloc(ioc->reply_post_free_dma_pool,
-            GFP_KERNEL, &ioc->reply_post[0].reply_post_free_dma);
-        if (!ioc->reply_post[0].reply_post_free) {
-            printk(MPT2SAS_ERR_FMT
-                "reply_post_free pool: pci_pool_alloc failed\n",
-                ioc->name);
-            goto out;
+        } else {
+            ioc->reply_post[i].reply_post_free =
+              (Mpi2ReplyDescriptorsUnion_t *)
+              ((long)ioc->reply_post[i-1].reply_post_free +
+              reply_post_free_sz);
+            ioc->reply_post[i].reply_post_free_dma = (dma_addr_t)
+              (ioc->reply_post[i-1].reply_post_free_dma +
+              reply_post_free_sz);
         }
-        memset(ioc->reply_post[0].reply_post_free, 0, sz);
-        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
-            "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
-            ioc->name, ioc->reply_post[0].reply_post_free,
+        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+            "reply post free pool (0x%p): depth(%d),"
+            "element_size(%d), pool_size(%d kB)\n", ioc->name,
+            ioc->reply_post[i].reply_post_free,
             ioc->reply_post_queue_depth, 8, sz/1024));
         dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
             "reply_post_free_dma = (0x%llx)\n", ioc->name,
             (unsigned long long)
-            ioc->reply_post[0].reply_post_free_dma));
-        total_sz += sz;
-    }
+            ioc->reply_post[i].reply_post_free_dma));
+        i++;
+    } while (ioc->rdpq_array_enable && i < ioc->reply_queue_count);
+
+    release_bad_memory_pools(ioc);
+    total_sz += ioc->reply_post_queue_depth *
+        sizeof(Mpi2DefaultReplyDescriptor_t) * ioc->reply_queue_count;

     ioc->config_page_sz = 512;
     ioc->config_page = pci_alloc_consistent(ioc->pdev,
@@ -3570,10 +3634,9 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER
*ioc, int sleep_flag)
     int i, r = 0;
     struct timeval current_time;
     u16 ioc_status;
-    u32 reply_post_free_array_sz;
+    u32 reply_post_free_array_sz = 0;
     Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
     dma_addr_t reply_post_free_array_dma;
-    struct dma_pool *reply_post_free_array_dma_pool = NULL;

     dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
         __func__));
@@ -3605,23 +3668,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER
*ioc, int sleep_flag)
     if (ioc->rdpq_array_enable) {
         reply_post_free_array_sz = ioc->reply_queue_count *
             sizeof(Mpi2IOCInitRDPQArrayEntry);
-        reply_post_free_array_dma_pool =
-            pci_pool_create("reply_post_free_array pool",
-            ioc->pdev, reply_post_free_array_sz, 16, 0);
-        if (!reply_post_free_array_dma_pool) {
-            printk(MPT2SAS_ERR_FMT
-            "reply_post_free_array pool: pci_pool_create failed\n",
-            ioc->name);
-            r = -ENOMEM;
-            goto out;
-        }
-        reply_post_free_array =
-            pci_pool_alloc(reply_post_free_array_dma_pool,
-            GFP_KERNEL, &reply_post_free_array_dma);
+        reply_post_free_array = pci_alloc_consistent(ioc->pdev,
+            reply_post_free_array_sz, &reply_post_free_array_dma);
         if (!reply_post_free_array) {
             printk(MPT2SAS_ERR_FMT
-             "reply_post_free_array pool: pci_pool_alloc failed\n",
-             ioc->name);
+            "reply_post_free_array: pci_alloc_consistent failed\n",
+            ioc->name);
             r = -ENOMEM;
             goto out;
         }
@@ -3675,15 +3727,10 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER
*ioc, int sleep_flag)
     }

  out:
-    if (ioc->rdpq_array_enable) {
-        if (reply_post_free_array) {
-            pci_pool_free(reply_post_free_array_dma_pool,
-                reply_post_free_array, reply_post_free_array_dma);
-            reply_post_free_array = NULL;
-        }
-        if (reply_post_free_array_dma_pool)
-            pci_pool_destroy(reply_post_free_array_dma_pool);
-    }
+    if (reply_post_free_array)
+        pci_free_consistent(ioc->pdev, reply_post_free_array_sz,
+                    reply_post_free_array,
+                    reply_post_free_array_dma);
     return r;
 }

@@ -4209,15 +4256,15 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER
*ioc, int sleep_flag,
 static int
 _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 {
-    int r, i, j = 0;
+    int r, i;
     unsigned long    flags;
     u32 reply_address;
     u16 smid;
     struct _tr_list *delayed_tr, *delayed_tr_next;
     u8 hide_flag;
     struct adapter_reply_queue *reply_q;
-    long reply_post_free;
-    u32 reply_post_free_sz;
+    Mpi2ReplyDescriptorsUnion_t *reply_post_free = NULL;
+    unsigned int reply_post_free_sz, index = 0;

     dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
         __func__));
@@ -4288,32 +4335,23 @@ _base_make_ioc_operational(struct
MPT2SAS_ADAPTER *ioc, int sleep_flag)
         _base_assign_reply_queues(ioc);

     /* initialize Reply Post Free Queue */
-    if (ioc->rdpq_array_enable) {
-        list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
-            reply_q->reply_post_host_index = 0;
-            reply_q->reply_post_free =
-                ioc->reply_post[j++].reply_post_free;
-            for (i = 0; i < ioc->reply_post_queue_depth; i++)
-                reply_q->reply_post_free[i].Words =
-                    cpu_to_le64(ULLONG_MAX);
-            if (!_base_is_controller_msix_enabled(ioc))
-                goto skip_init_reply_post_free_queue;
-        }
-    } else {
-        reply_post_free = (long)ioc->reply_post[0].reply_post_free;
-        reply_post_free_sz = ioc->reply_post_queue_depth *
-            sizeof(Mpi2DefaultReplyDescriptor_t);
-        list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
-            reply_q->reply_post_host_index = 0;
-            reply_q->reply_post_free =
-                (Mpi2ReplyDescriptorsUnion_t *)reply_post_free;
-            for (i = 0; i < ioc->reply_post_queue_depth; i++)
-                reply_q->reply_post_free[i].Words =
-                    cpu_to_le64(ULLONG_MAX);
-            if (!_base_is_controller_msix_enabled(ioc))
-                goto skip_init_reply_post_free_queue;
+    reply_post_free_sz = ioc->reply_post_queue_depth *
+                sizeof(Mpi2DefaultReplyDescriptor_t);
+    list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
+        reply_post_free = ioc->reply_post[index].reply_post_free;
+        reply_q->reply_post_free = reply_post_free;
+        reply_q->reply_post_host_index = 0;
+        memset(reply_post_free, 0xff, reply_post_free_sz);
+        if (!_base_is_controller_msix_enabled(ioc))
+            goto skip_init_reply_post_free_queue;
+        /*
+         * If RDPQ is enabled, switch to the next allocation.
+         * Otherwise advance within the contiguous region.
+         */
+        if (ioc->rdpq_array_enable)
+            index++;
+        else
             reply_post_free += reply_post_free_sz;
-        }
     }
  skip_init_reply_post_free_queue:

diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h
b/drivers/scsi/mpt2sas/mpt2sas_base.h
index ec15e0e..8b9a50d 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -642,6 +642,20 @@ struct reply_post_struct {
 };

 /**
+ * struct bad_reply_post_pools - per bad reply post pool which doesn't
+ *             satisfy MPI SPEC rule of having same upper 32bits
+ *             of memory address in a set of 8 reply queues
+ * @reply_post_free: virtual address of reply post pool
+ * @reply_post_free_dma: Physical address of reply post pool
+ * @list: Bad reply post pool list
+ */
+struct bad_reply_post_pools {
+    Mpi2ReplyDescriptorsUnion_t     *reply_post_free;
+    dma_addr_t                      reply_post_free_dma;
+    struct list_head         list;
+};
+
+/**
  * enum mutex_type - task management mutex type
  * @TM_MUTEX_OFF: mutex is not required becuase calling function is
acquiring it
  * @TM_MUTEX_ON: mutex is required
@@ -785,6 +799,7 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct
MPT2SAS_ADAPTER *ioc);
  * @reply_free_host_index: tail index in pool to insert free replys
  * @reply_post_queue_depth: reply post queue depth
  * @reply_post_struct: struct for reply_post_free physical & virt address
+ * @bad_reply_post_pool_list: list of bad reply post queue pools
  * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
  * @rdpq_array_enable: rdpq_array support is enabled in the driver
  * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
@@ -981,6 +996,7 @@ struct MPT2SAS_ADAPTER {
     /* reply post queue */
     u16         reply_post_queue_depth;
     struct reply_post_struct *reply_post;
+    struct list_head bad_reply_post_pool_list;
     struct dma_pool *reply_post_free_dma_pool;
     u8        reply_queue_count;
     struct list_head reply_queue_list;

On Wed, Jul 23, 2014 at 6:55 AM, Martin K. Petersen
<martin.petersen@oracle.com> wrote:
>>>>>> "Sreekanth" == Sreekanth Reddy <sreekanth.reddy@avagotech.com> writes:
>
> Sreekanth,
>
>>> Why do you need to special case !rdpq? Isn't reply_queue_count = 1 in
>>> that case?
>
> Sreekanth> [Sreekanth] we have added this RDPQ support in phase18. So,
> Sreekanth> the firmware from less than phase18 doesn't have this RDPQ
> Sreekanth> support.
>
> Yes, but a single allocation is a subset of multiple allocations. That
> has nothing to do with firmware phase and whether RDPQ is available or
> not.
>
> I have attached a simplified patch below. I probably messed something up
> but you get the idea.
>
> When a new feature is introduced you guys generally go:
>
>         if (new_feature) {
>                 /* Huge block of code */
>         } else {
>                 /* Almost identical huge block of original code */
>         }
>
> I assume that's done to leave the original code paths unchanged. But
> that approach doesn't fly around here. You'll have to come up with a
> generic approach that reduces code duplication and which minimizes the
> differences between the new feature and the old one.
>
> As an example:
>
> Original patch:
>  mpt2sas_base.c |  923 +++++++++++++++++++++++++++++++++------------------------
>  mpt2sas_base.h |   18 -
>  2 files changed, 558 insertions(+), 383 deletions(-)
>
> My patch:
>  mpt2sas_base.c |  207 +++++++++++++++++++++++++++++++++++++++++----------------
>  mpt2sas_base.h |   18 +++-
>  2 files changed, 166 insertions(+), 59 deletions(-)
>
>
> commit ef510bd8dc0e43f8c58012ba9f54213b26381464
> Author: Martin K. Petersen <martin.petersen@oracle.com>
> Date:   Tue Jul 22 20:56:27 2014 -0400
>
>     Up to now, driver allocates a single contiguous block of memory pool for
>     all reply queues and passes down a single address in the
>     ReplyDescriptorPostQueueAddress field of the IOC Init Request Message to
>     the firmware.
>
>     When firmware receives this address, it will program each of the Reply
>     Descriptor Post Queue registers, as each reply queue has its own
>     register. Thus the firmware, starting from a base address it determines
>     the starting address of the subsequent reply queues through some simple
>     arithmetic calculations.
>
>     The size of this contiguous block of memory pool is directly
>     proportional to number of MSI-X vectors and the HBA queue depth. For
>     example higher MSI-X vectors requires larger contiguous block of memory
>     pool.
>
>     But some of the OS kernels are unable to allocate this larger
>     contiguous block of memory pool.
>
>     So, the proposal is to allocate memory independently for each Reply
>     Queue and pass down all of the addresses to the firmware.  Then the
>     firmware will just take each address and program the value into the
>     correct register.
>
>     When HBAs with older firmware(i.e. without RDPQ capability) is used with
>     this new driver then the max_msix_vectors value would be set to 8 by
>     default.
>
>     Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
>     Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
>
> diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
> index 22c4575241fc..2d39d5196788 100644
> --- a/drivers/scsi/mpt2sas/mpt2sas_base.c
> +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
> @@ -92,6 +92,8 @@ static int disable_discovery = -1;
>  module_param(disable_discovery, int, 0);
>  MODULE_PARM_DESC(disable_discovery, " disable discovery ");
>
> +static int _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag);
> +
>  /**
>   * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
>   *
> @@ -1424,6 +1426,9 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
>         ioc->reply_queue_count = min_t(int, ioc->cpu_count,
>             ioc->msix_vector_count);
>
> +       if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
> +               max_msix_vectors = 8;
> +
>         if (max_msix_vectors > 0) {
>                 ioc->reply_queue_count = min_t(int, max_msix_vectors,
>                     ioc->reply_queue_count);
> @@ -1552,6 +1557,16 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
>         }
>
>         _base_mask_interrupts(ioc);
> +
> +       r = _base_get_ioc_facts(ioc, CAN_SLEEP);
> +       if (r)
> +               goto out_fail;
> +
> +       if (!ioc->rdpq_array_enable_assigned) {
> +               ioc->rdpq_array_enable = ioc->rdpq_array_capable;
> +               ioc->rdpq_array_enable_assigned = 1;
> +       }
> +
>         r = _base_enable_msix(ioc);
>         if (r)
>                 goto out_fail;
> @@ -2390,15 +2405,25 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
>                 ioc->reply_free = NULL;
>         }
>
> -       if (ioc->reply_post_free) {
> -               pci_pool_free(ioc->reply_post_free_dma_pool,
> -                   ioc->reply_post_free, ioc->reply_post_free_dma);
> +       if (ioc->reply_post) {
> +               for (i = 0; i < ioc->reply_queue_count ; i++) {
> +                       struct reply_post_struct *rps = &ioc->reply_post[i];
> +
> +                       if (rps->reply_post_free) {
> +                               pci_pool_free(ioc->reply_post_free_dma_pool,
> +                                             rps->reply_post_free,
> +                                             rps->reply_post_free_dma);
> +                               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
> +                                       "reply_post_free_pool(0x%p): free\n",
> +                                       ioc->name, rps->reply_post_free));
> +                               rps->reply_post_free = NULL;
> +                       }
> +               }
> +
>                 if (ioc->reply_post_free_dma_pool)
>                         pci_pool_destroy(ioc->reply_post_free_dma_pool);
> -               dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
> -                   "reply_post_free_pool(0x%p): free\n", ioc->name,
> -                   ioc->reply_post_free));
> -               ioc->reply_post_free = NULL;
> +
> +               kfree(ioc->reply_post);
>         }
>
>         if (ioc->config_page) {
> @@ -2443,7 +2468,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
>         struct mpt2sas_facts *facts;
>         u16 max_sge_elements;
>         u16 chains_needed_per_io;
> -       u32 sz, total_sz, reply_post_free_sz;
> +       u32 sz, total_sz;
>         u32 retry_sz;
>         u16 max_request_credit;
>         int i;
> @@ -2752,36 +2777,52 @@ chain_done:
>             "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
>         total_sz += sz;
>
> -       /* reply post queue, 16 byte align */
> -       reply_post_free_sz = ioc->reply_post_queue_depth *
> -           sizeof(Mpi2DefaultReplyDescriptor_t);
> -       if (_base_is_controller_msix_enabled(ioc))
> -               sz = reply_post_free_sz * ioc->reply_queue_count;
> -       else
> -               sz = reply_post_free_sz;
> -       ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
> -           ioc->pdev, sz, 16, 0);
> -       if (!ioc->reply_post_free_dma_pool) {
> -               printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create "
> -                   "failed\n", ioc->name);
> +       /* reply post queue, 16-byte alignment, do not cross 2GB boundary */
> +       sz = ioc->reply_post_queue_depth * sizeof(Mpi2DefaultReplyDescriptor_t);
> +
> +       ioc->reply_post = kcalloc(ioc->reply_queue_count,
> +                                 sizeof(struct reply_post_struct), GFP_KERNEL);
> +       if (!ioc->reply_post) {
> +               printk(MPT2SAS_ERR_FMT "reply_post_free pool: kcalloc failed\n",
> +                      ioc->name);
>                 goto out;
>         }
> -       ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
> -           GFP_KERNEL, &ioc->reply_post_free_dma);
> -       if (!ioc->reply_post_free) {
> -               printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc "
> -                   "failed\n", ioc->name);
> +
> +       ioc->reply_post_free_dma_pool =
> +               pci_pool_create("reply_post_free pool", ioc->pdev, sz, 16,
> +                               2L * 1024 * 1024 * 1024);
> +       if (!ioc->reply_post_free_dma_pool) {
> +               printk(MPT2SAS_ERR_FMT
> +                      "reply_post_free pool: pci_pool_create failed\n",
> +                      ioc->name);
>                 goto out;
>         }
> -       memset(ioc->reply_post_free, 0, sz);
> -       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
> -           "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
> -           ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
> -           sz/1024));
> -       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = "
> -           "(0x%llx)\n", ioc->name, (unsigned long long)
> -           ioc->reply_post_free_dma));
> -       total_sz += sz;
> +
> +       for (i = 0; i < ioc->reply_queue_count ; i++) {
> +               ioc->reply_post[i].reply_post_free =
> +                       pci_pool_alloc(ioc->reply_post_free_dma_pool,
> +                                      GFP_KERNEL,
> +                                      &ioc->reply_post[i].reply_post_free_dma);
> +               if (!ioc->reply_post[i].reply_post_free) {
> +                       printk(MPT2SAS_ERR_FMT
> +                              "reply_post_free pool: pci_pool_alloc failed\n"
> +                              , ioc->name);
> +                       goto out;
> +               }
> +
> +               dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
> +                                       "reply post free pool (0x%p): depth(%d),"
> +                                       "element_size(%d), pool_size(%d kB)\n",
> +                                       ioc->name,
> +                                       ioc->reply_post[i].reply_post_free,
> +                                       ioc->reply_post_queue_depth, 8,
> +                                       sz/1024));
> +               dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
> +                                       "reply_post_free_dma = (0x%llx)\n",
> +                                       ioc->name, (unsigned long long)
> +                                       ioc->reply_post[i].reply_post_free_dma));
> +       }
> +       total_sz += sz * ioc->reply_queue_count;
>
>         ioc->config_page_sz = 512;
>         ioc->config_page = pci_alloc_consistent(ioc->pdev,
> @@ -2793,15 +2834,15 @@ chain_done:
>         }
>         dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size"
>             "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz));
> -       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma"
> -           "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma));
> +       dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma (0x%llx)\n",
> +           ioc->name, (unsigned long long)ioc->config_page_dma));
>         total_sz += ioc->config_page_sz;
>
>         printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n",
>             ioc->name, total_sz/1024);
> -       printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), "
> -           "Max Controller Queue Depth(%d)\n",
> -           ioc->name, ioc->shost->can_queue, facts->RequestCredit);
> +       printk(MPT2SAS_INFO_FMT
> +       "Current Controller Queue Depth(%d), Max Controller Queue Depth(%d)\n",
> +        ioc->name, ioc->shost->can_queue, facts->RequestCredit);
>         printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n",
>             ioc->name, ioc->shost->sg_tablesize);
>         return 0;
> @@ -3489,9 +3530,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
>  {
>         Mpi2IOCInitRequest_t mpi_request;
>         Mpi2IOCInitReply_t mpi_reply;
> -       int r;
> +       int i, r = 0;
>         struct timeval current_time;
>         u16 ioc_status;
> +       u32 reply_post_free_array_sz = 0;
> +       Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
> +       dma_addr_t reply_post_free_array_dma;
>
>         dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
>             __func__));
> @@ -3520,9 +3564,35 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
>             cpu_to_le64((u64)ioc->request_dma);
>         mpi_request.ReplyFreeQueueAddress =
>             cpu_to_le64((u64)ioc->reply_free_dma);
> -       mpi_request.ReplyDescriptorPostQueueAddress =
> -           cpu_to_le64((u64)ioc->reply_post_free_dma);
>
> +       if (ioc->rdpq_array_enable) {
> +               reply_post_free_array_sz = ioc->reply_queue_count *
> +                   sizeof(Mpi2IOCInitRDPQArrayEntry);
> +
> +               reply_post_free_array = pci_alloc_consistent(ioc->pdev,
> +                               reply_post_free_array_sz,
> +                               &reply_post_free_array_dma);
> +
> +               if (!reply_post_free_array) {
> +                       printk(MPT2SAS_ERR_FMT
> +                              "reply_post_free_array: pci_alloc_consistent failed\n",
> +                              ioc->name);
> +                       r = -ENOMEM;
> +                       goto out;
> +               }
> +
> +               memset(reply_post_free_array, 0, reply_post_free_array_sz);
> +
> +               for (i = 0; i < ioc->reply_queue_count; i++)
> +                       reply_post_free_array[i].RDPQBaseAddress =
> +                           cpu_to_le64(ioc->reply_post[i].reply_post_free_dma);
> +
> +               mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
> +               mpi_request.ReplyDescriptorPostQueueAddress =
> +                   cpu_to_le64(reply_post_free_array_dma);
> +       } else
> +               mpi_request.ReplyDescriptorPostQueueAddress =
> +                   cpu_to_le64(ioc->reply_post[0].reply_post_free_dma);
>
>         /* This time stamp specifies number of milliseconds
>          * since epoch ~ midnight January 1, 1970.
> @@ -3550,7 +3620,7 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
>         if (r != 0) {
>                 printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
>                     ioc->name, __func__, r);
> -               return r;
> +               goto out;
>         }
>
>         ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
> @@ -3560,7 +3630,13 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
>                 r = -EIO;
>         }
>
> -       return 0;
> + out:
> +       if (reply_post_free_array)
> +               pci_free_consistent(ioc->pdev, reply_post_free_array_sz,
> +                                   reply_post_free_array,
> +                                   reply_post_free_array_dma);
> +
> +       return r;
>  }
>
>  /**
> @@ -4092,8 +4168,6 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
>         struct _tr_list *delayed_tr, *delayed_tr_next;
>         u8 hide_flag;
>         struct adapter_reply_queue *reply_q;
> -       long reply_post_free;
> -       u32 reply_post_free_sz;
>
>         dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
>             __func__));
> @@ -4164,20 +4238,32 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
>                 _base_assign_reply_queues(ioc);
>
>         /* initialize Reply Post Free Queue */
> -       reply_post_free = (long)ioc->reply_post_free;
> -       reply_post_free_sz = ioc->reply_post_queue_depth *
> -           sizeof(Mpi2DefaultReplyDescriptor_t);
>         list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
> +               Mpi2ReplyDescriptorsUnion_t *reply_post_free;
> +               unsigned int reply_post_free_sz, index = 0;
> +
> +               reply_post_free_sz = ioc->reply_post_queue_depth *
> +                       sizeof(Mpi2DefaultReplyDescriptor_t);
> +               reply_post_free = ioc->reply_post[index].reply_post_free;
> +
> +               reply_q->reply_post_free = reply_post_free;
>                 reply_q->reply_post_host_index = 0;
> -               reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
> -                   reply_post_free;
> -               for (i = 0; i < ioc->reply_post_queue_depth; i++)
> -                       reply_q->reply_post_free[i].Words =
> -                                                       cpu_to_le64(ULLONG_MAX);
> +
> +               memset(reply_post_free, 0xff, reply_post_free_sz);
> +
>                 if (!_base_is_controller_msix_enabled(ioc))
>                         goto skip_init_reply_post_free_queue;
> -               reply_post_free += reply_post_free_sz;
> +
> +               /*
> +                * If RDPQ is enabled, switch to the next allocation.
> +                * Otherwise advance within the contiguous region.
> +                */
> +               if (ioc->rdpq_array_enable)
> +                       index++;
> +               else
> +                       reply_post_free += reply_post_free_sz;
>         }
> +
>   skip_init_reply_post_free_queue:
>
>         r = _base_send_ioc_init(ioc, sleep_flag);
> @@ -4304,6 +4390,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
>                 }
>         }
>
> +       ioc->rdpq_array_enable_assigned = 0;
>         r = mpt2sas_base_map_resources(ioc);
>         if (r)
>                 goto out_free_resources;
> @@ -4664,6 +4751,16 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
>                 r = -EFAULT;
>                 goto out;
>         }
> +
> +       r = _base_get_ioc_facts(ioc, CAN_SLEEP);
> +       if (r)
> +               goto out;
> +
> +       if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
> +               panic("%s: Issue occurred with flashing controller firmware."
> +                     "Please reboot the system and ensure that the correct"
> +                     "firmware version is running\n", ioc->name);
> +
>         r = _base_make_ioc_operational(ioc, sleep_flag);
>         if (!r)
>                 _base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
> diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
> index fd3b998c75b1..e9749cb7c044 100644
> --- a/drivers/scsi/mpt2sas/mpt2sas_base.h
> +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
> @@ -634,6 +634,11 @@ struct mpt2sas_port_facts {
>         u16                     MaxPostedCmdBuffers;
>  };
>
> +struct reply_post_struct {
> +       Mpi2ReplyDescriptorsUnion_t     *reply_post_free;
> +       dma_addr_t                      reply_post_free_dma;
> +};
> +
>  /**
>   * enum mutex_type - task management mutex type
>   * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it
> @@ -777,8 +782,11 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
>   * @reply_free_dma_pool:
>   * @reply_free_host_index: tail index in pool to insert free replys
>   * @reply_post_queue_depth: reply post queue depth
> - * @reply_post_free: pool for reply post (64bit descriptor)
> - * @reply_post_free_dma:
> + * @reply_post_struct: struct for reply_post_free physical & virt address
> + * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
> + * @rdpq_array_enable: rdpq_array support is enabled in the driver
> + * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
> + *                             is assigned only ones
>   * @reply_queue_count: number of reply queue's
>   * @reply_queue_list: link list contaning the reply queue info
>   * @reply_post_host_index: head index in the pool where FW completes IO
> @@ -970,11 +978,13 @@ struct MPT2SAS_ADAPTER {
>
>         /* reply post queue */
>         u16             reply_post_queue_depth;
> -       Mpi2ReplyDescriptorsUnion_t *reply_post_free;
> -       dma_addr_t      reply_post_free_dma;
> +       struct reply_post_struct *reply_post;
>         struct dma_pool *reply_post_free_dma_pool;
>         u8              reply_queue_count;
>         struct list_head reply_queue_list;
> +       u8              rdpq_array_capable;
> +       u8              rdpq_array_enable;
> +       u8              rdpq_array_enable_assigned;
>
>         struct list_head delayed_tr_list;
>         struct list_head delayed_tr_volume_list;

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-07-23 17:37       ` Sreekanth Reddy
@ 2014-07-23 19:46         ` Martin K. Petersen
  2014-07-25 12:57           ` Sreekanth Reddy
  2017-04-25 11:51           ` Sreekanth Reddy
  0 siblings, 2 replies; 20+ messages in thread
From: Martin K. Petersen @ 2014-07-23 19:46 UTC (permalink / raw)
  To: Sreekanth Reddy
  Cc: Martin K. Petersen, jejb, James E.J. Bottomley, linux-scsi,
	Sathya Prakash, Nagalakshmi Nandigama, linux-kernel,
	Christoph Hellwig

>>>>> "Sreekanth" == Sreekanth Reddy <sreekanth.reddy@avagotech.com> writes:

Sreekanth,

Sreekanth> 2. As per MPI Spec, each set of 8 reply descriptor post
Sreekanth> queues must have the same value for the upper 32-bits of
Sreekanth> their memory address. So allocated set of eight queues in a
Sreekanth> single pool and added a new function is_MSB_are_same() to
Sreekanth> check whether higher 32 bits of this pool memory address are
Sreekanth> same or not. If this functions returns zero then we are
Sreekanth> saving these pools in the bad_reply_post_pool list. then
Sreekanth> releasing these pools once we get the required memory pools.

Why don't you just set pci_set_consistent_dma_mask() to DMA_BIT_MASK(32)
before you allocate the queue entries?

-- 
Martin K. Petersen	Oracle Linux Engineering

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-07-23 19:46         ` Martin K. Petersen
@ 2014-07-25 12:57           ` Sreekanth Reddy
  2014-07-25 19:43             ` Martin K. Petersen
  2017-04-25 11:51           ` Sreekanth Reddy
  1 sibling, 1 reply; 20+ messages in thread
From: Sreekanth Reddy @ 2014-07-25 12:57 UTC (permalink / raw)
  To: Martin K. Petersen
  Cc: jejb, James E.J. Bottomley, linux-scsi, Sathya Prakash,
	Nagalakshmi Nandigama, linux-kernel, Christoph Hellwig

Hi Martin,

Following are the changes that I have done in this patch over the
first RDPQ support patch,

1. Reduced the redundancy in the function
_base_release_memory_pools(), _base_allocate_memory_pools().
2. Set pci_set_consistent_dma_mask() to DMA_BIT_MASK(32). still I am
analysing whether this change may affect on any other things or not?

Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>

diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c
b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 6b2a79e..cf69e61 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -1186,7 +1186,7 @@ _base_config_dma_addressing(struct
MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
             dma_get_required_mask(&pdev->dev);
         if ((required_mask > DMA_BIT_MASK(32)) && !pci_set_dma_mask(pdev,
             DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(pdev,
-            DMA_BIT_MASK(64))) {
+            DMA_BIT_MASK(32))) {
             ioc->base_add_sg_single = &_base_add_sg_single_64;
             ioc->sge_size = sizeof(Mpi2SGESimple64_t);
             desc = "64";
@@ -1424,6 +1424,9 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
     ioc->reply_queue_count = min_t(int, ioc->cpu_count,
         ioc->msix_vector_count);

+    if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
+        max_msix_vectors = 8;
+
     if (max_msix_vectors > 0) {
         ioc->reply_queue_count = min_t(int, max_msix_vectors,
             ioc->reply_queue_count);
@@ -1477,6 +1480,335 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
 }

 /**
+ * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
+ * a write to the doorbell)
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
+ */
+static int
+_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
+    int sleep_flag)
+{
+    u32 cntdn, count;
+    u32 int_status;
+
+    count = 0;
+    cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+    do {
+        int_status = readl(&ioc->chip->HostInterruptStatus);
+        if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
+            dhsprintk(ioc, printk(MPT2SAS_INFO_FMT
+                "%s: successful count(%d), timeout(%d)\n",
+                ioc->name, __func__, count, timeout));
+            return 0;
+        }
+        if (sleep_flag == CAN_SLEEP)
+            msleep(1);
+        else
+            udelay(500);
+        count++;
+    } while (--cntdn);
+
+    printk(MPT2SAS_ERR_FMT
+        "%s: failed due to timeout count(%d), int_status(%x)!\n",
+        ioc->name, __func__, count, int_status);
+    return -EFAULT;
+}
+
+/**
+ * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to
+ * doorbell.
+ */
+static int
+_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
+    int sleep_flag)
+{
+    u32 cntdn, count;
+    u32 int_status;
+    u32 doorbell;
+
+    count = 0;
+    cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+    do {
+        int_status = readl(&ioc->chip->HostInterruptStatus);
+        if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
+            dhsprintk(ioc, printk(MPT2SAS_INFO_FMT
+                "%s: successful count(%d), timeout(%d)\n",
+                ioc->name, __func__, count, timeout));
+            return 0;
+        } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
+            doorbell = readl(&ioc->chip->Doorbell);
+            if ((doorbell & MPI2_IOC_STATE_MASK) ==
+                MPI2_IOC_STATE_FAULT) {
+                mpt2sas_base_fault_info(ioc , doorbell);
+                return -EFAULT;
+            }
+        } else if (int_status == 0xFFFFFFFF)
+            goto out;
+
+        if (sleep_flag == CAN_SLEEP)
+            msleep(1);
+        else
+            udelay(500);
+        count++;
+    } while (--cntdn);
+
+ out:
+    printk(MPT2SAS_ERR_FMT
+        "%s: failed due to timeout count(%d), int_status(%x)!\n",
+        ioc->name, __func__, count, int_status);
+    return -EFAULT;
+}
+
+/**
+ * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use
+ * @ioc: per adapter object
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ *
+ */
+static int
+_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,
+    int sleep_flag)
+{
+    u32 cntdn, count;
+    u32 doorbell_reg;
+
+    count = 0;
+    cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
+    do {
+        doorbell_reg = readl(&ioc->chip->Doorbell);
+        if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
+            dhsprintk(ioc, printk(MPT2SAS_INFO_FMT
+                "%s: successful count(%d), timeout(%d)\n",
+                ioc->name, __func__, count, timeout));
+            return 0;
+        }
+        if (sleep_flag == CAN_SLEEP)
+            msleep(1);
+        else
+            udelay(500);
+        count++;
+    } while (--cntdn);
+
+    printk(MPT2SAS_ERR_FMT
+        "%s: failed due to timeout count(%d), doorbell_reg(%x)!\n",
+        ioc->name, __func__, count, doorbell_reg);
+    return -EFAULT;
+}
+
+/**
+ * _base_handshake_req_reply_wait - send request thru doorbell interface
+ * @ioc: per adapter object
+ * @request_bytes: request length
+ * @request: pointer having request payload
+ * @reply_bytes: reply length
+ * @reply: pointer to reply payload
+ * @timeout: timeout in second
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
+    u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
+{
+    MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
+    int i;
+    u8 failed;
+    u16 dummy;
+    __le32 *mfp;
+
+    /* make sure doorbell is not in use */
+    if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
+        printk(MPT2SAS_ERR_FMT "doorbell is in use (line=%d)\n",
+            ioc->name, __LINE__);
+        return -EFAULT;
+    }
+
+    /* clear pending doorbell interrupts from previous state changes */
+    if (readl(&ioc->chip->HostInterruptStatus) &
+        MPI2_HIS_IOC2SYS_DB_STATUS)
+        writel(0, &ioc->chip->HostInterruptStatus);
+
+    /* send message to ioc */
+    writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
+        ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
+        &ioc->chip->Doorbell);
+
+    if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {
+        printk(MPT2SAS_ERR_FMT
+           "doorbell handshake int failed (line=%d)\n",
+           ioc->name, __LINE__);
+        return -EFAULT;
+    }
+    writel(0, &ioc->chip->HostInterruptStatus);
+
+    if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
+        printk(MPT2SAS_ERR_FMT
+            "doorbell handshake ack failed (line=%d)\n",
+            ioc->name, __LINE__);
+        return -EFAULT;
+    }
+
+    /* send message 32-bits at a time */
+    for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
+        writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
+        if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
+            failed = 1;
+    }
+
+    if (failed) {
+        printk(MPT2SAS_ERR_FMT
+           "doorbell handshake sending request failed (line=%d)\n",
+           ioc->name, __LINE__);
+        return -EFAULT;
+    }
+
+    /* now wait for the reply */
+    if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
+        printk(MPT2SAS_ERR_FMT
+           "doorbell handshake int failed (line=%d)\n",
+           ioc->name, __LINE__);
+        return -EFAULT;
+    }
+
+    /* read the first two 16-bits, it gives the total length of the reply */
+    reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+        & MPI2_DOORBELL_DATA_MASK);
+    writel(0, &ioc->chip->HostInterruptStatus);
+    if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+        printk(MPT2SAS_ERR_FMT
+           "doorbell handshake int failed (line=%d)\n",
+           ioc->name, __LINE__);
+        return -EFAULT;
+    }
+    reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+        & MPI2_DOORBELL_DATA_MASK);
+    writel(0, &ioc->chip->HostInterruptStatus);
+
+    for (i = 2; i < default_reply->MsgLength * 2; i++)  {
+        if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+            printk(MPT2SAS_ERR_FMT
+                "doorbell handshake int failed (line=%d)\n",
+                ioc->name, __LINE__);
+            return -EFAULT;
+        }
+        if (i >=  reply_bytes/2) /* overflow case */
+            dummy = readl(&ioc->chip->Doorbell);
+        else
+            reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
+                & MPI2_DOORBELL_DATA_MASK);
+        writel(0, &ioc->chip->HostInterruptStatus);
+    }
+
+    _base_wait_for_doorbell_int(ioc, 5, sleep_flag);
+    if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) {
+        dhsprintk(ioc, printk(MPT2SAS_INFO_FMT
+            "doorbell is in use (line=%d)\n", ioc->name, __LINE__));
+    }
+    writel(0, &ioc->chip->HostInterruptStatus);
+
+    if (ioc->logging_level & MPT_DEBUG_INIT) {
+        mfp = (__le32 *)reply;
+        pr_info("\toffset:data\n");
+        for (i = 0; i < reply_bytes/4; i++)
+            pr_info("\t[0x%02x]:%08x\n", i*4,
+                le32_to_cpu(mfp[i]));
+    }
+    return 0;
+}
+
+/**
+ * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
+ * @ioc: per adapter object
+ * @sleep_flag: CAN_SLEEP or NO_SLEEP
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+static int
+_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
+{
+    Mpi2IOCFactsRequest_t mpi_request;
+    Mpi2IOCFactsReply_t mpi_reply;
+    struct mpt2sas_facts *facts;
+    int mpi_reply_sz, mpi_request_sz, r;
+
+    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
+        __func__));
+
+    mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
+    mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
+    memset(&mpi_request, 0, mpi_request_sz);
+    mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
+    r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
+        (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
+
+    if (r != 0) {
+        printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
+            ioc->name, __func__, r);
+        return r;
+    }
+
+    facts = &ioc->facts;
+    memset(facts, 0, sizeof(struct mpt2sas_facts));
+    facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
+    facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
+    facts->VP_ID = mpi_reply.VP_ID;
+    facts->VF_ID = mpi_reply.VF_ID;
+    facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
+    facts->MaxChainDepth = mpi_reply.MaxChainDepth;
+    facts->WhoInit = mpi_reply.WhoInit;
+    facts->NumberOfPorts = mpi_reply.NumberOfPorts;
+    facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;
+    facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
+    facts->MaxReplyDescriptorPostQueueDepth =
+        le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
+    facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
+    facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
+    if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
+        ioc->ir_firmware = 1;
+    if ((facts->IOCCapabilities &
+          MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE))
+        ioc->rdpq_array_capable = 1;
+    facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
+    facts->IOCRequestFrameSize =
+        le16_to_cpu(mpi_reply.IOCRequestFrameSize);
+    facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
+    facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
+    ioc->shost->max_id = -1;
+    facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
+    facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
+    facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
+    facts->HighPriorityCredit =
+        le16_to_cpu(mpi_reply.HighPriorityCredit);
+    facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
+    facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
+
+    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+        "hba queue depth(%d), max chains per io(%d)\n", ioc->name,
+        facts->RequestCredit, facts->MaxChainDepth));
+    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+        "request frame size(%d), reply frame size(%d)\n", ioc->name,
+        facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
+    return 0;
+}
+
+/**
  * mpt2sas_base_map_resources - map in controller resources (io/irq/memap)
  * @ioc: per adapter object
  *
@@ -1552,6 +1884,16 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
     }

     _base_mask_interrupts(ioc);
+
+    r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+    if (r)
+        goto out_fail;
+
+    if (!ioc->rdpq_array_enable_assigned) {
+        ioc->rdpq_array_enable = ioc->rdpq_array_capable;
+        ioc->rdpq_array_enable_assigned = 1;
+    }
+
     r = _base_enable_msix(ioc);
     if (r)
         goto out_fail;
@@ -2349,7 +2691,7 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
 static void
 _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 {
-    int i;
+    int i = 0;

     dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
         __func__));
@@ -2390,15 +2732,25 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
         ioc->reply_free = NULL;
     }

-    if (ioc->reply_post_free) {
-        pci_pool_free(ioc->reply_post_free_dma_pool,
-            ioc->reply_post_free, ioc->reply_post_free_dma);
+    if (ioc->reply_post) {
+        do {
+            if (ioc->reply_post[i].reply_post_free) {
+                pci_pool_free(
+                  ioc->reply_post_free_dma_pool,
+                  ioc->reply_post[i].reply_post_free,
+                  ioc->reply_post[i].reply_post_free_dma);
+                dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+                  "reply_post_free_pool(0x%p): free\n",
+                  ioc->name,
+                  ioc->reply_post[i].reply_post_free));
+                ioc->reply_post[i].reply_post_free = NULL;
+            }
+        } while (ioc->rdpq_array_enable &&
+                (++i < ioc->reply_queue_count));
+
         if (ioc->reply_post_free_dma_pool)
             pci_pool_destroy(ioc->reply_post_free_dma_pool);
-        dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
-            "reply_post_free_pool(0x%p): free\n", ioc->name,
-            ioc->reply_post_free));
-        ioc->reply_post_free = NULL;
+        kfree(ioc->reply_post);
     }

     if (ioc->config_page) {
@@ -2429,7 +2781,6 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
     }
 }

-
 /**
  * _base_allocate_memory_pools - allocate start of day memory pools
  * @ioc: per adapter object
@@ -2752,233 +3103,130 @@ chain_done:
         "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
     total_sz += sz;

-    /* reply post queue, 16 byte align */
     reply_post_free_sz = ioc->reply_post_queue_depth *
         sizeof(Mpi2DefaultReplyDescriptor_t);
-    if (_base_is_controller_msix_enabled(ioc))
-        sz = reply_post_free_sz * ioc->reply_queue_count;
-    else
+    if (ioc->rdpq_array_enable)
         sz = reply_post_free_sz;
-    ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
-        ioc->pdev, sz, 16, 0);
-    if (!ioc->reply_post_free_dma_pool) {
-        printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create "
-            "failed\n", ioc->name);
-        goto out;
+    else {
+        if (_base_is_controller_msix_enabled(ioc))
+            sz = reply_post_free_sz * ioc->reply_queue_count;
+        else
+            sz = reply_post_free_sz;
     }
-    ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
-        GFP_KERNEL, &ioc->reply_post_free_dma);
-    if (!ioc->reply_post_free) {
-        printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc "
-            "failed\n", ioc->name);
+
+    ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ?
+        (ioc->reply_queue_count):1,
+        sizeof(struct reply_post_struct), GFP_KERNEL);
+
+    if (!ioc->reply_post) {
+        printk(MPT2SAS_ERR_FMT "reply_post_free pool: kcalloc failed\n",
+            ioc->name);
         goto out;
     }
-    memset(ioc->reply_post_free, 0, sz);
-    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
-        "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
-        ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
-        sz/1024));
-    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = "
-        "(0x%llx)\n", ioc->name, (unsigned long long)
-        ioc->reply_post_free_dma));
-    total_sz += sz;

-    ioc->config_page_sz = 512;
-    ioc->config_page = pci_alloc_consistent(ioc->pdev,
-        ioc->config_page_sz, &ioc->config_page_dma);
-    if (!ioc->config_page) {
-        printk(MPT2SAS_ERR_FMT "config page: pci_pool_alloc "
-            "failed\n", ioc->name);
+    ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
+        ioc->pdev, sz, 16, 0);
+    if (!ioc->reply_post_free_dma_pool) {
+        printk(MPT2SAS_ERR_FMT
+         "reply_post_free pool: pci_pool_create failed\n",
+         ioc->name);
         goto out;
     }
-    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size"
-        "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz));
-    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma"
-        "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma));
-    total_sz += ioc->config_page_sz;
-
-    printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n",
-        ioc->name, total_sz/1024);
-    printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), "
-        "Max Controller Queue Depth(%d)\n",
-        ioc->name, ioc->shost->can_queue, facts->RequestCredit);
-    printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n",
-        ioc->name, ioc->shost->sg_tablesize);
-    return 0;
-
- out:
-    return -ENOMEM;
-}
-
-
-/**
- * mpt2sas_base_get_iocstate - Get the current state of a MPT adapter.
- * @ioc: Pointer to MPT_ADAPTER structure
- * @cooked: Request raw or cooked IOC state
- *
- * Returns all IOC Doorbell register bits if cooked==0, else just the
- * Doorbell bits in MPI_IOC_STATE_MASK.
- */
-u32
-mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked)
-{
-    u32 s, sc;
-
-    s = readl(&ioc->chip->Doorbell);
-    sc = s & MPI2_IOC_STATE_MASK;
-    return cooked ? sc : s;
-}
-
-/**
- * _base_wait_on_iocstate - waiting on a particular ioc state
- * @ioc_state: controller state { READY, OPERATIONAL, or RESET }
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_wait_on_iocstate(struct MPT2SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
-    int sleep_flag)
-{
-    u32 count, cntdn;
-    u32 current_state;
-
-    count = 0;
-    cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
-    do {
-        current_state = mpt2sas_base_get_iocstate(ioc, 1);
-        if (current_state == ioc_state)
-            return 0;
-        if (count && current_state == MPI2_IOC_STATE_FAULT)
-            break;
-        if (sleep_flag == CAN_SLEEP)
-            msleep(1);
-        else
-            udelay(500);
-        count++;
-    } while (--cntdn);
-
-    return current_state;
-}

-/**
- * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
- * a write to the doorbell)
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
- */
-static int
-_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
-    int sleep_flag)
-{
-    u32 cntdn, count;
-    u32 int_status;
-
-    count = 0;
-    cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
-    do {
-        int_status = readl(&ioc->chip->HostInterruptStatus);
-        if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
-            dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
-                "successful count(%d), timeout(%d)\n", ioc->name,
-                __func__, count, timeout));
-            return 0;
-        }
-        if (sleep_flag == CAN_SLEEP)
-            msleep(1);
-        else
-            udelay(500);
-        count++;
-    } while (--cntdn);
-
-    printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
-        "int_status(%x)!\n", ioc->name, __func__, count, int_status);
-    return -EFAULT;
-}
-
-/**
- * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to
- * doorbell.
- */
-static int
-_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
-    int sleep_flag)
-{
-    u32 cntdn, count;
-    u32 int_status;
-    u32 doorbell;
-
-    count = 0;
-    cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
-    do {
-        int_status = readl(&ioc->chip->HostInterruptStatus);
-        if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
-            dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
-                "successful count(%d), timeout(%d)\n", ioc->name,
-                __func__, count, timeout));
-            return 0;
-        } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
-            doorbell = readl(&ioc->chip->Doorbell);
-            if ((doorbell & MPI2_IOC_STATE_MASK) ==
-                MPI2_IOC_STATE_FAULT) {
-                mpt2sas_base_fault_info(ioc , doorbell);
-                return -EFAULT;
-            }
-        } else if (int_status == 0xFFFFFFFF)
+    i = 0;
+    do {
+        ioc->reply_post[i].reply_post_free =
+            pci_pool_alloc(ioc->reply_post_free_dma_pool,
+            GFP_KERNEL,
+            &ioc->reply_post[i].reply_post_free_dma);
+        if (!ioc->reply_post[i].reply_post_free) {
+            printk(MPT2SAS_ERR_FMT
+            "reply_post_free pool: pci_pool_alloc failed\n",
+            ioc->name);
             goto out;
+        }
+        memset(ioc->reply_post[i].reply_post_free, 0, sz);
+        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+            "reply post free pool (0x%p): depth(%d),"
+            "element_size(%d), pool_size(%d kB)\n", ioc->name,
+            ioc->reply_post[i].reply_post_free,
+            ioc->reply_post_queue_depth, 8, sz/1024));
+        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+            "reply_post_free_dma = (0x%llx)\n", ioc->name,
+            (unsigned long long)
+            ioc->reply_post[i].reply_post_free_dma));
+        total_sz += sz;
+    } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));

-        if (sleep_flag == CAN_SLEEP)
-            msleep(1);
-        else
-            udelay(500);
-        count++;
-    } while (--cntdn);
+    ioc->config_page_sz = 512;
+    ioc->config_page = pci_alloc_consistent(ioc->pdev,
+        ioc->config_page_sz, &ioc->config_page_dma);
+    if (!ioc->config_page) {
+        printk(MPT2SAS_ERR_FMT
+            "config page: pci_pool_alloc failed\n", ioc->name);
+        goto out;
+    }
+    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+        "config page(0x%p): size(%d)\n",
+        ioc->name, ioc->config_page, ioc->config_page_sz));
+    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma (0x%llx)\n",
+        ioc->name, (unsigned long long)ioc->config_page_dma));
+    total_sz += ioc->config_page_sz;
+
+    printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n",
+        ioc->name, total_sz/1024);
+    printk(MPT2SAS_INFO_FMT
+    "Current Controller Queue Depth(%d), Max Controller Queue Depth(%d)\n",
+     ioc->name, ioc->shost->can_queue, facts->RequestCredit);
+    printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n",
+        ioc->name, ioc->shost->sg_tablesize);
+    return 0;

  out:
-    printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
-        "int_status(%x)!\n", ioc->name, __func__, count, int_status);
-    return -EFAULT;
+    return -ENOMEM;
 }

 /**
- * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use
- * @ioc: per adapter object
+ * mpt2sas_base_get_iocstate - Get the current state of a MPT adapter.
+ * @ioc: Pointer to MPT_ADAPTER structure
+ * @cooked: Request raw or cooked IOC state
+ *
+ * Returns all IOC Doorbell register bits if cooked==0, else just the
+ * Doorbell bits in MPI_IOC_STATE_MASK.
+ */
+u32
+mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked)
+{
+    u32 s, sc;
+
+    s = readl(&ioc->chip->Doorbell);
+    sc = s & MPI2_IOC_STATE_MASK;
+    return cooked ? sc : s;
+}
+
+/**
+ * _base_wait_on_iocstate - waiting on a particular ioc state
+ * @ioc_state: controller state { READY, OPERATIONAL, or RESET }
  * @timeout: timeout in second
  * @sleep_flag: CAN_SLEEP or NO_SLEEP
  *
  * Returns 0 for success, non-zero for failure.
- *
  */
 static int
-_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,
+_base_wait_on_iocstate(struct MPT2SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
     int sleep_flag)
 {
-    u32 cntdn, count;
-    u32 doorbell_reg;
+    u32 count, cntdn;
+    u32 current_state;

     count = 0;
     cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
     do {
-        doorbell_reg = readl(&ioc->chip->Doorbell);
-        if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
-            dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
-                "successful count(%d), timeout(%d)\n", ioc->name,
-                __func__, count, timeout));
+        current_state = mpt2sas_base_get_iocstate(ioc, 1);
+        if (current_state == ioc_state)
             return 0;
-        }
+        if (count && current_state == MPI2_IOC_STATE_FAULT)
+            break;
         if (sleep_flag == CAN_SLEEP)
             msleep(1);
         else
@@ -2986,9 +3234,7 @@ _base_wait_for_doorbell_not_used(struct
MPT2SAS_ADAPTER *ioc, int timeout,
         count++;
     } while (--cntdn);

-    printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
-        "doorbell_reg(%x)!\n", ioc->name, __func__, count, doorbell_reg);
-    return -EFAULT;
+    return current_state;
 }

 /**
@@ -3040,123 +3286,6 @@ _base_send_ioc_reset(struct MPT2SAS_ADAPTER
*ioc, u8 reset_type, int timeout,
 }

 /**
- * _base_handshake_req_reply_wait - send request thru doorbell interface
- * @ioc: per adapter object
- * @request_bytes: request length
- * @request: pointer having request payload
- * @reply_bytes: reply length
- * @reply: pointer to reply payload
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
-    u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
-{
-    MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
-    int i;
-    u8 failed;
-    u16 dummy;
-    __le32 *mfp;
-
-    /* make sure doorbell is not in use */
-    if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
-        printk(MPT2SAS_ERR_FMT "doorbell is in use "
-            " (line=%d)\n", ioc->name, __LINE__);
-        return -EFAULT;
-    }
-
-    /* clear pending doorbell interrupts from previous state changes */
-    if (readl(&ioc->chip->HostInterruptStatus) &
-        MPI2_HIS_IOC2SYS_DB_STATUS)
-        writel(0, &ioc->chip->HostInterruptStatus);
-
-    /* send message to ioc */
-    writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
-        ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
-        &ioc->chip->Doorbell);
-
-    if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {
-        printk(MPT2SAS_ERR_FMT "doorbell handshake "
-           "int failed (line=%d)\n", ioc->name, __LINE__);
-        return -EFAULT;
-    }
-    writel(0, &ioc->chip->HostInterruptStatus);
-
-    if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
-        printk(MPT2SAS_ERR_FMT "doorbell handshake "
-            "ack failed (line=%d)\n", ioc->name, __LINE__);
-        return -EFAULT;
-    }
-
-    /* send message 32-bits at a time */
-    for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
-        writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
-        if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
-            failed = 1;
-    }
-
-    if (failed) {
-        printk(MPT2SAS_ERR_FMT "doorbell handshake "
-            "sending request failed (line=%d)\n", ioc->name, __LINE__);
-        return -EFAULT;
-    }
-
-    /* now wait for the reply */
-    if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
-        printk(MPT2SAS_ERR_FMT "doorbell handshake "
-           "int failed (line=%d)\n", ioc->name, __LINE__);
-        return -EFAULT;
-    }
-
-    /* read the first two 16-bits, it gives the total length of the reply */
-    reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
-        & MPI2_DOORBELL_DATA_MASK);
-    writel(0, &ioc->chip->HostInterruptStatus);
-    if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
-        printk(MPT2SAS_ERR_FMT "doorbell handshake "
-           "int failed (line=%d)\n", ioc->name, __LINE__);
-        return -EFAULT;
-    }
-    reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
-        & MPI2_DOORBELL_DATA_MASK);
-    writel(0, &ioc->chip->HostInterruptStatus);
-
-    for (i = 2; i < default_reply->MsgLength * 2; i++)  {
-        if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
-            printk(MPT2SAS_ERR_FMT "doorbell "
-                "handshake int failed (line=%d)\n", ioc->name,
-                __LINE__);
-            return -EFAULT;
-        }
-        if (i >=  reply_bytes/2) /* overflow case */
-            dummy = readl(&ioc->chip->Doorbell);
-        else
-            reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
-                & MPI2_DOORBELL_DATA_MASK);
-        writel(0, &ioc->chip->HostInterruptStatus);
-    }
-
-    _base_wait_for_doorbell_int(ioc, 5, sleep_flag);
-    if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) {
-        dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "doorbell is in use "
-            " (line=%d)\n", ioc->name, __LINE__));
-    }
-    writel(0, &ioc->chip->HostInterruptStatus);
-
-    if (ioc->logging_level & MPT_DEBUG_INIT) {
-        mfp = (__le32 *)reply;
-        printk(KERN_INFO "\toffset:data\n");
-        for (i = 0; i < reply_bytes/4; i++)
-            printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
-                le32_to_cpu(mfp[i]));
-    }
-    return 0;
-}
-
-/**
  * mpt2sas_base_sas_iounit_control - send sas iounit control to FW
  * @ioc: per adapter object
  * @mpi_reply: the reply payload from FW
@@ -3406,78 +3535,6 @@ _base_get_port_facts(struct MPT2SAS_ADAPTER
*ioc, int port, int sleep_flag)
 }

 /**
- * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
-    Mpi2IOCFactsRequest_t mpi_request;
-    Mpi2IOCFactsReply_t mpi_reply;
-    struct mpt2sas_facts *facts;
-    int mpi_reply_sz, mpi_request_sz, r;
-
-    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
-        __func__));
-
-    mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
-    mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
-    memset(&mpi_request, 0, mpi_request_sz);
-    mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
-    r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
-        (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
-
-    if (r != 0) {
-        printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
-            ioc->name, __func__, r);
-        return r;
-    }
-
-    facts = &ioc->facts;
-    memset(facts, 0, sizeof(struct mpt2sas_facts));
-    facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
-    facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
-    facts->VP_ID = mpi_reply.VP_ID;
-    facts->VF_ID = mpi_reply.VF_ID;
-    facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
-    facts->MaxChainDepth = mpi_reply.MaxChainDepth;
-    facts->WhoInit = mpi_reply.WhoInit;
-    facts->NumberOfPorts = mpi_reply.NumberOfPorts;
-    facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;
-    facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
-    facts->MaxReplyDescriptorPostQueueDepth =
-        le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
-    facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
-    facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
-    if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
-        ioc->ir_firmware = 1;
-    facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
-    facts->IOCRequestFrameSize =
-        le16_to_cpu(mpi_reply.IOCRequestFrameSize);
-    facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
-    facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
-    ioc->shost->max_id = -1;
-    facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
-    facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
-    facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
-    facts->HighPriorityCredit =
-        le16_to_cpu(mpi_reply.HighPriorityCredit);
-    facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
-    facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
-
-    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hba queue depth(%d), "
-        "max chains per io(%d)\n", ioc->name, facts->RequestCredit,
-        facts->MaxChainDepth));
-    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request frame size(%d), "
-        "reply frame size(%d)\n", ioc->name,
-        facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
-    return 0;
-}
-
-/**
  * _base_send_ioc_init - send ioc_init to firmware
  * @ioc: per adapter object
  * @sleep_flag: CAN_SLEEP or NO_SLEEP
@@ -3489,9 +3546,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER
*ioc, int sleep_flag)
 {
     Mpi2IOCInitRequest_t mpi_request;
     Mpi2IOCInitReply_t mpi_reply;
-    int r;
+    int i, r = 0;
     struct timeval current_time;
     u16 ioc_status;
+    u32 reply_post_free_array_sz = 0;
+    Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
+    dma_addr_t reply_post_free_array_dma;

     dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
         __func__));
@@ -3520,9 +3580,30 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER
*ioc, int sleep_flag)
         cpu_to_le64((u64)ioc->request_dma);
     mpi_request.ReplyFreeQueueAddress =
         cpu_to_le64((u64)ioc->reply_free_dma);
-    mpi_request.ReplyDescriptorPostQueueAddress =
-        cpu_to_le64((u64)ioc->reply_post_free_dma);
-
+    if (ioc->rdpq_array_enable) {
+        reply_post_free_array_sz = ioc->reply_queue_count *
+            sizeof(Mpi2IOCInitRDPQArrayEntry);
+        reply_post_free_array = pci_alloc_consistent(ioc->pdev,
+            reply_post_free_array_sz, &reply_post_free_array_dma);
+        if (!reply_post_free_array) {
+            printk(MPT2SAS_ERR_FMT
+            "reply_post_free_array: pci_alloc_consistent failed\n",
+            ioc->name);
+            r = -ENOMEM;
+            goto out;
+        }
+        memset(reply_post_free_array, 0, reply_post_free_array_sz);
+        for (i = 0; i < ioc->reply_queue_count; i++)
+            reply_post_free_array[i].RDPQBaseAddress =
+                cpu_to_le64(
+                (u64)ioc->reply_post[i].reply_post_free_dma);
+        mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
+        mpi_request.ReplyDescriptorPostQueueAddress =
+            cpu_to_le64((u64)reply_post_free_array_dma);
+    } else {
+        mpi_request.ReplyDescriptorPostQueueAddress =
+            cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
+    }

     /* This time stamp specifies number of milliseconds
      * since epoch ~ midnight January 1, 1970.
@@ -3550,7 +3631,7 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc,
int sleep_flag)
     if (r != 0) {
         printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
             ioc->name, __func__, r);
-        return r;
+        goto out;
     }

     ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
@@ -3560,7 +3641,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER
*ioc, int sleep_flag)
         r = -EIO;
     }

-    return 0;
+ out:
+    if (reply_post_free_array)
+        pci_free_consistent(ioc->pdev, reply_post_free_array_sz,
+                    reply_post_free_array,
+                    reply_post_free_array_dma);
+    return r;
 }

 /**
@@ -4093,7 +4179,7 @@ _base_make_ioc_operational(struct
MPT2SAS_ADAPTER *ioc, int sleep_flag)
     u8 hide_flag;
     struct adapter_reply_queue *reply_q;
     long reply_post_free;
-    u32 reply_post_free_sz;
+    unsigned int reply_post_free_sz, index = 0;

     dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
         __func__));
@@ -4164,19 +4250,28 @@ _base_make_ioc_operational(struct
MPT2SAS_ADAPTER *ioc, int sleep_flag)
         _base_assign_reply_queues(ioc);

     /* initialize Reply Post Free Queue */
-    reply_post_free = (long)ioc->reply_post_free;
     reply_post_free_sz = ioc->reply_post_queue_depth *
-        sizeof(Mpi2DefaultReplyDescriptor_t);
+                sizeof(Mpi2DefaultReplyDescriptor_t);
+    reply_post_free = (long)ioc->reply_post[index].reply_post_free;
     list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
         reply_q->reply_post_host_index = 0;
-        reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
-            reply_post_free;
+        reply_q->reply_post_free =
+             (Mpi2ReplyDescriptorsUnion_t *) reply_post_free;
         for (i = 0; i < ioc->reply_post_queue_depth; i++)
             reply_q->reply_post_free[i].Words =
-                            cpu_to_le64(ULLONG_MAX);
+                        cpu_to_le64(ULLONG_MAX);
+
         if (!_base_is_controller_msix_enabled(ioc))
             goto skip_init_reply_post_free_queue;
-        reply_post_free += reply_post_free_sz;
+        /*
+         * If RDPQ is enabled, switch to the next allocation.
+         * Otherwise advance within the contiguous region.
+         */
+        if (ioc->rdpq_array_enable)
+            reply_post_free = (long)
+                ioc->reply_post[++index].reply_post_free;
+        else
+            reply_post_free += reply_post_free_sz;
     }
  skip_init_reply_post_free_queue:

@@ -4304,6 +4399,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
         }
     }

+    ioc->rdpq_array_enable_assigned = 0;
     r = mpt2sas_base_map_resources(ioc);
     if (r)
         goto out_free_resources;
@@ -4664,6 +4760,16 @@ mpt2sas_base_hard_reset_handler(struct
MPT2SAS_ADAPTER *ioc, int sleep_flag,
         r = -EFAULT;
         goto out;
     }
+
+    r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+    if (r)
+        goto out;
+
+    if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
+        panic("%s: Issue occurred with flashing controller firmware."
+              "Please reboot the system and ensure that the correct"
+              "firmware version is running\n", ioc->name);
+
     r = _base_make_ioc_operational(ioc, sleep_flag);
     if (!r)
         _base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h
b/drivers/scsi/mpt2sas/mpt2sas_base.h
index be2ae90..ec15e0e 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -636,6 +636,11 @@ struct mpt2sas_port_facts {
     u16            MaxPostedCmdBuffers;
 };

+struct reply_post_struct {
+    Mpi2ReplyDescriptorsUnion_t    *reply_post_free;
+    dma_addr_t            reply_post_free_dma;
+};
+
 /**
  * enum mutex_type - task management mutex type
  * @TM_MUTEX_OFF: mutex is not required becuase calling function is
acquiring it
@@ -779,8 +784,11 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct
MPT2SAS_ADAPTER *ioc);
  * @reply_free_dma_pool:
  * @reply_free_host_index: tail index in pool to insert free replys
  * @reply_post_queue_depth: reply post queue depth
- * @reply_post_free: pool for reply post (64bit descriptor)
- * @reply_post_free_dma:
+ * @reply_post_struct: struct for reply_post_free physical & virt address
+ * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
+ * @rdpq_array_enable: rdpq_array support is enabled in the driver
+ * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
+ *                is assigned only ones
  * @reply_queue_count: number of reply queue's
  * @reply_queue_list: link list contaning the reply queue info
  * @reply_post_host_index: head index in the pool where FW completes IO
@@ -972,11 +980,13 @@ struct MPT2SAS_ADAPTER {

     /* reply post queue */
     u16         reply_post_queue_depth;
-    Mpi2ReplyDescriptorsUnion_t *reply_post_free;
-    dma_addr_t    reply_post_free_dma;
+    struct reply_post_struct *reply_post;
     struct dma_pool *reply_post_free_dma_pool;
     u8        reply_queue_count;
     struct list_head reply_queue_list;
+    u8              rdpq_array_capable;
+    u8              rdpq_array_enable;
+    u8              rdpq_array_enable_assigned;

     struct list_head delayed_tr_list;
     struct list_head delayed_tr_volume_list;

On Thu, Jul 24, 2014 at 1:16 AM, Martin K. Petersen
<martin.petersen@oracle.com> wrote:
>>>>>> "Sreekanth" == Sreekanth Reddy <sreekanth.reddy@avagotech.com> writes:
>
> Sreekanth,
>
> Sreekanth> 2. As per MPI Spec, each set of 8 reply descriptor post
> Sreekanth> queues must have the same value for the upper 32-bits of
> Sreekanth> their memory address. So allocated set of eight queues in a
> Sreekanth> single pool and added a new function is_MSB_are_same() to
> Sreekanth> check whether higher 32 bits of this pool memory address are
> Sreekanth> same or not. If this functions returns zero then we are
> Sreekanth> saving these pools in the bad_reply_post_pool list. then
> Sreekanth> releasing these pools once we get the required memory pools.
>
> Why don't you just set pci_set_consistent_dma_mask() to DMA_BIT_MASK(32)
> before you allocate the queue entries?
>
> --
> Martin K. Petersen      Oracle Linux Engineering

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-07-25 12:57           ` Sreekanth Reddy
@ 2014-07-25 19:43             ` Martin K. Petersen
  2014-07-30 14:55               ` Sreekanth Reddy
  0 siblings, 1 reply; 20+ messages in thread
From: Martin K. Petersen @ 2014-07-25 19:43 UTC (permalink / raw)
  To: Sreekanth Reddy
  Cc: Martin K. Petersen, jejb, James E.J. Bottomley, linux-scsi,
	Sathya Prakash, Nagalakshmi Nandigama, linux-kernel,
	Christoph Hellwig

>>>>> "Sreekanth" == Sreekanth Reddy <sreekanth.reddy@avagotech.com> writes:

Sreekanth,

Sreekanth> Following are the changes that I have done in this patch over
Sreekanth> the first RDPQ support patch,

Please, please do the function moves in a different patch. Or use a
simple prototype declaration like I did to avoid moving the code around
in the first place.

Sreekanth> 2. Set pci_set_consistent_dma_mask() to
Sreekanth>    DMA_BIT_MASK(32). still I am analysing whether this change
Sreekanth>    may affect on any other things or not?

I think you're done allocating things by the time this is called. But to
be sure you can call _base_config_dma_addressing() after you're done
with the RDPQ allocations (or rearrange the code so you allocate RDPQ
before the DMA mask is upped in general).

-- 
Martin K. Petersen	Oracle Linux Engineering

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-07-25 19:43             ` Martin K. Petersen
@ 2014-07-30 14:55               ` Sreekanth Reddy
  2014-08-05 18:46                 ` Martin K. Petersen
  0 siblings, 1 reply; 20+ messages in thread
From: Sreekanth Reddy @ 2014-07-30 14:55 UTC (permalink / raw)
  To: Martin K. Petersen
  Cc: jejb, James E.J. Bottomley, linux-scsi, Sathya Prakash,
	Nagalakshmi Nandigama, linux-kernel, Christoph Hellwig

Hi Martin,

Sorry for the delay as I was on vacation.

Here are the change set when compared to the initial patch

1. Declared the following functions at the beginning of the
mpt2sas_base.c file instead of moving all these functions before
mpt2sas_base_map_resources() function
        a. _base_wait_for_doorbell_int()
        b. _base_wait_for_doorbell_ack()
        c. _base_wait_for_doorbell_not_used()
        d. _base_handshake_req_reply_wait()
        e. _base_get_ioc_facts()

2. Initially set the consistent DMA mask to 32 bit and then change it
to 64 bit mask after allocating RDPQ pools by calling the function
_base_change_consistent_dma_mask. This is to ensure that all the upper
32 bits of RDPQ entries's base address to be same. Also allocated the
RDPQ pools first and then allocated remaining pools such as request
pool, sense buffer pools etc. Also this patch takes care to set the
consistent DMA mask to 64 bit (if it supports) even after resume
operation from hibernation.

3. Reduced the redundancy between the RDPQ and non-RDPQ support in
these following functions
        a. _base_release_memory_pools()
        b. _base_allocate_memory_pools()
        c. _base_send_ioc_init()
        d. _base_make_ioc_operational()

Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
---

diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c
b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 6b2a79e..d81230a 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -92,6 +92,22 @@ static int disable_discovery = -1;
 module_param(disable_discovery, int, 0);
 MODULE_PARM_DESC(disable_discovery, " disable discovery ");

+static int dma_mask;
+
+static int
+_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
+                int sleep_flag);
+static int
+_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
+                int sleep_flag);
+static int
+_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,
+                 int sleep_flag);
+static int
+_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
+    u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag);
+static int
+_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag);
 /**
  * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
  *
@@ -1179,17 +1195,22 @@ static int
 _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
 {
     struct sysinfo s;
-    char *desc = NULL;
+    u64 consistent_dma_mask;
+
+    if (dma_mask)
+        consistent_dma_mask = DMA_BIT_MASK(64);
+    else
+        consistent_dma_mask = DMA_BIT_MASK(32);

     if (sizeof(dma_addr_t) > 4) {
         const uint64_t required_mask =
             dma_get_required_mask(&pdev->dev);
         if ((required_mask > DMA_BIT_MASK(32)) && !pci_set_dma_mask(pdev,
             DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(pdev,
-            DMA_BIT_MASK(64))) {
+            consistent_dma_mask)) {
             ioc->base_add_sg_single = &_base_add_sg_single_64;
             ioc->sge_size = sizeof(Mpi2SGESimple64_t);
-            desc = "64";
+            dma_mask = 64;
             goto out;
         }
     }
@@ -1198,18 +1219,29 @@ _base_config_dma_addressing(struct
MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
         && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
         ioc->base_add_sg_single = &_base_add_sg_single_32;
         ioc->sge_size = sizeof(Mpi2SGESimple32_t);
-        desc = "32";
+        dma_mask = 32;
     } else
         return -ENODEV;

  out:
     si_meminfo(&s);
-    printk(MPT2SAS_INFO_FMT "%s BIT PCI BUS DMA ADDRESSING SUPPORTED, "
-        "total mem (%ld kB)\n", ioc->name, desc, convert_to_kb(s.totalram));
+    printk(MPT2SAS_INFO_FMT
+        "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
+        ioc->name, dma_mask, convert_to_kb(s.totalram));

     return 0;
 }

+static int
+_base_change_consistent_dma_mask(struct MPT2SAS_ADAPTER *ioc,
+                  struct pci_dev *pdev)
+{
+    if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+        if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
+            return -ENODEV;
+    }
+    return 0;
+}
 /**
  * _base_check_enable_msix - checks MSIX capabable.
  * @ioc: per adapter object
@@ -1424,6 +1456,9 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
     ioc->reply_queue_count = min_t(int, ioc->cpu_count,
         ioc->msix_vector_count);

+    if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
+        max_msix_vectors = 8;
+
     if (max_msix_vectors > 0) {
         ioc->reply_queue_count = min_t(int, max_msix_vectors,
             ioc->reply_queue_count);
@@ -1552,6 +1587,16 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
     }

     _base_mask_interrupts(ioc);
+
+    r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+    if (r)
+        goto out_fail;
+
+    if (!ioc->rdpq_array_enable_assigned) {
+        ioc->rdpq_array_enable = ioc->rdpq_array_capable;
+        ioc->rdpq_array_enable_assigned = 1;
+    }
+
     r = _base_enable_msix(ioc);
     if (r)
         goto out_fail;
@@ -2349,7 +2394,8 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
 static void
 _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 {
-    int i;
+    int i = 0;
+    struct reply_post_struct *rps;

     dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
         __func__));
@@ -2390,15 +2436,25 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
         ioc->reply_free = NULL;
     }

-    if (ioc->reply_post_free) {
-        pci_pool_free(ioc->reply_post_free_dma_pool,
-            ioc->reply_post_free, ioc->reply_post_free_dma);
+    if (ioc->reply_post) {
+        do {
+            rps = &ioc->reply_post[i];
+            if (rps->reply_post_free) {
+                pci_pool_free(
+                    ioc->reply_post_free_dma_pool,
+                    rps->reply_post_free,
+                    rps->reply_post_free_dma);
+                dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+                    "reply_post_free_pool(0x%p): free\n",
+                    ioc->name, rps->reply_post_free));
+                rps->reply_post_free = NULL;
+            }
+        } while (ioc->rdpq_array_enable &&
+               (++i < ioc->reply_queue_count));
+
         if (ioc->reply_post_free_dma_pool)
             pci_pool_destroy(ioc->reply_post_free_dma_pool);
-        dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
-            "reply_post_free_pool(0x%p): free\n", ioc->name,
-            ioc->reply_post_free));
-        ioc->reply_post_free = NULL;
+        kfree(ioc->reply_post);
     }

     if (ioc->config_page) {
@@ -2541,6 +2597,69 @@ _base_allocate_memory_pools(struct
MPT2SAS_ADAPTER *ioc,  int sleep_flag)
         ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
         ioc->chains_needed_per_io));

+    /* reply post queue, 16 byte align */
+    reply_post_free_sz = ioc->reply_post_queue_depth *
+        sizeof(Mpi2DefaultReplyDescriptor_t);
+    if (ioc->rdpq_array_enable)
+        sz = reply_post_free_sz;
+    else {
+        if (_base_is_controller_msix_enabled(ioc))
+            sz = reply_post_free_sz * ioc->reply_queue_count;
+        else
+            sz = reply_post_free_sz;
+    }
+
+    ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ?
+        (ioc->reply_queue_count):1,
+        sizeof(struct reply_post_struct), GFP_KERNEL);
+
+    if (!ioc->reply_post) {
+        printk(MPT2SAS_ERR_FMT "reply_post_free pool: kcalloc failed\n",
+            ioc->name);
+        goto out;
+    }
+    ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
+        ioc->pdev, sz, 16, 0);
+    if (!ioc->reply_post_free_dma_pool) {
+        printk(MPT2SAS_ERR_FMT
+         "reply_post_free pool: pci_pool_create failed\n",
+         ioc->name);
+        goto out;
+    }
+    i = 0;
+    do {
+        ioc->reply_post[i].reply_post_free =
+            pci_pool_alloc(ioc->reply_post_free_dma_pool,
+            GFP_KERNEL,
+            &ioc->reply_post[i].reply_post_free_dma);
+        if (!ioc->reply_post[i].reply_post_free) {
+            printk(MPT2SAS_ERR_FMT
+            "reply_post_free pool: pci_pool_alloc failed\n",
+            ioc->name);
+            goto out;
+        }
+        memset(ioc->reply_post[i].reply_post_free, 0, sz);
+        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+            "reply post free pool (0x%p): depth(%d),"
+            "element_size(%d), pool_size(%d kB)\n", ioc->name,
+            ioc->reply_post[i].reply_post_free,
+            ioc->reply_post_queue_depth, 8, sz/1024));
+        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+            "reply_post_free_dma = (0x%llx)\n", ioc->name,
+            (unsigned long long)
+            ioc->reply_post[i].reply_post_free_dma));
+        total_sz += sz;
+    } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));
+
+    if (dma_mask == 64) {
+        if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) {
+            printk(MPT2SAS_WARN_FMT
+                "no suitable consistent DMA mask for %s\n",
+                ioc->name, pci_name(ioc->pdev));
+            goto out;
+        }
+    }
+
     ioc->scsiio_depth = ioc->hba_queue_depth -
         ioc->hi_priority_depth - ioc->internal_depth;

@@ -2752,37 +2871,6 @@ chain_done:
         "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
     total_sz += sz;

-    /* reply post queue, 16 byte align */
-    reply_post_free_sz = ioc->reply_post_queue_depth *
-        sizeof(Mpi2DefaultReplyDescriptor_t);
-    if (_base_is_controller_msix_enabled(ioc))
-        sz = reply_post_free_sz * ioc->reply_queue_count;
-    else
-        sz = reply_post_free_sz;
-    ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
-        ioc->pdev, sz, 16, 0);
-    if (!ioc->reply_post_free_dma_pool) {
-        printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create "
-            "failed\n", ioc->name);
-        goto out;
-    }
-    ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
-        GFP_KERNEL, &ioc->reply_post_free_dma);
-    if (!ioc->reply_post_free) {
-        printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc "
-            "failed\n", ioc->name);
-        goto out;
-    }
-    memset(ioc->reply_post_free, 0, sz);
-    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
-        "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
-        ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
-        sz/1024));
-    dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = "
-        "(0x%llx)\n", ioc->name, (unsigned long long)
-        ioc->reply_post_free_dma));
-    total_sz += sz;
-
     ioc->config_page_sz = 512;
     ioc->config_page = pci_alloc_consistent(ioc->pdev,
         ioc->config_page_sz, &ioc->config_page_dma);
@@ -3454,6 +3542,9 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc,
int sleep_flag)
     facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
     if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
         ioc->ir_firmware = 1;
+    if ((facts->IOCCapabilities &
+          MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE))
+        ioc->rdpq_array_capable = 1;
     facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
     facts->IOCRequestFrameSize =
         le16_to_cpu(mpi_reply.IOCRequestFrameSize);
@@ -3489,9 +3580,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER
*ioc, int sleep_flag)
 {
     Mpi2IOCInitRequest_t mpi_request;
     Mpi2IOCInitReply_t mpi_reply;
-    int r;
+    int i, r = 0;
     struct timeval current_time;
     u16 ioc_status;
+    u32 reply_post_free_array_sz = 0;
+    Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
+    dma_addr_t reply_post_free_array_dma;

     dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
         __func__));
@@ -3520,9 +3614,31 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER
*ioc, int sleep_flag)
         cpu_to_le64((u64)ioc->request_dma);
     mpi_request.ReplyFreeQueueAddress =
         cpu_to_le64((u64)ioc->reply_free_dma);
-    mpi_request.ReplyDescriptorPostQueueAddress =
-        cpu_to_le64((u64)ioc->reply_post_free_dma);

+    if (ioc->rdpq_array_enable) {
+        reply_post_free_array_sz = ioc->reply_queue_count *
+            sizeof(Mpi2IOCInitRDPQArrayEntry);
+        reply_post_free_array = pci_alloc_consistent(ioc->pdev,
+            reply_post_free_array_sz, &reply_post_free_array_dma);
+        if (!reply_post_free_array) {
+            printk(MPT2SAS_ERR_FMT
+            "reply_post_free_array: pci_alloc_consistent failed\n",
+            ioc->name);
+            r = -ENOMEM;
+            goto out;
+        }
+        memset(reply_post_free_array, 0, reply_post_free_array_sz);
+        for (i = 0; i < ioc->reply_queue_count; i++)
+            reply_post_free_array[i].RDPQBaseAddress =
+                cpu_to_le64(
+                (u64)ioc->reply_post[i].reply_post_free_dma);
+        mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
+        mpi_request.ReplyDescriptorPostQueueAddress =
+            cpu_to_le64((u64)reply_post_free_array_dma);
+    } else {
+        mpi_request.ReplyDescriptorPostQueueAddress =
+            cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
+    }

     /* This time stamp specifies number of milliseconds
      * since epoch ~ midnight January 1, 1970.
@@ -3550,7 +3666,7 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc,
int sleep_flag)
     if (r != 0) {
         printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
             ioc->name, __func__, r);
-        return r;
+        goto out;
     }

     ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
@@ -3560,7 +3676,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER
*ioc, int sleep_flag)
         r = -EIO;
     }

-    return 0;
+out:
+    if (reply_post_free_array)
+        pci_free_consistent(ioc->pdev, reply_post_free_array_sz,
+                    reply_post_free_array,
+                    reply_post_free_array_dma);
+    return r;
 }

 /**
@@ -4093,7 +4214,7 @@ _base_make_ioc_operational(struct
MPT2SAS_ADAPTER *ioc, int sleep_flag)
     u8 hide_flag;
     struct adapter_reply_queue *reply_q;
     long reply_post_free;
-    u32 reply_post_free_sz;
+    u32 reply_post_free_sz, index = 0;

     dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
         __func__));
@@ -4164,19 +4285,27 @@ _base_make_ioc_operational(struct
MPT2SAS_ADAPTER *ioc, int sleep_flag)
         _base_assign_reply_queues(ioc);

     /* initialize Reply Post Free Queue */
-    reply_post_free = (long)ioc->reply_post_free;
     reply_post_free_sz = ioc->reply_post_queue_depth *
         sizeof(Mpi2DefaultReplyDescriptor_t);
+    reply_post_free = (long)ioc->reply_post[index].reply_post_free;
     list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
         reply_q->reply_post_host_index = 0;
         reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
             reply_post_free;
         for (i = 0; i < ioc->reply_post_queue_depth; i++)
             reply_q->reply_post_free[i].Words =
-                            cpu_to_le64(ULLONG_MAX);
+                             cpu_to_le64(ULLONG_MAX);
         if (!_base_is_controller_msix_enabled(ioc))
             goto skip_init_reply_post_free_queue;
-        reply_post_free += reply_post_free_sz;
+        /*
+         * If RDPQ is enabled, switch to the next allocation.
+         * Otherwise advance within the contiguous region.
+         */
+        if (ioc->rdpq_array_enable)
+            reply_post_free = (long)
+                ioc->reply_post[++index].reply_post_free;
+        else
+            reply_post_free += reply_post_free_sz;
     }
  skip_init_reply_post_free_queue:

@@ -4304,6 +4433,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
         }
     }

+    ioc->rdpq_array_enable_assigned = 0;
     r = mpt2sas_base_map_resources(ioc);
     if (r)
         goto out_free_resources;
@@ -4664,6 +4794,16 @@ mpt2sas_base_hard_reset_handler(struct
MPT2SAS_ADAPTER *ioc, int sleep_flag,
         r = -EFAULT;
         goto out;
     }
+
+    r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+    if (r)
+        goto out;
+
+    if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
+        panic("%s: Issue occurred with flashing controller firmware."
+              "Please reboot the system and ensure that the correct"
+              "firmware version is running\n", ioc->name);
+
     r = _base_make_ioc_operational(ioc, sleep_flag);
     if (!r)
         _base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h
b/drivers/scsi/mpt2sas/mpt2sas_base.h
index be2ae90..5f85002 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -636,6 +636,11 @@ struct mpt2sas_port_facts {
     u16            MaxPostedCmdBuffers;
 };

+struct reply_post_struct {
+    Mpi2ReplyDescriptorsUnion_t    *reply_post_free;
+    dma_addr_t            reply_post_free_dma;
+};
+
 /**
  * enum mutex_type - task management mutex type
  * @TM_MUTEX_OFF: mutex is not required becuase calling function is
acquiring it
@@ -779,8 +784,11 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct
MPT2SAS_ADAPTER *ioc);
  * @reply_free_dma_pool:
  * @reply_free_host_index: tail index in pool to insert free replys
  * @reply_post_queue_depth: reply post queue depth
- * @reply_post_free: pool for reply post (64bit descriptor)
- * @reply_post_free_dma:
+ * @reply_post_struct: struct for reply_post_free physical & virt address
+ * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
+ * @rdpq_array_enable: rdpq_array support is enabled in the driver
+ * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
+ *                is assigned only ones
  * @reply_queue_count: number of reply queue's
  * @reply_queue_list: link list contaning the reply queue info
  * @reply_post_host_index: head index in the pool where FW completes IO
@@ -972,8 +980,10 @@ struct MPT2SAS_ADAPTER {

     /* reply post queue */
     u16         reply_post_queue_depth;
-    Mpi2ReplyDescriptorsUnion_t *reply_post_free;
-    dma_addr_t    reply_post_free_dma;
+    struct reply_post_struct *reply_post;
+    u8        rdpq_array_capable;
+    u8        rdpq_array_enable;
+    u8        rdpq_array_enable_assigned;
     struct dma_pool *reply_post_free_dma_pool;
     u8        reply_queue_count;
     struct list_head reply_queue_list;

On Sat, Jul 26, 2014 at 1:13 AM, Martin K. Petersen
<martin.petersen@oracle.com> wrote:
>>>>>> "Sreekanth" == Sreekanth Reddy <sreekanth.reddy@avagotech.com> writes:
>
> Sreekanth,
>
> Sreekanth> Following are the changes that I have done in this patch over
> Sreekanth> the first RDPQ support patch,
>
> Please, please do the function moves in a different patch. Or use a
> simple prototype declaration like I did to avoid moving the code around
> in the first place.
>
> Sreekanth> 2. Set pci_set_consistent_dma_mask() to
> Sreekanth>    DMA_BIT_MASK(32). still I am analysing whether this change
> Sreekanth>    may affect on any other things or not?
>
> I think you're done allocating things by the time this is called. But to
> be sure you can call _base_config_dma_addressing() after you're done
> with the RDPQ allocations (or rearrange the code so you allocate RDPQ
> before the DMA mask is upped in general).
>
> --
> Martin K. Petersen      Oracle Linux Engineering

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-07-30 14:55               ` Sreekanth Reddy
@ 2014-08-05 18:46                 ` Martin K. Petersen
       [not found]                   ` <CAK=zhgpqW-t11JKiBRRM7Z4TEMyaEUBX943qT8faaKPk6Pk4XA@mail.gmail.com>
  0 siblings, 1 reply; 20+ messages in thread
From: Martin K. Petersen @ 2014-08-05 18:46 UTC (permalink / raw)
  To: Sreekanth Reddy
  Cc: Martin K. Petersen, jejb, James E.J. Bottomley, linux-scsi,
	Sathya Prakash, Nagalakshmi Nandigama, linux-kernel,
	Christoph Hellwig

>>>>> "Sreekanth" == Sreekanth Reddy <sreekanth.reddy@avagotech.com> writes:

Sreekanth,

Patch was mangled and I had to apply every single hunk by hand. Please
use git send-email.

+static int dma_mask;
+
+static int
+_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
+                int sleep_flag);
+static int
+_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
+                int sleep_flag);
+static int
+_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,
+                 int sleep_flag);
+static int
+_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
+    u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag);
+static int
+_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag);

Are you sure you need all these? _base_get_ioc_facts was the only one
that needed to be declared in my original patch.

+    if (ioc->rdpq_array_enable)
+        sz = reply_post_free_sz;
+    else {
+        if (_base_is_controller_msix_enabled(ioc))
+            sz = reply_post_free_sz * ioc->reply_queue_count;
+        else
+            sz = reply_post_free_sz;
+    }

sz = reply_post_free_sz;
if (_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable)
   sz *= ioc->reply_queue_count;

+    ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ?
+        (ioc->reply_queue_count):1,
+        sizeof(struct reply_post_struct), GFP_KERNEL);

You're special casing the !rdpq code path again. Why don't you just make
sure reply_queue_count is always correct?

+    do {
+        ioc->reply_post[i].reply_post_free =
+            pci_pool_alloc(ioc->reply_post_free_dma_pool,
+            GFP_KERNEL,
+            &ioc->reply_post[i].reply_post_free_dma);
+        if (!ioc->reply_post[i].reply_post_free) {
+            printk(MPT2SAS_ERR_FMT
+            "reply_post_free pool: pci_pool_alloc failed\n",
+            ioc->name);
+            goto out;
+        }
+        memset(ioc->reply_post[i].reply_post_free, 0, sz);
+        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+            "reply post free pool (0x%p): depth(%d),"
+            "element_size(%d), pool_size(%d kB)\n", ioc->name,
+            ioc->reply_post[i].reply_post_free,
+            ioc->reply_post_queue_depth, 8, sz/1024));
+        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+            "reply_post_free_dma = (0x%llx)\n", ioc->name,
+            (unsigned long long)
+            ioc->reply_post[i].reply_post_free_dma));
+        total_sz += sz;
+    } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));

Same thing. I think:

     for (i = 0; i < ioc->reply_queue_count ; i++) {

was much clearer.

If reply_queue_count is ever inconsistent wrt. ioc->rdpq_array_enable
and _base_is_controller_msix_enabled(ioc) then that's an orthogonal
problem that you should address directly instead of working around it
several places in the code.

-- 
Martin K. Petersen	Oracle Linux Engineering

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
       [not found]                     ` <CAK=zhgpiyt9xukGCNDOpEDmWRwFSMCcEiUQ190BW0UgiLGVP6g@mail.gmail.com>
@ 2014-08-11 13:17                       ` Sreekanth Reddy
  2014-08-12  2:32                       ` Martin K. Petersen
  1 sibling, 0 replies; 20+ messages in thread
From: Sreekanth Reddy @ 2014-08-11 13:17 UTC (permalink / raw)
  To: Martin K. Petersen
  Cc: jejb, James E.J. Bottomley, linux-scsi, Sathya Prakash,
	Nagalakshmi Nandigama, linux-kernel, Christoph Hellwig

Hi Martin,

Please let me known any further changes are required so that I can
send this patch once again with git send-email.

Regards,
Sreekanth

On Mon, Aug 11, 2014 at 6:45 PM, Sreekanth Reddy
<sreekanth.reddy@avagotech.com> wrote:
> Hi Martin,
>
> Please let me known any further changes are required so that I can send this
> patch once again with git send-email.
>
> Regards,
> Sreekanth
>
>
> On Wed, Aug 6, 2014 at 10:57 AM, Sreekanth Reddy
> <sreekanth.reddy@avagotech.com> wrote:
>>
>> Hi Martin,
>>
>> Replied inline.
>>
>> On Wed, Aug 6, 2014 at 12:16 AM, Martin K. Petersen
>> <martin.petersen@oracle.com> wrote:
>>>
>>> >>>>> "Sreekanth" == Sreekanth Reddy <sreekanth.reddy@avagotech.com>
>>> >>>>> writes:
>>>
>>> Sreekanth,
>>>
>>> Patch was mangled and I had to apply every single hunk by hand. Please
>>> use git send-email.
>>>
>> Sorry, Next time onwards I will take of this.
>>
>>>
>>> +static int dma_mask;
>>> +
>>> +static int
>>> +_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
>>> +                int sleep_flag);
>>> +static int
>>> +_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
>>> +                int sleep_flag);
>>> +static int
>>> +_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int
>>> timeout,
>>> +                 int sleep_flag);
>>> +static int
>>> +_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int
>>> request_bytes,
>>> +    u32 *request, int reply_bytes, u16 *reply, int timeout, int
>>> sleep_flag);
>>> +static int
>>> +_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag);
>>>
>>> Are you sure you need all these? _base_get_ioc_facts was the only one
>>> that needed to be declared in my original patch.
>>
>>
>> Accepted only _base_get_ioc_facts is needs to be declared here.
>>
>>>
>>>
>>> +    if (ioc->rdpq_array_enable)
>>> +        sz = reply_post_free_sz;
>>> +    else {
>>> +        if (_base_is_controller_msix_enabled(ioc))
>>> +            sz = reply_post_free_sz * ioc->reply_queue_count;
>>> +        else
>>> +            sz = reply_post_free_sz;
>>> +    }
>>>
>>> sz = reply_post_free_sz;
>>> if (_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable)
>>>    sz *= ioc->reply_queue_count;
>>
>>
>> Accepted. In the next time I will update this in the patch.
>>>
>>>
>>> +    ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ?
>>> +        (ioc->reply_queue_count):1,
>>> +        sizeof(struct reply_post_struct), GFP_KERNEL);
>>>
>>> You're special casing the !rdpq code path again. Why don't you just make
>>> sure reply_queue_count is always correct?
>>
>>
>> Here we are using the reply_post queue to store the base address of the
>> complete reply_post_free queue pool in case of non rdpq support scenario
>> (since here we allocate a complete memory pool of all the reply_queue_count
>> number of reply queues in single shot, so there is only one continuous
>> memory pool). so here the number of entries in the reply_post queue is one
>> in case of non rdpq support scenario.
>>
>> In case of rdpq support scenario reply_post queue will store the base
>> addresses of each and every reply_queue_count number of reply_post_free
>> queue pool. since here we allocate individual and separate reply_post_free
>> memory pool for each msix vector. so here reply_queue_count number of
>> individual reply_post_free queue pools are allocated, so the number of
>> entries in the reply_post queue is reply_queue_count value.
>>
>> So, here the number of entries in the reply_post queue is not dependent on
>> the reply_queue_count but it depends on the the rdpq_support enabled or not.
>> i.e. if rdpq support is enabled then the number of entries in this
>> reply_post queue is reply_queue_count value other wise it is one.
>>
>>>
>>>
>>> +    do {
>>> +        ioc->reply_post[i].reply_post_free =
>>> +            pci_pool_alloc(ioc->reply_post_free_dma_pool,
>>> +            GFP_KERNEL,
>>> +            &ioc->reply_post[i].reply_post_free_dma);
>>> +        if (!ioc->reply_post[i].reply_post_free) {
>>> +            printk(MPT2SAS_ERR_FMT
>>> +            "reply_post_free pool: pci_pool_alloc failed\n",
>>> +            ioc->name);
>>> +            goto out;
>>> +        }
>>> +        memset(ioc->reply_post[i].reply_post_free, 0, sz);
>>> +        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
>>> +            "reply post free pool (0x%p): depth(%d),"
>>> +            "element_size(%d), pool_size(%d kB)\n", ioc->name,
>>> +            ioc->reply_post[i].reply_post_free,
>>> +            ioc->reply_post_queue_depth, 8, sz/1024));
>>> +        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
>>> +            "reply_post_free_dma = (0x%llx)\n", ioc->name,
>>> +            (unsigned long long)
>>> +            ioc->reply_post[i].reply_post_free_dma));
>>> +        total_sz += sz;
>>> +    } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));
>>>
>>> Same thing. I think:
>>>
>>>      for (i = 0; i < ioc->reply_queue_count ; i++) {
>>>
>>> was much clearer.
>>
>>
>> I feel do while loop is suitable to reduce the redundancy code between the
>> rdpq support and non rdpq support scenarios.
>>
>> In case of non rdpq support scenario, this loop is executed only once to
>> allocate a continuous single memory pool for all reply_queue_count number of
>> reply_post_free queues.
>>
>> where as in case of rdpq support scenario, this loop is executed
>> reply_queue_count number of times for allocating individual and separate
>> memory pools for each reply_post_free queue.
>>
>>>
>>>
>>> If reply_queue_count is ever inconsistent wrt. ioc->rdpq_array_enable
>>> and _base_is_controller_msix_enabled(ioc) then that's an orthogonal
>>> problem that you should address directly instead of working around it
>>> several places in the code.
>>
>>
>>>
>>> --
>>> Martin K. Petersen      Oracle Linux Engineering
>>
>>
>> Regards,
>> Sreekanth
>
>

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
       [not found]                     ` <CAK=zhgpiyt9xukGCNDOpEDmWRwFSMCcEiUQ190BW0UgiLGVP6g@mail.gmail.com>
  2014-08-11 13:17                       ` Sreekanth Reddy
@ 2014-08-12  2:32                       ` Martin K. Petersen
  1 sibling, 0 replies; 20+ messages in thread
From: Martin K. Petersen @ 2014-08-12  2:32 UTC (permalink / raw)
  To: Sreekanth Reddy
  Cc: Martin K. Petersen, jejb, James E.J. Bottomley, linux-scsi,
	Sathya Prakash, Nagalakshmi Nandigama, linux-kernel,
	Christoph Hellwig

>>>>> "Sreekanth" == Sreekanth Reddy <sreekanth.reddy@avagotech.com> writes:

Sreekanth> Please let me known any further changes are required so that
Sreekanth> I can send this patch once again with git send-email.

I'm OK with the latest iteration.

-- 
Martin K. Petersen	Oracle Linux Engineering

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-07-23 19:46         ` Martin K. Petersen
  2014-07-25 12:57           ` Sreekanth Reddy
@ 2017-04-25 11:51           ` Sreekanth Reddy
  2017-04-26 22:25             ` Martin K. Petersen
  1 sibling, 1 reply; 20+ messages in thread
From: Sreekanth Reddy @ 2017-04-25 11:51 UTC (permalink / raw)
  To: Martin K. Petersen; +Cc: jejb, linux-scsi, linux-kernel, Christoph Hellwig

On Thu, Jul 24, 2014 at 1:16 AM, Martin K. Petersen
<martin.petersen@oracle.com> wrote:
>>>>>> "Sreekanth" == Sreekanth Reddy <sreekanth.reddy@avagotech.com> writes:
>
> Sreekanth,
>
> Sreekanth> 2. As per MPI Spec, each set of 8 reply descriptor post
> Sreekanth> queues must have the same value for the upper 32-bits of
> Sreekanth> their memory address. So allocated set of eight queues in a
> Sreekanth> single pool and added a new function is_MSB_are_same() to
> Sreekanth> check whether higher 32 bits of this pool memory address are
> Sreekanth> same or not. If this functions returns zero then we are
> Sreekanth> saving these pools in the bad_reply_post_pool list. then
> Sreekanth> releasing these pools once we get the required memory pools.
>
> Why don't you just set pci_set_consistent_dma_mask() to DMA_BIT_MASK(32)
> before you allocate the queue entries?

Martin,

I am taking out this old mail to find out is their any other better
way to make sure that allocated DMA pool doesn't cross particular
boundary line (in our case all upper 32 bits of this pool should be
same, i.e. all the buffer from the pool should be within the 4GB
boundary).

We need to satisfy this condition on those system where 32 bit dma
consistent mask is not supported and it only supports 64 bit dma
consistent mask. So on these system we can't set
pci_set_consistent_dma_mask() to DMA_BIT_MASK(32).

Thanks,
Sreekanth

>
> --
> Martin K. Petersen      Oracle Linux Engineering

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2017-04-25 11:51           ` Sreekanth Reddy
@ 2017-04-26 22:25             ` Martin K. Petersen
  2017-04-27  9:15               ` Kashyap Desai
  0 siblings, 1 reply; 20+ messages in thread
From: Martin K. Petersen @ 2017-04-26 22:25 UTC (permalink / raw)
  To: Sreekanth Reddy
  Cc: Martin K. Petersen, jejb, linux-scsi, linux-kernel, Christoph Hellwig


Sreekanth,

> We need to satisfy this condition on those system where 32 bit dma
> consistent mask is not supported and it only supports 64 bit dma
> consistent mask. So on these system we can't set
> pci_set_consistent_dma_mask() to DMA_BIT_MASK(32).

Which systems are you talking about?

It seems a bit unrealistic to require all devices to support 64-bit DMA.

-- 
Martin K. Petersen	Oracle Linux Engineering

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

* RE: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2017-04-26 22:25             ` Martin K. Petersen
@ 2017-04-27  9:15               ` Kashyap Desai
  0 siblings, 0 replies; 20+ messages in thread
From: Kashyap Desai @ 2017-04-27  9:15 UTC (permalink / raw)
  To: Martin K. Petersen, Sreekanth Reddy
  Cc: jejb, linux-scsi, linux-kernel, Christoph Hellwig

> -----Original Message-----
> From: linux-scsi-owner@vger.kernel.org [mailto:linux-scsi-
> owner@vger.kernel.org] On Behalf Of Martin K. Petersen
> Sent: Thursday, April 27, 2017 3:55 AM
> To: Sreekanth Reddy
> Cc: Martin K. Petersen; jejb@kernel.org; linux-scsi@vger.kernel.org;
linux-
> kernel@vger.kernel.org; Christoph Hellwig
> Subject: Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor
> Post Queue (RDPQ) Array support
>
>
> Sreekanth,
>
> > We need to satisfy this condition on those system where 32 bit dma
> > consistent mask is not supported and it only supports 64 bit dma
> > consistent mask. So on these system we can't set
> > pci_set_consistent_dma_mask() to DMA_BIT_MASK(32).
>
> Which systems are you talking about?
>
> It seems a bit unrealistic to require all devices to support 64-bit DMA.

Martin - We have found all devices to support 64-bit DMA on certain ARM64
platform. I discussed @linux-arm-kern. Below is a thread.

http://marc.info/?l=linux-arm-kernel&m=148880763816046&w=2

For ARM64, it is not supporting SWIOTLB and that is a reason we need to
make all DMA pool above 4GB.
Ea. If I map crash kernel above 4GB in x86_64 platform, they owner DMA 32
bit mask since arch specific code in x86_64 support SWIOTLB.
Same settings on ARM64 platform fails DAM 32 bit mask.

In one particular setup of ARM64, I also see below 4GB is mapped to SoC
and kernel component mapped above 4GB region.

Can we add in MR/IT driver below logic to meet this requirement ?

- Driver will attempt DMA buffer above 4GB and check the start and end
address of the physical address.
If DMA buffer cross the "Same 4GB region" ( I mean High Address should be
constant for that region.), driver will hold that region and attempt one
more allocation.
If second allocation is also not meeting "Same 4GB region", we will give
up driver load.

Before we attempt above logic, we would like to understand if we have any
other reliable method ways to handle this in Linux.

Most of the time, we are going to get "same 4GB region", so we are OK to
have this corner case to detect and bail out driver load. There is no
report of issue from field, but wanted to protect failure for future.

Thanks, Kashyap

>
> --
> Martin K. Petersen	Oracle Linux Engineering

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

* Re: [RESEND][PATCH 07/10] [SCSI] mpt2sas: Added Reply Descriptor Post Queue  (RDPQ) Array support
  2014-08-23 15:04 [RESEND][PATCH 07/10] [SCSI] mpt2sas: " Sreekanth Reddy
@ 2014-08-24 15:37 ` Christoph Hellwig
  0 siblings, 0 replies; 20+ messages in thread
From: Christoph Hellwig @ 2014-08-24 15:37 UTC (permalink / raw)
  To: Sreekanth Reddy
  Cc: jejb, hch, martin.petersen, linux-scsi, JBottomley,
	Sathya.Prakash, Nagalakshmi.Nandigama, linux-kernel,
	Robert Elliott

Can you please send me a single big series with all the mpt2 and mpt3
updates?  With all the resends I'm losing track.

Please also pick up third party mpt patches like
'[PATCH 3/3] mpt3sas, mpt2sas: fix scsi_add_host error handling problems in _scsih_probe' from Robert Elliott.

And while I can't enforce it on you git send-email really is your
friend for that.


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

* Re: [RESEND][PATCH 07/10] [SCSI] mpt2sas: Added Reply Descriptor Post Queue  (RDPQ) Array support
@ 2014-08-23 15:04 Sreekanth Reddy
  2014-08-24 15:37 ` Christoph Hellwig
  0 siblings, 1 reply; 20+ messages in thread
From: Sreekanth Reddy @ 2014-08-23 15:04 UTC (permalink / raw)
  To: jejb, hch
  Cc: martin.petersen, linux-scsi, JBottomley, Sathya.Prakash,
	Nagalakshmi.Nandigama, linux-kernel, Sreekanth Reddy

Up to now, Driver allocates a single contiguous block of memory
pool for all reply queues and passes down a single address in the
ReplyDescriptorPostQueueAddress field of the IOC Init Request
Message to the firmware.

When firmware receives this address, it will program each of the
Reply Descriptor Post Queue registers, as each reply queue has its
own register. Thus the firmware, starting from a base address it
determines the starting address of the subsequent reply queues
through some simple arithmetic calculations.

The size of this contiguous block of memory pool is directly proportional
to number of MSI-X vectors and the HBA queue depth. For example higher
MSIX vectors requires larger contiguous block of memory pool.

But some of the OS kernels are unable to allocate this larger
contiguous block of memory pool.

So, the proposal is to allocate memory independently for each
Reply Queue and pass down all of the addresses to the firmware.
Then the firmware will just take each address and program the value
into the correct register.

When HBAs with older firmware(i.e. without RDPQ capability) is used
with this new driver then the max_msix_vectors value would be set
to 8 by default.

Change_set in v1:

1. Declared _base_get_ioc_facts() function at the beginning of the mpt2sas_base.c
file instead of moving all these functions before mpt2sas_base_map_resources() function
	a. _base_wait_for_doorbell_int()
	b. _base_wait_for_doorbell_ack()
	c. _base_wait_for_doorbell_not_used()
	d. _base_handshake_req_reply_wait()
	e. _base_get_ioc_facts()

2. Initially set the consistent DMA mask to 32 bit and then change it to 64 bit mask
after allocating RDPQ pools by calling the function _base_change_consistent_dma_mask.
This is to ensure that all the upper 32 bits of RDPQ entries's base address to be same.

3. Reduced the redundancy between the RDPQ and non-RDPQ support in these following functions
	a. _base_release_memory_pools()
	b. _base_allocate_memory_pools()
	c. _base_send_ioc_init()
	d. _base_make_ioc_operational()

Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
---
 drivers/scsi/mpt2sas/mpt2sas_base.c | 236 +++++++++++++++++++++++++++---------
 drivers/scsi/mpt2sas/mpt2sas_base.h |  20 ++-
 2 files changed, 196 insertions(+), 60 deletions(-)

diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 24d0e52..bc37979 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -92,6 +92,9 @@ static int disable_discovery = -1;
 module_param(disable_discovery, int, 0);
 MODULE_PARM_DESC(disable_discovery, " disable discovery ");
 
+static int
+_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag);
+
 /**
  * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
  *
@@ -1179,17 +1182,22 @@ static int
 _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
 {
 	struct sysinfo s;
-	char *desc = NULL;
+	u64 consistent_dma_mask;
+
+	if (ioc->dma_mask)
+		consistent_dma_mask = DMA_BIT_MASK(64);
+	else
+		consistent_dma_mask = DMA_BIT_MASK(32);
 
 	if (sizeof(dma_addr_t) > 4) {
 		const uint64_t required_mask =
 		    dma_get_required_mask(&pdev->dev);
-		if ((required_mask > DMA_BIT_MASK(32)) && !pci_set_dma_mask(pdev,
-		    DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(pdev,
-		    DMA_BIT_MASK(64))) {
+		if ((required_mask > DMA_BIT_MASK(32)) &&
+		    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
+		    !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) {
 			ioc->base_add_sg_single = &_base_add_sg_single_64;
 			ioc->sge_size = sizeof(Mpi2SGESimple64_t);
-			desc = "64";
+			ioc->dma_mask = 64;
 			goto out;
 		}
 	}
@@ -1198,18 +1206,29 @@ _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
 	    && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
 		ioc->base_add_sg_single = &_base_add_sg_single_32;
 		ioc->sge_size = sizeof(Mpi2SGESimple32_t);
-		desc = "32";
+		ioc->dma_mask = 32;
 	} else
 		return -ENODEV;
 
  out:
 	si_meminfo(&s);
-	printk(MPT2SAS_INFO_FMT "%s BIT PCI BUS DMA ADDRESSING SUPPORTED, "
-	    "total mem (%ld kB)\n", ioc->name, desc, convert_to_kb(s.totalram));
+	printk(MPT2SAS_INFO_FMT
+	    "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
+	    ioc->name, ioc->dma_mask, convert_to_kb(s.totalram));
 
 	return 0;
 }
 
+static int
+_base_change_consistent_dma_mask(struct MPT2SAS_ADAPTER *ioc,
+				  struct pci_dev *pdev)
+{
+	if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+		if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
+			return -ENODEV;
+	}
+	return 0;
+}
 /**
  * _base_check_enable_msix - checks MSIX capabable.
  * @ioc: per adapter object
@@ -1406,6 +1425,9 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
 	ioc->reply_queue_count = min_t(int, ioc->cpu_count,
 	    ioc->msix_vector_count);
 
+	if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
+		max_msix_vectors = 8;
+
 	if (max_msix_vectors > 0) {
 		ioc->reply_queue_count = min_t(int, max_msix_vectors,
 		    ioc->reply_queue_count);
@@ -1534,6 +1556,16 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
 	}
 
 	_base_mask_interrupts(ioc);
+
+	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+	if (r)
+		goto out_fail;
+
+	if (!ioc->rdpq_array_enable_assigned) {
+		ioc->rdpq_array_enable = ioc->rdpq_array_capable;
+		ioc->rdpq_array_enable_assigned = 1;
+	}
+
 	r = _base_enable_msix(ioc);
 	if (r)
 		goto out_fail;
@@ -2331,7 +2363,8 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
 static void
 _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 {
-	int i;
+	int i = 0;
+	struct reply_post_struct *rps;
 
 	dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
@@ -2372,15 +2405,25 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 		ioc->reply_free = NULL;
 	}
 
-	if (ioc->reply_post_free) {
-		pci_pool_free(ioc->reply_post_free_dma_pool,
-		    ioc->reply_post_free, ioc->reply_post_free_dma);
+	if (ioc->reply_post) {
+		do {
+			rps = &ioc->reply_post[i];
+			if (rps->reply_post_free) {
+				pci_pool_free(
+				    ioc->reply_post_free_dma_pool,
+				    rps->reply_post_free,
+				    rps->reply_post_free_dma);
+				dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+				    "reply_post_free_pool(0x%p): free\n",
+				    ioc->name, rps->reply_post_free));
+				rps->reply_post_free = NULL;
+			}
+		} while (ioc->rdpq_array_enable &&
+			   (++i < ioc->reply_queue_count));
+
 		if (ioc->reply_post_free_dma_pool)
 			pci_pool_destroy(ioc->reply_post_free_dma_pool);
-		dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
-		    "reply_post_free_pool(0x%p): free\n", ioc->name,
-		    ioc->reply_post_free));
-		ioc->reply_post_free = NULL;
+		kfree(ioc->reply_post);
 	}
 
 	if (ioc->config_page) {
@@ -2523,6 +2566,65 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
 	    ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
 	    ioc->chains_needed_per_io));
 
+	/* reply post queue, 16 byte align */
+	reply_post_free_sz = ioc->reply_post_queue_depth *
+	    sizeof(Mpi2DefaultReplyDescriptor_t);
+
+	sz = reply_post_free_sz;
+	if (_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable)
+		sz *= ioc->reply_queue_count;
+
+	ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ?
+	    (ioc->reply_queue_count):1,
+	    sizeof(struct reply_post_struct), GFP_KERNEL);
+
+	if (!ioc->reply_post) {
+		printk(MPT2SAS_ERR_FMT "reply_post_free pool: kcalloc failed\n",
+			ioc->name);
+		goto out;
+	}
+	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
+	    ioc->pdev, sz, 16, 0);
+	if (!ioc->reply_post_free_dma_pool) {
+		printk(MPT2SAS_ERR_FMT
+		 "reply_post_free pool: pci_pool_create failed\n",
+		 ioc->name);
+		goto out;
+	}
+	i = 0;
+	do {
+		ioc->reply_post[i].reply_post_free =
+		    pci_pool_alloc(ioc->reply_post_free_dma_pool,
+		    GFP_KERNEL,
+		    &ioc->reply_post[i].reply_post_free_dma);
+		if (!ioc->reply_post[i].reply_post_free) {
+			printk(MPT2SAS_ERR_FMT
+			"reply_post_free pool: pci_pool_alloc failed\n",
+			ioc->name);
+			goto out;
+		}
+		memset(ioc->reply_post[i].reply_post_free, 0, sz);
+		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "reply post free pool (0x%p): depth(%d),"
+		    "element_size(%d), pool_size(%d kB)\n", ioc->name,
+		    ioc->reply_post[i].reply_post_free,
+		    ioc->reply_post_queue_depth, 8, sz/1024));
+		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "reply_post_free_dma = (0x%llx)\n", ioc->name,
+		    (unsigned long long)
+		    ioc->reply_post[i].reply_post_free_dma));
+		total_sz += sz;
+	} while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));
+
+	if (ioc->dma_mask == 64) {
+		if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) {
+			printk(MPT2SAS_WARN_FMT
+			    "no suitable consistent DMA mask for %s\n",
+			    ioc->name, pci_name(ioc->pdev));
+			goto out;
+		}
+	}
+
 	ioc->scsiio_depth = ioc->hba_queue_depth -
 	    ioc->hi_priority_depth - ioc->internal_depth;
 
@@ -2734,37 +2836,6 @@ chain_done:
 	    "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
 	total_sz += sz;
 
-	/* reply post queue, 16 byte align */
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
-	if (_base_is_controller_msix_enabled(ioc))
-		sz = reply_post_free_sz * ioc->reply_queue_count;
-	else
-		sz = reply_post_free_sz;
-	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
-	    ioc->pdev, sz, 16, 0);
-	if (!ioc->reply_post_free_dma_pool) {
-		printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create "
-		    "failed\n", ioc->name);
-		goto out;
-	}
-	ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
-	    GFP_KERNEL, &ioc->reply_post_free_dma);
-	if (!ioc->reply_post_free) {
-		printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc "
-		    "failed\n", ioc->name);
-		goto out;
-	}
-	memset(ioc->reply_post_free, 0, sz);
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
-	    "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
-	    ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
-	    sz/1024));
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = "
-	    "(0x%llx)\n", ioc->name, (unsigned long long)
-	    ioc->reply_post_free_dma));
-	total_sz += sz;
-
 	ioc->config_page_sz = 512;
 	ioc->config_page = pci_alloc_consistent(ioc->pdev,
 	    ioc->config_page_sz, &ioc->config_page_dma);
@@ -3436,6 +3507,9 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
 	if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
 		ioc->ir_firmware = 1;
+	if ((facts->IOCCapabilities &
+	      MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE))
+		ioc->rdpq_array_capable = 1;
 	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
 	facts->IOCRequestFrameSize =
 	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
@@ -3471,9 +3545,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 {
 	Mpi2IOCInitRequest_t mpi_request;
 	Mpi2IOCInitReply_t mpi_reply;
-	int r;
+	int i, r = 0;
 	struct timeval current_time;
 	u16 ioc_status;
+	u32 reply_post_free_array_sz = 0;
+	Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
+	dma_addr_t reply_post_free_array_dma;
 
 	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
@@ -3502,9 +3579,31 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	    cpu_to_le64((u64)ioc->request_dma);
 	mpi_request.ReplyFreeQueueAddress =
 	    cpu_to_le64((u64)ioc->reply_free_dma);
-	mpi_request.ReplyDescriptorPostQueueAddress =
-	    cpu_to_le64((u64)ioc->reply_post_free_dma);
 
+	if (ioc->rdpq_array_enable) {
+		reply_post_free_array_sz = ioc->reply_queue_count *
+		    sizeof(Mpi2IOCInitRDPQArrayEntry);
+		reply_post_free_array = pci_alloc_consistent(ioc->pdev,
+			reply_post_free_array_sz, &reply_post_free_array_dma);
+		if (!reply_post_free_array) {
+			printk(MPT2SAS_ERR_FMT
+			"reply_post_free_array: pci_alloc_consistent failed\n",
+			ioc->name);
+			r = -ENOMEM;
+			goto out;
+		}
+		memset(reply_post_free_array, 0, reply_post_free_array_sz);
+		for (i = 0; i < ioc->reply_queue_count; i++)
+			reply_post_free_array[i].RDPQBaseAddress =
+			    cpu_to_le64(
+				(u64)ioc->reply_post[i].reply_post_free_dma);
+		mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64((u64)reply_post_free_array_dma);
+	} else {
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
+	}
 
 	/* This time stamp specifies number of milliseconds
 	 * since epoch ~ midnight January 1, 1970.
@@ -3532,7 +3631,7 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	if (r != 0) {
 		printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
 		    ioc->name, __func__, r);
-		return r;
+		goto out;
 	}
 
 	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
@@ -3542,7 +3641,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 		r = -EIO;
 	}
 
-	return 0;
+out:
+	if (reply_post_free_array)
+		pci_free_consistent(ioc->pdev, reply_post_free_array_sz,
+				    reply_post_free_array,
+				    reply_post_free_array_dma);
+	return r;
 }
 
 /**
@@ -4075,7 +4179,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	u8 hide_flag;
 	struct adapter_reply_queue *reply_q;
 	long reply_post_free;
-	u32 reply_post_free_sz;
+	u32 reply_post_free_sz, index = 0;
 
 	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
@@ -4146,19 +4250,27 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 		_base_assign_reply_queues(ioc);
 
 	/* initialize Reply Post Free Queue */
-	reply_post_free = (long)ioc->reply_post_free;
 	reply_post_free_sz = ioc->reply_post_queue_depth *
 	    sizeof(Mpi2DefaultReplyDescriptor_t);
+	reply_post_free = (long)ioc->reply_post[index].reply_post_free;
 	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
 		reply_q->reply_post_host_index = 0;
 		reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
 		    reply_post_free;
 		for (i = 0; i < ioc->reply_post_queue_depth; i++)
 			reply_q->reply_post_free[i].Words =
-							cpu_to_le64(ULLONG_MAX);
+						     cpu_to_le64(ULLONG_MAX);
 		if (!_base_is_controller_msix_enabled(ioc))
 			goto skip_init_reply_post_free_queue;
-		reply_post_free += reply_post_free_sz;
+		/*
+		 * If RDPQ is enabled, switch to the next allocation.
+		 * Otherwise advance within the contiguous region.
+		 */
+		if (ioc->rdpq_array_enable)
+			reply_post_free = (long)
+			    ioc->reply_post[++index].reply_post_free;
+		else
+			reply_post_free += reply_post_free_sz;
 	}
  skip_init_reply_post_free_queue:
 
@@ -4286,6 +4398,8 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
 		}
 	}
 
+	ioc->rdpq_array_enable_assigned = 0;
+	ioc->dma_mask = 0;
 	r = mpt2sas_base_map_resources(ioc);
 	if (r)
 		goto out_free_resources;
@@ -4647,6 +4761,16 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
 		r = -EFAULT;
 		goto out;
 	}
+
+	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+	if (r)
+		goto out;
+
+	if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
+		panic("%s: Issue occurred with flashing controller firmware."
+		      "Please reboot the system and ensure that the correct"
+		      " firmware version is running\n", ioc->name);
+
 	r = _base_make_ioc_operational(ioc, sleep_flag);
 	if (!r)
 		_base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index e0e4dd4..9bc8e0b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -636,6 +636,11 @@ struct mpt2sas_port_facts {
 	u16			MaxPostedCmdBuffers;
 };
 
+struct reply_post_struct {
+	Mpi2ReplyDescriptorsUnion_t	*reply_post_free;
+	dma_addr_t			reply_post_free_dma;
+};
+
 /**
  * enum mutex_type - task management mutex type
  * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it
@@ -663,6 +668,7 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
  * @ir_firmware: IR firmware present
  * @bars: bitmask of BAR's that must be configured
  * @mask_interrupts: ignore interrupt
+ * @dma_mask: used to set the consistent dma mask
  * @fault_reset_work_q_name: fw fault work queue
  * @fault_reset_work_q: ""
  * @fault_reset_work: ""
@@ -779,8 +785,11 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
  * @reply_free_dma_pool:
  * @reply_free_host_index: tail index in pool to insert free replys
  * @reply_post_queue_depth: reply post queue depth
- * @reply_post_free: pool for reply post (64bit descriptor)
- * @reply_post_free_dma:
+ * @reply_post_struct: struct for reply_post_free physical & virt address
+ * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
+ * @rdpq_array_enable: rdpq_array support is enabled in the driver
+ * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
+ *				is assigned only ones
  * @reply_queue_count: number of reply queue's
  * @reply_queue_list: link list contaning the reply queue info
  * @reply_post_host_index: head index in the pool where FW completes IO
@@ -802,6 +811,7 @@ struct MPT2SAS_ADAPTER {
 	u8		ir_firmware;
 	int		bars;
 	u8		mask_interrupts;
+	int		dma_mask;
 
 	/* fw fault handler */
 	char		fault_reset_work_q_name[20];
@@ -972,8 +982,10 @@ struct MPT2SAS_ADAPTER {
 
 	/* reply post queue */
 	u16 		reply_post_queue_depth;
-	Mpi2ReplyDescriptorsUnion_t *reply_post_free;
-	dma_addr_t	reply_post_free_dma;
+	struct reply_post_struct *reply_post;
+	u8		rdpq_array_capable;
+	u8		rdpq_array_enable;
+	u8		rdpq_array_enable_assigned;
 	struct dma_pool *reply_post_free_dma_pool;
 	u8		reply_queue_count;
 	struct list_head reply_queue_list;
-- 
2.0.2


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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-08-12  9:24 Sreekanth Reddy
  2014-08-12  9:37 ` Joe Perches
@ 2014-08-21 20:35 ` Martin K. Petersen
  1 sibling, 0 replies; 20+ messages in thread
From: Martin K. Petersen @ 2014-08-21 20:35 UTC (permalink / raw)
  To: Sreekanth Reddy
  Cc: martin.petersen, jejb, linux-scsi, JBottomley, Sathya.Prakash,
	Nagalakshmi.Nandigama, linux-kernel, hch

>>>>> "Sreekanth" == Sreekanth Reddy <sreekanth.reddy@avagotech.com> writes:

Sreekanth> Sending the this patch once agin using git send-email.  Up to
Sreekanth> now, Driver allocates a single contiguous block of memory
Sreekanth> pool for all reply queues and passes down a single address in
Sreekanth> the ReplyDescriptorPostQueueAddress field of the IOC Init
Sreekanth> Request Message to the firmware.

Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>

-- 
Martin K. Petersen	Oracle Linux Engineering

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-08-12  9:37 ` Joe Perches
@ 2014-08-12  9:51   ` Sreekanth Reddy
  0 siblings, 0 replies; 20+ messages in thread
From: Sreekanth Reddy @ 2014-08-12  9:51 UTC (permalink / raw)
  To: Joe Perches
  Cc: Martin K. Petersen, jejb, linux-scsi, James E.J. Bottomley,
	Sathya Prakash, Nagalakshmi Nandigama, linux-kernel,
	Christoph Hellwig

On Tue, Aug 12, 2014 at 3:07 PM, Joe Perches <joe@perches.com> wrote:
> On Tue, 2014-08-12 at 14:54 +0530, Sreekanth Reddy wrote:
>> So, the proposal is to allocate memory independently for each
>> Reply Queue and pass down all of the addresses to the firmware.
>> Then the firmware will just take each address and program the value
>> into the correct register.
>
> trivial note:
>
>> diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
> []
>> @@ -1179,17 +1184,22 @@ static int
>>  _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
>>  {
>>       struct sysinfo s;
>> -     char *desc = NULL;
>> +     u64 consistent_dma_mask;
>> +
>> +     if (dma_mask)
>> +             consistent_dma_mask = DMA_BIT_MASK(64);
>> +     else
>> +             consistent_dma_mask = DMA_BIT_MASK(32);
>>
>>       if (sizeof(dma_addr_t) > 4) {
>>               const uint64_t required_mask =
>>                   dma_get_required_mask(&pdev->dev);
>>               if ((required_mask > DMA_BIT_MASK(32)) && !pci_set_dma_mask(pdev,
>>                   DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(pdev,
>> -                 DMA_BIT_MASK(64))) {
>> +                 consistent_dma_mask)) {
>
> This would be easier to read if the embedded functions
> within the if were on separate lines like:

Accepted. next time onwards I will take care of this.

>
>                 if ((required_mask > DMA_BIT_MASK(32)) &&
>                     !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
>                     !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) {
>
>

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

* Re: [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
  2014-08-12  9:24 Sreekanth Reddy
@ 2014-08-12  9:37 ` Joe Perches
  2014-08-12  9:51   ` Sreekanth Reddy
  2014-08-21 20:35 ` Martin K. Petersen
  1 sibling, 1 reply; 20+ messages in thread
From: Joe Perches @ 2014-08-12  9:37 UTC (permalink / raw)
  To: Sreekanth Reddy
  Cc: martin.petersen, jejb, linux-scsi, JBottomley, Sathya.Prakash,
	Nagalakshmi.Nandigama, linux-kernel, hch

On Tue, 2014-08-12 at 14:54 +0530, Sreekanth Reddy wrote:
> So, the proposal is to allocate memory independently for each
> Reply Queue and pass down all of the addresses to the firmware.
> Then the firmware will just take each address and program the value
> into the correct register.

trivial note:

> diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
[]
> @@ -1179,17 +1184,22 @@ static int
>  _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
>  {
>  	struct sysinfo s;
> -	char *desc = NULL;
> +	u64 consistent_dma_mask;
> +
> +	if (dma_mask)
> +		consistent_dma_mask = DMA_BIT_MASK(64);
> +	else
> +		consistent_dma_mask = DMA_BIT_MASK(32);
>  
>  	if (sizeof(dma_addr_t) > 4) {
>  		const uint64_t required_mask =
>  		    dma_get_required_mask(&pdev->dev);
>  		if ((required_mask > DMA_BIT_MASK(32)) && !pci_set_dma_mask(pdev,
>  		    DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(pdev,
> -		    DMA_BIT_MASK(64))) {
> +		    consistent_dma_mask)) {

This would be easier to read if the embedded functions
within the if were on separate lines like:

		if ((required_mask > DMA_BIT_MASK(32)) &&
		    !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
		    !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) {



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

* [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support
@ 2014-08-12  9:24 Sreekanth Reddy
  2014-08-12  9:37 ` Joe Perches
  2014-08-21 20:35 ` Martin K. Petersen
  0 siblings, 2 replies; 20+ messages in thread
From: Sreekanth Reddy @ 2014-08-12  9:24 UTC (permalink / raw)
  To: martin.petersen, jejb
  Cc: linux-scsi, JBottomley, Sathya.Prakash, Nagalakshmi.Nandigama,
	linux-kernel, hch, Sreekanth Reddy

Sending the this patch once agin using git send-email.

Up to now, Driver allocates a single contiguous block of memory
pool for all reply queues and passes down a single address in the
ReplyDescriptorPostQueueAddress field of the IOC Init Request
Message to the firmware.

When firmware receives this address, it will program each of the
Reply Descriptor Post Queue registers, as each reply queue has its
own register. Thus the firmware, starting from a base address it
determines the starting address of the subsequent reply queues
through some simple arithmetic calculations.

The size of this contiguous block of memory pool is directly proportional
to number of MSI-X vectors and the HBA queue depth. For example higher
MSIX vectors requires larger contiguous block of memory pool.

But some of the OS kernels are unable to allocate this larger
contiguous block of memory pool.

So, the proposal is to allocate memory independently for each
Reply Queue and pass down all of the addresses to the firmware.
Then the firmware will just take each address and program the value
into the correct register.

When HBAs with older firmware(i.e. without RDPQ capability) is used
with this new driver then the max_msix_vectors value would be set
to 8 by default.

Change_set in v2:

1. Declared _base_get_ioc_facts() function at the beginning of the mpt2sas_base.c
file instead of moving all these functions before mpt2sas_base_map_resources() function
        a. _base_wait_for_doorbell_int()
        b. _base_wait_for_doorbell_ack()
        c. _base_wait_for_doorbell_not_used()
        d. _base_handshake_req_reply_wait()
        e. _base_get_ioc_facts()

2. Initially set the consistent DMA mask to 32 bit and then change it to 64 bit mask
after allocating RDPQ pools by calling the function _base_change_consistent_dma_mask.
This is to ensure that all the upper 32 bits of RDPQ entries's base address to be same.

3. Reduced the redundancy between the RDPQ and non-RDPQ support in these following functions
        a. _base_release_memory_pools()
        b. _base_allocate_memory_pools()
        c. _base_send_ioc_init()
        d. _base_make_ioc_operational()

Signed-off-by: Sreekanth Reddy <Sreekanth.Reddy@avagotech.com>
---
 drivers/scsi/mpt2sas/mpt2sas_base.c | 233 +++++++++++++++++++++++++++---------
 drivers/scsi/mpt2sas/mpt2sas_base.h |  18 ++-
 2 files changed, 193 insertions(+), 58 deletions(-)

diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 24d0e52..018ae10 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -92,6 +92,11 @@ static int disable_discovery = -1;
 module_param(disable_discovery, int, 0);
 MODULE_PARM_DESC(disable_discovery, " disable discovery ");
 
+static int dma_mask;
+
+static int
+_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag);
+
 /**
  * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
  *
@@ -1179,17 +1184,22 @@ static int
 _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
 {
 	struct sysinfo s;
-	char *desc = NULL;
+	u64 consistent_dma_mask;
+
+	if (dma_mask)
+		consistent_dma_mask = DMA_BIT_MASK(64);
+	else
+		consistent_dma_mask = DMA_BIT_MASK(32);
 
 	if (sizeof(dma_addr_t) > 4) {
 		const uint64_t required_mask =
 		    dma_get_required_mask(&pdev->dev);
 		if ((required_mask > DMA_BIT_MASK(32)) && !pci_set_dma_mask(pdev,
 		    DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(pdev,
-		    DMA_BIT_MASK(64))) {
+		    consistent_dma_mask)) {
 			ioc->base_add_sg_single = &_base_add_sg_single_64;
 			ioc->sge_size = sizeof(Mpi2SGESimple64_t);
-			desc = "64";
+			dma_mask = 64;
 			goto out;
 		}
 	}
@@ -1198,18 +1208,29 @@ _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
 	    && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
 		ioc->base_add_sg_single = &_base_add_sg_single_32;
 		ioc->sge_size = sizeof(Mpi2SGESimple32_t);
-		desc = "32";
+		dma_mask = 32;
 	} else
 		return -ENODEV;
 
  out:
 	si_meminfo(&s);
-	printk(MPT2SAS_INFO_FMT "%s BIT PCI BUS DMA ADDRESSING SUPPORTED, "
-	    "total mem (%ld kB)\n", ioc->name, desc, convert_to_kb(s.totalram));
+	printk(MPT2SAS_INFO_FMT
+	    "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
+	    ioc->name, dma_mask, convert_to_kb(s.totalram));
 
 	return 0;
 }
 
+static int
+_base_change_consistent_dma_mask(struct MPT2SAS_ADAPTER *ioc,
+				  struct pci_dev *pdev)
+{
+	if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
+		if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
+			return -ENODEV;
+	}
+	return 0;
+}
 /**
  * _base_check_enable_msix - checks MSIX capabable.
  * @ioc: per adapter object
@@ -1406,6 +1427,9 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
 	ioc->reply_queue_count = min_t(int, ioc->cpu_count,
 	    ioc->msix_vector_count);
 
+	if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
+		max_msix_vectors = 8;
+
 	if (max_msix_vectors > 0) {
 		ioc->reply_queue_count = min_t(int, max_msix_vectors,
 		    ioc->reply_queue_count);
@@ -1534,6 +1558,16 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
 	}
 
 	_base_mask_interrupts(ioc);
+
+	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+	if (r)
+		goto out_fail;
+
+	if (!ioc->rdpq_array_enable_assigned) {
+		ioc->rdpq_array_enable = ioc->rdpq_array_capable;
+		ioc->rdpq_array_enable_assigned = 1;
+	}
+
 	r = _base_enable_msix(ioc);
 	if (r)
 		goto out_fail;
@@ -2331,7 +2365,8 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
 static void
 _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 {
-	int i;
+	int i = 0;
+	struct reply_post_struct *rps;
 
 	dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
@@ -2372,15 +2407,25 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
 		ioc->reply_free = NULL;
 	}
 
-	if (ioc->reply_post_free) {
-		pci_pool_free(ioc->reply_post_free_dma_pool,
-		    ioc->reply_post_free, ioc->reply_post_free_dma);
+	if (ioc->reply_post) {
+		do {
+			rps = &ioc->reply_post[i];
+			if (rps->reply_post_free) {
+				pci_pool_free(
+				    ioc->reply_post_free_dma_pool,
+				    rps->reply_post_free,
+				    rps->reply_post_free_dma);
+				dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
+				    "reply_post_free_pool(0x%p): free\n",
+				    ioc->name, rps->reply_post_free));
+				rps->reply_post_free = NULL;
+			}
+		} while (ioc->rdpq_array_enable &&
+			   (++i < ioc->reply_queue_count));
+
 		if (ioc->reply_post_free_dma_pool)
 			pci_pool_destroy(ioc->reply_post_free_dma_pool);
-		dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
-		    "reply_post_free_pool(0x%p): free\n", ioc->name,
-		    ioc->reply_post_free));
-		ioc->reply_post_free = NULL;
+		kfree(ioc->reply_post);
 	}
 
 	if (ioc->config_page) {
@@ -2523,6 +2568,65 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
 	    ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
 	    ioc->chains_needed_per_io));
 
+	/* reply post queue, 16 byte align */
+	reply_post_free_sz = ioc->reply_post_queue_depth *
+	    sizeof(Mpi2DefaultReplyDescriptor_t);
+
+	sz = reply_post_free_sz;
+	if (_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable)
+		sz *= ioc->reply_queue_count;
+
+	ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ?
+	    (ioc->reply_queue_count):1,
+	    sizeof(struct reply_post_struct), GFP_KERNEL);
+
+	if (!ioc->reply_post) {
+		printk(MPT2SAS_ERR_FMT "reply_post_free pool: kcalloc failed\n",
+			ioc->name);
+		goto out;
+	}
+	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
+	    ioc->pdev, sz, 16, 0);
+	if (!ioc->reply_post_free_dma_pool) {
+		printk(MPT2SAS_ERR_FMT
+		 "reply_post_free pool: pci_pool_create failed\n",
+		 ioc->name);
+		goto out;
+	}
+	i = 0;
+	do {
+		ioc->reply_post[i].reply_post_free =
+		    pci_pool_alloc(ioc->reply_post_free_dma_pool,
+		    GFP_KERNEL,
+		    &ioc->reply_post[i].reply_post_free_dma);
+		if (!ioc->reply_post[i].reply_post_free) {
+			printk(MPT2SAS_ERR_FMT
+			"reply_post_free pool: pci_pool_alloc failed\n",
+			ioc->name);
+			goto out;
+		}
+		memset(ioc->reply_post[i].reply_post_free, 0, sz);
+		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "reply post free pool (0x%p): depth(%d),"
+		    "element_size(%d), pool_size(%d kB)\n", ioc->name,
+		    ioc->reply_post[i].reply_post_free,
+		    ioc->reply_post_queue_depth, 8, sz/1024));
+		dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
+		    "reply_post_free_dma = (0x%llx)\n", ioc->name,
+		    (unsigned long long)
+		    ioc->reply_post[i].reply_post_free_dma));
+		total_sz += sz;
+	} while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));
+
+	if (dma_mask == 64) {
+		if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) {
+			printk(MPT2SAS_WARN_FMT
+			    "no suitable consistent DMA mask for %s\n",
+			    ioc->name, pci_name(ioc->pdev));
+			goto out;
+		}
+	}
+
 	ioc->scsiio_depth = ioc->hba_queue_depth -
 	    ioc->hi_priority_depth - ioc->internal_depth;
 
@@ -2734,37 +2838,6 @@ chain_done:
 	    "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
 	total_sz += sz;
 
-	/* reply post queue, 16 byte align */
-	reply_post_free_sz = ioc->reply_post_queue_depth *
-	    sizeof(Mpi2DefaultReplyDescriptor_t);
-	if (_base_is_controller_msix_enabled(ioc))
-		sz = reply_post_free_sz * ioc->reply_queue_count;
-	else
-		sz = reply_post_free_sz;
-	ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
-	    ioc->pdev, sz, 16, 0);
-	if (!ioc->reply_post_free_dma_pool) {
-		printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create "
-		    "failed\n", ioc->name);
-		goto out;
-	}
-	ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool ,
-	    GFP_KERNEL, &ioc->reply_post_free_dma);
-	if (!ioc->reply_post_free) {
-		printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc "
-		    "failed\n", ioc->name);
-		goto out;
-	}
-	memset(ioc->reply_post_free, 0, sz);
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool"
-	    "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n",
-	    ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8,
-	    sz/1024));
-	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = "
-	    "(0x%llx)\n", ioc->name, (unsigned long long)
-	    ioc->reply_post_free_dma));
-	total_sz += sz;
-
 	ioc->config_page_sz = 512;
 	ioc->config_page = pci_alloc_consistent(ioc->pdev,
 	    ioc->config_page_sz, &ioc->config_page_dma);
@@ -3436,6 +3509,9 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
 	if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
 		ioc->ir_firmware = 1;
+	if ((facts->IOCCapabilities &
+	      MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE))
+		ioc->rdpq_array_capable = 1;
 	facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
 	facts->IOCRequestFrameSize =
 	    le16_to_cpu(mpi_reply.IOCRequestFrameSize);
@@ -3471,9 +3547,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 {
 	Mpi2IOCInitRequest_t mpi_request;
 	Mpi2IOCInitReply_t mpi_reply;
-	int r;
+	int i, r = 0;
 	struct timeval current_time;
 	u16 ioc_status;
+	u32 reply_post_free_array_sz = 0;
+	Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
+	dma_addr_t reply_post_free_array_dma;
 
 	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
@@ -3502,9 +3581,31 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	    cpu_to_le64((u64)ioc->request_dma);
 	mpi_request.ReplyFreeQueueAddress =
 	    cpu_to_le64((u64)ioc->reply_free_dma);
-	mpi_request.ReplyDescriptorPostQueueAddress =
-	    cpu_to_le64((u64)ioc->reply_post_free_dma);
 
+	if (ioc->rdpq_array_enable) {
+		reply_post_free_array_sz = ioc->reply_queue_count *
+		    sizeof(Mpi2IOCInitRDPQArrayEntry);
+		reply_post_free_array = pci_alloc_consistent(ioc->pdev,
+			reply_post_free_array_sz, &reply_post_free_array_dma);
+		if (!reply_post_free_array) {
+			printk(MPT2SAS_ERR_FMT
+			"reply_post_free_array: pci_alloc_consistent failed\n",
+			ioc->name);
+			r = -ENOMEM;
+			goto out;
+		}
+		memset(reply_post_free_array, 0, reply_post_free_array_sz);
+		for (i = 0; i < ioc->reply_queue_count; i++)
+			reply_post_free_array[i].RDPQBaseAddress =
+			    cpu_to_le64(
+				(u64)ioc->reply_post[i].reply_post_free_dma);
+		mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64((u64)reply_post_free_array_dma);
+	} else {
+		mpi_request.ReplyDescriptorPostQueueAddress =
+		    cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
+	}
 
 	/* This time stamp specifies number of milliseconds
 	 * since epoch ~ midnight January 1, 1970.
@@ -3532,7 +3633,7 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	if (r != 0) {
 		printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
 		    ioc->name, __func__, r);
-		return r;
+		goto out;
 	}
 
 	ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
@@ -3542,7 +3643,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 		r = -EIO;
 	}
 
-	return 0;
+out:
+	if (reply_post_free_array)
+		pci_free_consistent(ioc->pdev, reply_post_free_array_sz,
+				    reply_post_free_array,
+				    reply_post_free_array_dma);
+	return r;
 }
 
 /**
@@ -4075,7 +4181,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 	u8 hide_flag;
 	struct adapter_reply_queue *reply_q;
 	long reply_post_free;
-	u32 reply_post_free_sz;
+	u32 reply_post_free_sz, index = 0;
 
 	dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
 	    __func__));
@@ -4146,19 +4252,27 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
 		_base_assign_reply_queues(ioc);
 
 	/* initialize Reply Post Free Queue */
-	reply_post_free = (long)ioc->reply_post_free;
 	reply_post_free_sz = ioc->reply_post_queue_depth *
 	    sizeof(Mpi2DefaultReplyDescriptor_t);
+	reply_post_free = (long)ioc->reply_post[index].reply_post_free;
 	list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
 		reply_q->reply_post_host_index = 0;
 		reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
 		    reply_post_free;
 		for (i = 0; i < ioc->reply_post_queue_depth; i++)
 			reply_q->reply_post_free[i].Words =
-							cpu_to_le64(ULLONG_MAX);
+						     cpu_to_le64(ULLONG_MAX);
 		if (!_base_is_controller_msix_enabled(ioc))
 			goto skip_init_reply_post_free_queue;
-		reply_post_free += reply_post_free_sz;
+		/*
+		 * If RDPQ is enabled, switch to the next allocation.
+		 * Otherwise advance within the contiguous region.
+		 */
+		if (ioc->rdpq_array_enable)
+			reply_post_free = (long)
+			    ioc->reply_post[++index].reply_post_free;
+		else
+			reply_post_free += reply_post_free_sz;
 	}
  skip_init_reply_post_free_queue:
 
@@ -4286,6 +4400,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
 		}
 	}
 
+	ioc->rdpq_array_enable_assigned = 0;
 	r = mpt2sas_base_map_resources(ioc);
 	if (r)
 		goto out_free_resources;
@@ -4647,6 +4762,16 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
 		r = -EFAULT;
 		goto out;
 	}
+
+	r = _base_get_ioc_facts(ioc, CAN_SLEEP);
+	if (r)
+		goto out;
+
+	if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
+		panic("%s: Issue occurred with flashing controller firmware."
+		      "Please reboot the system and ensure that the correct"
+		      " firmware version is running\n", ioc->name);
+
 	r = _base_make_ioc_operational(ioc, sleep_flag);
 	if (!r)
 		_base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index e0e4dd4..0d40318 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -636,6 +636,11 @@ struct mpt2sas_port_facts {
 	u16			MaxPostedCmdBuffers;
 };
 
+struct reply_post_struct {
+	Mpi2ReplyDescriptorsUnion_t	*reply_post_free;
+	dma_addr_t			reply_post_free_dma;
+};
+
 /**
  * enum mutex_type - task management mutex type
  * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it
@@ -779,8 +784,11 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
  * @reply_free_dma_pool:
  * @reply_free_host_index: tail index in pool to insert free replys
  * @reply_post_queue_depth: reply post queue depth
- * @reply_post_free: pool for reply post (64bit descriptor)
- * @reply_post_free_dma:
+ * @reply_post_struct: struct for reply_post_free physical & virt address
+ * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
+ * @rdpq_array_enable: rdpq_array support is enabled in the driver
+ * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
+ *				is assigned only ones
  * @reply_queue_count: number of reply queue's
  * @reply_queue_list: link list contaning the reply queue info
  * @reply_post_host_index: head index in the pool where FW completes IO
@@ -972,8 +980,10 @@ struct MPT2SAS_ADAPTER {
 
 	/* reply post queue */
 	u16 		reply_post_queue_depth;
-	Mpi2ReplyDescriptorsUnion_t *reply_post_free;
-	dma_addr_t	reply_post_free_dma;
+	struct reply_post_struct *reply_post;
+	u8		rdpq_array_capable;
+	u8		rdpq_array_enable;
+	u8		rdpq_array_enable_assigned;
 	struct dma_pool *reply_post_free_dma_pool;
 	u8		reply_queue_count;
 	struct list_head reply_queue_list;
-- 
2.0.2


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

end of thread, other threads:[~2017-04-27  9:15 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-25 10:34 [RESEND][PATCH 07/10][SCSI]mpt2sas: Added Reply Descriptor Post Queue (RDPQ) Array support Reddy, Sreekanth
2014-07-22  3:10 ` Martin K. Petersen
     [not found]   ` <CAK=zhgoQt5J=jh4jShAy5rBXNz34sN-tqf=uZDkY4zQJ9XhM5g@mail.gmail.com>
2014-07-23  1:25     ` Martin K. Petersen
2014-07-23 17:37       ` Sreekanth Reddy
2014-07-23 19:46         ` Martin K. Petersen
2014-07-25 12:57           ` Sreekanth Reddy
2014-07-25 19:43             ` Martin K. Petersen
2014-07-30 14:55               ` Sreekanth Reddy
2014-08-05 18:46                 ` Martin K. Petersen
     [not found]                   ` <CAK=zhgpqW-t11JKiBRRM7Z4TEMyaEUBX943qT8faaKPk6Pk4XA@mail.gmail.com>
     [not found]                     ` <CAK=zhgpiyt9xukGCNDOpEDmWRwFSMCcEiUQ190BW0UgiLGVP6g@mail.gmail.com>
2014-08-11 13:17                       ` Sreekanth Reddy
2014-08-12  2:32                       ` Martin K. Petersen
2017-04-25 11:51           ` Sreekanth Reddy
2017-04-26 22:25             ` Martin K. Petersen
2017-04-27  9:15               ` Kashyap Desai
2014-08-12  9:24 Sreekanth Reddy
2014-08-12  9:37 ` Joe Perches
2014-08-12  9:51   ` Sreekanth Reddy
2014-08-21 20:35 ` Martin K. Petersen
2014-08-23 15:04 [RESEND][PATCH 07/10] [SCSI] mpt2sas: " Sreekanth Reddy
2014-08-24 15:37 ` Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).