Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/scsi/lpfc/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 222 kB image not shown  

Quelle  lpfc_attr.c   Sprache: C

 
/*******************************************************************
 * 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.                                     *
 *******************************************************************/


#include <linux/ctype.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/aer.h>
#include <linux/gfp.h>
#include <linux/kernel.h>

#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/fc/fc_fs.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_logmsg.h"
#include "lpfc_version.h"
#include "lpfc_compat.h"
#include "lpfc_crtn.h"
#include "lpfc_vport.h"
#include "lpfc_attr.h"

#define LPFC_DEF_DEVLOSS_TMO 30
#define LPFC_MIN_DEVLOSS_TMO 1
#define LPFC_MAX_DEVLOSS_TMO 255

#define LPFC_MAX_INFO_TMP_LEN 100
#define LPFC_INFO_MORE_STR "\nCould be more info...\n"
/*
 * Write key size should be multiple of 4. If write key is changed
 * make sure that library write key is also changed.
 */

#define LPFC_REG_WRITE_KEY_SIZE 4
#define LPFC_REG_WRITE_KEY "EMLX"

const char *const trunk_errmsg[] = { /* map errcode */
 ""/* There is no such error code at index 0*/
 "link negotiated speed does not match existing"
  " trunk - link was \"low\" speed",
 "link negotiated speed does not match"
  " existing trunk - link was \"middle\" speed",
 "link negotiated speed does not match existing"
  " trunk - link was \"high\" speed",
 "Attached to non-trunking port - F_Port",
 "Attached to non-trunking port - N_Port",
 "FLOGI response timeout",
 "non-FLOGI frame received",
 "Invalid FLOGI response",
 "Trunking initialization protocol",
 "Trunk peer device mismatch",
};

/**
 * lpfc_jedec_to_ascii - Hex to ascii convertor according to JEDEC rules
 * @incr: integer to convert.
 * @hdw: ascii string holding converted integer plus a string terminator.
 *
 * Description:
 * JEDEC Joint Electron Device Engineering Council.
 * Convert a 32 bit integer composed of 8 nibbles into an 8 byte ascii
 * character string. The string is then terminated with a NULL in byte 9.
 * Hex 0-9 becomes ascii '0' to '9'.
 * Hex a-f becomes ascii '=' to 'B' capital B.
 *
 * Notes:
 * Coded for 32 bit integers only.
 **/

static void
lpfc_jedec_to_ascii(int incr, char hdw[])
{
 int i, j;
 for (i = 0; i < 8; i++) {
  j = (incr & 0xf);
  if (j <= 9)
   hdw[7 - i] = 0x30 +  j;
   else
   hdw[7 - i] = 0x61 + j - 10;
  incr = (incr >> 4);
 }
 hdw[8] = 0;
 return;
}

static ssize_t
lpfc_cmf_info_show(struct device *dev, struct device_attribute *attr,
     char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 struct lpfc_cgn_info *cp = NULL;
 struct lpfc_cgn_stat *cgs;
 int  len = 0;
 int cpu;
 u64 rcv, total;
 char tmp[LPFC_MAX_INFO_TMP_LEN] = {0};

 if (phba->cgn_i)
  cp = (struct lpfc_cgn_info *)phba->cgn_i->virt;

 scnprintf(tmp, sizeof(tmp),
    "Congestion Mgmt Info: E2Eattr %d Ver %d "
    "CMF %d cnt %d\n",
    phba->sli4_hba.pc_sli4_params.mi_cap,
    cp ? cp->cgn_info_version : 0,
    phba->sli4_hba.pc_sli4_params.cmf, phba->cmf_timer_cnt);

 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 if (!phba->sli4_hba.pc_sli4_params.cmf)
  goto buffer_done;

 switch (phba->cgn_init_reg_signal) {
 case EDC_CG_SIG_WARN_ONLY:
  scnprintf(tmp, sizeof(tmp),
     "Register: Init: Signal:WARN ");
  break;
 case EDC_CG_SIG_WARN_ALARM:
  scnprintf(tmp, sizeof(tmp),
     "Register: Init: Signal:WARN|ALARM ");
  break;
 default:
  scnprintf(tmp, sizeof(tmp),
     "Register: Init: Signal:NONE ");
  break;
 }
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 switch (phba->cgn_init_reg_fpin) {
 case LPFC_CGN_FPIN_WARN:
  scnprintf(tmp, sizeof(tmp),
     "FPIN:WARN\n");
  break;
 case LPFC_CGN_FPIN_ALARM:
  scnprintf(tmp, sizeof(tmp),
     "FPIN:ALARM\n");
  break;
 case LPFC_CGN_FPIN_BOTH:
  scnprintf(tmp, sizeof(tmp),
     "FPIN:WARN|ALARM\n");
  break;
 default:
  scnprintf(tmp, sizeof(tmp),
     "FPIN:NONE\n");
  break;
 }
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 switch (phba->cgn_reg_signal) {
 case EDC_CG_SIG_WARN_ONLY:
  scnprintf(tmp, sizeof(tmp),
     " Current: Signal:WARN ");
  break;
 case EDC_CG_SIG_WARN_ALARM:
  scnprintf(tmp, sizeof(tmp),
     " Current: Signal:WARN|ALARM ");
  break;
 default:
  scnprintf(tmp, sizeof(tmp),
     " Current: Signal:NONE ");
  break;
 }
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 switch (phba->cgn_reg_fpin) {
 case LPFC_CGN_FPIN_WARN:
  scnprintf(tmp, sizeof(tmp),
     "FPIN:WARN ACQEcnt:%d\n", phba->cgn_acqe_cnt);
  break;
 case LPFC_CGN_FPIN_ALARM:
  scnprintf(tmp, sizeof(tmp),
     "FPIN:ALARM ACQEcnt:%d\n", phba->cgn_acqe_cnt);
  break;
 case LPFC_CGN_FPIN_BOTH:
  scnprintf(tmp, sizeof(tmp),
     "FPIN:WARN|ALARM ACQEcnt:%d\n", phba->cgn_acqe_cnt);
  break;
 default:
  scnprintf(tmp, sizeof(tmp),
     "FPIN:NONE ACQEcnt:%d\n", phba->cgn_acqe_cnt);
  break;
 }
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 if (phba->cmf_active_mode != phba->cgn_p.cgn_param_mode) {
  switch (phba->cmf_active_mode) {
  case LPFC_CFG_OFF:
   scnprintf(tmp, sizeof(tmp), "Active: Mode:Off\n");
   break;
  case LPFC_CFG_MANAGED:
   scnprintf(tmp, sizeof(tmp), "Active: Mode:Managed\n");
   break;
  case LPFC_CFG_MONITOR:
   scnprintf(tmp, sizeof(tmp), "Active: Mode:Monitor\n");
   break;
  default:
   scnprintf(tmp, sizeof(tmp), "Active: Mode:Unknown\n");
  }
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;
 }

 switch (phba->cgn_p.cgn_param_mode) {
 case LPFC_CFG_OFF:
  scnprintf(tmp, sizeof(tmp), "Config: Mode:Off ");
  break;
 case LPFC_CFG_MANAGED:
  scnprintf(tmp, sizeof(tmp), "Config: Mode:Managed ");
  break;
 case LPFC_CFG_MONITOR:
  scnprintf(tmp, sizeof(tmp), "Config: Mode:Monitor ");
  break;
 default:
  scnprintf(tmp, sizeof(tmp), "Config: Mode:Unknown ");
 }
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 total = 0;
 rcv = 0;
 for_each_present_cpu(cpu) {
  cgs = per_cpu_ptr(phba->cmf_stat, cpu);
  total += atomic64_read(&cgs->total_bytes);
  rcv += atomic64_read(&cgs->rcv_bytes);
 }

 scnprintf(tmp, sizeof(tmp),
    "IObusy:%d Info:%d Bytes: Rcv:x%llx Total:x%llx\n",
    atomic_read(&phba->cmf_busy),
    phba->cmf_active_info, rcv, total);
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 scnprintf(tmp, sizeof(tmp),
    "Port_speed:%d Link_byte_cnt:%ld "
    "Max_byte_per_interval:%ld\n",
    lpfc_sli_port_speed_get(phba),
    (unsigned long)phba->cmf_link_byte_count,
    (unsigned long)phba->cmf_max_bytes_per_interval);
 strlcat(buf, tmp, PAGE_SIZE);

buffer_done:
 len = strnlen(buf, PAGE_SIZE);

 if (unlikely(len >= (PAGE_SIZE - 1))) {
  lpfc_printf_log(phba, KERN_INFO, LOG_CGN_MGMT,
    "6312 Catching potential buffer "
    "overflow > PAGE_SIZE = %lu bytes\n",
    PAGE_SIZE);
  strscpy(buf + PAGE_SIZE - 1 - sizeof(LPFC_INFO_MORE_STR),
   LPFC_INFO_MORE_STR, sizeof(LPFC_INFO_MORE_STR) + 1);
 }
 return len;
}

