diff options
Diffstat (limited to 'drivers/scsi/mpi3mr/mpi3mr_fw.c')
-rw-r--r-- | drivers/scsi/mpi3mr/mpi3mr_fw.c | 115 |
1 files changed, 89 insertions, 26 deletions
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index c196dc14ad20..f1ab76351bd8 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -345,6 +345,7 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, { u16 reply_desc_type, host_tag = 0; u16 ioc_status = MPI3_IOCSTATUS_SUCCESS; + u16 masked_ioc_status = MPI3_IOCSTATUS_SUCCESS; u32 ioc_loginfo = 0, sense_count = 0; struct mpi3_status_reply_descriptor *status_desc; struct mpi3_address_reply_descriptor *addr_desc; @@ -366,8 +367,8 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, if (ioc_status & MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info); - ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; - mpi3mr_reply_trigger(mrioc, ioc_status, ioc_loginfo); + masked_ioc_status = ioc_status & MPI3_IOCSTATUS_STATUS_MASK; + mpi3mr_reply_trigger(mrioc, masked_ioc_status, ioc_loginfo); break; case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY: addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc; @@ -380,7 +381,7 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, if (ioc_status & MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL) ioc_loginfo = le32_to_cpu(def_reply->ioc_log_info); - ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK; + masked_ioc_status = ioc_status & MPI3_IOCSTATUS_STATUS_MASK; if (def_reply->function == MPI3_FUNCTION_SCSI_IO) { scsi_reply = (struct mpi3_scsi_io_reply *)def_reply; sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc, @@ -393,7 +394,7 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, sshdr.asc, sshdr.ascq); } } - mpi3mr_reply_trigger(mrioc, ioc_status, ioc_loginfo); + mpi3mr_reply_trigger(mrioc, masked_ioc_status, ioc_loginfo); break; case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS: success_desc = (struct mpi3_success_reply_descriptor *)reply_desc; @@ -408,7 +409,10 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc, if (cmdptr->state & MPI3MR_CMD_PENDING) { cmdptr->state |= MPI3MR_CMD_COMPLETE; cmdptr->ioc_loginfo = ioc_loginfo; - cmdptr->ioc_status = ioc_status; + if (host_tag == MPI3MR_HOSTTAG_BSG_CMDS) + cmdptr->ioc_status = ioc_status; + else + cmdptr->ioc_status = masked_ioc_status; cmdptr->state &= ~MPI3MR_CMD_PENDING; if (def_reply) { cmdptr->state |= MPI3MR_CMD_REPLY_VALID; @@ -439,6 +443,7 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) u32 admin_reply_ci = mrioc->admin_reply_ci; u32 num_admin_replies = 0; u64 reply_dma = 0; + u16 threshold_comps = 0; struct mpi3_default_reply_descriptor *reply_desc; if (!atomic_add_unless(&mrioc->admin_reply_q_in_use, 1, 1)) @@ -462,6 +467,7 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) if (reply_dma) mpi3mr_repost_reply_buf(mrioc, reply_dma); num_admin_replies++; + threshold_comps++; if (++admin_reply_ci == mrioc->num_admin_replies) { admin_reply_ci = 0; exp_phase ^= 1; @@ -472,6 +478,11 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc) if ((le16_to_cpu(reply_desc->reply_flags) & MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) break; + if (threshold_comps == MPI3MR_THRESHOLD_REPLY_COUNT) { + writel(admin_reply_ci, + &mrioc->sysif_regs->admin_reply_queue_ci); + threshold_comps = 0; + } } while (1); writel(admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci); @@ -525,7 +536,7 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, u32 num_op_reply = 0; u64 reply_dma = 0; struct mpi3_default_reply_descriptor *reply_desc; - u16 req_q_idx = 0, reply_qidx; + u16 req_q_idx = 0, reply_qidx, threshold_comps = 0; reply_qidx = op_reply_q->qid - 1; @@ -556,6 +567,7 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, if (reply_dma) mpi3mr_repost_reply_buf(mrioc, reply_dma); num_op_reply++; + threshold_comps++; if (++reply_ci == op_reply_q->num_replies) { reply_ci = 0; @@ -577,13 +589,19 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc, break; } #endif + if (threshold_comps == MPI3MR_THRESHOLD_REPLY_COUNT) { + writel(reply_ci, + &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index); + atomic_sub(threshold_comps, &op_reply_q->pend_ios); + threshold_comps = 0; + } } while (1); writel(reply_ci, &mrioc->sysif_regs->oper_queue_indexes[reply_qidx].consumer_index); op_reply_q->ci = reply_ci; op_reply_q->ephase = exp_phase; - + atomic_sub(threshold_comps, &op_reply_q->pend_ios); atomic_dec(&op_reply_q->in_use); return num_op_reply; } @@ -710,7 +728,7 @@ static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata) mpi3mr_process_op_reply_q(mrioc, intr_info->op_reply_q); - usleep_range(MPI3MR_IRQ_POLL_SLEEP, 10 * MPI3MR_IRQ_POLL_SLEEP); + usleep_range(MPI3MR_IRQ_POLL_SLEEP, MPI3MR_IRQ_POLL_SLEEP + 1); } while (atomic_read(&intr_info->op_reply_q->pend_ios) && (num_op_reply < mrioc->max_host_ios)); @@ -1344,6 +1362,10 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) int retval = 0; enum mpi3mr_iocstate ioc_state; u64 base_info; + u8 retry = 0; + u64 start_time, elapsed_time_sec; + +retry_bring_ioc_ready: ioc_status = readl(&mrioc->sysif_regs->ioc_status); ioc_config = readl(&mrioc->sysif_regs->ioc_configuration); @@ -1362,26 +1384,23 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) ioc_info(mrioc, "controller is in %s state during detection\n", mpi3mr_iocstate_name(ioc_state)); - if (ioc_state == MRIOC_STATE_BECOMING_READY || - ioc_state == MRIOC_STATE_RESET_REQUESTED) { - timeout = mrioc->ready_timeout * 10; - do { - msleep(100); - } while (--timeout); + timeout = mrioc->ready_timeout * 10; + + do { + ioc_state = mpi3mr_get_iocstate(mrioc); + + if (ioc_state != MRIOC_STATE_BECOMING_READY && + ioc_state != MRIOC_STATE_RESET_REQUESTED) + break; if (!pci_device_is_present(mrioc->pdev)) { mrioc->unrecoverable = 1; - ioc_err(mrioc, - "controller is not present while waiting to reset\n"); - retval = -1; + ioc_err(mrioc, "controller is not present while waiting to reset\n"); goto out_device_not_present; } - ioc_state = mpi3mr_get_iocstate(mrioc); - ioc_info(mrioc, - "controller is in %s state after waiting to reset\n", - mpi3mr_iocstate_name(ioc_state)); - } + msleep(100); + } while (--timeout); if (ioc_state == MRIOC_STATE_READY) { ioc_info(mrioc, "issuing message unit reset (MUR) to bring to reset state\n"); @@ -1442,6 +1461,9 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) ioc_config |= MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC; writel(ioc_config, &mrioc->sysif_regs->ioc_configuration); + if (retry == 0) + start_time = jiffies; + timeout = mrioc->ready_timeout * 10; do { ioc_state = mpi3mr_get_iocstate(mrioc); @@ -1451,6 +1473,12 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) mpi3mr_iocstate_name(ioc_state)); return 0; } + ioc_status = readl(&mrioc->sysif_regs->ioc_status); + if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) || + (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) { + mpi3mr_print_fault_info(mrioc); + goto out_failed; + } if (!pci_device_is_present(mrioc->pdev)) { mrioc->unrecoverable = 1; ioc_err(mrioc, @@ -1459,9 +1487,19 @@ static int mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc) goto out_device_not_present; } msleep(100); - } while (--timeout); + elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000; + } while (elapsed_time_sec < mrioc->ready_timeout); out_failed: + elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000; + if ((retry < 2) && (elapsed_time_sec < (mrioc->ready_timeout - 60))) { + retry++; + + ioc_warn(mrioc, "retrying to bring IOC ready, retry_count:%d\n" + " elapsed time =%llu\n", retry, elapsed_time_sec); + + goto retry_bring_ioc_ready; + } ioc_state = mpi3mr_get_iocstate(mrioc); ioc_err(mrioc, "failed to bring to ready state, current state: %s\n", @@ -2653,7 +2691,7 @@ static void mpi3mr_watchdog_work(struct work_struct *work) return; } - if (mrioc->ts_update_counter++ >= MPI3MR_TSUPDATE_INTERVAL) { + if (mrioc->ts_update_counter++ >= mrioc->ts_update_interval) { mrioc->ts_update_counter = 0; mpi3mr_sync_timestamp(mrioc); } @@ -2742,8 +2780,8 @@ void mpi3mr_start_watchdog(struct mpi3mr_ioc *mrioc) snprintf(mrioc->watchdog_work_q_name, sizeof(mrioc->watchdog_work_q_name), "watchdog_%s%d", mrioc->name, mrioc->id); - mrioc->watchdog_work_q = - create_singlethread_workqueue(mrioc->watchdog_work_q_name); + mrioc->watchdog_work_q = alloc_ordered_workqueue( + "%s", WQ_MEM_RECLAIM, mrioc->watchdog_work_q_name); if (!mrioc->watchdog_work_q) { ioc_err(mrioc, "%s: failed (line=%d)\n", __func__, __LINE__); return; @@ -3827,6 +3865,29 @@ static int mpi3mr_repost_diag_bufs(struct mpi3mr_ioc *mrioc) } /** + * mpi3mr_read_tsu_interval - Update time stamp interval + * @mrioc: Adapter instance reference + * + * Update time stamp interval if its defined in driver page 1, + * otherwise use default value. + * + * Return: Nothing + */ +static void +mpi3mr_read_tsu_interval(struct mpi3mr_ioc *mrioc) +{ + struct mpi3_driver_page1 driver_pg1; + u16 pg_sz = sizeof(driver_pg1); + int retval = 0; + + mrioc->ts_update_interval = MPI3MR_TSUPDATE_INTERVAL; + + retval = mpi3mr_cfg_get_driver_pg1(mrioc, &driver_pg1, pg_sz); + if (!retval && driver_pg1.time_stamp_update) + mrioc->ts_update_interval = (driver_pg1.time_stamp_update * 60); +} + +/** * mpi3mr_print_ioc_info - Display controller information * @mrioc: Adapter instance reference * @@ -4122,6 +4183,7 @@ retry_init: goto out_failed_noretry; } + mpi3mr_read_tsu_interval(mrioc); mpi3mr_print_ioc_info(mrioc); if (!mrioc->cfg_page) { @@ -4303,6 +4365,7 @@ retry_init: goto out_failed_noretry; } + mpi3mr_read_tsu_interval(mrioc); mpi3mr_print_ioc_info(mrioc); if (is_resume) { |