scsi: mpi3mr: Gracefully handle online FW update operation

Enhance driver to gracefully handle discrepancies in certain key data sizes
between firmware update operations as mentioned below:

 - The driver displays an error message and marks the controller as
   unrecoverable if the firmware reports ReplyFrameSize that is greater
   than the current ReplyFrameSize.

 - If the firmware reports ReplyFrameSize greater than the current
   ReplyFrameSize then the driver uses the current ReplyFrameSize while
   copying the reply messages.

 - The driver displays an error message and marks the controller as
   unrecoverable if the firmware reports MaxOperationalReplyQueues less
   than the currently allocated operational reply queues count.

 - If the firmware reports MaxOperationalReplyQueues that is greater than
   the currently allocated operational reply queue count then the driver
   ignores the new increased value and uses the previously allocated number
   of operational queues only.

 - If the firmware reports MaxDevHandle greater than the previously used
   MaxDevHandle value after a reset then the driver re-allocates the
   'device remove pending bitmap' buffer with the newer size using
   krealloc().

Link: https://lore.kernel.org/r/20211220141159.16117-18-sreekanth.reddy@broadcom.com
Signed-off-by: Sreekanth Reddy <sreekanth.reddy@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Sreekanth Reddy 2021-12-20 19:41:51 +05:30 committed by Martin K. Petersen
parent b64845a7d4
commit c5758fc72b
2 changed files with 92 additions and 18 deletions

View File