static ssize_t
lpfc_vmid_info_show(struct device *dev, struct device_attribute *attr,
      char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 struct lpfc_vmid  *vmp;
 int  len = 0, i, j, k, cpu;
 char hxstr[LPFC_MAX_VMID_SIZE * 3] = {0};
 struct timespec64 curr_tm;
 struct lpfc_vmid_priority_range *vr;
 u64 *lta, rct_acc = 0, max_lta = 0;
 struct tm tm_val;

 ktime_get_ts64(&curr_tm);

 len += scnprintf(buf + len, PAGE_SIZE - len, "Key 'vmid':\n");

 /* if enabled continue, else return */
 if (lpfc_is_vmid_enabled(phba)) {
  len += scnprintf(buf + len, PAGE_SIZE - len,
     "lpfc VMID Page: ON\n\n");
 } else {
  len += scnprintf(buf + len, PAGE_SIZE - len,
     "lpfc VMID Page: OFF\n\n");
  return len;
 }

 /* if using priority tagging */
 if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) {
  len += scnprintf(buf + len, PAGE_SIZE - len,
    "VMID priority ranges:\n");
  vr = vport->vmid_priority.vmid_range;
  for (i = 0; i < vport->vmid_priority.num_descriptors; ++i) {
   len += scnprintf(buf + len, PAGE_SIZE - len,
     "\t[x%x - x%x], qos: x%x\n",
     vr->low, vr->high, vr->qos);
   vr++;
  }
 }

 for (i = 0; i < phba->cfg_max_vmid; i++) {
  vmp = &vport->vmid[i];
  max_lta = 0;

  /* only if the slot is used */
  if (!(vmp->flag & LPFC_VMID_SLOT_USED) ||
      !(vmp->flag & LPFC_VMID_REGISTERED))
   continue;

  /* if using priority tagging */
  if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO) {
   len += scnprintf(buf + len, PAGE_SIZE - len,
     "VEM ID: %02x:%02x:%02x:%02x:"
     "%02x:%02x:%02x:%02x:%02x:%02x:"
     "%02x:%02x:%02x:%02x:%02x:%02x\n",
     vport->lpfc_vmid_host_uuid[0],
     vport->lpfc_vmid_host_uuid[1],
     vport->lpfc_vmid_host_uuid[2],
     vport->lpfc_vmid_host_uuid[3],
     vport->lpfc_vmid_host_uuid[4],
     vport->lpfc_vmid_host_uuid[5],
     vport->lpfc_vmid_host_uuid[6],
     vport->lpfc_vmid_host_uuid[7],
     vport->lpfc_vmid_host_uuid[8],
     vport->lpfc_vmid_host_uuid[9],
     vport->lpfc_vmid_host_uuid[10],
     vport->lpfc_vmid_host_uuid[11],
     vport->lpfc_vmid_host_uuid[12],
     vport->lpfc_vmid_host_uuid[13],
     vport->lpfc_vmid_host_uuid[14],
     vport->lpfc_vmid_host_uuid[15]);
  }

  /* IO stats */
  len += scnprintf(buf + len, PAGE_SIZE - len,
    "ID00 READs:%llx WRITEs:%llx\n",
    vmp->io_rd_cnt,
    vmp->io_wr_cnt);
  for (j = 0, k = 0; j < strlen(vmp->host_vmid); j++, k += 3)
   sprintf((char *)(hxstr + k), "%2x ", vmp->host_vmid[j]);
  /* UUIDs */
  len += scnprintf(buf + len, PAGE_SIZE - len, "UUID:\n");
  len += scnprintf(buf + len, PAGE_SIZE - len, "%s\n", hxstr);

  len += scnprintf(buf + len, PAGE_SIZE - len, "String (%s)\n",
    vmp->host_vmid);

  if (vport->phba->pport->vmid_flag & LPFC_VMID_TYPE_PRIO)
   len += scnprintf(buf + len, PAGE_SIZE - len,
     "CS_CTL VMID: 0x%x\n",
     vmp->un.cs_ctl_vmid);
  else
   len += scnprintf(buf + len, PAGE_SIZE - len,
     "Application id: 0x%x\n",
     vmp->un.app_id);

  /* calculate the last access time */
  for_each_possible_cpu(cpu) {
   lta = per_cpu_ptr(vmp->last_io_time, cpu);
   if (!lta)
    continue;

   /* if last access time is less than timeout */
   if (time_after((unsigned long)*lta, jiffies))
    continue;

   if (*lta > max_lta)
    max_lta = *lta;
  }

  rct_acc = jiffies_to_msecs(jiffies - max_lta) / 1000;
  /* current time */
  time64_to_tm(ktime_get_real_seconds(),
        -(sys_tz.tz_minuteswest * 60) - rct_acc, &tm_val);

  len += scnprintf(buf + len, PAGE_SIZE - len,
     "Last Access Time :"
     "%ld-%d-%dT%02d:%02d:%02d\n\n",
     1900 + tm_val.tm_year, tm_val.tm_mon + 1,
     tm_val.tm_mday, tm_val.tm_hour,
     tm_val.tm_min, tm_val.tm_sec);

  if (len >= PAGE_SIZE)
   return len;

  memset(hxstr, 0, LPFC_MAX_VMID_SIZE * 3);
 }
 return len;
}

