Commit 3f4ce057 authored by Raghava Aditya Renukunta's avatar Raghava Aditya Renukunta Committed by Martin K. Petersen

aacraid: Fix RRQ overload

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>
parent 6bf3b630
...@@ -944,6 +944,7 @@ struct fib { ...@@ -944,6 +944,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*/
}; };
...@@ -2113,6 +2114,7 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor) ...@@ -2113,6 +2114,7 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
int aac_acquire_irq(struct aac_dev *dev); int aac_acquire_irq(struct aac_dev *dev);
void aac_free_irq(struct aac_dev *dev); void aac_free_irq(struct aac_dev *dev);
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);
struct fib *aac_fib_alloc_tag(struct aac_dev *dev, struct scsi_cmnd *scmd); struct fib *aac_fib_alloc_tag(struct aac_dev *dev, struct scsi_cmnd *scmd);
int aac_fib_setup(struct aac_dev *dev); int aac_fib_setup(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
...@@ -152,6 +174,12 @@ int aac_fib_setup(struct aac_dev * dev) ...@@ -152,6 +174,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 @@ static irqreturn_t aac_src_intr_message(int irq, void *dev_id) ...@@ -156,8 +156,8 @@ static 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;
...@@ -452,36 +452,20 @@ static int aac_src_deliver_message(struct fib *fib) ...@@ -452,36 +452,20 @@ static int aac_src_deliver_message(struct fib *fib)
#endif #endif
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