/drivers/scsi/lpfc/lpfc_init.c
C | 14064 lines | 9295 code | 1414 blank | 3355 comment | 1383 complexity | 79910e1fdb09cd24495d6340221fbfd4 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, LGPL-2.0
Large files files are truncated, but you can click here to view the full file
- /*******************************************************************
- * This file is part of the Emulex Linux Device Driver for *
- * Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2020 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. *
- *******************************************************************/
- #include <linux/blkdev.h>
- #include <linux/delay.h>
- #include <linux/dma-mapping.h>
- #include <linux/idr.h>
- #include <linux/interrupt.h>
- #include <linux/module.h>
- #include <linux/kthread.h>
- #include <linux/pci.h>
- #include <linux/spinlock.h>
- #include <linux/ctype.h>
- #include <linux/aer.h>
- #include <linux/slab.h>
- #include <linux/firmware.h>
- #include <linux/miscdevice.h>
- #include <linux/percpu.h>
- #include <linux/msi.h>
- #include <linux/irq.h>
- #include <linux/bitops.h>
- #include <linux/crash_dump.h>
- #include <linux/cpu.h>
- #include <linux/cpuhotplug.h>
- #include <scsi/scsi.h>
- #include <scsi/scsi_device.h>
- #include <scsi/scsi_host.h>
- #include <scsi/scsi_transport_fc.h>
- #include <scsi/scsi_tcq.h>
- #include <scsi/fc/fc_fs.h>
- #include <linux/nvme-fc-driver.h>
- #include "lpfc_hw4.h"
- #include "lpfc_hw.h"
- #include "lpfc_sli.h"
- #include "lpfc_sli4.h"
- #include "lpfc_nl.h"
- #include "lpfc_disc.h"
- #include "lpfc.h"
- #include "lpfc_scsi.h"
- #include "lpfc_nvme.h"
- #include "lpfc_nvmet.h"
- #include "lpfc_logmsg.h"
- #include "lpfc_crtn.h"
- #include "lpfc_vport.h"
- #include "lpfc_version.h"
- #include "lpfc_ids.h"
- static enum cpuhp_state lpfc_cpuhp_state;
- /* Used when mapping IRQ vectors in a driver centric manner */
- static uint32_t lpfc_present_cpu;
- static void __lpfc_cpuhp_remove(struct lpfc_hba *phba);
- static void lpfc_cpuhp_remove(struct lpfc_hba *phba);
- static void lpfc_cpuhp_add(struct lpfc_hba *phba);
- static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *);
- static int lpfc_post_rcv_buf(struct lpfc_hba *);
- static int lpfc_sli4_queue_verify(struct lpfc_hba *);
- static int lpfc_create_bootstrap_mbox(struct lpfc_hba *);
- static int lpfc_setup_endian_order(struct lpfc_hba *);
- static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *);
- static void lpfc_free_els_sgl_list(struct lpfc_hba *);
- static void lpfc_free_nvmet_sgl_list(struct lpfc_hba *);
- static void lpfc_init_sgl_list(struct lpfc_hba *);
- static int lpfc_init_active_sgl_array(struct lpfc_hba *);
- static void lpfc_free_active_sgl(struct lpfc_hba *);
- static int lpfc_hba_down_post_s3(struct lpfc_hba *phba);
- static int lpfc_hba_down_post_s4(struct lpfc_hba *phba);
- static int lpfc_sli4_cq_event_pool_create(struct lpfc_hba *);
- static void lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *);
- static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *);
- static void lpfc_sli4_disable_intr(struct lpfc_hba *);
- static uint32_t lpfc_sli4_enable_intr(struct lpfc_hba *, uint32_t);
- static void lpfc_sli4_oas_verify(struct lpfc_hba *phba);
- static uint16_t lpfc_find_cpu_handle(struct lpfc_hba *, uint16_t, int);
- static void lpfc_setup_bg(struct lpfc_hba *, struct Scsi_Host *);
- static struct scsi_transport_template *lpfc_transport_template = NULL;
- static struct scsi_transport_template *lpfc_vport_transport_template = NULL;
- static DEFINE_IDR(lpfc_hba_index);
- #define LPFC_NVMET_BUF_POST 254
- /**
- * 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;
- static char licensed[56] =
- "key unlock for use with gnu public licensed code only\0";
- static int init_key = 1;
- pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!pmb) {
- phba->link_state = LPFC_HBA_ERROR;
- return -ENOMEM;
- }
- mb = &pmb->u.mb;
- phba->link_state = LPFC_INIT_MBX_CMDS;
- if (lpfc_is_LC_HBA(phba->pcidev->device)) {
- if (init_key) {
- uint32_t *ptext = (uint32_t *) licensed;
- for (i = 0; i < 56; i += sizeof (uint32_t), ptext++)
- *ptext = cpu_to_be32(*ptext);
- init_key = 0;
- }
- lpfc_read_nv(phba, pmb);
- memset((char*)mb->un.varRDnvp.rsvd3, 0,
- sizeof (mb->un.varRDnvp.rsvd3));
- memcpy((char*)mb->un.varRDnvp.rsvd3, licensed,
- sizeof (licensed));
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
- if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "0324 Config Port initialization "
- "error, mbxCmd x%x READ_NVPARM, "
- "mbxStatus x%x\n",
- mb->mbxCommand, mb->mbxStatus);
- mempool_free(pmb, phba->mbox_mem_pool);
- return -ERESTART;
- }
- memcpy(phba->wwnn, (char *)mb->un.varRDnvp.nodename,
- sizeof(phba->wwnn));
- memcpy(phba->wwpn, (char *)mb->un.varRDnvp.portname,
- sizeof(phba->wwpn));
- }
- /*
- * 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;
- /* Setup and issue mailbox READ REV command */
- lpfc_read_rev(phba, pmb);
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
- if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0439 Adapter failed to init, mbxCmd x%x "
- "READ_REV, mbxStatus x%x\n",
- mb->mbxCommand, mb->mbxStatus);
- mempool_free( pmb, phba->mbox_mem_pool);
- return -ERESTART;
- }
- /*
- * 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_INIT,
- "0440 Adapter failed to init, READ_REV has "
- "missing revision information.\n");
- mempool_free(pmb, phba->mbox_mem_pool);
- return -ERESTART;
- }
- if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp) {
- mempool_free(pmb, phba->mbox_mem_pool);
- return -EINVAL;
- }
- /* Save information as VPD data */
- vp->rev.rBit = 1;
- memcpy(&vp->sli3Feat, &mb->un.varRdRev.sli3Feat, sizeof(uint32_t));
- vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev;
- memcpy(vp->rev.sli1FwName, (char*) mb->un.varRdRev.sli1FwName, 16);
- vp->rev.sli2FwRev = mb->un.varRdRev.sli2FwRev;
- memcpy(vp->rev.sli2FwName, (char *) mb->un.varRdRev.sli2FwName, 16);
- vp->rev.biuRev = mb->un.varRdRev.biuRev;
- vp->rev.smRev = mb->un.varRdRev.smRev;
- vp->rev.smFwRev = mb->un.varRdRev.un.smFwRev;
- vp->rev.endecRev = mb->un.varRdRev.endecRev;
- vp->rev.fcphHigh = mb->un.varRdRev.fcphHigh;
- vp->rev.fcphLow = mb->un.varRdRev.fcphLow;
- vp->rev.feaLevelHigh = mb->un.varRdRev.feaLevelHigh;
- vp->rev.feaLevelLow = mb->un.varRdRev.feaLevelLow;
- vp->rev.postKernRev = mb->un.varRdRev.postKernRev;
- vp->rev.opFwRev = mb->un.varRdRev.opFwRev;
- /* 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;
- if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset)
- mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset;
- lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET,
- lpfc_vpd_data + offset,
- mb->un.varDmp.word_cnt);
- offset += mb->un.varDmp.word_cnt;
- } while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE);
- lpfc_parse_vpd(phba, lpfc_vpd_data, offset);
- kfree(lpfc_vpd_data);
- out_free_mbox:
- mempool_free(pmb, phba->mbox_mem_pool);
- return 0;
- }
- /**
- * 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.
- **/
- static void
- 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.
- **/
- static void
- 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 */
- if (prg->dist < 4)
- dist = dist_char[prg->dist];
- if ((prg->dist == 3) && (prg->num == 0))
- snprintf(phba->OptionROMVersion, 32, "%d.%d%d",
- prg->ver, prg->rev, prg->lev);
- else
- snprintf(phba->OptionROMVersion, 32, "%d.%d%d%c%d",
- prg->ver, prg->rev, prg->lev,
- dist, prg->num);
- mempool_free(pmboxq, phba->mbox_mem_pool);
- return;
- }
- /**
- * lpfc_update_vport_wwn - Updates the fc_nodename, fc_portname,
- * cfg_soft_wwnn, cfg_soft_wwpn
- * @vport: pointer to lpfc vport data structure.
- *
- *
- * Return codes
- * None.
- **/
- void
- lpfc_update_vport_wwn(struct lpfc_vport *vport)
- {
- uint8_t vvvl = vport->fc_sparam.cmn.valid_vendor_ver_level;
- u32 *fawwpn_key = (u32 *)&vport->fc_sparam.un.vendorVersion[0];
- /* If the soft name exists then update it using the service params */
- if (vport->phba->cfg_soft_wwnn)
- u64_to_wwn(vport->phba->cfg_soft_wwnn,
- vport->fc_sparam.nodeName.u.wwn);
- if (vport->phba->cfg_soft_wwpn)
- u64_to_wwn(vport->phba->cfg_soft_wwpn,
- vport->fc_sparam.portName.u.wwn);
- /*
- * 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 || vport->phba->cfg_soft_wwnn)
- 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;
- if (vport->fc_portname.u.wwn[0] == 0 ||
- vport->phba->cfg_soft_wwpn ||
- (vvvl == 1 && cpu_to_be32(*fawwpn_key) == FAPWWN_KEY_VENDOR) ||
- vport->vport_flag & FAWWPN_SET) {
- memcpy(&vport->fc_portname, &vport->fc_sparam.portName,
- sizeof(struct lpfc_name));
- vport->vport_flag &= ~FAWWPN_SET;
- if (vvvl == 1 && cpu_to_be32(*fawwpn_key) == FAPWWN_KEY_VENDOR)
- vport->vport_flag |= FAWWPN_SET;
- }
- else
- memcpy(&vport->fc_sparam.portName, &vport->fc_portname,
- sizeof(struct lpfc_name));
- }
- /**
- * 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);
- pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!pmb) {
- phba->link_state = LPFC_HBA_ERROR;
- return -ENOMEM;
- }
- mb = &pmb->u.mb;
- /* Get login parameters for NID. */
- rc = lpfc_read_sparam(phba, pmb, 0);
- if (rc) {
- mempool_free(pmb, phba->mbox_mem_pool);
- return -ENOMEM;
- }
- pmb->vport = vport;
- if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0448 Adapter failed init, mbxCmd x%x "
- "READ_SPARM mbxStatus x%x\n",
- mb->mbxCommand, mb->mbxStatus);
- phba->link_state = LPFC_HBA_ERROR;
- mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
- mempool_free(pmb, phba->mbox_mem_pool);
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- return -EIO;
- }
- mp = (struct lpfc_dmabuf *)pmb->ctx_buf;
- 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;
- outptr = &vport->fc_nodename.u.s.IEEE[0];
- for (i = 0; i < 12; i++) {
- status = *outptr++;
- j = ((status & 0xf0) >> 4);
- if (j <= 9)
- phba->SerialNumber[i] =
- (char)((uint8_t) 0x30 + (uint8_t) j);
- else
- phba->SerialNumber[i] =
- (char)((uint8_t) 0x61 + (uint8_t) (j - 10));
- i++;
- j = (status & 0xf);
- if (j <= 9)
- phba->SerialNumber[i] =
- (char)((uint8_t) 0x30 + (uint8_t) j);
- else
- phba->SerialNumber[i] =
- (char)((uint8_t) 0x61 + (uint8_t) (j - 10));
- }
- }
- lpfc_read_config(phba, pmb);
- pmb->vport = vport;
- if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0453 Adapter failed to init, mbxCmd x%x "
- "READ_CONFIG, mbxStatus x%x\n",
- mb->mbxCommand, mb->mbxStatus);
- phba->link_state = LPFC_HBA_ERROR;
- mempool_free( pmb, phba->mbox_mem_pool);
- return -EIO;
- }
- /* 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);
- /*
- * Configure HBA MSI-X attention conditions to messages if MSI-X mode
- */
- if (phba->intr_type == MSIX) {
- rc = lpfc_config_msi(phba, pmb);
- if (rc) {
- mempool_free(pmb, phba->mbox_mem_pool);
- return -EIO;
- }
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL);
- if (rc != MBX_SUCCESS) {
- lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
- "0352 Config MSI mailbox command "
- "failed, mbxCmd x%x, mbxStatus x%x\n",
- pmb->u.mb.mbxCommand,
- pmb->u.mb.mbxStatus);
- mempool_free(pmb, phba->mbox_mem_pool);
- return -EIO;
- }
- }
- spin_lock_irq(&phba->hbalock);
- /* Initialize ERATT handling flag */
- phba->hba_flag &= ~HBA_ERATT_HANDLED;
- /* 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);
- writel(status, phba->HCregaddr);
- readl(phba->HCregaddr); /* flush */
- spin_unlock_irq(&phba->hbalock);
- /* Set up ring-0 (ELS) timer */
- timeout = phba->fc_ratov * 2;
- mod_timer(&vport->els_tmofunc,
- jiffies + msecs_to_jiffies(1000 * timeout));
- /* Set up heart beat (HB) timer */
- mod_timer(&phba->hb_tmofunc,
- jiffies + msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL));
- phba->hb_outstanding = 0;
- phba->last_completion_time = jiffies;
- /* Set up error attention (ERATT) polling timer */
- mod_timer(&phba->eratt_poll,
- jiffies + msecs_to_jiffies(1000 * phba->eratt_poll_interval));
- if (phba->hba_flag & LINK_DISABLED) {
- lpfc_printf_log(phba,
- KERN_ERR, LOG_INIT,
- "2598 Adapter Link is disabled.\n");
- lpfc_down_link(phba, pmb);
- pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
- if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
- lpfc_printf_log(phba,
- KERN_ERR, LOG_INIT,
- "2599 Adapter failed to issue DOWN_LINK"
- " mbox command rc 0x%x\n", rc);
- mempool_free(pmb, phba->mbox_mem_pool);
- return -EIO;
- }
- } else if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) {
- mempool_free(pmb, phba->mbox_mem_pool);
- rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
- if (rc)
- return rc;
- }
- /* MBOX buffer will be freed in mbox compl */
- pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!pmb) {
- phba->link_state = LPFC_HBA_ERROR;
- return -ENOMEM;
- }
- lpfc_config_async(phba, pmb, LPFC_ELS_RING);
- pmb->mbox_cmpl = lpfc_config_async_cmpl;
- pmb->vport = phba->pport;
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
- if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_INIT,
- "0456 Adapter failed to issue "
- "ASYNCEVT_ENABLE mbox status x%x\n",
- rc);
- mempool_free(pmb, phba->mbox_mem_pool);
- }
- /* Get Option rom version */
- pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!pmb) {
- phba->link_state = LPFC_HBA_ERROR;
- return -ENOMEM;
- }
- lpfc_dump_wakeup_param(phba, pmb);
- pmb->mbox_cmpl = lpfc_dump_wakeup_param_cmpl;
- pmb->vport = phba->pport;
- rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
- if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0435 Adapter failed "
- "to get Option ROM version status x%x\n", rc);
- mempool_free(pmb, phba->mbox_mem_pool);
- }
- return 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
- **/
- static int
- 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;
- pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!pmb) {
- phba->link_state = LPFC_HBA_ERROR;
- return -ENOMEM;
- }
- mb = &pmb->u.mb;
- pmb->vport = vport;
- if ((phba->cfg_link_speed > LPFC_USER_LINK_SPEED_MAX) ||
- ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_1G) &&
- !(phba->lmt & LMT_1Gb)) ||
- ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_2G) &&
- !(phba->lmt & LMT_2Gb)) ||
- ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_4G) &&
- !(phba->lmt & LMT_4Gb)) ||
- ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_8G) &&
- !(phba->lmt & LMT_8Gb)) ||
- ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_10G) &&
- !(phba->lmt & LMT_10Gb)) ||
- ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G) &&
- !(phba->lmt & LMT_16Gb)) ||
- ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_32G) &&
- !(phba->lmt & LMT_32Gb)) ||
- ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_64G) &&
- !(phba->lmt & LMT_64Gb))) {
- /* Reset link speed to auto */
- lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT,
- "1302 Invalid speed for this board:%d "
- "Reset link speed to auto.\n",
- phba->cfg_link_speed);
- phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO;
- }
- lpfc_init_link(phba, pmb, fc_topology, phba->cfg_link_speed);
- pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- if (phba->sli_rev < LPFC_SLI_REV4)
- lpfc_set_loopback_flag(phba);
- rc = lpfc_sli_issue_mbox(phba, pmb, flag);
- if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0498 Adapter failed to init, mbxCmd x%x "
- "INIT_LINK, mbxStatus x%x\n",
- mb->mbxCommand, mb->mbxStatus);
- if (phba->sli_rev <= LPFC_SLI_REV3) {
- /* Clear all interrupt enable conditions */
- writel(0, phba->HCregaddr);
- readl(phba->HCregaddr); /* flush */
- /* Clear all pending interrupts */
- writel(0xffffffff, phba->HAregaddr);
- readl(phba->HAregaddr); /* flush */
- }
- phba->link_state = LPFC_HBA_ERROR;
- if (rc != MBX_BUSY || flag == MBX_POLL)
- mempool_free(pmb, phba->mbox_mem_pool);
- return -EIO;
- }
- phba->cfg_suppress_link_up = LPFC_INITIALIZE_LINK;
- if (flag == MBX_POLL)
- mempool_free(pmb, phba->mbox_mem_pool);
- return 0;
- }
- /**
- * 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
- **/
- static int
- lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag)
- {
- LPFC_MBOXQ_t *pmb;
- int rc;
- pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
- if (!pmb) {
- phba->link_state = LPFC_HBA_ERROR;
- return -ENOMEM;
- }
- lpfc_printf_log(phba,
- KERN_ERR, LOG_INIT,
- "0491 Adapter Link is disabled.\n");
- lpfc_down_link(phba, pmb);
- pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- rc = lpfc_sli_issue_mbox(phba, pmb, flag);
- if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) {
- lpfc_printf_log(phba,
- KERN_ERR, LOG_INIT,
- "2522 Adapter failed to issue DOWN_LINK"
- " mbox command rc 0x%x\n", rc);
- mempool_free(pmb, phba->mbox_mem_pool);
- return -EIO;
- }
- if (flag == MBX_POLL)
- mempool_free(pmb, phba->mbox_mem_pool);
- return 0;
- }
- /**
- * 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 (phba->sli_rev <= LPFC_SLI_REV3) {
- /* Disable interrupts */
- writel(0, phba->HCregaddr);
- readl(phba->HCregaddr); /* flush */
- }
- if (phba->pport->load_flag & FC_UNLOADING)
- 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.
- **/
- static void
- lpfc_sli4_free_sp_events(struct lpfc_hba *phba)
- {
- struct lpfc_iocbq *rspiocbq;
- struct hbq_dmabuf *dmabuf;
- struct lpfc_cq_event *cq_event;
- spin_lock_irq(&phba->hbalock);
- phba->hba_flag &= ~HBA_SP_QUEUE_EVT;
- spin_unlock_irq(&phba->hbalock);
- 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.
- **/
- static void
- 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);
- count = 0;
- list_for_each_entry_safe(mp, next_mp, &buflist, list) {
- list_del(&mp->list);
- count++;
- lpfc_mbuf_free(phba, mp->virt, mp->phys);
- kfree(mp);
- }
- spin_lock_irq(&phba->hbalock);
- pring->postbufq_cnt -= count;
- 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
- **/
- static void
- 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->iocb_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
- int i;
- * @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.
- **/
- static int
- 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.
- **/
- static int
- lpfc_hba_down_post_s4(struct lpfc_hba *phba)
- {
- struct lpfc_io_buf *psb, *psb_next;
- struct lpfc_nvmet_rcv_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;
- lpfc_sli_hbqbuf_free_all(phba);
- lpfc_hba_clean_txcmplq(phba);
- /* 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.
- */
- spin_lock_irq(&phba->hbalock); /* required for lpfc_els_sgl_list and */
- /* scsl_buf_list */
- /* sgl_list_lock required because worker thread uses this
- * list.
- */
- spin_lock(&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;
- list_splice_init(&phba->sli4_hba.lpfc_abts_els_sgl_list,
- &phba->sli4_hba.lpfc_els_sgl_list);
- spin_unlock(&phba->sli4_hba.sgl_list_lock);
- /* abts_xxxx_buf_list_lock required because worker thread uses this
- * list.
- */
- cnt = 0;
- for (idx = 0; idx < phba->cfg_hdw_queue; idx++) {
- qp = &phba->sli4_hba.hdwq[idx];
- spin_lock(&qp->abts_io_buf_list_lock);
- list_splice_init(&qp->lpfc_abts_io_buf_list,
- &aborts);
- list_for_each_entry_safe(psb, psb_next, &aborts, list) {
- psb->pCmd = NULL;
- psb->status = IOSTAT_SUCCESS;
- cnt++;
- }
- spin_lock(&qp->io_buf_list_put_lock);
- list_splice_init(&aborts, &qp->lpfc_io_buf_list_put);
- qp->put_io_bufs += qp->abts_scsi_io_bufs;
- qp->put_io_bufs += qp->abts_nvme_io_bufs;
- qp->abts_scsi_io_bufs = 0;
- qp->abts_nvme_io_bufs = 0;
- spin_unlock(&qp->io_buf_list_put_lock);
- spin_unlock(&qp->abts_io_buf_list_lock);
- }
- spin_unlock_irq(&phba->hbalock);
- if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) {
- spin_lock_irq(&phba->sli4_hba.abts_nvmet_buf_list_lock);
- list_splice_init(&phba->sli4_hba.lpfc_abts_nvmet_ctx_list,
- &nvmet_aborts);
- spin_unlock_irq(&phba->sli4_hba.abts_nvmet_buf_list_lock);
- list_for_each_entry_safe(ctxp, ctxp_next, &nvmet_aborts, list) {
- ctxp->flag &= ~(LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP);
- lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf);
- }
- }
- lpfc_sli4_free_sp_events(phba);
- return cnt;
- }
- /**
- * 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
- * @ptr: unsigned long holds 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.
- **/
- static void
- lpfc_hb_timeout(struct timer_list *t)
- {
- struct lpfc_hba *phba;
- uint32_t tmo_posted;
- unsigned long iflag;
- phba = from_timer(phba, t, hb_tmofunc);
- /* Check for heart beat timeout conditions */
- spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
- tmo_posted = phba->pport->work_port_events & WORKER_HB_TMO;
- if (!tmo_posted)
- phba->pport->work_port_events |= WORKER_HB_TMO;
- spin_unlock_irqrestore(&phba->pport->work_port_lock, 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
- * @ptr: unsigned long holds 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.
- **/
- static void
- lpfc_rrq_timeout(struct timer_list *t)
- {
- struct lpfc_hba *phba;
- unsigned long iflag;
- phba = from_timer(phba, t, rrq_tmr);
- spin_lock_irqsave(&phba->pport->work_port_lock, iflag);
- if (!(phba->pport->load_flag & FC_UNLOADING))
- phba->hba_flag |= HBA_RRQ_ACTIVE;
- else
- phba->hba_flag &= ~HBA_RRQ_ACTIVE;
- spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag);
- if (!(phba->pport->load_flag & FC_UNLOADING))
- lpfc_worker_wake_up(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.
- **/
- static void
- lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq)
- {
- unsigned long drvr_flag;
- spin_lock_irqsave(&phba->hbalock, drvr_flag);
- phba->hb_outstanding = 0;
- spin_unlock_irqrestore(&phba->hbalock, drvr_flag);
- /* Check and reset heart-beat timer is necessary */
- mempool_free(pmboxq, phba->mbox_mem_pool);
- if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) &&
- !(phba->link_state == LPFC_HBA_ERROR) &&
- !(phba->pport->load_flag & FC_UNLOADING))
- mod_timer(&phba->hb_tmofunc,
- jiffies +
- msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL));
- return;
- }
- static void
- lpfc_hb_eq_delay_work(struct work_struct *work)
- {
- struct lpfc_hba *phba = container_of(to_delayed_work(work),
- struct lpfc_hba, eq_delay_work);
- struct lpfc_eq_intr_info *eqi, *eqi_new;
- struct lpfc_queue *eq, *eq_next;
- unsigned char *ena_delay = NULL;
- uint32_t usdelay;
- int i;
- if (!phba->cfg_auto_imax || phba->pport->load_flag & FC_UNLOADING)
- return;
- if (phba->link_state == LPFC_HBA_ERROR ||
- phba->pport->fc_flag & FC_OFFLINE_MODE)
- 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;
- }
- }
- for_each_present_cpu(i) {
- eqi = per_cpu_ptr(phba->sli4_hba.eq_info, i);
- if (ena_delay[i]) {
- usdelay = (eqi->icnt >> 10) * LPFC_EQ_DELAY_STEP;
- if (usdelay > LPFC_MAX_AUTO_EQ_DELAY)
- usdelay = LPFC_MAX_AUTO_EQ_DELAY;
- } else {
- usdelay = 0;
- }
- eqi->icnt = 0;
- list_for_each_entry_safe(eq, eq_next, &eqi->list, cpu_list) {
- if (unlikely(eq->last_cpu != i)) {
- eqi_new = per_cpu_ptr(phba->sli4_hba.eq_info,
- eq->last_cpu);
- list_move_tail(&eq->cpu_list, &eqi_new->list);
- continue;
- }
- if (usdelay != eq->q_mode)
- lpfc_modify_hba_eq_delay(phba, eq->hdwq, 1,
- usdelay);
- }
- }
- kfree(ena_delay);
- requeue:
- queue_delayed_work(phba->wq, &phba->eq_delay_work,
- msecs_to_jiffies(LPFC_EQ_DELAY_MSECS));
- }
- /**
- * 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.
- **/
- static void 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);
- #ifdef LPFC_MXP_STAT
- /* Snapshot pbl, pvt and busy count */
- lpfc_snapshot_mxp(phba, i);
- #endif
- }
- }
- /**
- * 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;
- LPFC_MBOXQ_t *pmboxq;
- struct lpfc_dmabuf *buf_ptr;
- int retval, i;
- 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 ((phba->link_state == LPFC_HBA_ERROR) ||
- (phba->pport->load_flag & FC_UNLOADING) ||
- (phba->pport->fc_flag & FC_OFFLINE_MODE))
- return;
- spin_lock_irq(&phba->pport->work_port_lock);
- if (time_after(phba->last_completion_time +
- msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL),
- jiffies)) {
- spin_unlock_irq(&phba->pport->work_port_lock);
- if (!phba->hb_outstanding)
- mod_timer(&phba->hb_tmofunc,
- jiffies +
- msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL));
- else
- mod_timer(&phba->hb_tmofunc,
- jiffies +
- msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT));
- return;
- }
- spin_unlock_irq(&phba->pport->work_port_lock);
- if (phba->elsbuf_cnt &&
- (phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) {
- spin_lock_irq(&phba->hbalock);
- list_splice_init(&phba->elsbuf, &completions);
- phba->elsbuf_cnt = 0;
- phba->elsbuf_prev_cnt = 0;
- spin_unlock_irq(&phba->hbalock);
- while (!list_empty(&completions)) {
- list_remove_head(&completions, buf_ptr,
- struct lpfc_dmabuf, list);
- lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys);
- kfree(buf_ptr);
- }
- }
- phba->elsbuf_prev_cnt = phba->elsbuf_cnt;
- /* If there is no heart beat outstanding, issue a heartbeat command */
- if (phba->cfg_enable_hba_heartbeat) {
- if (!phba->hb_outstanding) {
- if ((!(psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) &&
- (list_empty(&psli->mboxq))) {
- pmboxq = mempool_alloc(phba->mbox_mem_pool,
- GFP_KERNEL);
- if (!pmboxq) {
- mod_timer(&phba->hb_tmofunc,
- jiffies +
- msecs_to_jiffies(1000 *
- LPFC_HB_MBOX_INTERVAL));
- return;
- }
- lpfc_heart_beat(phba, pmboxq);
- pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl;
- pmboxq->vport = phba->pport;
- retval = lpfc_sli_issue_mbox(phba, pmboxq,
- MBX_NOWAIT);
- if (retval != MBX_BUSY &&
- retval != MBX_SUCCESS) {
- mempool_free(pmboxq,
- phba->mbox_mem_pool);
- mod_timer(&phba->hb_tmofunc,
- jiffies +
- msecs_to_jiffies(1000 *
- LPFC_HB_MBOX_INTERVAL));
- return;
- }
- phba->skipped_hb = 0;
- phba->hb_outstanding = 1;
- } else if (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;
- mod_timer(&phba->hb_tmofunc,
- jiffies +
- msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT));
- return;
- } else {
- /*
- * If heart beat timeout called with hb_outstanding 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 out"
- "standing:last compl time was %d ms.\n",
- jiffies_to_msecs(jiffies
- - phba->last_completion_time));
- mod_timer(&phba->hb_tmofunc,
- jiffies +
- msecs_to_jiffies(1000 * LPFC_HB_MBOX_TIMEOUT));
- }
- } else {
- mod_timer(&phba->hb_tmofunc,
- jiffies +
- msecs_to_jiffies(1000 * LPFC_HB_MBOX_INTERVAL));
- }
- }
- /**
- * 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.
- **/
- static void
- lpfc_offline_eratt(struct lpfc_hba *phba)
- {
- struct lpfc_sli *psli = &phba->sli;
- spin_lock_irq(&phba->hbalock);
- psli->sli_flag &= ~LPFC_SLI_ACTIVE;
- spin_unlock_irq(&phba->hbalock);
- lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT);
- lpfc_offline(phba);
- lpfc_reset_barrier(phba);
- spin_lock_irq(&phba->hbalock);
- lpfc_sli_brdreset(phba);
- spin_unlock_irq(&phba->hbalock);
- lpfc_hba_down_post(phba);
- lpfc_sli_brdready(phba, HS_MBRDY);
- lpfc_unblock_mgmt_io(phba);
- phba->link_state = LPFC_HBA_ERROR;
- return;
- }
- /**
- * 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);
- phba->link_state = LPFC_HBA_ERROR;
- spin_unlock_irq(&phba->hbalock);
- lpfc_offline_prep(phba, LPFC_MBX_NO_WAIT);
- lpfc_sli_flush_io_rings(phba);
- lpfc_offline(phba);
- lpfc_hba_down_post(phba);
- lpfc_unblock_mgmt_io(phba);
- }
- /**
- * 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.
- **/
- static void
- 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)) {
- spin_lock_irq(&phba->hbalock);
- phba->hba_flag &= ~DEFER_ERATT;
- spin_unlock_irq(&phba->hbalock);
- return;
- }
- lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
- "0479 Deferred Adapter Hardware Error "
- "Data: x%x x%x x%x\n",
- phba->work_hs,
- phba->work_status[0], phba->work_status[1]);
- spin_lock_irq(&phba->hbalock);
- psli->sli_flag &= ~LPFC_SLI_ACTIVE;
- spin_unlock_irq(&phba->hbalock);
- /*
- * 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 (phba->pport->load_flag & FC_UNLOADING) {
- 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) && (!(phba->pport->load_flag & FC_UNLOADING)))
- phba->work_hs = old_host_status & ~HS_FFER1;
- spin_lock_irq(&phba->hbalock);
- phba->hba_flag &= ~DEFER_ERATT;
- spin_unlock_irq(&phba->hbalock);
- phba->work_status[0] = readl(phba->MBslimaddr + 0xa8);
- phba->work_status[1] = readl(phba->MBslimaddr + 0xac);
- }
- static void
- lpfc_board_errevt_to_mgmt(struct lpfc_hba *phba)
- {
- struct lpfc_board_event_header board_event;
- struct Scsi_Host *shost;
- board_event.event_type = FC_REG_BOARD_EVENT;
- board_event.subcategory = LPFC_EVENT_PORTINTERR;
- shost = lpfc_shost_from_vport(phba->pport);
- fc_host_post_vendor_event(shost, fc_get_event_number(),
- sizeof(board_event),
- (char *) &board_event,
- LPFC_NL_VENDOR_ID);
- }
- /**
- * 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
- **/
- static void
- lpfc_handle_eratt_s3(struct lpfc_hba *phba)
- {
- struct lpfc_vport *vport = phba->pport;
- struct lpfc_sli *psli = &phba->sli;
- uint32_t event_data;
- unsigned long 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 …
Large files files are truncated, but you can click here to view the full file