/**
 * lpfc_drvr_version_show - Return the Emulex driver string with version number
 * @dev: class unused variable.
 * @attr: device attribute, not used.
 * @buf: on return contains the module description text.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_drvr_version_show(struct device *dev, struct device_attribute *attr,
         char *buf)
{
 return scnprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n");
}

/**
 * lpfc_enable_fip_show - Return the fip mode of the HBA
 * @dev: class unused variable.
 * @attr: device attribute, not used.
 * @buf: on return contains the module description text.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_enable_fip_show(struct device *dev, struct device_attribute *attr,
         char *buf)
{
 struct Scsi_Host *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 if (test_bit(HBA_FIP_SUPPORT, &phba->hba_flag))
  return scnprintf(buf, PAGE_SIZE, "1\n");
 else
  return scnprintf(buf, PAGE_SIZE, "0\n");
}

static ssize_t
lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr,
      char *buf)
{
 struct Scsi_Host *shost = class_to_shost(dev);
 struct lpfc_vport *vport = shost_priv(shost);
 struct lpfc_hba   *phba = vport->phba;
 struct lpfc_nvmet_tgtport *tgtp;
 struct nvme_fc_local_port *localport;
 struct lpfc_nvme_lport *lport;
 struct lpfc_nvme_rport *rport;
 struct lpfc_nodelist *ndlp;
 struct nvme_fc_remote_port *nrport;
 struct lpfc_fc4_ctrl_stat *cstat;
 uint64_t data1, data2, data3;
 uint64_t totin, totout, tot;
 unsigned long iflags;
 char *statep;
 int i;
 int len = 0;
 char tmp[LPFC_MAX_INFO_TMP_LEN] = {0};

 if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) {
  len = scnprintf(buf, PAGE_SIZE, "NVME Disabled\n");
  return len;
 }
 if (phba->nvmet_support) {
  if (!phba->targetport) {
   len = scnprintf(buf, PAGE_SIZE,
     "NVME Target: x%llx is not allocated\n",
     wwn_to_u64(vport->fc_portname.u.wwn));
   return len;
  }
  /* Port state is only one of two values for now. */
  if (phba->targetport->port_id)
   statep = "REGISTERED";
  else
   statep = "INIT";
  scnprintf(tmp, sizeof(tmp),
     "NVME Target Enabled State %s\n",
     statep);
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  scnprintf(tmp, sizeof(tmp),
     "%s%d WWPN x%llx WWNN x%llx DID x%06x\n",
     "NVME Target: lpfc",
     phba->brd_no,
     wwn_to_u64(vport->fc_portname.u.wwn),
     wwn_to_u64(vport->fc_nodename.u.wwn),
     phba->targetport->port_id);
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  if (strlcat(buf, "\nNVME Target: Statistics\n", PAGE_SIZE)
      >= PAGE_SIZE)
   goto buffer_done;

  tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private;
  scnprintf(tmp, sizeof(tmp),
     "LS: Rcv %08x Drop %08x Abort %08x\n",
     atomic_read(&tgtp->rcv_ls_req_in),
     atomic_read(&tgtp->rcv_ls_req_drop),
     atomic_read(&tgtp->xmt_ls_abort));
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  if (atomic_read(&tgtp->rcv_ls_req_in) !=
      atomic_read(&tgtp->rcv_ls_req_out)) {
   scnprintf(tmp, sizeof(tmp),
      "Rcv LS: in %08x != out %08x\n",
      atomic_read(&tgtp->rcv_ls_req_in),
      atomic_read(&tgtp->rcv_ls_req_out));
   if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
    goto buffer_done;
  }

  scnprintf(tmp, sizeof(tmp),
     "LS: Xmt %08x Drop %08x Cmpl %08x\n",
     atomic_read(&tgtp->xmt_ls_rsp),
     atomic_read(&tgtp->xmt_ls_drop),
     atomic_read(&tgtp->xmt_ls_rsp_cmpl));
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  scnprintf(tmp, sizeof(tmp),
     "LS: RSP Abort %08x xb %08x Err %08x\n",
     atomic_read(&tgtp->xmt_ls_rsp_aborted),
     atomic_read(&tgtp->xmt_ls_rsp_xb_set),
     atomic_read(&tgtp->xmt_ls_rsp_error));
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  scnprintf(tmp, sizeof(tmp),
     "FCP: Rcv %08x Defer %08x Release %08x "
     "Drop %08x\n",
     atomic_read(&tgtp->rcv_fcp_cmd_in),
     atomic_read(&tgtp->rcv_fcp_cmd_defer),
     atomic_read(&tgtp->xmt_fcp_release),
     atomic_read(&tgtp->rcv_fcp_cmd_drop));
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  if (atomic_read(&tgtp->rcv_fcp_cmd_in) !=
      atomic_read(&tgtp->rcv_fcp_cmd_out)) {
   scnprintf(tmp, sizeof(tmp),
      "Rcv FCP: in %08x != out %08x\n",
      atomic_read(&tgtp->rcv_fcp_cmd_in),
      atomic_read(&tgtp->rcv_fcp_cmd_out));
   if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
    goto buffer_done;
  }

  scnprintf(tmp, sizeof(tmp),
     "FCP Rsp: RD %08x rsp %08x WR %08x rsp %08x "
     "drop %08x\n",
     atomic_read(&tgtp->xmt_fcp_read),
     atomic_read(&tgtp->xmt_fcp_read_rsp),
     atomic_read(&tgtp->xmt_fcp_write),
     atomic_read(&tgtp->xmt_fcp_rsp),
     atomic_read(&tgtp->xmt_fcp_drop));
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  scnprintf(tmp, sizeof(tmp),
     "FCP Rsp Cmpl: %08x err %08x drop %08x\n",
     atomic_read(&tgtp->xmt_fcp_rsp_cmpl),
     atomic_read(&tgtp->xmt_fcp_rsp_error),
     atomic_read(&tgtp->xmt_fcp_rsp_drop));
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  scnprintf(tmp, sizeof(tmp),
     "FCP Rsp Abort: %08x xb %08x xricqe %08x\n",
     atomic_read(&tgtp->xmt_fcp_rsp_aborted),
     atomic_read(&tgtp->xmt_fcp_rsp_xb_set),
     atomic_read(&tgtp->xmt_fcp_xri_abort_cqe));
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  scnprintf(tmp, sizeof(tmp),
     "ABORT: Xmt %08x Cmpl %08x\n",
     atomic_read(&tgtp->xmt_fcp_abort),
     atomic_read(&tgtp->xmt_fcp_abort_cmpl));
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  scnprintf(tmp, sizeof(tmp),
     "ABORT: Sol %08x Usol %08x Err %08x Cmpl %08x\n",
     atomic_read(&tgtp->xmt_abort_sol),
     atomic_read(&tgtp->xmt_abort_unsol),
     atomic_read(&tgtp->xmt_abort_rsp),
     atomic_read(&tgtp->xmt_abort_rsp_error));
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  scnprintf(tmp, sizeof(tmp),
     "DELAY: ctx %08x fod %08x wqfull %08x\n",
     atomic_read(&tgtp->defer_ctx),
     atomic_read(&tgtp->defer_fod),
     atomic_read(&tgtp->defer_wqfull));
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  /* Calculate outstanding IOs */
  tot = atomic_read(&tgtp->rcv_fcp_cmd_drop);
  tot += atomic_read(&tgtp->xmt_fcp_release);
  tot = atomic_read(&tgtp->rcv_fcp_cmd_in) - tot;

  scnprintf(tmp, sizeof(tmp),
     "IO_CTX: %08x WAIT: cur %08x tot %08x\n"
     "CTX Outstanding %08llx\n\n",
     phba->sli4_hba.nvmet_xri_cnt,
     phba->sli4_hba.nvmet_io_wait_cnt,
     phba->sli4_hba.nvmet_io_wait_total,
     tot);
  strlcat(buf, tmp, PAGE_SIZE);
  goto buffer_done;
 }

 localport = vport->localport;
 if (!localport) {
  len = scnprintf(buf, PAGE_SIZE,
    "NVME Initiator x%llx is not allocated\n",
    wwn_to_u64(vport->fc_portname.u.wwn));
  return len;
 }
 lport = (struct lpfc_nvme_lport *)localport->private;
 if (strlcat(buf, "\nNVME Initiator Enabled\n", PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 scnprintf(tmp, sizeof(tmp),
    "XRI Dist lpfc%d Total %d IO %d ELS %d\n",
    phba->brd_no,
    phba->sli4_hba.max_cfg_param.max_xri,
    phba->sli4_hba.io_xri_max,
    lpfc_sli4_get_els_iocb_cnt(phba));
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 /* Port state is only one of two values for now. */
 if (localport->port_id)
  statep = "ONLINE";
 else
  statep = "UNKNOWN ";

 scnprintf(tmp, sizeof(tmp),
    "%s%d WWPN x%llx WWNN x%llx DID x%06x %s\n",
    "NVME LPORT lpfc",
    phba->brd_no,
    wwn_to_u64(vport->fc_portname.u.wwn),
    wwn_to_u64(vport->fc_nodename.u.wwn),
    localport->port_id, statep);
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);

 list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
  nrport = NULL;
  spin_lock(&ndlp->lock);
  rport = lpfc_ndlp_get_nrport(ndlp);
  if (rport)
   nrport = rport->remoteport;
  spin_unlock(&ndlp->lock);
  if (!nrport)
   continue;

  /* Port state is only one of two values for now. */
  switch (nrport->port_state) {
  case FC_OBJSTATE_ONLINE:
   statep = "ONLINE";
   break;
  case FC_OBJSTATE_UNKNOWN:
   statep = "UNKNOWN ";
   break;
  default:
   statep = "UNSUPPORTED";
   break;
  }

  /* Tab in to show lport ownership. */
  if (strlcat(buf, "NVME RPORT ", PAGE_SIZE) >= PAGE_SIZE)
   goto unlock_buf_done;
  if (phba->brd_no >= 10) {
   if (strlcat(buf, " ", PAGE_SIZE) >= PAGE_SIZE)
    goto unlock_buf_done;
  }

  scnprintf(tmp, sizeof(tmp), "WWPN x%llx ",
     nrport->port_name);
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto unlock_buf_done;

  scnprintf(tmp, sizeof(tmp), "WWNN x%llx ",
     nrport->node_name);
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto unlock_buf_done;

  scnprintf(tmp, sizeof(tmp), "DID x%06x ",
     nrport->port_id);
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto unlock_buf_done;

  /* An NVME rport can have multiple roles. */
  if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR) {
   if (strlcat(buf, "INITIATOR ", PAGE_SIZE) >= PAGE_SIZE)
    goto unlock_buf_done;
  }
  if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET) {
   if (strlcat(buf, "TARGET ", PAGE_SIZE) >= PAGE_SIZE)
    goto unlock_buf_done;
  }
  if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY) {
   if (strlcat(buf, "DISCSRVC ", PAGE_SIZE) >= PAGE_SIZE)
    goto unlock_buf_done;
  }
  if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR |
       FC_PORT_ROLE_NVME_TARGET |
       FC_PORT_ROLE_NVME_DISCOVERY)) {
   scnprintf(tmp, sizeof(tmp), "UNKNOWN ROLE x%x",
      nrport->port_role);
   if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
    goto unlock_buf_done;
  }

  scnprintf(tmp, sizeof(tmp), "%s\n", statep);
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto unlock_buf_done;
 }
 spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);

 if (!lport)
  goto buffer_done;

 if (strlcat(buf, "\nNVME Statistics\n", PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 scnprintf(tmp, sizeof(tmp),
    "LS: Xmt %010x Cmpl %010x Abort %08x\n",
    atomic_read(&lport->fc4NvmeLsRequests),
    atomic_read(&lport->fc4NvmeLsCmpls),
    atomic_read(&lport->xmt_ls_abort));
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 scnprintf(tmp, sizeof(tmp),
    "LS XMIT: Err %08x CMPL: xb %08x Err %08x\n",
    atomic_read(&lport->xmt_ls_err),
    atomic_read(&lport->cmpl_ls_xb),
    atomic_read(&lport->cmpl_ls_err));
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 totin = 0;
 totout = 0;
 for (i = 0; i < phba->cfg_hdw_queue; i++) {
  cstat = &phba->sli4_hba.hdwq[i].nvme_cstat;
  tot = cstat->io_cmpls;
  totin += tot;
  data1 = cstat->input_requests;
  data2 = cstat->output_requests;
  data3 = cstat->control_requests;
  totout += (data1 + data2 + data3);
 }
 scnprintf(tmp, sizeof(tmp),
    "Total FCP Cmpl %016llx Issue %016llx "
    "OutIO %016llx\n",
    totin, totout, totout - totin);
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 scnprintf(tmp, sizeof(tmp),
    "\tabort %08x noxri %08x nondlp %08x qdepth %08x "
    "wqerr %08x err %08x\n",
    atomic_read(&lport->xmt_fcp_abort),
    atomic_read(&lport->xmt_fcp_noxri),
    atomic_read(&lport->xmt_fcp_bad_ndlp),
    atomic_read(&lport->xmt_fcp_qdepth),
    atomic_read(&lport->xmt_fcp_wqerr),
    atomic_read(&lport->xmt_fcp_err));
 if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
  goto buffer_done;

 scnprintf(tmp, sizeof(tmp),
    "FCP CMPL: xb %08x Err %08x\n",
    atomic_read(&lport->cmpl_fcp_xb),
    atomic_read(&lport->cmpl_fcp_err));
 strlcat(buf, tmp, PAGE_SIZE);

 /* host_lock is already unlocked. */
 goto buffer_done;

 unlock_buf_done:
 spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);

 buffer_done:
 len = strnlen(buf, PAGE_SIZE);

 if (unlikely(len >= (PAGE_SIZE - 1))) {
  lpfc_printf_log(phba, KERN_INFO, LOG_NVME,
    "6314 Catching potential buffer "
    "overflow > PAGE_SIZE = %lu bytes\n",
    PAGE_SIZE);
  strscpy(buf + PAGE_SIZE - 1 - sizeof(LPFC_INFO_MORE_STR),
   LPFC_INFO_MORE_STR,
   sizeof(LPFC_INFO_MORE_STR) + 1);
 }

 return len;
}

