/** * mpi3mr_blk_mq_poll - Operational reply queue handler * @shost: SCSI Host reference * @queue_num: Request queue number (w.r.t OS it is hardware context number) * * Checks the specific operational reply queue and drains the * reply queue entries until the queue is empty and process the * individual reply descriptors. * * Return: 0 if queue is already processed,or number of reply * descriptors processed.
*/ int mpi3mr_blk_mq_poll(struct Scsi_Host *shost, unsignedint queue_num)
{ int num_entries = 0; struct mpi3mr_ioc *mrioc;
mrioc = (struct mpi3mr_ioc *)shost->hostdata;
if ((mrioc->reset_in_progress || mrioc->prepare_for_reset ||
mrioc->unrecoverable || mrioc->pci_err_recovery)) return 0;
staticvoid mpi3mr_calc_poll_queues(struct mpi3mr_ioc *mrioc, u16 max_vectors)
{ if (!mrioc->requested_poll_qcount) return;
/* Reserved for Admin and Default Queue */ if (max_vectors > 2 &&
(mrioc->requested_poll_qcount < max_vectors - 2)) {
ioc_info(mrioc, "enabled polled queues (%d) msix (%d)\n",
mrioc->requested_poll_qcount, max_vectors);
} else {
ioc_info(mrioc, "disabled polled queues (%d) msix (%d) because of no resources for default queue\n",
mrioc->requested_poll_qcount, max_vectors);
mrioc->requested_poll_qcount = 0;
}
}
/** * mpi3mr_setup_isr - Setup ISR for the controller * @mrioc: Adapter instance reference * @setup_one: Request one IRQ or more * * Allocate IRQ vectors and call mpi3mr_request_irq to setup ISR * * Return: 0 on success and non zero on failures.
*/ staticint mpi3mr_setup_isr(struct mpi3mr_ioc *mrioc, u8 setup_one)
{ unsignedint irq_flags = PCI_IRQ_MSIX; int max_vectors, min_vec; int retval; int i; struct irq_affinity desc = { .pre_vectors = 1, .post_vectors = 1 };
if (retval < 0) {
ioc_err(mrioc, "cannot allocate irq vectors, ret %d\n",
retval); goto out_failed;
}
/* * If only one MSI-x is allocated, then MSI-x 0 will be shared * between Admin queue and operational queue
*/ if (retval == min_vec)
mrioc->op_reply_q_offset = 0; elseif (retval != (max_vectors)) {
ioc_info(mrioc, "allocated vectors (%d) are less than configured (%d)\n",
retval, max_vectors);
}
/** * mpi3mr_reset_rc_name - get reset reason code name * @reason_code: reset reason code value * * Map reset reason to an NULL terminated ASCII string * * Return: name corresponding to reset reason value or NULL.
*/ staticconstchar *mpi3mr_reset_rc_name(enum mpi3mr_reset_reason reason_code)
{ int i; char *name = NULL;
for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_reason_codes); i++) { if (mpi3mr_reset_reason_codes[i].value == reason_code) {
name = mpi3mr_reset_reason_codes[i].name; break;
}
} return name;
}
/* Reset type to name mapper structure*/ staticconststruct {
u16 reset_type; char *name;
} mpi3mr_reset_types[] = {
{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, "soft" },
{ MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, "diag fault" },
};
/** * mpi3mr_reset_type_name - get reset type name * @reset_type: reset type value * * Map reset type to an NULL terminated ASCII string * * Return: name corresponding to reset type value or NULL.
*/ staticconstchar *mpi3mr_reset_type_name(u16 reset_type)
{ int i; char *name = NULL;
for (i = 0; i < ARRAY_SIZE(mpi3mr_reset_types); i++) { if (mpi3mr_reset_types[i].reset_type == reset_type) {
name = mpi3mr_reset_types[i].name; break;
}
} return name;
}
/** * mpi3mr_is_fault_recoverable - Read fault code and decide * whether the controller can be recoverable * @mrioc: Adapter instance reference * Return: true if fault is recoverable, false otherwise.
*/ staticinlinebool mpi3mr_is_fault_recoverable(struct mpi3mr_ioc *mrioc)
{
u32 fault;
switch (fault) { case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED: case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED:
ioc_warn(mrioc, "controller requires system power cycle, marking controller as unrecoverable\n"); returnfalse; case MPI3_SYSIF_FAULT_CODE_INSUFFICIENT_PCI_SLOT_POWER:
ioc_warn(mrioc, "controller faulted due to insufficient power,\n" " try by connecting it to a different slot\n"); returnfalse; default: break;
} returntrue;
}
/** * mpi3mr_print_fault_info - Display fault information * @mrioc: Adapter instance reference * * Display the controller fault information if there is a * controller fault. * * Return: Nothing.
*/ void mpi3mr_print_fault_info(struct mpi3mr_ioc *mrioc)
{
u32 ioc_status, code, code1, code2, code3;
/** * mpi3mr_get_iocstate - Get IOC State * @mrioc: Adapter instance reference * * Return a proper IOC state enum based on the IOC status and * IOC configuration and unrcoverable state of the controller. * * Return: Current IOC state.
*/ enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc)
{
u32 ioc_status, ioc_config;
u8 ready, enabled;
return;
out_failed:
ioc_warn(mrioc, "cannot allocate DMA memory for the mpt commands\n" "from the applications, application interface for MPT command is disabled\n");
mpi3mr_free_ioctl_dma_memory(mrioc);
}
/** * mpi3mr_clear_reset_history - clear reset history * @mrioc: Adapter instance reference * * Write the reset history bit in IOC status to clear the bit, * if it is already set. * * Return: Nothing.
*/ staticinlinevoid mpi3mr_clear_reset_history(struct mpi3mr_ioc *mrioc)
{
u32 ioc_status;
ioc_status = readl(&mrioc->sysif_regs->ioc_status); if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)
writel(ioc_status, &mrioc->sysif_regs->ioc_status);
}
/** * mpi3mr_issue_and_process_mur - Message unit Reset handler * @mrioc: Adapter instance reference * @reset_reason: Reset reason code * * Issue Message unit Reset to the controller and wait for it to * be complete. * * Return: 0 on success, -1 on failure.
*/ staticint mpi3mr_issue_and_process_mur(struct mpi3mr_ioc *mrioc,
u32 reset_reason)
{
u32 ioc_config, timeout, ioc_status, scratch_pad0; int retval = -1;
ioc_info(mrioc, "Issuing Message unit Reset(MUR)\n"); if (mrioc->unrecoverable) {
ioc_info(mrioc, "IOC is unrecoverable MUR not issued\n"); return retval;
}
mpi3mr_clear_reset_history(mrioc);
scratch_pad0 = ((MPI3MR_RESET_REASON_OSTYPE_LINUX <<
MPI3MR_RESET_REASON_OSTYPE_SHIFT) |
(mrioc->facts.ioc_num <<
MPI3MR_RESET_REASON_IOCNUM_SHIFT) | reset_reason);
writel(scratch_pad0, &mrioc->sysif_regs->scratchpad[0]);
ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
ioc_config &= ~MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC;
writel(ioc_config, &mrioc->sysif_regs->ioc_configuration);
timeout = MPI3MR_MUR_TIMEOUT * 10; do {
ioc_status = readl(&mrioc->sysif_regs->ioc_status); if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY)) {
mpi3mr_clear_reset_history(mrioc); break;
} if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
mpi3mr_print_fault_info(mrioc); break;
}
msleep(100);
} while (--timeout);
ioc_info(mrioc, "Base IOC Sts/Config after %s MUR is (0x%08x)/(0x%08x)\n",
(!retval) ? "successful" : "failed", ioc_status, ioc_config); 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
*/ staticint
mpi3mr_revalidate_factsdata(struct mpi3mr_ioc *mrioc)
{ unsignedlong *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;
}
if (mrioc->shost->max_sectors != (mrioc->facts.max_data_length / 512))
ioc_err(mrioc, "Warning: The maximum data transfer length\n" "\tchanged after reset: previous(%d), new(%d),\n" "the driver cannot change this at run time\n",
mrioc->shost->max_sectors * 512, mrioc->facts.max_data_length);
if ((mrioc->sas_transport_enabled) && (mrioc->facts.ioc_capabilities &
MPI3_IOCFACTS_CAPABILITY_MULTIPATH_SUPPORTED))
ioc_err(mrioc, "critical error: multipath capability is enabled at the\n" "\tcontroller while sas transport support is enabled at the\n" "\tdriver, please reboot the system or reload the driver\n");
if (mrioc->seg_tb_support) { if (!(mrioc->facts.ioc_capabilities &
MPI3_IOCFACTS_CAPABILITY_SEG_DIAG_TRACE_SUPPORTED)) {
ioc_err(mrioc, "critical error: previously enabled segmented trace\n" " buffer capability is disabled after reset. Please\n" " update the firmware or reboot the system or\n" " reload the driver to enable trace diag buffer\n");
mrioc->diag_buffers[0].disabled_after_reset = true;
} else
mrioc->diag_buffers[0].disabled_after_reset = false;
}
if (mrioc->facts.max_devhandle > mrioc->dev_handle_bitmap_bits) {
removepend_bitmap = bitmap_zalloc(mrioc->facts.max_devhandle,
GFP_KERNEL); if (!removepend_bitmap) {
ioc_err(mrioc, "failed to increase removepend_bitmap bits from %d to %d\n",
mrioc->dev_handle_bitmap_bits,
mrioc->facts.max_devhandle); return -EPERM;
}
bitmap_free(mrioc->removepend_bitmap);
mrioc->removepend_bitmap = removepend_bitmap;
ioc_info(mrioc, "increased bits of dev_handle_bitmap from %d to %d\n",
mrioc->dev_handle_bitmap_bits,
mrioc->facts.max_devhandle);
mrioc->dev_handle_bitmap_bits = mrioc->facts.max_devhandle;
}
return 0;
}
/** * mpi3mr_bring_ioc_ready - Bring controller to ready state * @mrioc: Adapter instance reference * * Set Enable IOC bit in IOC configuration register and wait for * the controller to become ready. * * Return: 0 on success, appropriate error on failure.
*/ staticint mpi3mr_bring_ioc_ready(struct mpi3mr_ioc *mrioc)
{
u32 ioc_config, ioc_status, timeout, host_diagnostic; 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);
base_info = lo_hi_readq(&mrioc->sysif_regs->ioc_information);
ioc_info(mrioc, "ioc_status(0x%08x), ioc_config(0x%08x), ioc_info(0x%016llx) at the bringup\n",
ioc_status, ioc_config, base_info);
if (!mpi3mr_is_fault_recoverable(mrioc)) {
mrioc->unrecoverable = 1; goto out_device_not_present;
}
/*The timeout value is in 2sec unit, changing it to seconds*/
mrioc->ready_timeout =
((base_info & MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_MASK) >>
MPI3_SYSIF_IOC_INFO_LOW_TIMEOUT_SHIFT) * 2;
ioc_state = mpi3mr_get_iocstate(mrioc);
ioc_info(mrioc, "controller is in %s state during detection\n",
mpi3mr_iocstate_name(ioc_state));
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"); goto out_device_not_present;
}
msleep(100);
} while (--timeout);
if (ioc_state == MRIOC_STATE_READY) {
ioc_info(mrioc, "issuing message unit reset (MUR) to bring to reset state\n");
retval = mpi3mr_issue_and_process_mur(mrioc,
MPI3MR_RESET_FROM_BRINGUP);
ioc_state = mpi3mr_get_iocstate(mrioc); if (retval)
ioc_err(mrioc, "message unit reset failed with error %d current state %s\n",
retval, mpi3mr_iocstate_name(ioc_state));
} if (ioc_state != MRIOC_STATE_RESET) { if (ioc_state == MRIOC_STATE_FAULT) {
timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
mpi3mr_print_fault_info(mrioc); do {
host_diagnostic =
readl(&mrioc->sysif_regs->host_diagnostic); if (!(host_diagnostic &
MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) break; if (!pci_device_is_present(mrioc->pdev)) {
mrioc->unrecoverable = 1;
ioc_err(mrioc, "controller is not present at the bringup\n"); goto out_device_not_present;
}
msleep(100);
} while (--timeout);
}
mpi3mr_print_fault_info(mrioc);
ioc_info(mrioc, "issuing soft reset to bring to reset state\n");
retval = mpi3mr_issue_reset(mrioc,
MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET,
MPI3MR_RESET_FROM_BRINGUP); if (retval) {
ioc_err(mrioc, "soft reset failed with error %d\n", retval); goto out_failed;
}
}
ioc_state = mpi3mr_get_iocstate(mrioc); if (ioc_state != MRIOC_STATE_RESET) {
ioc_err(mrioc, "cannot bring controller to reset state, current state: %s\n",
mpi3mr_iocstate_name(ioc_state)); goto out_failed;
}
mpi3mr_clear_reset_history(mrioc);
retval = mpi3mr_setup_admin_qpair(mrioc); if (retval) {
ioc_err(mrioc, "failed to setup admin queues: error %d\n",
retval); goto out_failed;
}
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",
mpi3mr_iocstate_name(ioc_state));
out_device_not_present: return retval;
}
/** * mpi3mr_soft_reset_success - Check softreset is success or not * @ioc_status: IOC status register value * @ioc_config: IOC config register value * * Check whether the soft reset is successful or not based on * IOC status and IOC config register values. * * Return: True when the soft reset is success, false otherwise.
*/ staticinlinebool
mpi3mr_soft_reset_success(u32 ioc_status, u32 ioc_config)
{ if (!((ioc_status & MPI3_SYSIF_IOC_STATUS_READY) ||
(ioc_config & MPI3_SYSIF_IOC_CONFIG_ENABLE_IOC))) returntrue; returnfalse;
}
/** * mpi3mr_diagfault_success - Check diag fault is success or not * @mrioc: Adapter reference * @ioc_status: IOC status register value * * Check whether the controller hit diag reset fault code. * * Return: True when there is diag fault, false otherwise.
*/ staticinlinebool mpi3mr_diagfault_success(struct mpi3mr_ioc *mrioc,
u32 ioc_status)
{
u32 fault;
if (!(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) returnfalse;
fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK; if (fault == MPI3_SYSIF_FAULT_CODE_DIAG_FAULT_RESET) {
mpi3mr_print_fault_info(mrioc); returntrue;
} returnfalse;
}
/** * mpi3mr_set_diagsave - Set diag save bit for snapdump * @mrioc: Adapter reference * * Set diag save bit in IOC configuration register to enable * snapdump. * * Return: Nothing.
*/ staticinlinevoid mpi3mr_set_diagsave(struct mpi3mr_ioc *mrioc)
{
u32 ioc_config;
/** * mpi3mr_issue_reset - Issue reset to the controller * @mrioc: Adapter reference * @reset_type: Reset type * @reset_reason: Reset reason code * * Unlock the host diagnostic registers and write the specific * reset type to that, wait for reset acknowledgment from the * controller, if the reset is not successful retry for the * predefined number of times. * * Return: 0 on success, non-zero on failure.
*/ staticint mpi3mr_issue_reset(struct mpi3mr_ioc *mrioc, u16 reset_type,
u16 reset_reason)
{ int retval = -1;
u8 unlock_retry_count = 0;
u32 host_diagnostic, ioc_status, ioc_config, scratch_pad0;
u32 timeout = MPI3MR_RESET_ACK_TIMEOUT * 10;
if ((reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET) &&
(reset_type != MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT)) return retval; if (mrioc->unrecoverable) return retval; if (reset_reason == MPI3MR_RESET_FROM_FIRMWARE) {
retval = 0; return retval;
}
ioc_info(mrioc, "%s reset due to %s(0x%x)\n",
mpi3mr_reset_type_name(reset_type),
mpi3mr_reset_rc_name(reset_reason), reset_reason);
mpi3mr_clear_reset_history(mrioc); do {
ioc_info(mrioc, "Write magic sequence to unlock host diag register (retry=%d)\n",
++unlock_retry_count); if (unlock_retry_count >= MPI3MR_HOSTDIAG_UNLOCK_RETRY_COUNT) {
ioc_err(mrioc, "%s reset failed due to unlock failure, host_diagnostic(0x%08x)\n",
mpi3mr_reset_type_name(reset_type),
host_diagnostic);
mrioc->unrecoverable = 1; return retval;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.