/** * 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;
}
msix_count_op_q =
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); /* * 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) {
mrioc->req_qinfo = kcalloc(num_queues, sizeof(struct op_req_qinfo), GFP_KERNEL); if (!mrioc->req_qinfo) {
retval = -1; goto out_failed;
}
if (mrioc->enable_segqueue)
ioc_info(mrioc, "allocating operational queues through segmented queues\n");
for (i = 0; i < num_queues; i++) { if (mpi3mr_create_op_reply_q(mrioc, i)) {
ioc_err(mrioc, "Cannot create OP RepQ %d\n", i); break;
} if (mpi3mr_create_op_req_q(mrioc, i,
mrioc->op_reply_qinfo[i].qid)) {
ioc_err(mrioc, "Cannot create OP ReqQ %d\n", i);
mpi3mr_delete_op_reply_q(mrioc, i); break;
}
}
if (i == 0) { /* Not even one queue is created successfully*/
retval = -1; goto out_failed;
}
ioc_status = readl(&mrioc->sysif_regs->ioc_status);
ioc_state = mpi3mr_get_iocstate(mrioc); if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
ioc_state != MRIOC_STATE_READY) {
mpi3mr_print_fault_info(mrioc);
retval = -1; goto out_failed;
}
mrioc->num_op_reply_q = mrioc->num_op_req_q = i;
ioc_info(mrioc, "successfully created %d operational queue pairs(default/polled) queue = (%d/%d)\n",
mrioc->num_op_reply_q, mrioc->default_qcount,
mrioc->active_poll_qcount);
spin_lock_irqsave(&op_req_q->q_lock, flags);
pi = op_req_q->pi;
max_entries = op_req_q->num_requests;
if (mpi3mr_check_req_qfull(op_req_q)) {
midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(
reply_qidx, mrioc->op_reply_q_offset);
mpi3mr_process_op_reply_q(mrioc, mrioc->intr_info[midx].op_reply_q);
if (mpi3mr_check_req_qfull(op_req_q)) {
retval = -EAGAIN; goto out;
}
}
if (mrioc->reset_in_progress) {
ioc_err(mrioc, "OpReqQ submit reset in progress\n");
retval = -EAGAIN; goto out;
} if (mrioc->pci_err_recovery) {
ioc_err(mrioc, "operational request queue submission failed due to pci error recovery in progress\n");
retval = -EAGAIN; goto out;
}
/* Reply queue is nearing to get full, push back IOs to SML */ if ((mrioc->prevent_reply_qfull == true) &&
(atomic_read(&op_reply_q->pend_ios) >
(op_reply_q->qfull_watermark))) {
atomic_inc(&mrioc->reply_qfull_count);
retval = -EAGAIN; goto out;
}
/** * mpi3mr_check_rh_fault_ioc - check reset history and fault * controller * @mrioc: Adapter instance reference * @reason_code: reason code for the fault. * * This routine will save snapdump and fault the controller with * the given reason code if it is not already in the fault or * not asynchronosuly reset. This will be used to handle * initilaization time faults/resets/timeout as in those cases * immediate soft reset invocation is not required. * * Return: None.
*/ void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code)
{
u32 ioc_status, host_diagnostic, timeout; union mpi3mr_trigger_data trigger_data;
if (mrioc->unrecoverable) {
ioc_err(mrioc, "controller is unrecoverable\n"); return;
}
if (!pci_device_is_present(mrioc->pdev)) {
mrioc->unrecoverable = 1;
ioc_err(mrioc, "controller is not present\n"); return;
}
memset(&trigger_data, 0, sizeof(trigger_data));
ioc_status = readl(&mrioc->sysif_regs->ioc_status);
out: if (data)
dma_free_coherent(&mrioc->pdev->dev, data_len, data,
data_dma); return retval;
}
/** * mpi3mr_watchdog_work - watchdog thread to monitor faults * @work: work struct * * Watch dog work periodically executed (1 second interval) to * monitor firmware fault and to issue periodic timer sync to * the firmware. * * Return: Nothing.
*/ staticvoid mpi3mr_watchdog_work(struct work_struct *work)
{ struct mpi3mr_ioc *mrioc =
container_of(work, struct mpi3mr_ioc, watchdog_work.work); unsignedlong flags; enum mpi3mr_iocstate ioc_state;
u32 host_diagnostic, ioc_status; union mpi3mr_trigger_data trigger_data;
u16 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH;
if (mrioc->reset_in_progress || mrioc->pci_err_recovery) return;
if (!mrioc->unrecoverable && !pci_device_is_present(mrioc->pdev)) {
ioc_err(mrioc, "watchdog could not detect the controller\n");
mrioc->unrecoverable = 1;
}
if (mrioc->unrecoverable) {
ioc_err(mrioc, "flush pending commands for unrecoverable controller\n");
mpi3mr_flush_cmds_for_unrecovered_controller(mrioc); return;
}
/*Check for fault state every one second and issue Soft reset*/
ioc_state = mpi3mr_get_iocstate(mrioc); if (ioc_state != MRIOC_STATE_FAULT) goto schedule_work;
trigger_data.fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
mpi3mr_set_trigger_data_in_all_hdb(mrioc,
MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0);
host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic); if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) { if (!mrioc->diagsave_timeout) {
mpi3mr_print_fault_info(mrioc);
ioc_warn(mrioc, "diag save in progress\n");
} if ((mrioc->diagsave_timeout++) <= MPI3_SYSIF_DIAG_SAVE_TIMEOUT) goto schedule_work;
}
out: if (data)
dma_free_coherent(&mrioc->pdev->dev, data_len, data, data_dma);
return retval;
}
/** * mpi3mr_check_reset_dma_mask - Process IOC facts data * @mrioc: Adapter instance reference * * Check whether the new DMA mask requested through IOCFacts by * firmware needs to be set, if so set it . * * Return: 0 on success, non-zero on failure.
*/ staticinlineint mpi3mr_check_reset_dma_mask(struct mpi3mr_ioc *mrioc)
{ struct pci_dev *pdev = mrioc->pdev; int r;
u64 facts_dma_mask = DMA_BIT_MASK(mrioc->facts.dma_mask);
if (!mrioc->facts.dma_mask || (mrioc->dma_mask <= facts_dma_mask)) return 0;
ioc_info(mrioc, "Changing DMA mask from 0x%016llx to 0x%016llx\n",
mrioc->dma_mask, facts_dma_mask);
r = dma_set_mask_and_coherent(&pdev->dev, facts_dma_mask); if (r) {
ioc_err(mrioc, "Setting DMA mask to 0x%016llx failed: %d\n",
facts_dma_mask, r); return r;
}
mrioc->dma_mask = facts_dma_mask; return r;
}
/** * mpi3mr_process_factsdata - Process IOC facts data * @mrioc: Adapter instance reference * @facts_data: Cached IOC facts data * * Convert IOC facts data into cpu endianness and cache it in * the driver . * * Return: Nothing.
*/ staticvoid mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, struct mpi3_ioc_facts_data *facts_data)
{
u32 ioc_config, req_sz, facts_flags;
/** * mpi3mr_alloc_reply_sense_bufs - Send IOC Init * @mrioc: Adapter instance reference * * Allocate and initialize the reply free buffers, sense * buffers, reply free queue and sense buffer queue. * * Return: 0 on success, non-zero on failures.
*/ staticint mpi3mr_alloc_reply_sense_bufs(struct mpi3mr_ioc *mrioc)
{ int retval = 0;
u32 sz, i;
if (mrioc->init_cmds.reply) return retval;
mrioc->init_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); if (!mrioc->init_cmds.reply) goto out_failed;
mrioc->bsg_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); if (!mrioc->bsg_cmds.reply) goto out_failed;
mrioc->transport_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); if (!mrioc->transport_cmds.reply) goto out_failed;
for (i = 0; i < MPI3MR_NUM_DEVRMCMD; i++) {
mrioc->dev_rmhs_cmds[i].reply = kzalloc(mrioc->reply_sz,
GFP_KERNEL); if (!mrioc->dev_rmhs_cmds[i].reply) goto out_failed;
}
for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++) {
mrioc->evtack_cmds[i].reply = kzalloc(mrioc->reply_sz,
GFP_KERNEL); if (!mrioc->evtack_cmds[i].reply) goto out_failed;
}
mrioc->host_tm_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); if (!mrioc->host_tm_cmds.reply) goto out_failed;
mrioc->pel_cmds.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); if (!mrioc->pel_cmds.reply) goto out_failed;
mrioc->pel_abort_cmd.reply = kzalloc(mrioc->reply_sz, GFP_KERNEL); if (!mrioc->pel_abort_cmd.reply) goto out_failed;
/** * mpi3mr_alloc_chain_bufs - Allocate chain buffers * @mrioc: Adapter instance reference * * Allocate chain buffers and set a bitmap to indicate free * chain buffers. Chain buffers are used to pass the SGE * information along with MPI3 SCSI IO requests for host I/O. * * Return: 0 on success, non-zero on failure
*/ staticint mpi3mr_alloc_chain_bufs(struct mpi3mr_ioc *mrioc)
{ int retval = 0;
u32 sz, i;
u16 num_chains;
for (i = 0; i < num_chains; i++) {
mrioc->chain_sgl_list[i].addr =
dma_pool_zalloc(mrioc->chain_buf_pool, GFP_KERNEL,
&mrioc->chain_sgl_list[i].dma_addr);
/** * mpi3mr_port_enable_complete - Mark port enable complete * @mrioc: Adapter instance reference * @drv_cmd: Internal command tracker * * Call back for asynchronous port enable request sets the * driver command to indicate port enable request is complete. * * Return: Nothing
*/ staticvoid mpi3mr_port_enable_complete(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd)
{
drv_cmd->callback = NULL;
mrioc->scan_started = 0; if (drv_cmd->state & MPI3MR_CMD_RESET)
mrioc->scan_failed = MPI3_IOCSTATUS_INTERNAL_ERROR; else
mrioc->scan_failed = drv_cmd->ioc_status;
drv_cmd->state = MPI3MR_CMD_NOTUSED;
}
/** * mpi3mr_issue_port_enable - Issue Port Enable * @mrioc: Adapter instance reference * @async: Flag to wait for completion or not * * Issue Port Enable MPI request through admin queue and if the * async flag is not set wait for the completion of the port * enable or time out. * * Return: 0 on success, non-zero on failures.
*/ int mpi3mr_issue_port_enable(struct mpi3mr_ioc *mrioc, u8 async)
{ struct mpi3_port_enable_request pe_req; int retval = 0;
u32 pe_timeout = MPI3MR_PORTENABLE_TIMEOUT;
retval = mpi3mr_issue_event_notification(mrioc); if (retval)
ioc_err(mrioc, "failed to issue event notification %d\n",
retval); return retval;
}
/** * mpi3mr_init_ioc - Initialize the controller * @mrioc: Adapter instance reference * * This the controller initialization routine, executed either * after soft reset or from pci probe callback. * Setup the required resources, memory map the controller * registers, create admin and operational reply queue pairs, * allocate required memory for reply pool, sense buffer pool, * issue IOC init request to the firmware, unmask the events and * issue port enable to discover SAS/SATA/NVMe devies and RAID * volumes. * * Return: 0 on success and non-zero on failure.
*/ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
{ int retval = 0;
u8 retry = 0; struct mpi3_ioc_facts_data facts_data;
u32 sz;
retry_init:
retval = mpi3mr_bring_ioc_ready(mrioc); if (retval) {
ioc_err(mrioc, "Failed to bring ioc ready: error %d\n",
retval); goto out_failed_noretry;
}
retval = mpi3mr_setup_isr(mrioc, 1); if (retval) {
ioc_err(mrioc, "Failed to setup ISR error %d\n",
retval); goto out_failed_noretry;
}
retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); if (retval) {
ioc_err(mrioc, "Failed to Issue IOC Facts %d\n",
retval); goto out_failed;
}
/** * mpi3mr_reinit_ioc - Re-Initialize the controller * @mrioc: Adapter instance reference * @is_resume: Called from resume or reset path * * This the controller re-initialization routine, executed from * the soft reset handler or resume callback. Creates * operational reply queue pairs, allocate required memory for * reply pool, sense buffer pool, issue IOC init request to the * firmware, unmask the events and issue port enable to discover * SAS/SATA/NVMe devices and RAID volumes. * * Return: 0 on success and non-zero on failure.
*/ int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume)
{ int retval = 0;
u8 retry = 0; struct mpi3_ioc_facts_data facts_data;
u32 pe_timeout, ioc_status;
dprint_reset(mrioc, "bringing up the controller to ready state\n");
retval = mpi3mr_bring_ioc_ready(mrioc); if (retval) {
ioc_err(mrioc, "failed to bring to ready state\n"); goto out_failed_noretry;
}
mrioc->io_admin_reset_sync = 0; if (is_resume || mrioc->block_on_pci_err) {
dprint_reset(mrioc, "setting up single ISR\n");
retval = mpi3mr_setup_isr(mrioc, 1); if (retval) {
ioc_err(mrioc, "failed to setup ISR\n"); goto out_failed_noretry;
}
} else
mpi3mr_ioc_enable_intr(mrioc);
dprint_reset(mrioc, "getting ioc_facts\n");
retval = mpi3mr_issue_iocfacts(mrioc, &facts_data); if (retval) {
ioc_err(mrioc, "failed to get ioc_facts\n"); goto out_failed;
}
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;
}
if (is_resume) {
dprint_reset(mrioc, "posting host diag buffers\n");
retval = mpi3mr_post_diag_bufs(mrioc); if (retval)
ioc_warn(mrioc, "failed to post host diag buffers\n");
} else {
retval = mpi3mr_repost_diag_bufs(mrioc); if (retval)
ioc_warn(mrioc, "failed to re post host diag buffers\n");
}
dprint_reset(mrioc, "sending ioc_init\n");
retval = mpi3mr_issue_iocinit(mrioc); if (retval) {
ioc_err(mrioc, "failed to send ioc_init\n"); goto out_failed;
}
dprint_reset(mrioc, "getting package version\n");
retval = mpi3mr_print_pkg_ver(mrioc); if (retval) {
ioc_err(mrioc, "failed to get package version\n"); goto out_failed;
}
if (is_resume || mrioc->block_on_pci_err) {
dprint_reset(mrioc, "setting up multiple ISR\n");
retval = mpi3mr_setup_isr(mrioc, 0); if (retval) {
ioc_err(mrioc, "failed to re-setup ISR\n"); goto out_failed_noretry;
}
}
size = op_req_q->segment_qd * mrioc->facts.op_req_sz;
segments = op_req_q->q_segments; for (i = 0; i < op_req_q->num_segments; i++)
memset(segments[i].segment, 0, size);
}
/** * mpi3mr_memset_buffers - memset memory for a controller * @mrioc: Adapter instance reference * * clear all the memory allocated for a controller, typically * called post reset to reuse the memory allocated during the * controller init. * * Return: Nothing.
*/ void mpi3mr_memset_buffers(struct mpi3mr_ioc *mrioc)
{
u16 i; struct mpi3mr_throttle_group_info *tg;
if (retval) { if ((ioc_status & MPI3_SYSIF_IOC_STATUS_SHUTDOWN_MASK)
== MPI3_SYSIF_IOC_STATUS_SHUTDOWN_IN_PROGRESS)
ioc_warn(mrioc, "shutdown still in progress after timeout\n");
}
ioc_info(mrioc, "Base IOC Sts/Config after %s shutdown is (0x%08x)/(0x%08x)\n",
(!retval) ? "successful" : "failed", ioc_status,
ioc_config);
}
/** * mpi3mr_cleanup_ioc - Cleanup controller * @mrioc: Adapter instance reference * * controller cleanup handler, Message unit reset or soft reset * and shutdown notification is issued to the controller. * * Return: Nothing.
*/ void mpi3mr_cleanup_ioc(struct mpi3mr_ioc *mrioc)
{ enum mpi3mr_iocstate ioc_state;
dprint_exit(mrioc, "cleaning up the controller\n");
mpi3mr_ioc_disable_intr(mrioc);
/** * mpi3mr_pel_wait_complete - PELWait Completion callback * @mrioc: Adapter instance reference * @drv_cmd: Internal command tracker * * This is a callback handler for the PELWait request and * firmware completes a PELWait request when it is aborted or a * new PEL entry is available. This sends AEN to the application * and if the PELwait completion is not due to PELAbort then * this will send a request for new PEL Sequence number * * Return: Nothing.
*/ staticvoid mpi3mr_pel_wait_complete(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd)
{ struct mpi3_pel_reply *pel_reply = NULL;
u16 ioc_status, pe_log_status; bool do_retry = false;
if (drv_cmd->state & MPI3MR_CMD_RESET) goto cleanup_drv_cmd;
/** * mpi3mr_pel_get_seqnum_complete - PELGetSeqNum Completion callback * @mrioc: Adapter instance reference * @drv_cmd: Internal command tracker * * This is a callback handler for the PEL get sequence number * request and a new PEL wait request will be issued to the * firmware from this * * Return: Nothing.
*/ void mpi3mr_pel_get_seqnum_complete(struct mpi3mr_ioc *mrioc, struct mpi3mr_drv_cmd *drv_cmd)
{ struct mpi3_pel_reply *pel_reply = NULL; struct mpi3_pel_seq *pel_seqnum_virt;
u16 ioc_status; bool do_retry = false;
if (drv_cmd->state & MPI3MR_CMD_REPLY_VALID)
pel_reply = (struct mpi3_pel_reply *)drv_cmd->reply; if (!pel_reply) {
dprint_bsg_err(mrioc, "pel_get_seqnum: failed due to no reply\n"); goto out_failed;
}
if (le16_to_cpu(pel_reply->pe_log_status) != MPI3_PEL_STATUS_SUCCESS) {
dprint_bsg_err(mrioc, "pel_get_seqnum: failed due to pel_log_status(0x%04x)\n",
le16_to_cpu(pel_reply->pe_log_status));
do_retry = true;
}
if (do_retry) { if (drv_cmd->retry_count < MPI3MR_PEL_RETRY_COUNT) {
drv_cmd->retry_count++;
dprint_bsg_err(mrioc, "pel_get_seqnum: retrying(%d)\n",
drv_cmd->retry_count);
mpi3mr_pel_get_seqnum_post(mrioc, drv_cmd); return;
}
dprint_bsg_err(mrioc, "pel_get_seqnum: failed after all retries(%d)\n",
drv_cmd->retry_count); goto out_failed;
}
mrioc->pel_newest_seqnum = le32_to_cpu(pel_seqnum_virt->newest) + 1;
drv_cmd->retry_count = 0;
mpi3mr_pel_wait_post(mrioc, drv_cmd);
/** * mpi3mr_check_op_admin_proc - * @mrioc: Adapter instance reference * * Check if any of the operation reply queues * or the admin reply queue are currently in use. * If any queue is in use, this function waits for * a maximum of 10 seconds for them to become available. * * Return: 0 on success, non-zero on failure.
*/ staticint mpi3mr_check_op_admin_proc(struct mpi3mr_ioc *mrioc)
{
/* Check admin_reply queue first to exit early */ if (atomic_read(&mrioc->admin_reply_q_in_use) == 1)
op_admin_in_use = true; else { /* Check op_reply queues */ int i;
for (i = 0; i < mrioc->num_queues; i++) { if (atomic_read(&mrioc->op_reply_qinfo[i].in_use) == 1) {
op_admin_in_use = true; break;
}
}
}
if (!op_admin_in_use) break;
msleep(100);
} while (++elapsed_time < timeout);
if (op_admin_in_use) return 1;
return 0;
}
/** * mpi3mr_soft_reset_handler - Reset the controller * @mrioc: Adapter instance reference * @reset_reason: Reset reason code * @snapdump: Flag to generate snapdump in firmware or not * * This is an handler for recovering controller by issuing soft * reset are diag fault reset. This is a blocking function and * when one reset is executed if any other resets they will be * blocked. All BSG requests will be blocked during the reset. If * controller reset is successful then the controller will be * reinitalized, otherwise the controller will be marked as not * recoverable * * In snapdump bit is set, the controller is issued with diag * fault reset so that the firmware can create a snap dump and * post that the firmware will result in F000 fault and the * driver will issue soft reset to recover from that. * * Return: 0 on success, non-zero on failure.
*/ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
u16 reset_reason, u8 snapdump)
{ int retval = 0, i; unsignedlong flags;
u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10; union mpi3mr_trigger_data trigger_data;
/* Block the reset handler until diag save in progress*/
dprint_reset(mrioc, "soft_reset_handler: check and block on diagsave_timeout(%d)\n",
mrioc->diagsave_timeout); while (mrioc->diagsave_timeout)
ssleep(1); /* * Block new resets until the currently executing one is finished and * return the status of the existing reset for all blocked resets
*/
dprint_reset(mrioc, "soft_reset_handler: acquiring reset_mutex\n"); if (!mutex_trylock(&mrioc->reset_mutex)) {
ioc_info(mrioc, "controller reset triggered by %s is blocked due to another reset in progress\n",
mpi3mr_reset_rc_name(reset_reason)); do {
ssleep(1);
} while (mrioc->reset_in_progress == 1);
ioc_info(mrioc, "returning previous reset result(%d) for the reset triggered by %s\n",
mrioc->prev_reset_result,
mpi3mr_reset_rc_name(reset_reason)); return mrioc->prev_reset_result;
}
ioc_info(mrioc, "controller reset is triggered by %s\n",
mpi3mr_reset_rc_name(reset_reason));
if (snapdump) {
mpi3mr_set_diagsave(mrioc);
retval = mpi3mr_issue_reset(mrioc,
MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason); if (!retval) {
trigger_data.fault = (readl(&mrioc->sysif_regs->fault) &
MPI3_SYSIF_FAULT_CODE_MASK); do {
host_diagnostic =
readl(&mrioc->sysif_regs->host_diagnostic); if (!(host_diagnostic &
MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS)) break;
msleep(100);
} while (--timeout);
mpi3mr_set_trigger_data_in_all_hdb(mrioc,
MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0);
}
}
retval = mpi3mr_issue_reset(mrioc,
MPI3_SYSIF_HOST_DIAG_RESET_ACTION_SOFT_RESET, reset_reason); if (retval) {
ioc_err(mrioc, "Failed to issue soft reset to the ioc\n"); goto out;
}
retval = mpi3mr_check_op_admin_proc(mrioc); if (retval) {
ioc_err(mrioc, "Soft reset failed due to an Admin or I/O queue polling\n" "thread still processing replies even after a 10 second\n" "timeout. Marking the controller as unrecoverable!\n");
goto out;
}
if (mrioc->num_io_throttle_group !=
mrioc->facts.max_io_throttle_group) {
ioc_err(mrioc, "max io throttle group doesn't match old(%d), new(%d)\n",
mrioc->num_io_throttle_group,
mrioc->facts.max_io_throttle_group);
retval = -EPERM; goto out;
}
/** * mpi3mr_post_cfg_req - Issue config requests and wait * @mrioc: Adapter instance reference * @cfg_req: Configuration request * @timeout: Timeout in seconds * @ioc_status: Pointer to return ioc status * * A generic function for posting MPI3 configuration request to * the firmware. This blocks for the completion of request for * timeout seconds and if the request times out this function * faults the controller with proper reason code. * * On successful completion of the request this function returns * appropriate ioc status from the firmware back to the caller. * * Return: 0 on success, non-zero on failure.
*/ staticint mpi3mr_post_cfg_req(struct mpi3mr_ioc *mrioc, struct mpi3_config_request *cfg_req, int timeout, u16 *ioc_status)
{ int retval = 0;
mutex_lock(&mrioc->cfg_cmds.mutex); if (mrioc->cfg_cmds.state & MPI3MR_CMD_PENDING) {
retval = -1;
ioc_err(mrioc, "sending config request failed due to command in use\n");
mutex_unlock(&mrioc->cfg_cmds.mutex); goto out;
}
mrioc->cfg_cmds.state = MPI3MR_CMD_PENDING;
mrioc->cfg_cmds.is_waiting = 1;
mrioc->cfg_cmds.callback = NULL;
mrioc->cfg_cmds.ioc_status = 0;
mrioc->cfg_cmds.ioc_loginfo = 0;
/** * mpi3mr_process_cfg_req - config page request processor * @mrioc: Adapter instance reference * @cfg_req: Configuration request * @cfg_hdr: Configuration page header * @timeout: Timeout in seconds * @ioc_status: Pointer to return ioc status * @cfg_buf: Memory pointer to copy config page or header * @cfg_buf_sz: Size of the memory to get config page or header * * This is handler for config page read, write and config page * header read operations. * * This function expects the cfg_req to be populated with page * type, page number, action for the header read and with page * address for all other operations. * * The cfg_hdr can be passed as null for reading required header * details for read/write pages the cfg_hdr should point valid * configuration page header. * * This allocates dmaable memory based on the size of the config * buffer and set the SGE of the cfg_req. * * For write actions, the config page data has to be passed in * the cfg_buf and size of the data has to be mentioned in the * cfg_buf_sz. * * For read/header actions, on successful completion of the * request with successful ioc_status the data will be copied * into the cfg_buf limited to a minimum of actual page size and * cfg_buf_sz * * * Return: 0 on success, non-zero on failure.
*/ staticint mpi3mr_process_cfg_req(struct mpi3mr_ioc *mrioc, struct mpi3_config_request *cfg_req, struct mpi3_config_page_header *cfg_hdr, int timeout, u16 *ioc_status, void *cfg_buf, u32 cfg_buf_sz)
{ struct dma_memory_desc mem_desc; int retval = -1;
u8 invalid_action = 0;
u8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST;
/** * mpi3mr_cfg_get_dev_pg0 - Read current device page0 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @dev_pg0: Pointer to return device page 0 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like device handle * * This is handler for config page read for a specific device * page0. The ioc_status has the controller returned ioc_status. * This routine doesn't check ioc_status to decide whether the * page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure.
*/ int mpi3mr_cfg_get_dev_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_device_page0 *dev_pg0, u16 pg_sz, u32 form, u32 form_spec)
{ struct mpi3_config_page_header cfg_hdr; struct mpi3_config_request cfg_req;
u32 page_address;
/** * mpi3mr_cfg_get_sas_phy_pg0 - Read current SAS Phy page0 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @phy_pg0: Pointer to return SAS Phy page 0 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like phy number * * This is handler for config page read for a specific SAS Phy * page0. The ioc_status has the controller returned ioc_status. * This routine doesn't check ioc_status to decide whether the * page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure.
*/ int mpi3mr_cfg_get_sas_phy_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_sas_phy_page0 *phy_pg0, u16 pg_sz, u32 form,
u32 form_spec)
{ struct mpi3_config_page_header cfg_hdr; struct mpi3_config_request cfg_req;
u32 page_address;
/** * mpi3mr_cfg_get_sas_phy_pg1 - Read current SAS Phy page1 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @phy_pg1: Pointer to return SAS Phy page 1 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like phy number * * This is handler for config page read for a specific SAS Phy * page1. The ioc_status has the controller returned ioc_status. * This routine doesn't check ioc_status to decide whether the * page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure.
*/ int mpi3mr_cfg_get_sas_phy_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_sas_phy_page1 *phy_pg1, u16 pg_sz, u32 form,
u32 form_spec)
{ struct mpi3_config_page_header cfg_hdr; struct mpi3_config_request cfg_req;
u32 page_address;
/** * mpi3mr_cfg_get_sas_exp_pg0 - Read current SAS Expander page0 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @exp_pg0: Pointer to return SAS Expander page 0 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like device handle * * This is handler for config page read for a specific SAS * Expander page0. The ioc_status has the controller returned * ioc_status. This routine doesn't check ioc_status to decide * whether the page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure.
*/ int mpi3mr_cfg_get_sas_exp_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_sas_expander_page0 *exp_pg0, u16 pg_sz, u32 form,
u32 form_spec)
{ struct mpi3_config_page_header cfg_hdr; struct mpi3_config_request cfg_req;
u32 page_address;
/** * mpi3mr_cfg_get_sas_exp_pg1 - Read current SAS Expander page1 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @exp_pg1: Pointer to return SAS Expander page 1 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like phy number * * This is handler for config page read for a specific SAS * Expander page1. The ioc_status has the controller returned * ioc_status. This routine doesn't check ioc_status to decide * whether the page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure.
*/ int mpi3mr_cfg_get_sas_exp_pg1(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_sas_expander_page1 *exp_pg1, u16 pg_sz, u32 form,
u32 form_spec)
{ struct mpi3_config_page_header cfg_hdr; struct mpi3_config_request cfg_req;
u32 page_address;
/** * mpi3mr_cfg_get_enclosure_pg0 - Read current Enclosure page0 * @mrioc: Adapter instance reference * @ioc_status: Pointer to return ioc status * @encl_pg0: Pointer to return Enclosure page 0 * @pg_sz: Size of the memory allocated to the page pointer * @form: The form to be used for addressing the page * @form_spec: Form specific information like device handle * * This is handler for config page read for a specific Enclosure * page0. The ioc_status has the controller returned ioc_status. * This routine doesn't check ioc_status to decide whether the * page read is success or not and it is the callers * responsibility. * * Return: 0 on success, non-zero on failure.
*/ int mpi3mr_cfg_get_enclosure_pg0(struct mpi3mr_ioc *mrioc, u16 *ioc_status, struct mpi3_enclosure_page0 *encl_pg0, u16 pg_sz, u32 form,
u32 form_spec)
{ struct mpi3_config_page_header cfg_hdr; struct mpi3_config_request cfg_req;
u32 page_address;
/** * mpi3mr_cfg_get_sas_io_unit_pg0 - Read current SASIOUnit page0 * @mrioc: Adapter instance reference * @sas_io_unit_pg0: Pointer to return SAS IO Unit page 0 * @pg_sz: Size of the memory allocated to the page pointer * * This is handler for config page read for the SAS IO Unit * page0. This routine checks ioc_status to decide whether the * page read is success or not. * * Return: 0 on success, non-zero on failure.
*/ int mpi3mr_cfg_get_sas_io_unit_pg0(struct mpi3mr_ioc *mrioc, struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0, u16 pg_sz)
{ struct mpi3_config_page_header cfg_hdr; struct mpi3_config_request cfg_req;
u16 ioc_status = 0;
if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
ioc_err(mrioc, "sas io unit page0 header read failed\n"); goto out_failed;
} if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
ioc_err(mrioc, "sas io unit page0 header read failed with ioc_status(0x%04x)\n",
ioc_status); goto out_failed;
}
cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg0, pg_sz)) {
ioc_err(mrioc, "sas io unit page0 read failed\n"); goto out_failed;
} if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
ioc_err(mrioc, "sas io unit page0 read failed with ioc_status(0x%04x)\n",
ioc_status); goto out_failed;
} return 0;
out_failed: return -1;
}
/** * mpi3mr_cfg_get_sas_io_unit_pg1 - Read current SASIOUnit page1 * @mrioc: Adapter instance reference * @sas_io_unit_pg1: Pointer to return SAS IO Unit page 1 * @pg_sz: Size of the memory allocated to the page pointer * * This is handler for config page read for the SAS IO Unit * page1. This routine checks ioc_status to decide whether the * page read is success or not. * * Return: 0 on success, non-zero on failure.
*/ int mpi3mr_cfg_get_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc, struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz)
{ struct mpi3_config_page_header cfg_hdr; struct mpi3_config_request cfg_req;
u16 ioc_status = 0;
if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
ioc_err(mrioc, "sas io unit page1 header read failed\n"); goto out_failed;
} if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
ioc_err(mrioc, "sas io unit page1 header read failed with ioc_status(0x%04x)\n",
ioc_status); goto out_failed;
}
cfg_req.action = MPI3_CONFIG_ACTION_READ_CURRENT;
if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
ioc_err(mrioc, "sas io unit page1 read failed\n"); goto out_failed;
} if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
ioc_err(mrioc, "sas io unit page1 read failed with ioc_status(0x%04x)\n",
ioc_status); goto out_failed;
} return 0;
out_failed: return -1;
}
/** * mpi3mr_cfg_set_sas_io_unit_pg1 - Write SASIOUnit page1 * @mrioc: Adapter instance reference * @sas_io_unit_pg1: Pointer to the SAS IO Unit page 1 to write * @pg_sz: Size of the memory allocated to the page pointer * * This is handler for config page write for the SAS IO Unit * page1. This routine checks ioc_status to decide whether the * page read is success or not. This will modify both current * and persistent page. * * Return: 0 on success, non-zero on failure.
*/ int mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc, struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz)
{ struct mpi3_config_page_header cfg_hdr; struct mpi3_config_request cfg_req;
u16 ioc_status = 0;
if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, sas_io_unit_pg1, pg_sz)) {
ioc_err(mrioc, "sas io unit page1 write persistent failed\n"); goto out_failed;
} if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
ioc_err(mrioc, "sas io unit page1 write persistent failed with ioc_status(0x%04x)\n",
ioc_status); goto out_failed;
} return 0;
out_failed: return -1;
}
/** * mpi3mr_cfg_get_driver_pg1 - Read current Driver page1 * @mrioc: Adapter instance reference * @driver_pg1: Pointer to return Driver page 1 * @pg_sz: Size of the memory allocated to the page pointer * * This is handler for config page read for the Driver page1. * This routine checks ioc_status to decide whether the page * read is success or not. * * Return: 0 on success, non-zero on failure.
*/ int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc, struct mpi3_driver_page1 *driver_pg1, u16 pg_sz)
{ struct mpi3_config_page_header cfg_hdr; struct mpi3_config_request cfg_req;
u16 ioc_status = 0;
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.