@ -752,6 +752,7 @@ struct mpi3mr_ioc {
dma_addr_t reply_buf_dma_max_address;
u16 reply_free_qsz;
u16 reply_sz;
struct dma_pool *reply_free_q_pool;
__le64 *reply_free_q;
dma_addr_t reply_free_q_dma;

View File

@ -13,6 +13,8 @@
static int
mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type, u32 reset_reason);
static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc);
static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
struct mpi3_ioc_facts_data *facts_data);
#if defined(writeq) && defined(CONFIG_64BIT)
static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
@ -376,7 +378,7 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
if (def_reply) {
cmdptr->state |= MPI3MR_CMD_REPLY_VALID;
memcpy((u8 *)cmdptr->reply, (u8 *)def_reply,
mrioc->facts.reply_sz);
mrioc->reply_sz);
}
if (cmdptr->is_waiting) {
complete(&cmdptr->done);
@ -996,6 +998,66 @@ static int mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
return retval;
}
/**
* mpi3mr_revalidate_factsdata - validate IOCFacts parameters
* during reset/resume
* @mrioc: Adapter instance reference
*
* Return zero if the new IOCFacts parameters value is compatible with
* older values else return -EPERM
*/
static int
mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
{
u16 dev_handle_bitmap_sz;
void *removepend_bitmap;
if (mrioc->facts.reply_sz > mrioc->reply_sz) {
ioc_err(mrioc,
"cannot increase reply size from %d to %d\n",
mrioc->reply_sz, mrioc->facts.reply_sz);
return -EPERM;
}
if (mrioc->facts.max_op_reply_q < mrioc->num_op_reply_q) {
ioc_err(mrioc,
"cannot reduce number of operational reply queues from %d to %d\n",
mrioc->num_op_reply_q,
mrioc->facts.max_op_reply_q);
return -EPERM;
}
if (mrioc->facts.max_op_req_q < mrioc->num_op_req_q) {
ioc_err(mrioc,
"cannot reduce number of operational request queues from %d to %d\n",
mrioc->num_op_req_q, mrioc->facts.max_op_req_q);
return -EPERM;
}
dev_handle_bitmap_sz = mrioc->facts.max_devhandle / 8;
if (mrioc->facts.max_devhandle % 8)
dev_handle_bitmap_sz++;
if (dev_handle_bitmap_sz > mrioc->dev_handle_bitmap_sz) {
removepend_bitmap = krealloc(mrioc->removepend_bitmap,
dev_handle_bitmap_sz, GFP_KERNEL);
if (!removepend_bitmap) {
ioc_err(mrioc,
"failed to increase removepend_bitmap sz from: %d to %d\n",
mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz);
return -EPERM;
}
memset(removepend_bitmap + mrioc->dev_handle_bitmap_sz, 0,
dev_handle_bitmap_sz - mrioc->dev_handle_bitmap_sz);
mrioc->removepend_bitmap = removepend_bitmap;
ioc_info(mrioc,
"increased dev_handle_bitmap_sz from %d to %d\n",
mrioc->dev_handle_bitmap_sz, dev_handle_bitmap_sz);
mrioc->dev_handle_bitmap_sz = dev_handle_bitmap_sz;
}
return 0;
}
/**
* mpi3mr_bring_ioc_ready - Bring controller to ready state
* @mrioc: Adapter instance reference
@ -1854,8 +1916,13 @@ static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
mrioc->intr_info_count - mrioc->op_reply_q_offset;
if (!mrioc->num_queues)
mrioc->num_queues = min_t(int, num_queues, msix_count_op_q);
num_queues = mrioc->num_queues;
ioc_info(mrioc, "Trying to create %d Operational Q pairs\n",
/*
* During reset set the num_queues to the number of queues
* that was set before the reset.
*/
num_queues = mrioc->num_op_reply_q ?
mrioc->num_op_reply_q : mrioc->num_queues;
ioc_info(mrioc, "trying to create %d operational queue pairs\n",
num_queues);
if (!mrioc->req_qinfo) {
@ -2447,6 +2514,7 @@ static int mpi3mr_issue_iocfacts(struct mpi3mr_ioc *mrioc,
goto out_unlock;
}
memcpy(facts_data, (u8 *)data, data_len);
mpi3mr_process_factsdata(mrioc, facts_data);
out_unlock:
mrioc->init_cmds.state = MPI3MR_CMD_NOTUSED;
mutex_unlock(&mrioc->init_cmds.mutex);
@ -2593,12 +2661,6 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
ioc_info(mrioc, "DMA mask %d InitialPE status 0x%x\n",
mrioc->facts.dma_mask, (facts_flags &
MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK));
mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD;
if (reset_devices)
mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
MPI3MR_HOST_IOS_KDUMP);
}
/**
@ -2618,18 +2680,18 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
if (mrioc->init_cmds.reply)
return retval;
mrioc->init_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL);
mrioc->init_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
if (!mrioc->init_cmds.reply)
goto out_failed;
for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->facts.reply_sz,
mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz,
GFP_KERNEL);
if (!mrioc->dev_rmhs_cmds[i].reply)
goto out_failed;
}
mrioc->host_tm_cmds.reply = kzalloc(mrioc->facts.reply_sz, GFP_KERNEL);
mrioc->host_tm_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL);
if (!mrioc->host_tm_cmds.reply)
goto out_failed;
@ -2655,7 +2717,7 @@ static int mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
mrioc->sense_buf_q_sz = mrioc->num_sense_bufs + 1;
/* reply buffer pool, 16 byte align */
sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
sz = mrioc->num_reply_bufs * mrioc->reply_sz;
mrioc->reply_buf_pool = dma_pool_create("reply_buf pool",
&mrioc->pdev->dev, sz, 16, 0);
if (!mrioc->reply_buf_pool) {
@ -2731,10 +2793,10 @@ static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc)
u32 sz, i;
dma_addr_t phy_addr;
sz = mrioc->num_reply_bufs * mrioc->facts.reply_sz;
sz = mrioc->num_reply_bufs * mrioc->reply_sz;
ioc_info(mrioc,
"reply buf pool(0x%p): depth(%d), frame_size(%d), pool_size(%d kB), reply_dma(0x%llx)\n",
mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->facts.reply_sz,
mrioc->reply_buf, mrioc->num_reply_bufs, mrioc->reply_sz,
(sz / 1024), (unsigned long long)mrioc->reply_buf_dma);
sz = mrioc->reply_free_qsz * 8;
ioc_info(mrioc,
@ -2754,7 +2816,7 @@ static void mpimr_initialize_reply_sbuf_queues(struct mpi3mr_ioc *mrioc)
/* initialize Reply buffer Queue */
for (i = 0, phy_addr = mrioc->reply_buf_dma;
i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->facts.reply_sz)
i < mrioc->num_reply_bufs; i++, phy_addr += mrioc->reply_sz)
mrioc->reply_free_q[i] = cpu_to_le64(phy_addr);
mrioc->reply_free_q[i] = cpu_to_le64(0);
@ -3459,7 +3521,13 @@ retry_init:
goto out_failed;
}
mpi3mr_process_factsdata(mrioc, &facts_data);
mrioc->max_host_ios = mrioc->facts.max_reqs - MPI3MR_INTERNAL_CMDS_RESVD;
if (reset_devices)
mrioc->max_host_ios = min_t(int, mrioc->max_host_ios,
MPI3MR_HOST_IOS_KDUMP);
mrioc->reply_sz = mrioc->facts.reply_sz;
retval = mpi3mr_check_reset_dma_mask(mrioc);
if (retval) {
@ -3582,7 +3650,12 @@ retry_init:
goto out_failed;
}
mpi3mr_process_factsdata(mrioc, &facts_data);
dprint_reset(mrioc, "validating ioc_facts\n");
retval = mpi3mr_revalidate_factsdata(mrioc);
if (retval) {
ioc_err(mrioc, "failed to revalidate ioc_facts data\n");
goto out_failed_noretry;
}
mpi3mr_print_ioc_info(mrioc);