Commit 34bb7098 authored by Raghava Aditya Renukunta's avatar Raghava Aditya Renukunta Committed by Sasha Levin

aacraid: Fix RRQ overload

[ Upstream commit 3f4ce057 ]

The driver utilizes an array of atomic variables to keep track of IO
submissions to each vector. To submit an IO multiple threads iterate
through the array to find a vector which has empty slots to send an
IO. The reading and updating of the variable is not atomic, causing race
conditions when a thread uses a full vector to submit an IO.

Fixed by mapping each FIB to a vector, the submission path then uses
said vector to submit IO thereby removing the possibly of a race
condition.The vector assignment is started from 1 since vector 0 is
reserved for the use of AIF management FIBS.If the number of MSIx
vectors is 1 (MSI or INTx mode) then all the fibs are allocated to
vector 0.

Fixes: 495c0217 "aacraid: MSI-x support"
Cc: stable@vger.kernel.org # v4.1
Signed-off-by: default avatarRaghava Aditya Renukunta <raghavaaditya.renukunta@pmcs.com>
Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: default avatarTomas Henzl <thenzl@redhat.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarSasha Levin <sasha.levin@oracle.com>
parent acab7e2c
...@@ -939,6 +939,7 @@ struct fib { ...@@ -939,6 +939,7 @@ struct fib {
*/ */
struct list_head fiblink; struct list_head fiblink;
void *data; void *data;
u32 vector_no;
struct hw_fib *hw_fib_va; /* Actual shared object */ struct hw_fib *hw_fib_va; /* Actual shared object */
dma_addr_t hw_fib_pa; /* physical address of hw_fib*/ dma_addr_t hw_fib_pa; /* physical address of hw_fib*/
}; };
...@@ -2098,6 +2099,7 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor) ...@@ -2098,6 +2099,7 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
#define AAC_OWNER_FIRMWARE 0x106 #define AAC_OWNER_FIRMWARE 0x106
const char *aac_driverinfo(struct Scsi_Host *); const char *aac_driverinfo(struct Scsi_Host *);
void aac_fib_vector_assign(struct aac_dev *dev);
struct fib *aac_fib_alloc(struct aac_dev *dev); struct fib *aac_fib_alloc(struct aac_dev *dev);
int aac_fib_setup(struct aac_dev *dev); int aac_fib_setup(struct aac_dev *dev);
void aac_fib_map_free(struct aac_dev *dev); void aac_fib_map_free(struct aac_dev *dev);
......
...@@ -90,6 +90,28 @@ void aac_fib_map_free(struct aac_dev *dev) ...@@ -90,6 +90,28 @@ void aac_fib_map_free(struct aac_dev *dev)
dev->hw_fib_pa = 0; dev->hw_fib_pa = 0;
} }
void aac_fib_vector_assign(struct aac_dev *dev)
{
u32 i = 0;
u32 vector = 1;
struct fib *fibptr = NULL;
for (i = 0, fibptr = &dev->fibs[i];
i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
i++, fibptr++) {
if ((dev->max_msix == 1) ||
(i > ((dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1)
- dev->vector_cap))) {
fibptr->vector_no = 0;
} else {
fibptr->vector_no = vector;
vector++;
if (vector == dev->max_msix)
vector = 1;
}
}
}
/** /**
* aac_fib_setup - setup the fibs * aac_fib_setup - setup the fibs
* @dev: Adapter to set up * @dev: Adapter to set up
...@@ -151,6 +173,12 @@ int aac_fib_setup(struct aac_dev * dev) ...@@ -151,6 +173,12 @@ int aac_fib_setup(struct aac_dev * dev)
hw_fib_pa = hw_fib_pa + hw_fib_pa = hw_fib_pa +
dev->max_fib_size + sizeof(struct aac_fib_xporthdr); dev->max_fib_size + sizeof(struct aac_fib_xporthdr);
} }
/*
*Assign vector numbers to fibs
*/
aac_fib_vector_assign(dev);
/* /*
* Add the fib chain to the free list * Add the fib chain to the free list
*/ */
......
...@@ -156,8 +156,8 @@ irqreturn_t aac_src_intr_message(int irq, void *dev_id) ...@@ -156,8 +156,8 @@ irqreturn_t aac_src_intr_message(int irq, void *dev_id)
break; break;
if (dev->msi_enabled && dev->max_msix > 1) if (dev->msi_enabled && dev->max_msix > 1)
atomic_dec(&dev->rrq_outstanding[vector_no]); atomic_dec(&dev->rrq_outstanding[vector_no]);
aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
dev->host_rrq[index++] = 0; dev->host_rrq[index++] = 0;
aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL);
if (index == (vector_no + 1) * dev->vector_cap) if (index == (vector_no + 1) * dev->vector_cap)
index = vector_no * dev->vector_cap; index = vector_no * dev->vector_cap;
dev->host_rrq_idx[vector_no] = index; dev->host_rrq_idx[vector_no] = index;
...@@ -448,36 +448,20 @@ static int aac_src_deliver_message(struct fib *fib) ...@@ -448,36 +448,20 @@ static int aac_src_deliver_message(struct fib *fib)
dma_addr_t address; dma_addr_t address;
struct aac_fib_xporthdr *pFibX; struct aac_fib_xporthdr *pFibX;
u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size); u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size);
u16 vector_no;
atomic_inc(&q->numpending); atomic_inc(&q->numpending);
if (dev->msi_enabled && fib->hw_fib_va->header.Command != AifRequest && if (dev->msi_enabled && fib->hw_fib_va->header.Command != AifRequest &&
dev->max_msix > 1) { dev->max_msix > 1) {
u_int16_t vector_no, first_choice = 0xffff; vector_no = fib->vector_no;
vector_no = dev->fibs_pushed_no % dev->max_msix;
do {
vector_no += 1;
if (vector_no == dev->max_msix)
vector_no = 1;
if (atomic_read(&dev->rrq_outstanding[vector_no]) <
dev->vector_cap)
break;
if (0xffff == first_choice)
first_choice = vector_no;
else if (vector_no == first_choice)
break;
} while (1);
if (vector_no == first_choice)
vector_no = 0;
atomic_inc(&dev->rrq_outstanding[vector_no]);
if (dev->fibs_pushed_no == 0xffffffff)
dev->fibs_pushed_no = 0;
else
dev->fibs_pushed_no++;
fib->hw_fib_va->header.Handle += (vector_no << 16); fib->hw_fib_va->header.Handle += (vector_no << 16);
} else {
vector_no = 0;
} }
atomic_inc(&dev->rrq_outstanding[vector_no]);
if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) { if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE2) {
/* Calculate the amount to the fibsize bits */ /* Calculate the amount to the fibsize bits */
fibsize = (hdr_size + 127) / 128 - 1; fibsize = (hdr_size + 127) / 128 - 1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment