Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 895427bd authored by James Smart's avatar James Smart Committed by Martin K. Petersen
Browse files

scsi: lpfc: NVME Initiator: Base modifications



NVME Initiator: Base modifications

This patch adds base modifications for NVME initiator support.

The base modifications consist of:
- Formal split of SLI3 rings from SLI-4 WQs (sometimes referred to as
  rings as well) as implementation now widely varies between the two.
- Addition of configuration modes:
   SCSI initiator only; NVME initiator only; NVME target only; and
   SCSI and NVME initiator.
   The configuration mode drives overall adapter configuration,
   offloads enabled, and resource splits.
   NVME support is only available on SLI-4 devices and newer fw.
- Implements the following based on configuration mode:
  - Exchange resources are split by protocol; Obviously, if only
     1 mode, then no split occurs. Default is 50/50. module attribute
     allows tuning.
  - Pools and config parameters are separated per-protocol
  - Each protocol has it's own set of queues, but share interrupt
    vectors.
     SCSI:
       SLI3 devices have few queues and the original style of queue
         allocation remains.
       SLI4 devices piggy back on an "io-channel" concept that
         eventually needs to merge with scsi-mq/blk-mq support (it is
	 underway).  For now, the paradigm continues as it existed
	 prior. io channel allocates N msix and N WQs (N=4 default)
	 and either round robins or uses cpu # modulo N for scheduling.
	 A bunch of module parameters allow the configuration to be
	 tuned.
     NVME (initiator):
       Allocates an msix per cpu (or whatever pci_alloc_irq_vectors
         gets)
       Allocates a WQ per cpu, and maps the WQs to msix on a WQ #
         modulo msix vector count basis.
       Module parameters exist to cap/control the config if desired.
  - Each protocol has its own buffer and dma pools.

I apologize for the size of the patch.

Signed-off-by: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <james.smart@broadcom.com>

----
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 1d9d5a98
Loading
Loading
Loading
Loading
+71 −9
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
 *******************************************************************/

#include <scsi/scsi_host.h>
#include <linux/ktime.h>

#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_SCSI_LPFC_DEBUG_FS)
#define CONFIG_SCSI_LPFC_DEBUG_FS
@@ -53,6 +54,7 @@ struct lpfc_sli2_slim;
#define LPFC_MAX_SG_SEG_CNT	4096	/* sg element count per scsi cmnd */
#define LPFC_MAX_SGL_SEG_CNT	512	/* SGL element count per scsi cmnd */
#define LPFC_MAX_BPL_SEG_CNT	4096	/* BPL element count per scsi cmnd */
#define LPFC_MIN_NVME_SEG_CNT	254

#define LPFC_MAX_SGE_SIZE       0x80000000 /* Maximum data allowed in a SGE */
#define LPFC_IOCB_LIST_CNT	2250	/* list of IOCBs for fast-path usage. */
@@ -114,6 +116,13 @@ enum lpfc_polling_flags {
	DISABLE_FCP_RING_INT    = 0x2
};

struct perf_prof {
	uint16_t cmd_cpu[40];
	uint16_t rsp_cpu[40];
	uint16_t qh_cpu[40];
	uint16_t wqidx[40];
};