static ssize_t
lpfc_scsi_stat_show(struct device *dev, struct device_attribute *attr,
      char *buf)
{
 struct Scsi_Host *shost = class_to_shost(dev);
 struct lpfc_vport *vport = shost_priv(shost);
 struct lpfc_hba *phba = vport->phba;
 int len;
 struct lpfc_fc4_ctrl_stat *cstat;
 u64 data1, data2, data3;
 u64 tot, totin, totout;
 int i;
 char tmp[LPFC_MAX_SCSI_INFO_TMP_LEN] = {0};

 if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_FCP) ||
     (phba->sli_rev != LPFC_SLI_REV4))
  return 0;

 scnprintf(buf, PAGE_SIZE, "SCSI HDWQ Statistics\n");

 totin = 0;
 totout = 0;
 for (i = 0; i < phba->cfg_hdw_queue; i++) {
  cstat = &phba->sli4_hba.hdwq[i].scsi_cstat;
  tot = cstat->io_cmpls;
  totin += tot;
  data1 = cstat->input_requests;
  data2 = cstat->output_requests;
  data3 = cstat->control_requests;
  totout += (data1 + data2 + data3);

  scnprintf(tmp, sizeof(tmp), "HDWQ (%d): Rd %016llx Wr %016llx "
     "IO %016llx ", i, data1, data2, data3);
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;

  scnprintf(tmp, sizeof(tmp), "Cmpl %016llx OutIO %016llx\n",
     tot, ((data1 + data2 + data3) - tot));
  if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE)
   goto buffer_done;
 }
 scnprintf(tmp, sizeof(tmp), "Total FCP Cmpl %016llx Issue %016llx "
    "OutIO %016llx\n", totin, totout, totout - totin);
 strlcat(buf, tmp, PAGE_SIZE);

buffer_done:
 len = strnlen(buf, PAGE_SIZE);

 return len;
}

static ssize_t
lpfc_bg_info_show(struct device *dev, struct device_attribute *attr,
    char *buf)
{
 struct Scsi_Host *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 if (phba->cfg_enable_bg) {
  if (phba->sli3_options & LPFC_SLI3_BG_ENABLED)
   return scnprintf(buf, PAGE_SIZE,
     "BlockGuard Enabled\n");
  else
   return scnprintf(buf, PAGE_SIZE,
     "BlockGuard Not Supported\n");
 } else
  return scnprintf(buf, PAGE_SIZE,
     "BlockGuard Disabled\n");
}

static ssize_t
lpfc_bg_guard_err_show(struct device *dev, struct device_attribute *attr,
         char *buf)
{
 struct Scsi_Host *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 return scnprintf(buf, PAGE_SIZE, "%llu\n",
   (unsigned long long)phba->bg_guard_err_cnt);
}

static ssize_t
lpfc_bg_apptag_err_show(struct device *dev, struct device_attribute *attr,
   char *buf)
{
 struct Scsi_Host *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 return scnprintf(buf, PAGE_SIZE, "%llu\n",
   (unsigned long long)phba->bg_apptag_err_cnt);
}

static ssize_t
lpfc_bg_reftag_err_show(struct device *dev, struct device_attribute *attr,
   char *buf)
{
 struct Scsi_Host *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 return scnprintf(buf, PAGE_SIZE, "%llu\n",
   (unsigned long long)phba->bg_reftag_err_cnt);
}

