/******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.broadcom.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * * * * This program is free software; you can redistribute it and/or * * modify it under the terms of version 2 of the GNU General * * Public License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful. * * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * * TO BE LEGALLY INVALID. See the GNU General Public License for * * more details, a copy of which can be found in the file COPYING * * included with this package. *
*******************************************************************/
staticenum cpuhp_state lpfc_cpuhp_state; /* Used when mapping IRQ vectors in a driver centric manner */ static uint32_t lpfc_present_cpu; staticbool lpfc_pldv_detect;
/** * lpfc_config_port_prep - Perform lpfc initialization prior to config port * @phba: pointer to lpfc hba data structure. * * This routine will do LPFC initialization prior to issuing the CONFIG_PORT * mailbox command. It retrieves the revision information from the HBA and * collects the Vital Product Data (VPD) about the HBA for preparing the * configuration of the HBA. * * Return codes: * 0 - success. * -ERESTART - requests the SLI layer to reset the HBA and try again. * Any other value - indicates an error.
**/ int
lpfc_config_port_prep(struct lpfc_hba *phba)
{
lpfc_vpd_t *vp = &phba->vpd; int i = 0, rc;
LPFC_MBOXQ_t *pmb;
MAILBOX_t *mb; char *lpfc_vpd_data = NULL;
uint16_t offset = 0; staticchar licensed[56] = "key unlock for use with gnu public licensed code only\0"; staticint init_key = 1;
/* * Clear all option bits except LPFC_SLI3_BG_ENABLED, * which was already set in lpfc_get_cfgparam()
*/
phba->sli3_options &= (uint32_t)LPFC_SLI3_BG_ENABLED;
/* * The value of rr must be 1 since the driver set the cv field to 1. * This setting requires the FW to set all revision fields.
*/ if (mb->un.varRdRev.rr == 0) {
vp->rev.rBit = 0;
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0440 Adapter failed to init, READ_REV has " "missing revision information.\n");
mempool_free(pmb, phba->mbox_mem_pool); return -ERESTART;
}
/* If the sli feature level is less then 9, we must * tear down all RPIs and VPIs on link down if NPIV * is enabled.
*/ if (vp->rev.feaLevelHigh < 9)
phba->sli3_options |= LPFC_SLI3_VPORT_TEARDOWN;
if (lpfc_is_LC_HBA(phba->pcidev->device))
memcpy(phba->RandomData, (char *)&mb->un.varWords[24], sizeof (phba->RandomData));
/* Get adapter VPD information */
lpfc_vpd_data = kmalloc(DMP_VPD_SIZE, GFP_KERNEL); if (!lpfc_vpd_data) goto out_free_mbox; do {
lpfc_dump_mem(phba, pmb, offset, DMP_REGION_VPD);
rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0441 VPD not present on adapter, " "mbxCmd x%x DUMP VPD, mbxStatus x%x\n",
mb->mbxCommand, mb->mbxStatus);
mb->un.varDmp.word_cnt = 0;
} /* dump mem may return a zero when finished or we got a * mailbox error, either way we are done.
*/ if (mb->un.varDmp.word_cnt == 0) break;
/** * lpfc_config_async_cmpl - Completion handler for config async event mbox cmd * @phba: pointer to lpfc hba data structure. * @pmboxq: pointer to the driver internal queue element for mailbox command. * * This is the completion handler for driver's configuring asynchronous event * mailbox command to the device. If the mailbox command returns successfully, * it will set internal async event support flag to 1; otherwise, it will * set internal async event support flag to 0.
**/ staticvoid
lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
{ if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS)
phba->temp_sensor_support = 1; else
phba->temp_sensor_support = 0;
mempool_free(pmboxq, phba->mbox_mem_pool); return;
}
/** * lpfc_dump_wakeup_param_cmpl - dump memory mailbox command completion handler * @phba: pointer to lpfc hba data structure. * @pmboxq: pointer to the driver internal queue element for mailbox command. * * This is the completion handler for dump mailbox command for getting * wake up parameters. When this command complete, the response contain * Option rom version of the HBA. This function translate the version number * into a human readable string and store it in OptionROMVersion.
**/ staticvoid
lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
{ struct prog_id *prg;
uint32_t prog_id_word; char dist = ' '; /* character array used for decoding dist type. */ char dist_char[] = "nabx";
if (pmboxq->u.mb.mbxStatus != MBX_SUCCESS) {
mempool_free(pmboxq, phba->mbox_mem_pool); return;
}
prg = (struct prog_id *) &prog_id_word;
/* word 7 contain option rom version */
prog_id_word = pmboxq->u.mb.un.varWords[7];
/* Decode the Option rom version word to a readable string */
dist = dist_char[prg->dist];
/* * If the name is empty or there exists a soft name * then copy the service params name, otherwise use the fc name
*/ if (vport->fc_nodename.u.wwn[0] == 0)
memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName, sizeof(struct lpfc_name)); else
memcpy(&vport->fc_sparam.nodeName, &vport->fc_nodename, sizeof(struct lpfc_name));
/* * If the port name has changed, then set the Param changes flag * to unreg the login
*/ if (vport->fc_portname.u.wwn[0] != 0 &&
memcmp(&vport->fc_portname, &vport->fc_sparam.portName, sizeof(struct lpfc_name))) {
vport->vport_flag |= FAWWPN_PARAM_CHG;
/** * lpfc_config_port_post - Perform lpfc initialization after config port * @phba: pointer to lpfc hba data structure. * * This routine will do LPFC initialization after the CONFIG_PORT mailbox * command call. It performs all internal resource and state setups on the * port: post IOCB buffers, enable appropriate host interrupt attentions, * ELS ring timers, etc. * * Return codes * 0 - success. * Any other value - error.
**/ int
lpfc_config_port_post(struct lpfc_hba *phba)
{ struct lpfc_vport *vport = phba->pport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
LPFC_MBOXQ_t *pmb;
MAILBOX_t *mb; struct lpfc_dmabuf *mp; struct lpfc_sli *psli = &phba->sli;
uint32_t status, timeout; int i, j; int rc;
spin_lock_irq(&phba->hbalock); /* * If the Config port completed correctly the HBA is not * over heated any more.
*/ if (phba->over_temp_state == HBA_OVER_TEMP)
phba->over_temp_state = HBA_NORMAL_TEMP;
spin_unlock_irq(&phba->hbalock);
/* This dmabuf was allocated by lpfc_read_sparam. The dmabuf is no * longer needed. Prevent unintended ctx_buf access as the mbox is * reused.
*/
memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm));
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
pmb->ctx_buf = NULL;
lpfc_update_vport_wwn(vport);
/* Update the fc_host data structures with new wwn. */
fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn);
fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn);
fc_host_max_npiv_vports(shost) = phba->max_vpi;
/* If no serial number in VPD data, use low 6 bytes of WWNN */ /* This should be consolidated into parse_vpd ? - mr */ if (phba->SerialNumber[0] == 0) {
uint8_t *outptr;
/* Check if the port is disabled */
lpfc_sli_read_link_ste(phba);
/* Reset the DFT_HBA_Q_DEPTH to the max xri */ if (phba->cfg_hba_queue_depth > mb->un.varRdConfig.max_xri) {
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "3359 HBA queue depth changed from %d to %d\n",
phba->cfg_hba_queue_depth,
mb->un.varRdConfig.max_xri);
phba->cfg_hba_queue_depth = mb->un.varRdConfig.max_xri;
}
phba->lmt = mb->un.varRdConfig.lmt;
/* Get the default values for Model Name and Description */
lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc);
phba->link_state = LPFC_LINK_DOWN;
/* Only process IOCBs on ELS ring till hba_state is READY */ if (psli->sli3_ring[LPFC_EXTRA_RING].sli.sli3.cmdringaddr)
psli->sli3_ring[LPFC_EXTRA_RING].flag |= LPFC_STOP_IOCB_EVENT; if (psli->sli3_ring[LPFC_FCP_RING].sli.sli3.cmdringaddr)
psli->sli3_ring[LPFC_FCP_RING].flag |= LPFC_STOP_IOCB_EVENT;
/* Post receive buffers for desired rings */ if (phba->sli_rev != 3)
lpfc_post_rcv_buf(phba);
spin_lock_irq(&phba->hbalock); /* Initialize ERATT handling flag */
clear_bit(HBA_ERATT_HANDLED, &phba->hba_flag);
/* Enable appropriate host interrupts */ if (lpfc_readl(phba->HCregaddr, &status)) {
spin_unlock_irq(&phba->hbalock); return -EIO;
}
status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA; if (psli->num_rings > 0)
status |= HC_R0INT_ENA; if (psli->num_rings > 1)
status |= HC_R1INT_ENA; if (psli->num_rings > 2)
status |= HC_R2INT_ENA; if (psli->num_rings > 3)
status |= HC_R3INT_ENA;
if ((phba->cfg_poll & ENABLE_FCP_RING_POLLING) &&
(phba->cfg_poll & DISABLE_FCP_RING_INT))
status &= ~(HC_R0INT_ENA);
if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0435 Adapter failed " "to get Option ROM version status x%x\n", rc);
mempool_free(pmb, phba->mbox_mem_pool);
}
return 0;
}
/** * lpfc_sli4_refresh_params - update driver copy of params. * @phba: Pointer to HBA context object. * * This is called to refresh driver copy of dynamic fields from the * common_get_sli4_parameters descriptor.
**/ int
lpfc_sli4_refresh_params(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *mboxq; struct lpfc_mqe *mqe; struct lpfc_sli4_parameters *mbx_sli4_parameters; int length, rc;
mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!mboxq) return -ENOMEM;
/* Are we forcing MI off via module parameter? */ if (phba->cfg_enable_mi)
phba->sli4_hba.pc_sli4_params.mi_ver =
bf_get(cfg_mi_ver, mbx_sli4_parameters); else
phba->sli4_hba.pc_sli4_params.mi_ver = 0;
/** * lpfc_hba_init_link - Initialize the FC link * @phba: pointer to lpfc hba data structure. * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT * * This routine will issue the INIT_LINK mailbox command call. * It is available to other drivers through the lpfc_hba data * structure for use as a delayed link up mechanism with the * module parameter lpfc_suppress_link_up. * * Return code * 0 - success * Any other value - error
**/ staticint
lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag)
{ return lpfc_hba_init_link_fc_topology(phba, phba->cfg_topology, flag);
}
/** * lpfc_hba_init_link_fc_topology - Initialize FC link with desired topology * @phba: pointer to lpfc hba data structure. * @fc_topology: desired fc topology. * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT * * This routine will issue the INIT_LINK mailbox command call. * It is available to other drivers through the lpfc_hba data * structure for use as a delayed link up mechanism with the * module parameter lpfc_suppress_link_up. * * Return code * 0 - success * Any other value - error
**/ int
lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology,
uint32_t flag)
{ struct lpfc_vport *vport = phba->pport;
LPFC_MBOXQ_t *pmb;
MAILBOX_t *mb; int rc;
/** * lpfc_hba_down_link - this routine downs the FC link * @phba: pointer to lpfc hba data structure. * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT * * This routine will issue the DOWN_LINK mailbox command call. * It is available to other drivers through the lpfc_hba data * structure for use to stop the link. * * Return code * 0 - success * Any other value - error
**/ staticint
lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag)
{
LPFC_MBOXQ_t *pmb; int rc;
/** * lpfc_hba_down_prep - Perform lpfc uninitialization prior to HBA reset * @phba: pointer to lpfc HBA data structure. * * This routine will do LPFC uninitialization before the HBA is reset when * bringing down the SLI Layer. * * Return codes * 0 - success. * Any other value - error.
**/ int
lpfc_hba_down_prep(struct lpfc_hba *phba)
{ struct lpfc_vport **vports; int i;
if (test_bit(FC_UNLOADING, &phba->pport->load_flag))
lpfc_cleanup_discovery_resources(phba->pport); else {
vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vports &&
vports[i] != NULL; i++)
lpfc_cleanup_discovery_resources(vports[i]);
lpfc_destroy_vport_work_array(phba, vports);
} return 0;
}
/** * lpfc_sli4_free_sp_events - Cleanup sp_queue_events to free * rspiocb which got deferred * * @phba: pointer to lpfc HBA data structure. * * This routine will cleanup completed slow path events after HBA is reset * when bringing down the SLI Layer. * * * Return codes * void.
**/ staticvoid
lpfc_sli4_free_sp_events(struct lpfc_hba *phba)
{ struct lpfc_iocbq *rspiocbq; struct hbq_dmabuf *dmabuf; struct lpfc_cq_event *cq_event;
clear_bit(HBA_SP_QUEUE_EVT, &phba->hba_flag);
while (!list_empty(&phba->sli4_hba.sp_queue_event)) { /* Get the response iocb from the head of work queue */
spin_lock_irq(&phba->hbalock);
list_remove_head(&phba->sli4_hba.sp_queue_event,
cq_event, struct lpfc_cq_event, list);
spin_unlock_irq(&phba->hbalock);
switch (bf_get(lpfc_wcqe_c_code, &cq_event->cqe.wcqe_cmpl)) { case CQE_CODE_COMPL_WQE:
rspiocbq = container_of(cq_event, struct lpfc_iocbq,
cq_event);
lpfc_sli_release_iocbq(phba, rspiocbq); break; case CQE_CODE_RECEIVE: case CQE_CODE_RECEIVE_V1:
dmabuf = container_of(cq_event, struct hbq_dmabuf,
cq_event);
lpfc_in_buf_free(phba, &dmabuf->dbuf);
}
}
}
/** * lpfc_hba_free_post_buf - Perform lpfc uninitialization after HBA reset * @phba: pointer to lpfc HBA data structure. * * This routine will cleanup posted ELS buffers after the HBA is reset * when bringing down the SLI Layer. * * * Return codes * void.
**/ staticvoid
lpfc_hba_free_post_buf(struct lpfc_hba *phba)
{ struct lpfc_sli *psli = &phba->sli; struct lpfc_sli_ring *pring; struct lpfc_dmabuf *mp, *next_mp;
LIST_HEAD(buflist); int count;
if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)
lpfc_sli_hbqbuf_free_all(phba); else { /* Cleanup preposted buffers on the ELS ring */
pring = &psli->sli3_ring[LPFC_ELS_RING];
spin_lock_irq(&phba->hbalock);
list_splice_init(&pring->postbufq, &buflist);
spin_unlock_irq(&phba->hbalock);
/** * lpfc_hba_clean_txcmplq - Perform lpfc uninitialization after HBA reset * @phba: pointer to lpfc HBA data structure. * * This routine will cleanup the txcmplq after the HBA is reset when bringing * down the SLI Layer. * * Return codes * void
**/ staticvoid
lpfc_hba_clean_txcmplq(struct lpfc_hba *phba)
{ struct lpfc_sli *psli = &phba->sli; struct lpfc_queue *qp = NULL; struct lpfc_sli_ring *pring;
LIST_HEAD(completions); int i; struct lpfc_iocbq *piocb, *next_iocb;
if (phba->sli_rev != LPFC_SLI_REV4) { for (i = 0; i < psli->num_rings; i++) {
pring = &psli->sli3_ring[i];
spin_lock_irq(&phba->hbalock); /* At this point in time the HBA is either reset or DOA * Nothing should be on txcmplq as it will * NEVER complete.
*/
list_splice_init(&pring->txcmplq, &completions);
pring->txcmplq_cnt = 0;
spin_unlock_irq(&phba->hbalock);
lpfc_sli_abort_iocb_ring(phba, pring);
} /* Cancel all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &completions,
IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); return;
}
list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) {
pring = qp->pring; if (!pring) continue;
spin_lock_irq(&pring->ring_lock);
list_for_each_entry_safe(piocb, next_iocb,
&pring->txcmplq, list)
piocb->cmd_flag &= ~LPFC_IO_ON_TXCMPLQ;
list_splice_init(&pring->txcmplq, &completions);
pring->txcmplq_cnt = 0;
spin_unlock_irq(&pring->ring_lock);
lpfc_sli_abort_iocb_ring(phba, pring);
} /* Cancel all the IOCBs from the completions list */
lpfc_sli_cancel_iocbs(phba, &completions,
IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED);
}
/** * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset * @phba: pointer to lpfc HBA data structure. * * This routine will do uninitialization after the HBA is reset when bring * down the SLI Layer. * * Return codes * 0 - success. * Any other value - error.
**/ staticint
lpfc_hba_down_post_s3(struct lpfc_hba *phba)
{
lpfc_hba_free_post_buf(phba);
lpfc_hba_clean_txcmplq(phba); return 0;
}
/** * lpfc_hba_down_post_s4 - Perform lpfc uninitialization after HBA reset * @phba: pointer to lpfc HBA data structure. * * This routine will do uninitialization after the HBA is reset when bring * down the SLI Layer. * * Return codes * 0 - success. * Any other value - error.
**/ staticint
lpfc_hba_down_post_s4(struct lpfc_hba *phba)
{ struct lpfc_io_buf *psb, *psb_next; struct lpfc_async_xchg_ctx *ctxp, *ctxp_next; struct lpfc_sli4_hdw_queue *qp;
LIST_HEAD(aborts);
LIST_HEAD(nvme_aborts);
LIST_HEAD(nvmet_aborts); struct lpfc_sglq *sglq_entry = NULL; int cnt, idx;
/* At this point in time the HBA is either reset or DOA. Either * way, nothing should be on lpfc_abts_els_sgl_list, it needs to be * on the lpfc_els_sgl_list so that it can either be freed if the * driver is unloading or reposted if the driver is restarting * the port.
*/
/* sgl_list_lock required because worker thread uses this * list.
*/
spin_lock_irq(&phba->sli4_hba.sgl_list_lock);
list_for_each_entry(sglq_entry,
&phba->sli4_hba.lpfc_abts_els_sgl_list, list)
sglq_entry->state = SGL_FREED;
/** * lpfc_hba_down_post - Wrapper func for hba down post routine * @phba: pointer to lpfc HBA data structure. * * This routine wraps the actual SLI3 or SLI4 routine for performing * uninitialization after the HBA is reset when bring down the SLI Layer. * * Return codes * 0 - success. * Any other value - error.
**/ int
lpfc_hba_down_post(struct lpfc_hba *phba)
{ return (*phba->lpfc_hba_down_post)(phba);
}
/** * lpfc_hb_timeout - The HBA-timer timeout handler * @t: timer context used to obtain the pointer to lpfc hba data structure. * * This is the HBA-timer timeout handler registered to the lpfc driver. When * this timer fires, a HBA timeout event shall be posted to the lpfc driver * work-port-events bitmap and the worker thread is notified. This timeout * event will be used by the worker thread to invoke the actual timeout * handler routine, lpfc_hb_timeout_handler. Any periodical operations will * be performed in the timeout handler and the HBA timeout event bit shall * be cleared by the worker thread after it has taken the event bitmap out.
**/ staticvoid
lpfc_hb_timeout(struct timer_list *t)
{ struct lpfc_hba *phba;
uint32_t tmo_posted; unsignedlong iflag;
/* Tell the worker thread there is work to do */ if (!tmo_posted)
lpfc_worker_wake_up(phba); return;
}
/** * lpfc_rrq_timeout - The RRQ-timer timeout handler * @t: timer context used to obtain the pointer to lpfc hba data structure. * * This is the RRQ-timer timeout handler registered to the lpfc driver. When * this timer fires, a RRQ timeout event shall be posted to the lpfc driver * work-port-events bitmap and the worker thread is notified. This timeout * event will be used by the worker thread to invoke the actual timeout * handler routine, lpfc_rrq_handler. Any periodical operations will * be performed in the timeout handler and the RRQ timeout event bit shall * be cleared by the worker thread after it has taken the event bitmap out.
**/ staticvoid
lpfc_rrq_timeout(struct timer_list *t)
{ struct lpfc_hba *phba;
/** * lpfc_hb_mbox_cmpl - The lpfc heart-beat mailbox command callback function * @phba: pointer to lpfc hba data structure. * @pmboxq: pointer to the driver internal queue element for mailbox command. * * This is the callback function to the lpfc heart-beat mailbox command. * If configured, the lpfc driver issues the heart-beat mailbox command to * the HBA every LPFC_HB_MBOX_INTERVAL (current 5) seconds. At the time the * heart-beat mailbox command is issued, the driver shall set up heart-beat * timeout timer to LPFC_HB_MBOX_TIMEOUT (current 30) seconds and marks * heart-beat outstanding state. Once the mailbox command comes back and * no error conditions detected, the heart-beat mailbox command timer is * reset to LPFC_HB_MBOX_INTERVAL seconds and the heart-beat outstanding * state is cleared for the next heart-beat. If the timer expired with the * heart-beat outstanding state set, the driver will put the HBA offline.
**/ staticvoid
lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
{
clear_bit(HBA_HBEAT_INP, &phba->hba_flag);
clear_bit(HBA_HBEAT_TMO, &phba->hba_flag);
/* Check and reset heart-beat timer if necessary */
mempool_free(pmboxq, phba->mbox_mem_pool); if (!test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag) &&
!(phba->link_state == LPFC_HBA_ERROR) &&
!test_bit(FC_UNLOADING, &phba->pport->load_flag))
mod_timer(&phba->hb_tmofunc,
jiffies +
secs_to_jiffies(LPFC_HB_MBOX_INTERVAL)); return;
}
/* Skip if we've already handled this eq's primary CPU */ if (eq->chann != i) continue;
idle_stat = &phba->sli4_hba.idle_stat[i];
/* get_cpu_idle_time returns values as running counters. Thus, * to know the amount for this period, the prior counter values * need to be subtracted from the current counter values. * From there, the idle time stat can be calculated as a * percentage of 100 - the sum of the other consumption times.
*/
wall_idle = get_cpu_idle_time(i, &wall, 1);
diff_idle = wall_idle - idle_stat->prev_idle;
diff_wall = wall - idle_stat->prev_wall;
if (!phba->cfg_auto_imax ||
test_bit(FC_UNLOADING, &phba->pport->load_flag)) return;
if (phba->link_state == LPFC_HBA_ERROR ||
test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) goto requeue;
ena_delay = kcalloc(phba->sli4_hba.num_possible_cpu, sizeof(*ena_delay),
GFP_KERNEL); if (!ena_delay) goto requeue;
for (i = 0; i < phba->cfg_irq_chann; i++) { /* Get the EQ corresponding to the IRQ vector */
eq = phba->sli4_hba.hba_eq_hdl[i].eq; if (!eq) continue; if (eq->q_mode || eq->q_flag & HBA_EQ_DELAY_CHK) {
eq->q_flag &= ~HBA_EQ_DELAY_CHK;
ena_delay[eq->last_cpu] = 1;
}
}
/** * lpfc_hb_mxp_handler - Multi-XRI pools handler to adjust XRI distribution * @phba: pointer to lpfc hba data structure. * * For each heartbeat, this routine does some heuristic methods to adjust * XRI distribution. The goal is to fully utilize free XRIs.
**/ staticvoid lpfc_hb_mxp_handler(struct lpfc_hba *phba)
{
u32 i;
u32 hwq_count;
hwq_count = phba->cfg_hdw_queue; for (i = 0; i < hwq_count; i++) { /* Adjust XRIs in private pool */
lpfc_adjust_pvt_pool_count(phba, i);
/* Adjust high watermark */
lpfc_adjust_high_watermark(phba, i);
/** * lpfc_issue_hb_mbox - Issues heart-beat mailbox command * @phba: pointer to lpfc hba data structure. * * If a HB mbox is not already in progrees, this routine will allocate * a LPFC_MBOXQ_t, populate it with a MBX_HEARTBEAT (0x31) command, * and issue it. The HBA_HBEAT_INP flag means the command is in progress.
**/ int
lpfc_issue_hb_mbox(struct lpfc_hba *phba)
{
LPFC_MBOXQ_t *pmboxq; int retval;
/* Is a Heartbeat mbox already in progress */ if (test_bit(HBA_HBEAT_INP, &phba->hba_flag)) return 0;
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!pmboxq) return -ENOMEM;
/** * lpfc_issue_hb_tmo - Signals heartbeat timer to issue mbox command * @phba: pointer to lpfc hba data structure. * * The heartbeat timer (every 5 sec) will fire. If the HBA_HBEAT_TMO * flag is set, it will force a MBX_HEARTBEAT mbox command, regardless * of the value of lpfc_enable_hba_heartbeat. * If lpfc_enable_hba_heartbeat is set, the timeout routine will always * try to issue a MBX_HEARTBEAT mbox command.
**/ void
lpfc_issue_hb_tmo(struct lpfc_hba *phba)
{ if (phba->cfg_enable_hba_heartbeat) return;
set_bit(HBA_HBEAT_TMO, &phba->hba_flag);
}
/** * lpfc_hb_timeout_handler - The HBA-timer timeout handler * @phba: pointer to lpfc hba data structure. * * This is the actual HBA-timer timeout handler to be invoked by the worker * thread whenever the HBA timer fired and HBA-timeout event posted. This * handler performs any periodic operations needed for the device. If such * periodic event has already been attended to either in the interrupt handler * or by processing slow-ring or fast-ring events within the HBA-timer * timeout window (LPFC_HB_MBOX_INTERVAL), this handler just simply resets * the timer for the next timeout period. If lpfc heart-beat mailbox command * is configured and there is no heart-beat mailbox command outstanding, a * heart-beat mailbox is issued and timer set properly. Otherwise, if there * has been a heart-beat mailbox command outstanding, the HBA shall be put * to offline.
**/ void
lpfc_hb_timeout_handler(struct lpfc_hba *phba)
{ struct lpfc_vport **vports; struct lpfc_dmabuf *buf_ptr; int retval = 0; int i, tmo; struct lpfc_sli *psli = &phba->sli;
LIST_HEAD(completions);
if (phba->cfg_xri_rebalancing) { /* Multi-XRI pools handler */
lpfc_hb_mxp_handler(phba);
}
vports = lpfc_create_vport_work_array(phba); if (vports != NULL) for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
lpfc_rcv_seq_check_edtov(vports[i]);
lpfc_fdmi_change_check(vports[i]);
}
lpfc_destroy_vport_work_array(phba, vports);
/* If there is no heart beat outstanding, issue a heartbeat command */ if (phba->cfg_enable_hba_heartbeat) { /* If IOs are completing, no need to issue a MBX_HEARTBEAT */
spin_lock_irq(&phba->pport->work_port_lock); if (time_after(phba->last_completion_time +
secs_to_jiffies(LPFC_HB_MBOX_INTERVAL),
jiffies)) {
spin_unlock_irq(&phba->pport->work_port_lock); if (test_bit(HBA_HBEAT_INP, &phba->hba_flag))
tmo = (1000 * LPFC_HB_MBOX_TIMEOUT); else
tmo = (1000 * LPFC_HB_MBOX_INTERVAL); goto out;
}
spin_unlock_irq(&phba->pport->work_port_lock);
/* Check if a MBX_HEARTBEAT is already in progress */ if (test_bit(HBA_HBEAT_INP, &phba->hba_flag)) { /* * If heart beat timeout called with HBA_HBEAT_INP set * we need to give the hb mailbox cmd a chance to * complete or TMO.
*/
lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0459 Adapter heartbeat still outstanding: " "last compl time was %d ms.\n",
jiffies_to_msecs(jiffies
- phba->last_completion_time));
tmo = (1000 * LPFC_HB_MBOX_TIMEOUT);
} else { if ((!(psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) &&
(list_empty(&psli->mboxq))) {
retval = lpfc_issue_hb_mbox(phba); if (retval) {
tmo = (1000 * LPFC_HB_MBOX_INTERVAL); goto out;
}
phba->skipped_hb = 0;
} elseif (time_before_eq(phba->last_completion_time,
phba->skipped_hb)) {
lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "2857 Last completion time not " " updated in %d ms\n",
jiffies_to_msecs(jiffies
- phba->last_completion_time));
} else
phba->skipped_hb = jiffies;
tmo = (1000 * LPFC_HB_MBOX_TIMEOUT); goto out;
}
} else { /* Check to see if we want to force a MBX_HEARTBEAT */ if (test_bit(HBA_HBEAT_TMO, &phba->hba_flag)) {
retval = lpfc_issue_hb_mbox(phba); if (retval)
tmo = (1000 * LPFC_HB_MBOX_INTERVAL); else
tmo = (1000 * LPFC_HB_MBOX_TIMEOUT); goto out;
}
tmo = (1000 * LPFC_HB_MBOX_INTERVAL);
}
out:
mod_timer(&phba->hb_tmofunc, jiffies + msecs_to_jiffies(tmo));
}
/** * lpfc_offline_eratt - Bring lpfc offline on hardware error attention * @phba: pointer to lpfc hba data structure. * * This routine is called to bring the HBA offline when HBA hardware error * other than Port Error 6 has been detected.
**/ staticvoid
lpfc_offline_eratt(struct lpfc_hba *phba)
{ struct lpfc_sli *psli = &phba->sli;
/** * lpfc_sli4_offline_eratt - Bring lpfc offline on SLI4 hardware error attention * @phba: pointer to lpfc hba data structure. * * This routine is called to bring a SLI4 HBA offline when HBA hardware error * other than Port Error 6 has been detected.
**/ void
lpfc_sli4_offline_eratt(struct lpfc_hba *phba)
{
spin_lock_irq(&phba->hbalock); if (phba->link_state == LPFC_HBA_ERROR &&
test_bit(HBA_PCI_ERR, &phba->bit_flags)) {
spin_unlock_irq(&phba->hbalock); return;
}
phba->link_state = LPFC_HBA_ERROR;
spin_unlock_irq(&phba->hbalock);
/** * lpfc_handle_deferred_eratt - The HBA hardware deferred error handler * @phba: pointer to lpfc hba data structure. * * This routine is invoked to handle the deferred HBA hardware error * conditions. This type of error is indicated by HBA by setting ER1 * and another ER bit in the host status register. The driver will * wait until the ER1 bit clears before handling the error condition.
**/ staticvoid
lpfc_handle_deferred_eratt(struct lpfc_hba *phba)
{
uint32_t old_host_status = phba->work_hs; struct lpfc_sli *psli = &phba->sli;
/* If the pci channel is offline, ignore possible errors, * since we cannot communicate with the pci card anyway.
*/ if (pci_channel_offline(phba->pcidev)) {
clear_bit(DEFER_ERATT, &phba->hba_flag); return;
}
/* * Firmware stops when it triggred erratt. That could cause the I/Os * dropped by the firmware. Error iocb (I/O) on txcmplq and let the * SCSI layer retry it after re-establishing link.
*/
lpfc_sli_abort_fcp_rings(phba);
/* * There was a firmware error. Take the hba offline and then * attempt to restart it.
*/
lpfc_offline_prep(phba, LPFC_MBX_WAIT);
lpfc_offline(phba);
/* Wait for the ER1 bit to clear.*/ while (phba->work_hs & HS_FFER1) {
msleep(100); if (lpfc_readl(phba->HSregaddr, &phba->work_hs)) {
phba->work_hs = UNPLUG_ERR ; break;
} /* If driver is unloading let the worker thread continue */ if (test_bit(FC_UNLOADING, &phba->pport->load_flag)) {
phba->work_hs = 0; break;
}
}
/* * This is to ptrotect against a race condition in which * first write to the host attention register clear the * host status register.
*/ if (!phba->work_hs && !test_bit(FC_UNLOADING, &phba->pport->load_flag))
phba->work_hs = old_host_status & ~HS_FFER1;
/** * lpfc_handle_eratt_s3 - The SLI3 HBA hardware error handler * @phba: pointer to lpfc hba data structure. * * This routine is invoked to handle the following HBA hardware error * conditions: * 1 - HBA error attention interrupt * 2 - DMA ring index out of range * 3 - Mailbox command came back as unknown
**/ staticvoid
lpfc_handle_eratt_s3(struct lpfc_hba *phba)
{ struct lpfc_vport *vport = phba->pport; struct lpfc_sli *psli = &phba->sli;
uint32_t event_data; unsignedlong temperature; struct temp_event temp_event_data; struct Scsi_Host *shost;
/* If the pci channel is offline, ignore possible errors, * since we cannot communicate with the pci card anyway.
*/ if (pci_channel_offline(phba->pcidev)) {
clear_bit(DEFER_ERATT, &phba->hba_flag); return;
}
/* If resets are disabled then leave the HBA alone and return */ if (!phba->cfg_enable_hba_reset) return;
/* Send an internal error event to mgmt application */
lpfc_board_errevt_to_mgmt(phba);
if (test_bit(DEFER_ERATT, &phba->hba_flag))
lpfc_handle_deferred_eratt(phba);
/* * Firmware stops when it triggled erratt with HS_FFER6. * That could cause the I/Os dropped by the firmware. * Error iocb (I/O) on txcmplq and let the SCSI layer * retry it after re-establishing link.
*/
lpfc_sli_abort_fcp_rings(phba);
/* * There was a firmware error. Take the hba offline and then * attempt to restart it.
*/
lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT);
lpfc_offline(phba);
lpfc_sli_brdrestart(phba); if (lpfc_online(phba) == 0) { /* Initialize the HBA */
lpfc_unblock_mgmt_io(phba); return;
}
lpfc_unblock_mgmt_io(phba);
} elseif (phba->work_hs & HS_CRIT_TEMP) {
temperature = readl(phba->MBslimaddr + TEMPERATURE_OFFSET);
temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT;
temp_event_data.event_code = LPFC_CRIT_TEMP;
temp_event_data.data = (uint32_t)temperature;
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0406 Adapter maximum temperature exceeded " "(%ld), taking this port offline " "Data: x%x x%x x%x\n",
temperature, phba->work_hs,
phba->work_status[0], phba->work_status[1]);
} else { /* The if clause above forces this code path when the status * failure is a value other than FFER6. Do not call the offline * twice. This is the adapter hardware error path.
*/
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "0457 Adapter Hardware Error " "Data: x%x x%x x%x\n",
phba->work_hs,
phba->work_status[0], phba->work_status[1]);
/** * lpfc_sli4_port_sta_fn_reset - The SLI4 function reset due to port status reg * @phba: pointer to lpfc hba data structure. * @mbx_action: flag for mailbox shutdown action. * @en_rn_msg: send reset/port recovery message. * This routine is invoked to perform an SLI4 port PCI function reset in * response to port status register polling attention. It waits for port * status register (ERR, RDY, RN) bits before proceeding with function reset. * During this process, interrupt vectors are freed and later requested * for handling possible port resource change.
**/ staticint
lpfc_sli4_port_sta_fn_reset(struct lpfc_hba *phba, int mbx_action, bool en_rn_msg)
{ int rc;
uint32_t intr_mode;
LPFC_MBOXQ_t *mboxq;
/* Notifying the transport that the targets are going offline. */
lpfc_scsi_dev_block(phba);
if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >=
LPFC_SLI_INTF_IF_TYPE_2) { /* * On error status condition, driver need to wait for port * ready before performing reset.
*/
rc = lpfc_sli4_pdev_status_reg_wait(phba); if (rc) return rc;
}
/* need reset: attempt for port recovery */ if (en_rn_msg)
lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "2887 Reset Needed: Attempting Port " "Recovery...\n");
/* If we are no wait, the HBA has been reset and is not * functional, thus we should clear * (LPFC_SLI_ACTIVE | LPFC_SLI_MBOX_ACTIVE) flags.
*/ if (mbx_action == LPFC_MBX_NO_WAIT) {
spin_lock_irq(&phba->hbalock);
phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE; if (phba->sli.mbox_active) {
mboxq = phba->sli.mbox_active;
mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED;
__lpfc_mbox_cmpl_put(phba, mboxq);
phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
phba->sli.mbox_active = NULL;
}
spin_unlock_irq(&phba->hbalock);
}
lpfc_offline_prep(phba, mbx_action);
lpfc_sli_flush_io_rings(phba);
lpfc_nvmels_flush_cmd(phba);
lpfc_offline(phba); /* release interrupt for possible resource change */
lpfc_sli4_disable_intr(phba);
rc = lpfc_sli_brdrestart(phba); if (rc) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "6309 Failed to restart board\n"); return rc;
} /* request and enable interrupt */
intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); if (intr_mode == LPFC_INTR_ERROR) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3175 Failed to enable interrupt\n"); return -EIO;
}
phba->intr_mode = intr_mode;
rc = lpfc_online(phba); if (rc == 0)
lpfc_unblock_mgmt_io(phba);
/* If the pci channel is offline, ignore possible errors, since * we cannot communicate with the pci card anyway.
*/ if (pci_channel_offline(phba->pcidev)) {
lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT, "3166 pci channel is offline\n");
lpfc_sli_flush_io_rings(phba); return;
}
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.