/* Provide DMA memory definitions the driver uses per port instance. */
struct lpfc_dmabuf {
	struct list_head list;
@@ -131,10 +140,24 @@ struct lpfc_dma_pool {
struct hbq_dmabuf {
	struct lpfc_dmabuf hbuf;
	struct lpfc_dmabuf dbuf;
	uint32_t size;
	uint16_t total_size;
	uint16_t bytes_recv;
	uint32_t tag;
	struct lpfc_cq_event cq_event;
	unsigned long time_stamp;
	void *context;
};

struct rqb_dmabuf {
	struct lpfc_dmabuf hbuf;
	struct lpfc_dmabuf dbuf;
	uint16_t total_size;
	uint16_t bytes_recv;
	void *context;
	struct lpfc_iocbq *iocbq;
	struct lpfc_sglq *sglq;
	struct lpfc_queue *hrq;	  /* ptr to associated Header RQ */
	struct lpfc_queue *drq;	  /* ptr to associated Data RQ */
};

/* Priority bit.  Set value to exceed low water mark in lpfc_mem. */
@@ -442,6 +465,11 @@ struct lpfc_vport {
	uint16_t fdmi_num_disc;
	uint32_t fdmi_hba_mask;
	uint32_t fdmi_port_mask;

	/* There is a single nvme instance per vport. */
	struct nvme_fc_local_port *localport;
	uint8_t  nvmei_support; /* driver supports NVME Initiator */
	uint32_t last_fcp_wqidx;
};

struct hbq_s {
@@ -459,10 +487,9 @@ struct hbq_s {
					       struct hbq_dmabuf *);
};

#define LPFC_MAX_HBQS  4
/* this matches the position in the lpfc_hbq_defs array */
#define LPFC_ELS_HBQ	0
#define LPFC_EXTRA_HBQ	1
#define LPFC_MAX_HBQS	1

enum hba_temp_state {
	HBA_NORMAL_TEMP,
@@ -652,6 +679,8 @@ struct lpfc_hba {
					 * Firmware supports Forced Link Speed
					 * capability
					 */
#define HBA_NVME_IOQ_FLUSH      0x80000 /* NVME IO queues flushed. */

	uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/
	struct lpfc_dmabuf slim2p;

@@ -700,6 +729,8 @@ struct lpfc_hba {
	uint8_t  wwpn[8];
	uint32_t RandomData[7];
	uint8_t  fcp_embed_io;
	uint8_t  nvme_support;	/* Firmware supports NVME */
	uint8_t  nvmet_support;	/* driver supports NVMET */
	uint8_t  mds_diags_support;

	/* HBA Config Parameters */
@@ -725,6 +756,9 @@ struct lpfc_hba {
	uint32_t cfg_fcp_imax;
	uint32_t cfg_fcp_cpu_map;
	uint32_t cfg_fcp_io_channel;
	uint32_t cfg_nvme_oas;
	uint32_t cfg_nvme_io_channel;
	uint32_t cfg_nvme_enable_fb;
	uint32_t cfg_total_seg_cnt;
	uint32_t cfg_sg_seg_cnt;
	uint32_t cfg_sg_dma_buf_size;
@@ -770,6 +804,12 @@ struct lpfc_hba {
#define LPFC_FDMI_SUPPORT	1	/* FDMI supported? */
	uint32_t cfg_enable_SmartSAN;
	uint32_t cfg_enable_mds_diags;
	uint32_t cfg_enable_fc4_type;
	uint32_t cfg_xri_split;
#define LPFC_ENABLE_FCP  1
#define LPFC_ENABLE_NVME 2
#define LPFC_ENABLE_BOTH 3
	uint32_t io_channel_irqs;	/* number of irqs for io channels */
	lpfc_vpd_t vpd;		/* vital product data */

	struct pci_dev *pcidev;
@@ -784,11 +824,11 @@ struct lpfc_hba {
	unsigned long data_flags;

	uint32_t hbq_in_use;		/* HBQs in use flag */
	struct list_head rb_pend_list;  /* Received buffers to be processed */
	uint32_t hbq_count;	        /* Count of configured HBQs */
	struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies  */

	atomic_t fcp_qidx;		/* next work queue to post work to */
	atomic_t fcp_qidx;         /* next FCP WQ (RR Policy) */
	atomic_t nvme_qidx;        /* next NVME WQ (RR Policy) */

	phys_addr_t pci_bar0_map;     /* Physical address for PCI BAR0 */
	phys_addr_t pci_bar1_map;     /* Physical address for PCI BAR1 */
@@ -843,9 +883,17 @@ struct lpfc_hba {
	/*
	 * stat  counters
	 */
	uint64_t fc4InputRequests;
	uint64_t fc4OutputRequests;
	uint64_t fc4ControlRequests;
	uint64_t fc4ScsiInputRequests;
	uint64_t fc4ScsiOutputRequests;
	uint64_t fc4ScsiControlRequests;
	uint64_t fc4ScsiIoCmpls;
	uint64_t fc4NvmeInputRequests;
	uint64_t fc4NvmeOutputRequests;
	uint64_t fc4NvmeControlRequests;
	uint64_t fc4NvmeIoCmpls;
	uint64_t fc4NvmeLsRequests;
	uint64_t fc4NvmeLsCmpls;

	uint64_t bg_guard_err_cnt;
	uint64_t bg_apptag_err_cnt;
	uint64_t bg_reftag_err_cnt;
@@ -856,17 +904,23 @@ struct lpfc_hba {
	struct list_head lpfc_scsi_buf_list_get;
	struct list_head lpfc_scsi_buf_list_put;
	uint32_t total_scsi_bufs;
	spinlock_t nvme_buf_list_get_lock;  /* NVME buf alloc list lock */
	spinlock_t nvme_buf_list_put_lock;  /* NVME buf free list lock */
	struct list_head lpfc_nvme_buf_list_get;
	struct list_head lpfc_nvme_buf_list_put;
	uint32_t total_nvme_bufs;
	struct list_head lpfc_iocb_list;
	uint32_t total_iocbq_bufs;
	struct list_head active_rrq_list;
	spinlock_t hbalock;

	/* pci_mem_pools */
	struct pci_pool *lpfc_scsi_dma_buf_pool;
	struct pci_pool *lpfc_sg_dma_buf_pool;
	struct pci_pool *lpfc_mbuf_pool;
	struct pci_pool *lpfc_hrb_pool;	/* header receive buffer pool */
	struct pci_pool *lpfc_drb_pool; /* data receive buffer pool */
	struct pci_pool *lpfc_hbq_pool;	/* SLI3 hbq buffer pool */
	struct pci_pool *txrdy_payload_pool;
	struct lpfc_dma_pool lpfc_mbuf_safety_pool;

	mempool_t *mbox_mem_pool;
@@ -1092,3 +1146,11 @@ lpfc_sli_read_hs(struct lpfc_hba *phba)

	return 0;
}

static inline struct lpfc_sli_ring *
lpfc_phba_elsring(struct lpfc_hba *phba)
{
	if (phba->sli_rev == LPFC_SLI_REV4)
		return phba->sli4_hba.els_wq->pring;
	return &phba->sli.sli3_ring[LPFC_ELS_RING];
}
+334 −40
Original line number Diff line number Diff line
@@ -35,14 +35,17 @@
#include <scsi/scsi_transport_fc.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_scsi.h"
#include "lpfc.h"
#include "lpfc_scsi.h"
#include "lpfc_nvme.h"
#include "lpfc_logmsg.h"
#include "lpfc_version.h"
#include "lpfc_compat.h"
@@ -129,6 +132,124 @@ lpfc_enable_fip_show(struct device *dev, struct device_attribute *attr,
		return snprintf(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 nvme_fc_local_port *localport;
	struct lpfc_nvme_lport *lport;
	struct lpfc_nvme_rport *rport;
	struct nvme_fc_remote_port *nrport;
	char *statep;
	int len = 0;

	if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) {
		len += snprintf(buf, PAGE_SIZE, "NVME Disabled\n");
		return len;
	}

	localport = vport->localport;
	if (!localport) {
		len = snprintf(buf, PAGE_SIZE,
				"NVME Initiator x%llx is not allocated\n",
				wwn_to_u64(vport->fc_portname.u.wwn));
		return len;
	}
	len = snprintf(buf, PAGE_SIZE, "NVME Initiator Enabled\n");

	spin_lock_irq(shost->host_lock);
	lport = (struct lpfc_nvme_lport *)localport->private;

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

	len += snprintf(buf + len, PAGE_SIZE - len,
			"%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);

	list_for_each_entry(rport, &lport->rport_list, list) {
		/* local short-hand pointer. */
		nrport = rport->remoteport;

		/* 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. */
		len += snprintf(buf + len, PAGE_SIZE - len,
				"NVME RPORT       ");
		if (phba->brd_no >= 10)
			len += snprintf(buf + len, PAGE_SIZE - len, " ");

		len += snprintf(buf + len, PAGE_SIZE - len, "WWPN x%llx ",
				nrport->port_name);
		len += snprintf(buf + len, PAGE_SIZE - len, "WWNN x%llx ",
				nrport->node_name);
		len += snprintf(buf + len, PAGE_SIZE - len, "DID x%06x ",
				nrport->port_id);

		switch (nrport->port_role) {
		case FC_PORT_ROLE_NVME_INITIATOR:
			len +=  snprintf(buf + len, PAGE_SIZE - len,
					 "INITIATOR ");
			break;
		case FC_PORT_ROLE_NVME_TARGET:
			len +=  snprintf(buf + len, PAGE_SIZE - len,
					 "TARGET ");
			break;
		case FC_PORT_ROLE_NVME_DISCOVERY:
			len +=  snprintf(buf + len, PAGE_SIZE - len,
					 "DISCOVERY ");
			break;
		default:
			len +=  snprintf(buf + len, PAGE_SIZE - len,
					 "UNKNOWN_ROLE x%x",
					 nrport->port_role);
			break;
		}
		len +=  snprintf(buf + len, PAGE_SIZE - len, "%s  ", statep);
		/* Terminate the string. */
		len +=  snprintf(buf + len, PAGE_SIZE - len, "\n");
	}
	spin_unlock_irq(shost->host_lock);

	len += snprintf(buf + len, PAGE_SIZE, "\nNVME Statistics\n");
	len += snprintf(buf+len, PAGE_SIZE-len,
			"LS: Xmt %016llx Cmpl %016llx\n",
			phba->fc4NvmeLsRequests,
			phba->fc4NvmeLsCmpls);

	len += snprintf(buf+len, PAGE_SIZE-len,
			"FCP: Rd %016llx Wr %016llx IO %016llx\n",
			phba->fc4NvmeInputRequests,
			phba->fc4NvmeOutputRequests,
			phba->fc4NvmeControlRequests);

	len += snprintf(buf+len, PAGE_SIZE-len,
			"    Cmpl %016llx\n", phba->fc4NvmeIoCmpls);

	return len;
}

static ssize_t
lpfc_bg_info_show(struct device *dev, struct device_attribute *attr,
		  char *buf)
@@ -675,6 +796,28 @@ lpfc_issue_lip(struct Scsi_Host *shost)
	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 %s %s\n",
					"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.
@@ -694,10 +837,10 @@ 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 cnt = 0;
	int i;
	int rc;

@@ -717,20 +860,24 @@ lpfc_do_offline(struct lpfc_hba *phba, uint32_t type)
	/* 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->ring[i];
		while (!list_empty(&pring->txcmplq)) {
			msleep(10);
			if (cnt++ > 500) {  /* 5 secs */
				lpfc_printf_log(phba,
					KERN_WARNING, LOG_INIT,
					"0466 Outstanding IO when "
					"bringing Adapter offline\n");
				break;
			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:
	init_completion(&online_compl);
	rc = lpfc_workq_post_event(phba, &status, &online_compl, type);
	if (rc == 0)
@@ -1945,6 +2092,7 @@ lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \
}


static DEVICE_ATTR(nvme_info, 0444, lpfc_nvme_info_show, NULL);
static DEVICE_ATTR(bg_info, S_IRUGO, lpfc_bg_info_show, NULL);
static DEVICE_ATTR(bg_guard_err, S_IRUGO, lpfc_bg_guard_err_show, NULL);
static DEVICE_ATTR(bg_apptag_err, S_IRUGO, lpfc_bg_apptag_err_show, NULL);
@@ -2816,9 +2964,9 @@ lpfc_txq_hw_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct Scsi_Host  *shost = class_to_shost(dev);
	struct lpfc_hba   *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
	struct lpfc_sli_ring *pring = lpfc_phba_elsring(phba);

	return snprintf(buf, PAGE_SIZE, "%d\n",
		phba->sli.ring[LPFC_ELS_RING].txq_max);
	return snprintf(buf, PAGE_SIZE, "%d\n", pring->txq_max);
}

static DEVICE_ATTR(txq_hw, S_IRUGO,
@@ -2829,9 +2977,9 @@ lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr,
{
	struct Scsi_Host  *shost = class_to_shost(dev);
	struct lpfc_hba   *phba = ((struct lpfc_vport *) shost->hostdata)->phba;
	struct lpfc_sli_ring *pring = lpfc_phba_elsring(phba);

	return snprintf(buf, PAGE_SIZE, "%d\n",
		phba->sli.ring[LPFC_ELS_RING].txcmplq_max);
	return snprintf(buf, PAGE_SIZE, "%d\n", pring->txcmplq_max);
}

static DEVICE_ATTR(txcmplq_hw, S_IRUGO,
@@ -3029,6 +3177,31 @@ lpfc_vport_param_store(devloss_tmo)
static DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
		   lpfc_devloss_tmo_show, lpfc_devloss_tmo_store);

/*
 * lpfc_enable_fc4_type: Defines what FC4 types are supported.
 * Supported Values:  1 - register just FCP
 *                    3 - register both FCP and NVME
 * Supported values are [1,3]. Default value is 3
 */
LPFC_ATTR_R(enable_fc4_type, LPFC_ENABLE_BOTH,
	    LPFC_ENABLE_FCP, LPFC_ENABLE_BOTH,
	    "Define fc4 type to register with fabric.");

/*
 * lpfc_xri_split: Defines the division of XRI resources between SCSI and NVME
 * This parameter is only used if:
 *     lpfc_enable_fc4_type is 3 - register both FCP and NVME
 *
 * ELS/CT always get 10% of XRIs, up to a maximum of 250
 * The remaining XRIs get split up based on lpfc_xri_split per port:
 *
 * Supported Values are in percentages
 * the xri_split value is the percentage the SCSI port will get. The remaining
 * percentage will go to NVME.
 */
LPFC_ATTR_R(xri_split, 50, 10, 90,
	     "Division of XRI resources between SCSI and NVME");

/*
# lpfc_log_verbose: Only turn this flag on if you are willing to risk being
# deluged with LOTS of information.
@@ -4143,13 +4316,14 @@ lpfc_fcp_imax_store(struct device *dev, struct device_attribute *attr,
	/*
	 * Value range for the HBA is [5000,5000000]
	 * The value for each EQ depends on how many EQs are configured.
	 * Allow value == 0
	 */
	if (val < LPFC_MIN_IMAX || val > LPFC_MAX_IMAX)
	if (val && (val < LPFC_MIN_IMAX || val > LPFC_MAX_IMAX))
		return -EINVAL;

	phba->cfg_fcp_imax = (uint32_t)val;
	for (i = 0; i < phba->cfg_fcp_io_channel; i += LPFC_MAX_EQ_DELAY)
		lpfc_modify_fcp_eq_delay(phba, i);
	for (i = 0; i < phba->io_channel_irqs; i++)
		lpfc_modify_hba_eq_delay(phba, i);

	return strlen(buf);
}
@@ -4187,7 +4361,8 @@ lpfc_fcp_imax_init(struct lpfc_hba *phba, int val)
		return 0;
	}

	if (val >= LPFC_MIN_IMAX && val <= LPFC_MAX_IMAX) {
	if ((val >= LPFC_MIN_IMAX && val <= LPFC_MAX_IMAX) ||
	    (val == 0)) {
		phba->cfg_fcp_imax = val;
		return 0;
	}
@@ -4376,6 +4551,17 @@ LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1,
LPFC_VPORT_ATTR_RW(first_burst_size, 0, 0, 65536,
		   "First burst size for Targets that support first burst");

/*
* lpfc_nvme_enable_fb: Enable NVME first burst on I and T functions.
* For the Initiator (I), enabling this parameter means that an NVME
* PRLI response with FBA enabled and an FB_SIZE set to a nonzero value
* will be processed by the initiator for subsequent NVME FCP IO.
* Parameter supported on physical port only - no NPIV support.
* Value range is [0,1]. Default value is 0 (disabled).
*/
LPFC_ATTR_RW(nvme_enable_fb, 0, 0, 1,
	     "Enable First Burst feature on I and T functions.");

/*
# lpfc_max_scsicmpl_time: Use scsi command completion time to control I/O queue
# depth. Default value is 0. When the value of this parameter is zero the
@@ -4423,16 +4609,24 @@ static DEVICE_ATTR(lpfc_max_scsicmpl_time, S_IRUGO | S_IWUSR,
LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support");

/*
# lpfc_fcp_io_sched: Determine scheduling algrithmn for issuing FCP cmds
# range is [0,1]. Default value is 0.
# For [0], FCP commands are issued to Work Queues ina round robin fashion.
# For [1], FCP commands are issued to a Work Queue associated with the
#          current CPU.
# It would be set to 1 by the driver if it's able to set up cpu affinity
# for FCP I/Os through Work Queue associated with the current CPU. Otherwise,
# roundrobin scheduling of FCP I/Os through WQs will be used.
 * lpfc_io_sched: Determine scheduling algrithmn for issuing FCP cmds
 * range is [0,1]. Default value is 0.
 * For [0], FCP commands are issued to Work Queues ina round robin fashion.
 * For [1], FCP commands are issued to a Work Queue associated with the
 *          current CPU.
 *
 * LPFC_FCP_SCHED_ROUND_ROBIN == 0
 * LPFC_FCP_SCHED_BY_CPU == 1
 *
 * The driver dynamically sets this to 1 (BY_CPU) if it's able to set up cpu
 * affinity for FCP/NVME I/Os through Work Queues associated with the current
 * CPU. Otherwise, the default 0 (Round Robin) scheduling of FCP/NVME I/Os
 * through WQs will be used.
 */
LPFC_ATTR_RW(fcp_io_sched, 0, 0, 1, "Determine scheduling algorithm for "
LPFC_ATTR_RW(fcp_io_sched, LPFC_FCP_SCHED_ROUND_ROBIN,
	     LPFC_FCP_SCHED_ROUND_ROBIN,
	     LPFC_FCP_SCHED_BY_CPU,
	     "Determine scheduling algorithm for "
	     "issuing commands [0] - Round Robin, [1] - Current CPU");

/*
@@ -4560,14 +4754,53 @@ LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or "
	    "MSI-X (2), if possible");

/*
# lpfc_fcp_io_channel: Set the number of FCP EQ/CQ/WQ IO channels
#
# Value range is [1,7]. Default value is 4.
 * lpfc_nvme_oas: Use the oas bit when sending NVME IOs
 *
 *      0  = NVME OAS disabled
 *      1  = NVME OAS enabled
 *
 * Value range is [0,1]. Default value is 0.
 */
LPFC_ATTR_R(fcp_io_channel, LPFC_FCP_IO_CHAN_DEF, LPFC_FCP_IO_CHAN_MIN,
	    LPFC_FCP_IO_CHAN_MAX,
LPFC_ATTR_RW(nvme_oas, 0, 0, 1,
	     "Use OAS bit on NVME IOs");

/*
 * lpfc_fcp_io_channel: Set the number of FCP IO channels the driver
 * will advertise it supports to the SCSI layer. This also will map to
 * the number of WQs the driver will create.
 *
 *      0    = Configure the number of io channels to the number of active CPUs.
 *      1,32 = Manually specify how many io channels to use.
 *
 * Value range is [0,32]. Default value is 4.
 */
LPFC_ATTR_R(fcp_io_channel,
	    LPFC_FCP_IO_CHAN_DEF,
	    LPFC_HBA_IO_CHAN_MIN, LPFC_HBA_IO_CHAN_MAX,
	    "Set the number of FCP I/O channels");

/*
 * lpfc_nvme_io_channel: Set the number of IO hardware queues the driver
 * will advertise it supports to the NVME layer. This also will map to
 * the number of WQs the driver will create.
 *
 * This module parameter is valid when lpfc_enable_fc4_type is set
 * to support NVME.
 *
 * The NVME Layer will try to create this many, plus 1 administrative
 * hardware queue. The administrative queue will always map to WQ 0
 * A hardware IO queue maps (qidx) to a specific driver WQ.
 *
 *      0    = Configure the number of io channels to the number of active CPUs.
 *      1,32 = Manually specify how many io channels to use.
 *
 * Value range is [0,32]. Default value is 0.
 */
LPFC_ATTR_R(nvme_io_channel,
	    LPFC_NVME_IO_CHAN_DEF,
	    LPFC_HBA_IO_CHAN_MIN, LPFC_HBA_IO_CHAN_MAX,
	    "Set the number of NVME I/O channels");

/*
# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware.
#       0  = HBA resets disabled
@@ -4692,6 +4925,7 @@ LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT,
LPFC_ATTR_R(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics");

struct device_attribute *lpfc_hba_attrs[] = {
	&dev_attr_nvme_info,
	&dev_attr_bg_info,
	&dev_attr_bg_guard_err,
	&dev_attr_bg_apptag_err,
@@ -4718,6 +4952,8 @@ struct device_attribute *lpfc_hba_attrs[] = {
	&dev_attr_lpfc_peer_port_login,
	&dev_attr_lpfc_nodev_tmo,
	&dev_attr_lpfc_devloss_tmo,
	&dev_attr_lpfc_enable_fc4_type,
	&dev_attr_lpfc_xri_split,
	&dev_attr_lpfc_fcp_class,
	&dev_attr_lpfc_use_adisc,
	&dev_attr_lpfc_first_burst_size,
@@ -4752,9 +4988,12 @@ struct device_attribute *lpfc_hba_attrs[] = {
	&dev_attr_lpfc_poll_tmo,
	&dev_attr_lpfc_task_mgmt_tmo,
	&dev_attr_lpfc_use_msi,
	&dev_attr_lpfc_nvme_oas,
	&dev_attr_lpfc_fcp_imax,
	&dev_attr_lpfc_fcp_cpu_map,
	&dev_attr_lpfc_fcp_io_channel,
	&dev_attr_lpfc_nvme_io_channel,
	&dev_attr_lpfc_nvme_enable_fb,
	&dev_attr_lpfc_enable_bg,
	&dev_attr_lpfc_soft_wwnn,
	&dev_attr_lpfc_soft_wwpn,
@@ -5764,9 +6003,9 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
	lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
	lpfc_enable_SmartSAN_init(phba, lpfc_enable_SmartSAN);
	lpfc_use_msi_init(phba, lpfc_use_msi);
	lpfc_nvme_oas_init(phba, lpfc_nvme_oas);
	lpfc_fcp_imax_init(phba, lpfc_fcp_imax);
	lpfc_fcp_cpu_map_init(phba, lpfc_fcp_cpu_map);
	lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel);
	lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset);
	lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat);

@@ -5789,8 +6028,43 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
	else
		phba->cfg_poll = lpfc_poll;

	lpfc_enable_fc4_type_init(phba, lpfc_enable_fc4_type);

	/* Initialize first burst. Target vs Initiator are different. */
	lpfc_nvme_enable_fb_init(phba, lpfc_nvme_enable_fb);
	lpfc_fcp_io_channel_init(phba, lpfc_fcp_io_channel);
	lpfc_nvme_io_channel_init(phba, lpfc_nvme_io_channel);

	if (phba->sli_rev != LPFC_SLI_REV4) {
		/* NVME only supported on SLI4 */
		phba->nvmet_support = 0;
		phba->cfg_enable_fc4_type = LPFC_ENABLE_FCP;
	} else {
		/* We MUST have FCP support */
		if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP))
			phba->cfg_enable_fc4_type |= LPFC_ENABLE_FCP;
	}

	/* A value of 0 means use the number of CPUs found in the system */
	if (phba->cfg_nvme_io_channel == 0)
		phba->cfg_nvme_io_channel = phba->sli4_hba.num_present_cpu;
	if (phba->cfg_fcp_io_channel == 0)
		phba->cfg_fcp_io_channel = phba->sli4_hba.num_present_cpu;

	if (phba->cfg_enable_fc4_type == LPFC_ENABLE_FCP)
		phba->cfg_nvme_io_channel = 0;

	if (phba->cfg_enable_fc4_type == LPFC_ENABLE_NVME)
		phba->cfg_fcp_io_channel = 0;

	if (phba->cfg_fcp_io_channel > phba->cfg_nvme_io_channel)
		phba->io_channel_irqs = phba->cfg_fcp_io_channel;
	else
		phba->io_channel_irqs = phba->cfg_nvme_io_channel;

	phba->cfg_soft_wwnn = 0L;
	phba->cfg_soft_wwpn = 0L;
	lpfc_xri_split_init(phba, lpfc_xri_split);
	lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt);
	lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth);
	lpfc_hba_log_verbose_init(phba, lpfc_log_verbose);
@@ -5806,6 +6080,26 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
	return;
}

/**
 * lpfc_nvme_mod_param_dep - Adjust module parameter value based on
 * dependencies between protocols and roles.
 * @phba: lpfc_hba pointer.
 **/
void
lpfc_nvme_mod_param_dep(struct lpfc_hba *phba)
{
	phba->nvmet_support = 0;
	if (phba->cfg_nvme_io_channel > phba->sli4_hba.num_present_cpu)
		phba->cfg_nvme_io_channel = phba->sli4_hba.num_present_cpu;
	if (phba->cfg_fcp_io_channel > phba->sli4_hba.num_present_cpu)
		phba->cfg_fcp_io_channel = phba->sli4_hba.num_present_cpu;

	if (phba->cfg_fcp_io_channel > phba->cfg_nvme_io_channel)
		phba->io_channel_irqs = phba->cfg_fcp_io_channel;
	else
		phba->io_channel_irqs = phba->cfg_nvme_io_channel;
}

/**
 * lpfc_get_vport_cfgparam - Used during port create, init the vport structure
 * @vport: lpfc_vport pointer.
+18 −9
Original line number Diff line number Diff line
@@ -1704,6 +1704,7 @@ lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba)
	struct lpfc_vport **vports;
	struct Scsi_Host *shost;
	struct lpfc_sli *psli;
	struct lpfc_queue *qp = NULL;
	struct lpfc_sli_ring *pring;
	int i = 0;

@@ -1711,9 +1712,6 @@ lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba)
	if (!psli)
		return -ENODEV;

	pring = &psli->ring[LPFC_FCP_RING];
	if (!pring)
		return -ENODEV;

	if ((phba->link_state == LPFC_HBA_ERROR) ||
	    (psli->sli_flag & LPFC_BLOCK_MGMT_IO) ||
@@ -1732,10 +1730,18 @@ lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba)
		scsi_block_requests(shost);
	}

	while (!list_empty(&pring->txcmplq)) {
		if (i++ > 500)  /* wait up to 5 seconds */
	if (phba->sli_rev != LPFC_SLI_REV4) {
		pring = &psli->sli3_ring[LPFC_FCP_RING];
		lpfc_emptyq_wait(phba, &pring->txcmplq, &phba->hbalock);
		return 0;
	}
	list_for_each_entry(qp, &phba->sli4_hba.lpfc_wq_list, wq_list) {
		pring = qp->pring;
		if (!pring || (pring->ringno != LPFC_FCP_RING))
			continue;
		if (!lpfc_emptyq_wait(phba, &pring->txcmplq,
				      &pring->ring_lock))
			break;
		msleep(10);
	}
	return 0;
}
@@ -2875,8 +2881,7 @@ diag_cmd_data_alloc(struct lpfc_hba *phba,
static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri,
			     size_t len)
{
	struct lpfc_sli *psli = &phba->sli;
	struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING];
	struct lpfc_sli_ring *pring;
	struct lpfc_iocbq *cmdiocbq;
	IOCB_t *cmd = NULL;
	struct list_head head, *curr, *next;
@@ -2890,6 +2895,8 @@ static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri,
	int iocb_stat;
	int i = 0;

	pring = lpfc_phba_elsring(phba);

	cmdiocbq = lpfc_sli_get_iocbq(phba);
	rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL);
	if (rxbmp != NULL) {
@@ -5403,13 +5410,15 @@ lpfc_bsg_timeout(struct bsg_job *job)
	struct lpfc_vport *vport = shost_priv(fc_bsg_to_shost(job));
	struct lpfc_hba *phba = vport->phba;
	struct lpfc_iocbq *cmdiocb;
	struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
	struct lpfc_sli_ring *pring;
	struct bsg_job_data *dd_data;
	unsigned long flags;
	int rc = 0;
	LIST_HEAD(completions);
	struct lpfc_iocbq *check_iocb, *next_iocb;

	pring = lpfc_phba_elsring(phba);

	/* if job's driver data is NULL, the command completed or is in the
	 * the process of completing.  In this case, return status to request
	 * so the timeout is retried.  This avoids double completion issues
+25 −2

File changed.

Preview size limit exceeded, changes collapsed.

+131 −47

File changed.

Preview size limit exceeded, changes collapsed.

Loading