/**
 * lpfc_info_show - Return some pci info about the host in ascii
 * @dev: class converted to a Scsi_host structure.
 * @attr: device attribute, not used.
 * @buf: on return contains the formatted text from lpfc_info().
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_info_show(struct device *dev, struct device_attribute *attr,
        char *buf)
{
 struct Scsi_Host *host = class_to_shost(dev);

 return scnprintf(buf, PAGE_SIZE, "%s\n", lpfc_info(host));
}

/**
 * lpfc_serialnum_show - Return the hba serial number in ascii
 * @dev: class converted to a Scsi_host structure.
 * @attr: device attribute, not used.
 * @buf: on return contains the formatted text serial number.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_serialnum_show(struct device *dev, struct device_attribute *attr,
      char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 return scnprintf(buf, PAGE_SIZE, "%s\n", phba->SerialNumber);
}

/**
 * lpfc_temp_sensor_show - Return the temperature sensor level
 * @dev: class converted to a Scsi_host structure.
 * @attr: device attribute, not used.
 * @buf: on return contains the formatted support level.
 *
 * Description:
 * Returns a number indicating the temperature sensor level currently
 * supported, zero or one in ascii.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_temp_sensor_show(struct device *dev, struct device_attribute *attr,
        char *buf)
{
 struct Scsi_Host *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 return scnprintf(buf, PAGE_SIZE, "%d\n", phba->temp_sensor_support);
}

/**
 * lpfc_modeldesc_show - Return the model description of the hba
 * @dev: class converted to a Scsi_host structure.
 * @attr: device attribute, not used.
 * @buf: on return contains the scsi vpd model description.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_modeldesc_show(struct device *dev, struct device_attribute *attr,
      char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ModelDesc);
}

/**
 * lpfc_modelname_show - Return the model name of the hba
 * @dev: class converted to a Scsi_host structure.
 * @attr: device attribute, not used.
 * @buf: on return contains the scsi vpd model name.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_modelname_show(struct device *dev, struct device_attribute *attr,
      char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ModelName);
}

/**
 * lpfc_programtype_show - Return the program type of the hba
 * @dev: class converted to a Scsi_host structure.
 * @attr: device attribute, not used.
 * @buf: on return contains the scsi vpd program type.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_programtype_show(struct device *dev, struct device_attribute *attr,
        char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 return scnprintf(buf, PAGE_SIZE, "%s\n", phba->ProgramType);
}

/**
 * lpfc_vportnum_show - Return the port number in ascii of the hba
 * @dev: class converted to a Scsi_host structure.
 * @attr: device attribute, not used.
 * @buf: on return contains scsi vpd program type.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_vportnum_show(struct device *dev, struct device_attribute *attr,
     char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 return scnprintf(buf, PAGE_SIZE, "%s\n", phba->Port);
}

/**
 * lpfc_fwrev_show - Return the firmware rev running in the hba
 * @dev: class converted to a Scsi_host structure.
 * @attr: device attribute, not used.
 * @buf: on return contains the scsi vpd program type.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_fwrev_show(struct device *dev, struct device_attribute *attr,
  char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 uint32_t if_type;
 uint8_t sli_family;
 char fwrev[FW_REV_STR_SIZE];
 int len;

 lpfc_decode_firmware_rev(phba, fwrev, 1);
 if_type = phba->sli4_hba.pc_sli4_params.if_type;
 sli_family = phba->sli4_hba.pc_sli4_params.sli_family;

 if (phba->sli_rev < LPFC_SLI_REV4)
  len = scnprintf(buf, PAGE_SIZE, "%s, sli-%d\n",
          fwrev, phba->sli_rev);
 else
  len = scnprintf(buf, PAGE_SIZE, "%s, sli-%d:%d:%x\n",
          fwrev, phba->sli_rev, if_type, sli_family);

 return len;
}

/**
 * lpfc_hdw_show - Return the jedec information about the hba
 * @dev: class converted to a Scsi_host structure.
 * @attr: device attribute, not used.
 * @buf: on return contains the scsi vpd program type.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_hdw_show(struct device *dev, struct device_attribute *attr, char *buf)
{
 char hdw[9];
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 lpfc_vpd_t *vp = &phba->vpd;

 lpfc_jedec_to_ascii(vp->rev.biuRev, hdw);
 return scnprintf(buf, PAGE_SIZE, "%s %08x %08x\n", hdw,
    vp->rev.smRev, vp->rev.smFwRev);
}

/**
 * lpfc_option_rom_version_show - Return the adapter ROM FCode version
 * @dev: class converted to a Scsi_host structure.
 * @attr: device attribute, not used.
 * @buf: on return contains the ROM and FCode ascii strings.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_option_rom_version_show(struct device *dev, struct device_attribute *attr,
        char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 char fwrev[FW_REV_STR_SIZE];

 if (phba->sli_rev < LPFC_SLI_REV4)
  return scnprintf(buf, PAGE_SIZE, "%s\n",
    phba->OptionROMVersion);

 lpfc_decode_firmware_rev(phba, fwrev, 1);
 return scnprintf(buf, PAGE_SIZE, "%s\n", fwrev);
}

/**
 * lpfc_link_state_show - Return the link state of the port
 * @dev: class converted to a Scsi_host structure.
 * @attr: device attribute, not used.
 * @buf: on return contains text describing the state of the link.
 *
 * Notes:
 * The switch statement has no default so zero will be returned.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_link_state_show(struct device *dev, struct device_attribute *attr,
       char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 int  len = 0;

 switch (phba->link_state) {
 case LPFC_LINK_UNKNOWN:
 case LPFC_WARM_START:
 case LPFC_INIT_START:
 case LPFC_INIT_MBX_CMDS:
 case LPFC_LINK_DOWN:
 case LPFC_HBA_ERROR:
  if (test_bit(LINK_DISABLED, &phba->hba_flag))
   len += scnprintf(buf + len, PAGE_SIZE-len,
    "Link Down - User disabled\n");
  else
   len += scnprintf(buf + len, PAGE_SIZE-len,
    "Link Down\n");
  break;
 case LPFC_LINK_UP:
 case LPFC_CLEAR_LA:
 case LPFC_HBA_READY:
  len += scnprintf(buf + len, PAGE_SIZE-len, "Link Up - ");

  switch (vport->port_state) {
  case LPFC_LOCAL_CFG_LINK:
   len += scnprintf(buf + len, PAGE_SIZE-len,
     "Configuring Link\n");
   break;
  case LPFC_FDISC:
  case LPFC_FLOGI:
  case LPFC_FABRIC_CFG_LINK:
  case LPFC_NS_REG:
  case LPFC_NS_QRY:
  case LPFC_BUILD_DISC_LIST:
  case LPFC_DISC_AUTH:
   len += scnprintf(buf + len, PAGE_SIZE - len,
     "Discovery\n");
   break;
  case LPFC_VPORT_READY:
   len += scnprintf(buf + len, PAGE_SIZE - len,
     "Ready\n");
   break;

  case LPFC_VPORT_FAILED:
   len += scnprintf(buf + len, PAGE_SIZE - len,
     "Failed\n");
   break;

  case LPFC_VPORT_UNKNOWN:
   len += scnprintf(buf + len, PAGE_SIZE - len,
     "Unknown\n");
   break;
  }
  if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) {
   if (test_bit(FC_PUBLIC_LOOP, &vport->fc_flag))
    len += scnprintf(buf + len, PAGE_SIZE-len,
      " Public Loop\n");
   else
    len += scnprintf(buf + len, PAGE_SIZE-len,
      " Private Loop\n");
  } else {
   if (test_bit(FC_FABRIC, &vport->fc_flag)) {
    if (phba->sli_rev == LPFC_SLI_REV4 &&
        vport->port_type == LPFC_PHYSICAL_PORT &&
        phba->sli4_hba.fawwpn_flag &
     LPFC_FAWWPN_FABRIC)
     len += scnprintf(buf + len,
        PAGE_SIZE - len,
        " Fabric FA-PWWN\n");
    else
     len += scnprintf(buf + len,
        PAGE_SIZE - len,
        " Fabric\n");
   } else {
    len += scnprintf(buf + len, PAGE_SIZE-len,
      " Point-2-Point\n");
   }
  }
 }

 if ((phba->sli_rev == LPFC_SLI_REV4) &&
     ((bf_get(lpfc_sli_intf_if_type,
      &phba->sli4_hba.sli_intf) ==
      LPFC_SLI_INTF_IF_TYPE_6))) {
  struct lpfc_trunk_link link = phba->trunk_link;

  if (bf_get(lpfc_conf_trunk_port0, &phba->sli4_hba))
   len += scnprintf(buf + len, PAGE_SIZE - len,
    "Trunk port 0: Link %s %s\n",
    (link.link0.state == LPFC_LINK_UP) ?
     "Up" : "Down. ",
    trunk_errmsg[link.link0.fault]);

  if (bf_get(lpfc_conf_trunk_port1, &phba->sli4_hba))
   len += scnprintf(buf + len, PAGE_SIZE - len,
    "Trunk port 1: Link %s %s\n",
    (link.link1.state == LPFC_LINK_UP) ?
     "Up" : "Down. ",
    trunk_errmsg[link.link1.fault]);

  if (bf_get(lpfc_conf_trunk_port2, &phba->sli4_hba))
   len += scnprintf(buf + len, PAGE_SIZE - len,
    "Trunk port 2: Link %s %s\n",
    (link.link2.state == LPFC_LINK_UP) ?
     "Up" : "Down. ",
    trunk_errmsg[link.link2.fault]);

  if (bf_get(lpfc_conf_trunk_port3, &phba->sli4_hba))
   len += scnprintf(buf + len, PAGE_SIZE - len,
    "Trunk port 3: Link %s %s\n",
    (link.link3.state == LPFC_LINK_UP) ?
     "Up" : "Down. ",
    trunk_errmsg[link.link3.fault]);

 }

 return len;
}

/**
 * lpfc_sli4_protocol_show - Return the fip mode of the HBA
 * @dev: class unused variable.
 * @attr: device attribute, not used.
 * @buf: on return contains the module description text.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_sli4_protocol_show(struct device *dev, struct device_attribute *attr,
   char *buf)
{
 struct Scsi_Host *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba *phba = vport->phba;

 if (phba->sli_rev < LPFC_SLI_REV4)
  return scnprintf(buf, PAGE_SIZE, "fc\n");

 if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) {
  if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_GE)
   return scnprintf(buf, PAGE_SIZE, "fcoe\n");
  if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC)
   return scnprintf(buf, PAGE_SIZE, "fc\n");
 }
 return scnprintf(buf, PAGE_SIZE, "unknown\n");
}

/**
 * lpfc_oas_supported_show - Return whether or not Optimized Access Storage
 *     (OAS) is supported.
 * @dev: class unused variable.
 * @attr: device attribute, not used.
 * @buf: on return contains the module description text.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_oas_supported_show(struct device *dev, struct device_attribute *attr,
   char *buf)
{
 struct Scsi_Host *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
 struct lpfc_hba *phba = vport->phba;

 return scnprintf(buf, PAGE_SIZE, "%d\n",
   phba->sli4_hba.pc_sli4_params.oas_supported);
}

/**
 * lpfc_link_state_store - Transition the link_state on an HBA port
 * @dev: class device that is converted into a Scsi_host.
 * @attr: device attribute, not used.
 * @buf: one or more lpfc_polling_flags values.
 * @count: not used.
 *
 * Returns:
 * -EINVAL if the buffer is not "up" or "down"
 * return from link state change function if non-zero
 * length of the buf on success
 **/

static ssize_t
lpfc_link_state_store(struct device *dev, struct device_attribute *attr,
  const char *buf, size_t count)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 int status = -EINVAL;

 if ((strncmp(buf, "up"sizeof("up") - 1) == 0) &&
   (phba->link_state == LPFC_LINK_DOWN))
  status = phba->lpfc_hba_init_link(phba, MBX_NOWAIT);
 else if ((strncmp(buf, "down"sizeof("down") - 1) == 0) &&
   (phba->link_state >= LPFC_LINK_UP))
  status = phba->lpfc_hba_down_link(phba, MBX_NOWAIT);

 if (status == 0)
  return strlen(buf);
 else
  return status;
}

/**
 * lpfc_num_discovered_ports_show - Return sum of mapped and unmapped vports
 * @dev: class device that is converted into a Scsi_host.
 * @attr: device attribute, not used.
 * @buf: on return contains the sum of fc mapped and unmapped.
 *
 * Description:
 * Returns the ascii text number of the sum of the fc mapped and unmapped
 * vport counts.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_num_discovered_ports_show(struct device *dev,
          struct device_attribute *attr, char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;

 return scnprintf(buf, PAGE_SIZE, "%d\n",
    atomic_read(&vport->fc_map_cnt) +
    atomic_read(&vport->fc_unmap_cnt));
}

/**
 * lpfc_issue_lip - Misnomer, name carried over from long ago
 * @shost: Scsi_Host pointer.
 *
 * Description:
 * Bring the link down gracefully then re-init the link. The firmware will
 * re-init the fiber channel interface as required. Does not issue a LIP.
 *
 * Returns:
 * -EPERM port offline or management commands are being blocked
 * -ENOMEM cannot allocate memory for the mailbox command
 * -EIO error sending the mailbox command
 * zero for success
 **/

static int
lpfc_issue_lip(struct Scsi_Host *shost)
{
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 LPFC_MBOXQ_t *pmboxq;
 int mbxstatus = MBXERR_ERROR;

 /*
 * If the link is offline, disabled or BLOCK_MGMT_IO
 * it doesn't make any sense to allow issue_lip
 */

 if (test_bit(FC_OFFLINE_MODE, &vport->fc_flag) ||
     test_bit(LINK_DISABLED, &phba->hba_flag) ||
     (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO))
  return -EPERM;

 pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL);

 if (!pmboxq)
  return -ENOMEM;

 memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
 pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK;
 pmboxq->u.mb.mbxOwner = OWN_HOST;

 if (test_bit(FC_PT2PT, &vport->fc_flag))
  clear_bit(FC_PT2PT_NO_NVME, &vport->fc_flag);

 mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2);

 if ((mbxstatus == MBX_SUCCESS) &&
     (pmboxq->u.mb.mbxStatus == 0 ||
      pmboxq->u.mb.mbxStatus == MBXERR_LINK_DOWN)) {
  memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
  lpfc_init_link(phba, pmboxq, phba->cfg_topology,
          phba->cfg_link_speed);
  mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq,
           phba->fc_ratov * 2);
  if ((mbxstatus == MBX_SUCCESS) &&
      (pmboxq->u.mb.mbxStatus == MBXERR_SEC_NO_PERMISSION))
   lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI,
     "2859 SLI authentication is required "
     "for INIT_LINK but has not done yet\n");
 }

 lpfc_set_loopback_flag(phba);
 if (mbxstatus != MBX_TIMEOUT)
  mempool_free(pmboxq, phba->mbox_mem_pool);

 if (mbxstatus == MBXERR_ERROR)
  return -EIO;

 return 0;
}

int
lpfc_emptyq_wait(struct lpfc_hba *phba, struct list_head *q, spinlock_t *lock)
{
 int cnt = 0;

 spin_lock_irq(lock);
 while (!list_empty(q)) {
  spin_unlock_irq(lock);
  msleep(20);
  if (cnt++ > 250) {  /* 5 secs */
   lpfc_printf_log(phba, KERN_WARNING, LOG_INIT,
     "0466 Outstanding IO when "
     "bringing Adapter offline\n");
    return 0;
  }
  spin_lock_irq(lock);
 }
 spin_unlock_irq(lock);
 return 1;
}

/**
 * lpfc_do_offline - Issues a mailbox command to bring the link down
 * @phba: lpfc_hba pointer.
 * @type: LPFC_EVT_OFFLINE, LPFC_EVT_WARM_START, LPFC_EVT_KILL.
 *
 * Notes:
 * Assumes any error from lpfc_do_offline() will be negative.
 * Can wait up to 5 seconds for the port ring buffers count
 * to reach zero, prints a warning if it is not zero and continues.
 * lpfc_workq_post_event() returns a non-zero return code if call fails.
 *
 * Returns:
 * -EIO error posting the event
 * zero for success
 **/

static int
lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
{
 struct completion online_compl;
 struct lpfc_queue *qp = NULL;
 struct lpfc_sli_ring *pring;
 struct lpfc_sli *psli;
 int status = 0;
 int i;
 int rc;

 init_completion(&online_compl);
 rc = lpfc_workq_post_event(phba, &status, &online_compl,
         LPFC_EVT_OFFLINE_PREP);
 if (rc == 0)
  return -ENOMEM;

 wait_for_completion(&online_compl);

 if (status != 0)
  return -EIO;

 psli = &phba->sli;

 /*
 * If freeing the queues have already started, don't access them.
 * Otherwise set FREE_WAIT to indicate that queues are being used
 * to hold the freeing process until we finish.
 */

 spin_lock_irq(&phba->hbalock);
 if (!(psli->sli_flag & LPFC_QUEUE_FREE_INIT)) {
  psli->sli_flag |= LPFC_QUEUE_FREE_WAIT;
 } else {
  spin_unlock_irq(&phba->hbalock);
  goto skip_wait;
 }
 spin_unlock_irq(&phba->hbalock);

 /* Wait a little for things to settle down, but not
 * long enough for dev loss timeout to expire.
 */

 if (phba->sli_rev != LPFC_SLI_REV4) {
  for (i = 0; i < psli->num_rings; i++) {
   pring = &psli->sli3_ring[i];
   if (!lpfc_emptyq_wait(phba, &pring->txcmplq,
           &phba->hbalock))
    goto out;
  }
 } else {
  list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) {
   pring = qp->pring;
   if (!pring)
    continue;
   if (!lpfc_emptyq_wait(phba, &pring->txcmplq,
           &pring->ring_lock))
    goto out;
  }
 }
out:
 spin_lock_irq(&phba->hbalock);
 psli->sli_flag &= ~LPFC_QUEUE_FREE_WAIT;
 spin_unlock_irq(&phba->hbalock);

skip_wait:
 init_completion(&online_compl);
 rc = lpfc_workq_post_event(phba, &status, &online_compl, type);
 if (rc == 0)
  return -ENOMEM;

 wait_for_completion(&online_compl);

 if (status != 0)
  return -EIO;

 return 0;
}

/**
 * lpfc_reset_pci_bus - resets PCI bridge controller's secondary bus of an HBA
 * @phba: lpfc_hba pointer.
 *
 * Description:
 * Issues a PCI secondary bus reset for the phba->pcidev.
 *
 * Notes:
 * First walks the bus_list to ensure only PCI devices with Emulex
 * vendor id, device ids that support hot reset, only one occurrence
 * of function 0, and all ports on the bus are in offline mode to ensure the
 * hot reset only affects one valid HBA.
 *
 * Returns:
 * -ENOTSUPP, cfg_enable_hba_reset must be of value 2
 * -ENODEV,   NULL ptr to pcidev
 * -EBADSLT,  detected invalid device
 * -EBUSY,    port is not in offline state
 *      0,    successful
 */

static int
lpfc_reset_pci_bus(struct lpfc_hba *phba)
{
 struct pci_dev *pdev = phba->pcidev;
 struct Scsi_Host *shost = NULL;
 struct lpfc_hba *phba_other = NULL;
 struct pci_dev *ptr = NULL;
 int res;

 if (phba->cfg_enable_hba_reset != 2)
  return -ENOTSUPP;

 if (!pdev) {
  lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "8345 pdev NULL!\n");
  return -ENODEV;
 }

 res = lpfc_check_pci_resettable(phba);
 if (res)
  return res;

 /* Walk the list of devices on the pci_dev's bus */
 list_for_each_entry(ptr, &pdev->bus->devices, bus_list) {
  /* Check port is offline */
  shost = pci_get_drvdata(ptr);
  if (shost) {
   phba_other =
    ((struct lpfc_vport *)shost->hostdata)->phba;
   if (!test_bit(FC_OFFLINE_MODE,
          &phba_other->pport->fc_flag)) {
    lpfc_printf_log(phba_other, KERN_INFO, LOG_INIT,
      "8349 WWPN = 0x%02x%02x%02x%02x"
      "%02x%02x%02x%02x is not "
      "offline!\n",
      phba_other->wwpn[0],
      phba_other->wwpn[1],
      phba_other->wwpn[2],
      phba_other->wwpn[3],
      phba_other->wwpn[4],
      phba_other->wwpn[5],
      phba_other->wwpn[6],
      phba_other->wwpn[7]);
    return -EBUSY;
   }
  }
 }

 /* Issue PCI bus reset */
 res = pci_reset_bus(pdev);
 if (res) {
  lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
    "8350 PCI reset bus failed: %d\n", res);
 }

 return res;
}

/**
 * lpfc_selective_reset - Offline then onlines the port
 * @phba: lpfc_hba pointer.
 *
 * Description:
 * If the port is configured to allow a reset then the hba is brought
 * offline then online.
 *
 * Notes:
 * Assumes any error from lpfc_do_offline() will be negative.
 * Do not make this function static.
 *
 * Returns:
 * lpfc_do_offline() return code if not zero
 * -EIO reset not configured or error posting the event
 * zero for success
 **/

int
lpfc_selective_reset(struct lpfc_hba *phba)
{
 struct completion online_compl;
 int status = 0;
 int rc;

 if (!phba->cfg_enable_hba_reset)
  return -EACCES;

 if (!test_bit(FC_OFFLINE_MODE, &phba->pport->fc_flag)) {
  status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);

  if (status != 0)
   return status;
 }

 init_completion(&online_compl);
 rc = lpfc_workq_post_event(phba, &status, &online_compl,
         LPFC_EVT_ONLINE);
 if (rc == 0)
  return -ENOMEM;

 wait_for_completion(&online_compl);

 if (status != 0)
  return -EIO;

 return 0;
}

/**
 * lpfc_issue_reset - Selectively resets an adapter
 * @dev: class device that is converted into a Scsi_host.
 * @attr: device attribute, not used.
 * @buf: containing the string "selective".
 * @count: unused variable.
 *
 * Description:
 * If the buf contains the string "selective" then lpfc_selective_reset()
 * is called to perform the reset.
 *
 * Notes:
 * Assumes any error from lpfc_selective_reset() will be negative.
 * If lpfc_selective_reset() returns zero then the length of the buffer
 * is returned which indicates success
 *
 * Returns:
 * -EINVAL if the buffer does not contain the string "selective"
 * length of buf if lpfc-selective_reset() if the call succeeds
 * return value of lpfc_selective_reset() if the call fails
**/

static ssize_t
lpfc_issue_reset(struct device *dev, struct device_attribute *attr,
   const char *buf, size_t count)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 int status = -EINVAL;

 if (!phba->cfg_enable_hba_reset)
  return -EACCES;

 if (strncmp(buf, "selective"sizeof("selective") - 1) == 0)
  status = phba->lpfc_selective_reset(phba);

 if (status == 0)
  return strlen(buf);
 else
  return status;
}

/**
 * lpfc_sli4_pdev_status_reg_wait - Wait for pdev status register for readyness
 * @phba: lpfc_hba pointer.
 *
 * Description:
 * SLI4 interface type-2 device to wait on the sliport status register for
 * the readyness after performing a firmware reset.
 *
 * Returns:
 * zero for success, -EPERM when port does not have privilege to perform the
 * reset, -EIO when port timeout from recovering from the reset.
 *
 * Note:
 * As the caller will interpret the return code by value, be careful in making
 * change or addition to return codes.
 **/

int
lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba)
{
 struct lpfc_register portstat_reg = {0};
 int i;

 msleep(100);
 if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
         &portstat_reg.word0))
  return -EIO;

 /* verify if privileged for the request operation */
 if (!bf_get(lpfc_sliport_status_rn, &portstat_reg) &&
     !bf_get(lpfc_sliport_status_err, &portstat_reg))
  return -EPERM;

 /* There is no point to wait if the port is in an unrecoverable
 * state.
 */

 if (lpfc_sli4_unrecoverable_port(&portstat_reg))
  return -EIO;

 /* wait for the SLI port firmware ready after firmware reset */
 for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) {
  msleep(10);
  if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr,
          &portstat_reg.word0))
   continue;
  if (!bf_get(lpfc_sliport_status_err, &portstat_reg))
   continue;
  if (!bf_get(lpfc_sliport_status_rn, &portstat_reg))
   continue;
  if (!bf_get(lpfc_sliport_status_rdy, &portstat_reg))
   continue;
  break;
 }

 if (i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT)
  return 0;
 else
  return -EIO;
}

/**
 * lpfc_sli4_pdev_reg_request - Request physical dev to perform a register acc
 * @phba: lpfc_hba pointer.
 * @opcode: The sli4 config command opcode.
 *
 * Description:
 * Request SLI4 interface type-2 device to perform a physical register set
 * access.
 *
 * Returns:
 * zero for success
 **/

static ssize_t
lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode)
{
 struct completion online_compl;
 struct pci_dev *pdev = phba->pcidev;
 unsigned long before_fc_flag;
 uint32_t sriov_nr_virtfn;
 uint32_t reg_val;
 int status = 0, rc = 0;
 int job_posted = 1, sriov_err;

 if (!phba->cfg_enable_hba_reset)
  return -EACCES;

 if ((phba->sli_rev < LPFC_SLI_REV4) ||
     (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) <
      LPFC_SLI_INTF_IF_TYPE_2))
  return -EPERM;

 /* Keep state if we need to restore back */
 before_fc_flag = phba->pport->fc_flag;
 sriov_nr_virtfn = phba->cfg_sriov_nr_virtfn;

 if (opcode == LPFC_FW_DUMP) {
  init_completion(&online_compl);
  phba->fw_dump_cmpl = &online_compl;
 } else {
  /* Disable SR-IOV virtual functions if enabled */
  if (phba->cfg_sriov_nr_virtfn) {
   pci_disable_sriov(pdev);
   phba->cfg_sriov_nr_virtfn = 0;
  }

  status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);

  if (status != 0)
   return status;

  /* wait for the device to be quiesced before firmware reset */
  msleep(100);
 }

 reg_val = readl(phba->sli4_hba.conf_regs_memmap_p +
   LPFC_CTL_PDEV_CTL_OFFSET);

 if (opcode == LPFC_FW_DUMP)
  reg_val |= LPFC_FW_DUMP_REQUEST;
 else if (opcode == LPFC_FW_RESET)
  reg_val |= LPFC_CTL_PDEV_CTL_FRST;
 else if (opcode == LPFC_DV_RESET)
  reg_val |= LPFC_CTL_PDEV_CTL_DRST;

 writel(reg_val, phba->sli4_hba.conf_regs_memmap_p +
        LPFC_CTL_PDEV_CTL_OFFSET);
 /* flush */
 readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET);

 /* delay driver action following IF_TYPE_2 reset */
 rc = lpfc_sli4_pdev_status_reg_wait(phba);

 if (rc == -EPERM) {
  /* no privilege for reset */
  lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
    "3150 No privilege to perform the requested "
    "access: x%x\n", reg_val);
 } else if (rc == -EIO) {
  /* reset failed, there is nothing more we can do */
  lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
    "3153 Fail to perform the requested "
    "access: x%x\n", reg_val);
  if (phba->fw_dump_cmpl)
   phba->fw_dump_cmpl = NULL;
  return rc;
 }

 /* keep the original port state */
 if (test_bit(FC_OFFLINE_MODE, &before_fc_flag)) {
  if (phba->fw_dump_cmpl)
   phba->fw_dump_cmpl = NULL;
  goto out;
 }

 /* Firmware dump will trigger an HA_ERATT event, and
 * lpfc_handle_eratt_s4 routine already handles bringing the port back
 * online.
 */

 if (opcode == LPFC_FW_DUMP) {
  wait_for_completion(phba->fw_dump_cmpl);
 } else  {
  init_completion(&online_compl);
  job_posted = lpfc_workq_post_event(phba, &status, &online_compl,
         LPFC_EVT_ONLINE);
  if (!job_posted)
   goto out;

  wait_for_completion(&online_compl);
 }
out:
 /* in any case, restore the virtual functions enabled as before */
 if (sriov_nr_virtfn) {
  /* If fw_dump was performed, first disable to clean up */
  if (opcode == LPFC_FW_DUMP) {
   pci_disable_sriov(pdev);
   phba->cfg_sriov_nr_virtfn = 0;
  }

  sriov_err =
   lpfc_sli_probe_sriov_nr_virtfn(phba, sriov_nr_virtfn);
  if (!sriov_err)
   phba->cfg_sriov_nr_virtfn = sriov_nr_virtfn;
 }

 /* return proper error code */
 if (!rc) {
  if (!job_posted)
   rc = -ENOMEM;
  else if (status)
   rc = -EIO;
 }
 return rc;
}

/**
 * lpfc_nport_evt_cnt_show - Return the number of nport events
 * @dev: class device that is converted into a Scsi_host.
 * @attr: device attribute, not used.
 * @buf: on return contains the ascii number of nport events.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_nport_evt_cnt_show(struct device *dev, struct device_attribute *attr,
   char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;

 return scnprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
}

static int
lpfc_set_trunking(struct lpfc_hba *phba, char *buff_out)
{
 LPFC_MBOXQ_t *mbox = NULL;
 u32 payload_len;
 unsigned long val = 0;
 char *pval = NULL;
 int rc = 0;

 if (!strncmp("enable", buff_out,
     strlen("enable"))) {
  pval = buff_out + strlen("enable") + 1;
  rc = kstrtoul(pval, 0, &val);
  if (rc)
   return rc; /* Invalid  number */
 } else if (!strncmp("disable", buff_out,
     strlen("disable"))) {
  val = 0;
 } else {
  return -EINVAL;  /* Invalid command */
 }

 switch (val) {
 case 0:
  val = 0x0; /* Disable */
  break;
 case 2:
  val = 0x1; /* Enable two port trunk */
  break;
 case 4:
  val = 0x2; /* Enable four port trunk */
  break;
 default:
  return -EINVAL;
 }

 lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
   "0070 Set trunk mode with val %ld ", val);

 mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
 if (!mbox)
  return -ENOMEM;

 payload_len = sizeof(struct lpfc_mbx_set_trunk_mode) -
        sizeof(struct lpfc_sli4_cfg_mhdr);
 lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE,
    LPFC_MBOX_OPCODE_FCOE_FC_SET_TRUNK_MODE,
    payload_len, LPFC_SLI4_MBX_EMBED);

 bf_set(lpfc_mbx_set_trunk_mode,
        &mbox->u.mqe.un.set_trunk_mode,
        val);
 rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL);
 if (rc)
  lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
    "0071 Set trunk mode failed with status: %d",
    rc);
 mempool_free(mbox, phba->mbox_mem_pool);

 return 0;
}

static ssize_t
lpfc_xcvr_data_show(struct device *dev, struct device_attribute *attr,
      char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 int rc;
 int len = 0;
 struct lpfc_rdp_context *rdp_context;
 u16 temperature;
 u16 rx_power;
 u16 tx_bias;
 u16 tx_power;
 u16 vcc;
 char chbuf[128];
 u16 wavelength = 0;
 struct sff_trasnceiver_codes_byte7 *trasn_code_byte7;

 /* Get transceiver information */
 rdp_context = kmalloc(sizeof(*rdp_context), GFP_KERNEL);
 if (!rdp_context) {
  len = scnprintf(buf, PAGE_SIZE - len,
    "SPF info NA: alloc failure\n");
  return len;
 }

 rc = lpfc_get_sfp_info_wait(phba, rdp_context);
 if (rc) {
  len = scnprintf(buf, PAGE_SIZE - len, "SFP info NA:\n");
  goto out_free_rdp;
 }

 strscpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_NAME], 16);

 len = scnprintf(buf, PAGE_SIZE - len, "VendorName:\t%s\n", chbuf);
 len += scnprintf(buf + len, PAGE_SIZE - len,
    "VendorOUI:\t%02x-%02x-%02x\n",
    (uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI],
    (uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI + 1],
    (uint8_t)rdp_context->page_a0[SSF_VENDOR_OUI + 2]);
 strscpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_PN], 16);
 len += scnprintf(buf + len, PAGE_SIZE - len, "VendorPN:\t%s\n", chbuf);
 strscpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_SN], 16);
 len += scnprintf(buf + len, PAGE_SIZE - len, "VendorSN:\t%s\n", chbuf);
 strscpy(chbuf, &rdp_context->page_a0[SSF_VENDOR_REV], 4);
 len += scnprintf(buf + len, PAGE_SIZE - len, "VendorRev:\t%s\n", chbuf);
 strscpy(chbuf, &rdp_context->page_a0[SSF_DATE_CODE], 8);
 len += scnprintf(buf + len, PAGE_SIZE - len, "DateCode:\t%s\n", chbuf);
 len += scnprintf(buf + len, PAGE_SIZE - len, "Identifier:\t%xh\n",
    (uint8_t)rdp_context->page_a0[SSF_IDENTIFIER]);
 len += scnprintf(buf + len, PAGE_SIZE - len, "ExtIdentifier:\t%xh\n",
    (uint8_t)rdp_context->page_a0[SSF_EXT_IDENTIFIER]);
 len += scnprintf(buf + len, PAGE_SIZE - len, "Connector:\t%xh\n",
    (uint8_t)rdp_context->page_a0[SSF_CONNECTOR]);
 wavelength = (rdp_context->page_a0[SSF_WAVELENGTH_B1] << 8) |
        rdp_context->page_a0[SSF_WAVELENGTH_B0];

 len += scnprintf(buf + len, PAGE_SIZE - len, "Wavelength:\t%d nm\n",
    wavelength);
 trasn_code_byte7 = (struct sff_trasnceiver_codes_byte7 *)
   &rdp_context->page_a0[SSF_TRANSCEIVER_CODE_B7];

 len += scnprintf(buf + len, PAGE_SIZE - len, "Speeds: \t");
 if (*(uint8_t *)trasn_code_byte7 == 0) {
  len += scnprintf(buf + len, PAGE_SIZE - len, "Unknown\n");
 } else {
  if (trasn_code_byte7->fc_sp_100MB)
   len += scnprintf(buf + len, PAGE_SIZE - len, "1 ");
  if (trasn_code_byte7->fc_sp_200mb)
   len += scnprintf(buf + len, PAGE_SIZE - len, "2 ");
  if (trasn_code_byte7->fc_sp_400MB)
   len += scnprintf(buf + len, PAGE_SIZE - len, "4 ");
  if (trasn_code_byte7->fc_sp_800MB)
   len += scnprintf(buf + len, PAGE_SIZE - len, "8 ");
  if (trasn_code_byte7->fc_sp_1600MB)
   len += scnprintf(buf + len, PAGE_SIZE - len, "16 ");
  if (trasn_code_byte7->fc_sp_3200MB)
   len += scnprintf(buf + len, PAGE_SIZE - len, "32 ");
  if (trasn_code_byte7->speed_chk_ecc)
   len += scnprintf(buf + len, PAGE_SIZE - len, "64 ");
  len += scnprintf(buf + len, PAGE_SIZE - len, "GB\n");
 }
 temperature = (rdp_context->page_a2[SFF_TEMPERATURE_B1] << 8 |
         rdp_context->page_a2[SFF_TEMPERATURE_B0]);
 vcc = (rdp_context->page_a2[SFF_VCC_B1] << 8 |
        rdp_context->page_a2[SFF_VCC_B0]);
 tx_power = (rdp_context->page_a2[SFF_TXPOWER_B1] << 8 |
      rdp_context->page_a2[SFF_TXPOWER_B0]);
 tx_bias = (rdp_context->page_a2[SFF_TX_BIAS_CURRENT_B1] << 8 |
     rdp_context->page_a2[SFF_TX_BIAS_CURRENT_B0]);
 rx_power = (rdp_context->page_a2[SFF_RXPOWER_B1] << 8 |
      rdp_context->page_a2[SFF_RXPOWER_B0]);

 len += scnprintf(buf + len, PAGE_SIZE - len,
    "Temperature:\tx%04x C\n", temperature);
 len += scnprintf(buf + len, PAGE_SIZE - len, "Vcc:\t\tx%04x V\n", vcc);
 len += scnprintf(buf + len, PAGE_SIZE - len,
    "TxBiasCurrent:\tx%04x mA\n", tx_bias);
 len += scnprintf(buf + len, PAGE_SIZE - len, "TxPower:\tx%04x mW\n",
    tx_power);
 len += scnprintf(buf + len, PAGE_SIZE - len, "RxPower:\tx%04x mW\n",
    rx_power);
out_free_rdp:
 kfree(rdp_context);
 return len;
}

/**
 * lpfc_board_mode_show - Return the state of the board
 * @dev: class device that is converted into a Scsi_host.
 * @attr: device attribute, not used.
 * @buf: on return contains the state of the adapter.
 *
 * Returns: size of formatted string.
 **/

static ssize_t
lpfc_board_mode_show(struct device *dev, struct device_attribute *attr,
       char *buf)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 char  * state;

 if (phba->link_state == LPFC_HBA_ERROR)
  state = "error";
 else if (phba->link_state == LPFC_WARM_START)
  state = "warm start";
 else if (phba->link_state == LPFC_INIT_START)
  state = "offline";
 else
  state = "online";

 return scnprintf(buf, PAGE_SIZE, "%s\n", state);
}

/**
 * lpfc_board_mode_store - Puts the hba in online, offline, warm or error state
 * @dev: class device that is converted into a Scsi_host.
 * @attr: device attribute, not used.
 * @buf: containing one of the strings "online", "offline", "warm" or "error".
 * @count: unused variable.
 *
 * Returns:
 * -EACCES if enable hba reset not enabled
 * -EINVAL if the buffer does not contain a valid string (see above)
 * -EIO if lpfc_workq_post_event() or lpfc_do_offline() fails
 * buf length greater than zero indicates success
 **/

static ssize_t
lpfc_board_mode_store(struct device *dev, struct device_attribute *attr,
        const char *buf, size_t count)
{
 struct Scsi_Host  *shost = class_to_shost(dev);
 struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
 struct lpfc_hba   *phba = vport->phba;
 struct completion online_compl;
 char *board_mode_str = NULL;
 int status = 0;
 int rc;

 if (!phba->cfg_enable_hba_reset) {
  status = -EACCES;
  goto board_mode_out;
 }

 lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT,
    "3050 lpfc_board_mode set to %s\n", buf);

 init_completion(&online_compl);

 if(strncmp(buf, "online"sizeof("online") - 1) == 0) {
  rc = lpfc_workq_post_event(phba, &status, &online_compl,
          LPFC_EVT_ONLINE);
  if (rc == 0) {
   status = -ENOMEM;
   goto board_mode_out;
  }
  wait_for_completion(&online_compl);
  if (status)
   status = -EIO;
 } else if (strncmp(buf, "offline"sizeof("offline") - 1) == 0)
  status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE);
 else if (strncmp(buf, "warm"sizeof("warm") - 1) == 0)
  if (phba->sli_rev == LPFC_SLI_REV4)
   status = -EINVAL;
  else
   status = lpfc_do_offline(phba, LPFC_EVT_WARM_START);
 else if (strncmp(buf, "error"sizeof("error") - 1) == 0)
  if (phba->sli_rev == LPFC_SLI_REV4)
   status = -EINVAL;
  else
   status = lpfc_do_offline(phba, LPFC_EVT_KILL);
 else if (strncmp(buf, "dump"sizeof("dump") - 1) == 0)
  status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_DUMP);
 else if (strncmp(buf, "fw_reset"sizeof("fw_reset") - 1) == 0)
  status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_RESET);
 else if (strncmp(buf, "dv_reset"sizeof("dv_reset") - 1) == 0)
  status = lpfc_sli4_pdev_reg_request(phba, LPFC_DV_RESET);
 else if (strncmp(buf, "pci_bus_reset"sizeof("pci_bus_reset") - 1)
   == 0)
  status = lpfc_reset_pci_bus(phba);
 else if (strncmp(buf, "heartbeat"sizeof("heartbeat") - 1) == 0)
  lpfc_issue_hb_tmo(phba);
 else if (strncmp(buf, "trunk"sizeof("trunk") - 1) == 0)
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=94 H=90 G=91

¤ Dauer der Verarbeitung: 0.46 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.