scsi: fnic: Add the NVMe/FC transport path

Build fnic_nvme.c and fnic_nvme.h into the driver.

Add NVMe local-port and remote-port registration, I/O submission, DMA
mapping, tag management, completion and abort handling, LS response
handling, and tport/lport cleanup.

Update shared fnic structures, FCPIO descriptors, FDLS state, and
device-command definitions needed by the NVMe transport path.

Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202605280430.wTYAqI3A-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202605280619.pmobiDWp-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202605280519.Jd4fmgAZ-lkp@intel.com/
Reviewed-by: Sesidhar Baddela <sebaddel@cisco.com>
Reviewed-by: Arulprabhu Ponnusamy <arulponn@cisco.com>
Reviewed-by: Gian Carlo Boffa <gcboffa@cisco.com>
Reviewed-by: Arun Easi <aeasi@cisco.com>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Reviewed-by: Lee Duncan <lduncan@suse.com>
Signed-off-by: Karan Tilak Kumar <kartilak@cisco.com>
Co-developed-by: Hannes Reinecke <hare@kernel.org>
Link: https://patch.msgid.link/20260724174811.5118-7-kartilak@cisco.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Karan Tilak Kumar
2026-07-24 10:48:04 -07:00
committed by Martin K. Petersen
parent 188dfadf02
commit 5efdd5cf92
12 changed files with 2315 additions and 13 deletions

View File

@@ -6,6 +6,7 @@ fnic-y := \
fnic_attrs.o \
fnic_isr.o \
fnic_main.o \
fnic_nvme.o \
fnic_res.o \
fnic_fcs.o \
fdls_disc.o \

View File

@@ -21,6 +21,18 @@
#define FCPIO_HOST_SEQ_ID_RANGE_START 0x80
#define FCPIO_HOST_SEQ_ID_RANGE_END 0xff
struct fnic_nvme_io_event {
struct list_head links;
struct work_struct io_work;
void *arg1;
};
struct fnic_io_event_s {
struct list_head links;
struct work_struct io_work;
void *arg1;
};
/*
* Command entry type
*/

View File

@@ -27,6 +27,7 @@
#include "vnic_stats.h"
#include "vnic_scsi.h"
#include "fnic_fdls.h"
#include "fnic_nvme.h"
#define DRV_NAME "fnic"
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
@@ -80,6 +81,8 @@
#define FNIC_DEV_RST_ABTS_DONE BIT(19)
#define FNIC_DEV_RST_TERM_DONE BIT(20)
#define FNIC_DEV_RST_ABTS_PENDING BIT(21)
#define FNIC_NVME_ADMIN_IO_TIMER_PENDING BIT(22)
#define FNIC_NVME_ADMIN_IO BIT(23)
#define FNIC_FW_RESET_TIMEOUT 60000 /* mSec */
#define FNIC_FCOE_MAX_CMD_LEN 16
@@ -238,7 +241,7 @@ extern spinlock_t reset_fnic_list_lock;
extern struct list_head reset_fnic_list;
extern struct workqueue_struct *reset_fnic_work_queue;
extern struct work_struct reset_fnic_work;
extern struct workqueue_struct *fnic_cmpl_queue;
#define FNIC_MAIN_LOGGING 0x01
#define FNIC_FCS_LOGGING 0x02
@@ -352,6 +355,11 @@ struct fnic_frame_list {
int rx_ethhdr_stripped;
};
struct fnic_tag_t {
struct list_head free_list;
int tag_id;
};
struct fnic_event {
struct list_head list;
struct fnic *fnic;
@@ -469,6 +477,13 @@ struct fnic {
struct list_head vlan_list;
/*** FIP related data members -- end ***/
/* NVME data members */
struct sbitmap nvfnic_tag_map;
struct work_struct nvme_io_cmpl_work;
atomic_t nvme_io_event_queued;
struct llist_head nvme_io_event_llist;
struct completion *nvme_lport_unreg_done;
/* copy work queue cache line section */
____cacheline_aligned struct vnic_wq_copy hw_copy_wq[FNIC_WQ_COPY_MAX];
____cacheline_aligned struct fnic_cpy_wq sw_copy_wq[FNIC_WQ_COPY_MAX];
@@ -522,6 +537,7 @@ int fnic_host_reset(struct Scsi_Host *shost);
void fnic_reset(struct Scsi_Host *shost);
int fnic_issue_fc_host_lip(struct Scsi_Host *shost);
void fnic_get_host_port_state(struct Scsi_Host *shost);
void fnic_fcpio_reset(struct fnic *fnic);
int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do, unsigned int cq_index);
int fnic_wq_cmpl_handler(struct fnic *fnic, int);
int fnic_flogi_reg_handler(struct fnic *fnic, u32);
@@ -568,6 +584,8 @@ void fnic_scsi_unload(struct fnic *fnic);
void fnic_scsi_unload_cleanup(struct fnic *fnic);
int fnic_get_debug_info(struct stats_debug_info *info,
struct fnic *fnic);
int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq,
unsigned int hwq);
struct fnic_scsi_iter_data {
struct fnic *fnic;

View File

@@ -155,7 +155,6 @@ void fnic_fdls_init(struct fnic *fnic, int usefip)
iport->hwmac[3], iport->hwmac[4], iport->hwmac[5]);
INIT_LIST_HEAD(&iport->tport_list);
INIT_LIST_HEAD(&iport->tport_list_pending_del);
fnic_fdls_disc_init(iport);
}
@@ -728,7 +727,7 @@ fdls_send_fcoe_frame(struct fnic *fnic, void *frame, int frame_size,
return ret;
}
void fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
int fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
int frame_size)
{
struct fnic *fnic = iport->fnic;
@@ -736,7 +735,7 @@ void fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
/* If module unload is in-progress, don't send */
if (fnic->in_remove)
return;
return -ESHUTDOWN;
if (iport->fabric.flags & FNIC_FDLS_FPMA_LEARNT) {
srcmac = iport->fpma;
@@ -746,7 +745,7 @@ void fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
dstmac = FCOE_ALL_FCF_MAC;
}
fdls_send_fcoe_frame(fnic, frame, frame_size, srcmac, dstmac);
return fdls_send_fcoe_frame(fnic, frame, frame_size, srcmac, dstmac);
}
int
@@ -1020,6 +1019,8 @@ void fnic_delete_fcp_tports(struct fnic *fnic)
fnic_del_tport_timer_sync(fnic, tport);
if (IS_FNIC_FCP_INITIATOR(fnic))
fnic_fdls_remove_tport(&fnic->iport, tport, flags);
else if (IS_FNIC_NVME_INITIATOR(fnic))
nvfnic_delete_tport(&fnic->iport, tport, flags);
}
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
}
@@ -1047,6 +1048,8 @@ void fnic_tport_event_handler(struct work_struct *work)
if (tport->state == FDLS_TGT_STATE_READY) {
if (IS_FNIC_FCP_INITIATOR(fnic))
fnic_fdls_add_tport(&fnic->iport, tport, flags);
else if (IS_FNIC_NVME_INITIATOR(fnic))
nvfnic_add_tport(fnic, tport, flags);
} else {
FNIC_FCS_DBG(KERN_INFO, fnic,
"Target not ready. Add rport event dropped: 0x%x",
@@ -1059,6 +1062,8 @@ void fnic_tport_event_handler(struct work_struct *work)
if (tport->state == FDLS_TGT_STATE_OFFLINING) {
if (IS_FNIC_FCP_INITIATOR(fnic))
fnic_fdls_remove_tport(&fnic->iport, tport, flags);
else if (IS_FNIC_NVME_INITIATOR(fnic))
nvfnic_delete_tport(&fnic->iport, tport, flags);
} else {
FNIC_FCS_DBG(KERN_INFO, fnic,
"remove rport event dropped tport fcid: 0x%x",

View File

@@ -97,6 +97,7 @@
#define fdls_get_state(_fdls_fabric) ((_fdls_fabric)->state)
#define FNIC_FDMI_ACTIVE 0x8
#define FNIC_LPORT_NVME_REGISTERED 0x4
#define FNIC_FIRST_LINK_UP 0x2
#define fdls_set_tport_state(_tport, _state) (_tport->state = _state)
@@ -122,6 +123,13 @@
#define FNIC_FRAME_TYPE_TGT_PRLI 0x2800
#define FNIC_FRAME_TYPE_TGT_ADISC 0x2A00
#define FNIC_FRAME_TYPE_TGT_LOGO 0x2C00
#define FNIC_FRAME_TYPE_NVME_LS 0x3000
#define NVFNIC_FCPIO_TAG_POOL_SZ (2048)
#define NVFNIC_LS_REQ_OXID_POOL_SZ (64)
#define NVFNIC_LS_REQ_OXID_BASE (0x2500)
#define FNIC_LPORT_NVME_REGISTERED 0x4
struct fnic_fip_fcf_s {
uint16_t vlan_id;
@@ -223,6 +231,8 @@ struct fnic_tport_s {
struct fc_rport *rport;
char str_wwpn[20];
char str_wwnn[20];
struct list_head ls_req_list;
struct nvme_fc_remote_port *nv_rport;
};
/* OXID pool related structures */
@@ -291,7 +301,6 @@ struct fnic_iport_s {
struct fnic_fdls_fip_s fip;
struct fnic_fdls_fabric_s fabric;
struct list_head tport_list;
struct list_head tport_list_pending_del;
/* list of tports for which we are yet to send PLOGO */
struct list_head inprocess_tport_list;
struct list_head deleted_tport_list;
@@ -311,6 +320,13 @@ struct fnic_iport_s {
struct fnic_iport_stats iport_stats;
char str_wwpn[20];
char str_wwnn[20];
/* nvme */;
void *nvfnic_fcpio_tag[NVFNIC_FCPIO_TAG_POOL_SZ];
struct nvme_fc_local_port *nv_lport;
struct nvme_fc_port_template *nv_tmpl;
struct fnic_oxid_pool_s ls_req_oxid_pool;
struct list_head fcpio_list;
};
struct rport_dd_data_s {
@@ -339,6 +355,7 @@ enum fnic_recv_frame_type_e {
FNIC_TPORT_ADISC_RSP,
FNIC_TPORT_BLS_ABTS_RSP,
FNIC_TPORT_LOGO_RSP,
FNIC_LS_REQ_ABTS_RSP,
/* unsolicited requests */
FNIC_BLS_ABTS_REQ,
@@ -371,6 +388,12 @@ enum fnic_port_speeds {
DCEM_PORTSPEED_128G = 128000,
};
static inline bool fdls_tport_is_offline(struct fnic_tport_s *tport)
{
return (tport->state == FDLS_TGT_STATE_OFFLINING ||
tport->state == FDLS_TGT_STATE_OFFLINE);
}
/* Function Declarations */
/* fdls_disc.c */
void fnic_fdls_disc_init(struct fnic_iport_s *iport);
@@ -401,7 +424,7 @@ void fdls_fdmi_retry_plogi(struct fnic_iport_s *iport);
/* fnic_fcs.c */
void fnic_fdls_init(struct fnic *fnic, int usefip);
void fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
int fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
int frame_size);
void fnic_fcoe_send_vlan_req(struct fnic *fnic);
int fnic_send_fip_frame(struct fnic_iport_s *iport,

View File

@@ -6,13 +6,19 @@
#ifndef _FNIC_IO_H_
#define _FNIC_IO_H_
#include <scsi/fc/fc_fs.h>
#include <scsi/fc/fc_fcp.h>
#include "fnic_fdls.h"
#include "fcpio.h"
#include <linux/nvme-fc-driver.h>
#define FNIC_DFLT_SG_DESC_CNT 32
#define FNIC_MAX_SG_DESC_CNT 256 /* Maximum descriptors per sgl */
#define FNIC_SG_DESC_ALIGN 16 /* Descriptor address alignment */
#define NVME_STAT_ERROR 0x2
#define NVME_STAT_TASK_SET_FULL 0x3
struct host_sg_desc {
__le64 addr;
__le32 len;
@@ -39,6 +45,7 @@ enum fnic_ioreq_state {
FNIC_IOREQ_ABTS_PENDING,
FNIC_IOREQ_ABTS_COMPLETE,
FNIC_IOREQ_CMD_COMPLETE,
FNIC_IOREQ_RESET_TERM,
};
struct fnic_io_req {
@@ -50,12 +57,27 @@ struct fnic_io_req {
dma_addr_t sgl_list_pa; /* dma address for sgl list */
u16 sgl_cnt;
u8 sgl_type; /* device DMA descriptor list type */
u8 sgl_mapped:1; /* set when sgl_list_pa is a valid DMA mapping */
u8 io_completed:1; /* set to 1 when fw completes IO */
u32 port_id; /* remote port DID */
unsigned long start_time; /* in jiffies */
u32 tag;
enum fnic_ioreq_state cmd_state;
u32 cmd_flags;
u32 abts_state;
struct completion *abts_done; /* completion for abts */
struct completion *dr_done; /* completion for device reset */
unsigned int tag;
struct scsi_cmnd *sc; /* midlayer's cmd pointer */
struct vnic_wq_copy *wq;
struct llist_node nvfnic_io_cmpl;
struct nvmefc_fcp_req *fcp_req;
void (*done)(struct fnic_io_req *io_req);
unsigned long waitq_start_time; /* in jiffies */
struct timer_list admin_io_timer;
uint32_t status;
struct fnic_tag_t *tag_data;
struct fnic_io_event_s io_evt;
};
#endif /* _FNIC_IO_H_ */

View File

@@ -42,12 +42,12 @@ static struct kmem_cache *fdls_frame_cache;
static struct kmem_cache *fdls_frame_elem_cache;
static struct kmem_cache *fdls_frame_recv_cache;
static LIST_HEAD(fnic_list);
static DEFINE_SPINLOCK(fnic_list_lock);
static DEFINE_IDA(fnic_ida);
struct work_struct reset_fnic_work;
LIST_HEAD(reset_fnic_list);
DEFINE_SPINLOCK(reset_fnic_list_lock);
DEFINE_SPINLOCK(fnic_list_lock);
/* Supported devices by fnic module */
static const struct pci_device_id fnic_id_table[] = {
@@ -89,6 +89,15 @@ module_param(fnic_fc_trace_max_pages, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(fnic_fc_trace_max_pages,
"Total allocated memory pages for fc trace buffer");
unsigned int nvme_dev_loss_tmo = 30;
module_param_named(nvme_dev_loss_tmo, nvme_dev_loss_tmo, uint, 0644);
MODULE_PARM_DESC(nvme_dev_loss_tmo, "configurable NVME dev loss timeout");
unsigned int nvme_max_ios_to_process = 16;
module_param(nvme_max_ios_to_process, uint, 0644);
MODULE_PARM_DESC(nvme_max_ios_to_process,
"Maximum number of NVME IOs to process per work queue");
static unsigned int fnic_max_qdepth = FNIC_DFLT_QUEUE_DEPTH;
module_param(fnic_max_qdepth, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(fnic_max_qdepth, "Queue depth to report for each LUN");
@@ -100,6 +109,7 @@ MODULE_PARM_DESC(pc_rscn_handling_feature_flag,
struct workqueue_struct *reset_fnic_work_queue;
struct workqueue_struct *fnic_fip_queue;
struct workqueue_struct *fnic_cmpl_queue;
static int fnic_sdev_init(struct scsi_device *sdev)
{
@@ -549,6 +559,9 @@ static int fnic_cleanup(struct fnic *fnic)
vnic_wq_copy_clean(&fnic->hw_copy_wq[i],
fnic_wq_copy_cleanup_handler);
if (IS_FNIC_NVME_INITIATOR(fnic))
nvfnic_flush_nvme_io_list(fnic);
for (i = 0; i < fnic->cq_count; i++)
vnic_cq_clean(&fnic->cq[i]);
for (i = 0; i < fnic->intr_count; i++)
@@ -678,6 +691,59 @@ static int fnic_scsi_drv_init(struct fnic *fnic)
return 0;
}
static int fnic_nvme_drv_init(struct fnic *fnic)
{
int ret;
int hwq;
fnic->fnic_max_tag_id = NVFNIC_FCPIO_TAG_POOL_SZ;
for (hwq = 0; hwq < fnic->wq_copy_count; hwq++) {
fnic->sw_copy_wq[hwq].ioreq_table_size = fnic->fnic_max_tag_id;
fnic->sw_copy_wq[hwq].io_req_table =
kzalloc((fnic->sw_copy_wq[hwq].ioreq_table_size + 1) *
sizeof(struct fnic_io_req *), GFP_KERNEL);
if (!fnic->sw_copy_wq[hwq].io_req_table) {
fnic_free_ioreq_tables_mq(fnic);
return -ENOMEM;
}
}
dev_info(&fnic->pdev->dev, "fnic copy wqs: %d, Q0 ioreq table size: %d\n",
fnic->wq_copy_count, fnic->sw_copy_wq[0].ioreq_table_size);
if (sbitmap_init_node(&fnic->nvfnic_tag_map, NVFNIC_FCPIO_TAG_POOL_SZ,
-1, GFP_KERNEL, NUMA_NO_NODE, false, true)) {
dev_err(&fnic->pdev->dev,
"Unable to allocate tag pool\n");
ret = -ENOMEM;
goto out_free_ioreq_tables;
}
fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache);
if (!fnic->io_req_pool) {
ret = -ENOMEM;
goto out_free_sbitmap;
}
init_llist_head(&fnic->nvme_io_event_llist);
INIT_WORK(&fnic->nvme_io_cmpl_work, nvfnic_nvme_iodone_work);
ret = nvfnic_add_lport(fnic);
if (ret)
goto out_free_req_pool;
return 0;
out_free_req_pool:
mempool_destroy(fnic->io_req_pool);
out_free_sbitmap:
sbitmap_free(&fnic->nvfnic_tag_map);
out_free_ioreq_tables:
fnic_free_ioreq_tables_mq(fnic);
return ret;
}
void fnic_mq_map_queues_cpus(struct Scsi_Host *host)
{
struct fnic *fnic = *((struct fnic **) shost_priv(host));
@@ -1057,6 +1123,7 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_LIST_HEAD(&fnic->frame_queue);
INIT_LIST_HEAD(&fnic->tx_queue);
INIT_LIST_HEAD(&fnic->tport_event_list);
init_llist_head(&fnic->nvme_io_event_llist);
INIT_DELAYED_WORK(&iport->oxid_pool.schedule_oxid_free_retry,
fdls_schedule_oxid_free_retry_work);
@@ -1091,6 +1158,10 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = fnic_scsi_drv_init(fnic);
if (err)
goto err_out_scsi_drv_init;
} else if (IS_FNIC_NVME_INITIATOR(fnic)) {
err = fnic_nvme_drv_init(fnic);
if (err)
goto err_out_nvme_drv_init;
}
err = fnic_stats_debugfs_init(fnic);
@@ -1113,6 +1184,7 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
fnic_free_ioreq_tables_mq(fnic);
if (IS_FNIC_FCP_INITIATOR(fnic))
scsi_remove_host(fnic->host);
err_out_nvme_drv_init:
err_out_scsi_drv_init:
fnic_free_intr(fnic);
err_out_fnic_request_intr:
@@ -1190,6 +1262,8 @@ static void fnic_remove(struct pci_dev *pdev)
if (IS_FNIC_FCP_INITIATOR(fnic))
fnic_scsi_unload(fnic);
else if (IS_FNIC_NVME_INITIATOR(fnic))
nvfnic_nvme_unload(fnic);
if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI)
timer_delete_sync(&fnic->notify_timer);
@@ -1215,6 +1289,11 @@ static void fnic_remove(struct pci_dev *pdev)
*/
fnic_cleanup(fnic);
if (IS_FNIC_NVME_INITIATOR(fnic)) {
sbitmap_free(&fnic->nvfnic_tag_map);
fnic_free_ioreq_tables_mq(fnic);
}
spin_lock_irqsave(&fnic_list_lock, flags);
list_del(&fnic->list);
spin_unlock_irqrestore(&fnic_list_lock, flags);
@@ -1356,6 +1435,15 @@ static int __init fnic_init_module(void)
goto err_create_fip_workq;
}
fnic_cmpl_queue =
alloc_workqueue("fnic_cmpl_wq",
WQ_PERCPU | WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
if (!fnic_cmpl_queue) {
pr_err("fnic completion work queue create failed\n");
err = -ENOMEM;
goto err_create_cmpl_workq;
}
if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON) {
reset_fnic_work_queue =
create_singlethread_workqueue("reset_fnic_work_queue");
@@ -1387,6 +1475,8 @@ static int __init fnic_init_module(void)
err_pci_register:
fc_release_transport(fnic_fc_transport);
err_fc_transport:
destroy_workqueue(fnic_cmpl_queue);
err_create_cmpl_workq:
destroy_workqueue(fnic_fip_queue);
err_create_fip_workq:
if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON)
@@ -1415,6 +1505,7 @@ static int __init fnic_init_module(void)
static void __exit fnic_cleanup_module(void)
{
pci_unregister_driver(&fnic_driver);
destroy_workqueue(fnic_cmpl_queue);
destroy_workqueue(fnic_event_queue);
if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,210 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
*/
#ifndef _FNIC_NVME_H
#define _FNIC_NVME_H
#include "fdls_fc.h"
#include "fnic_fdls.h"
#define FNIC_NVME_TPORT_REMOVE_WAIT (5 * 1000)
#define FNIC_NVME_TPORT_LIST_EMPTY_WAIT (FNIC_NVME_TPORT_REMOVE_WAIT * 2)
#define FNIC_TPORT_CLEANUP_WAIT_COUNT 8
#define FNIC_NVME_LPORT_REMOVE_WAIT (2 * 60 * 1000)
#define FNIC_LS_REQ_FLAGS_NONE 0x0
#define FNIC_LS_REQ_FLAGS_ABORTED 0x1
#define FNIC_LS_REQ_FLAGS_DONE 0x2
#define FNIC_LS_REQ_ABORT_COMPLETED 0x4
#define FNIC_STATUS_LS_REQ_ABORTED 0x1
#define FNIC_LS_REQ_MIN_TMO_SECS (2)
#define FNIC_LS_REQ_MAX_TMO_SECS (5)
#define FNIC_NVME_ADMIN_IO_TIMEOUT 30000 /* mSec */
#define FNIC_NVME_NO_FREE_TAG (0xFFFF)
#define FNIC_LS_REQ_TMO_MSECS(tmo) (((tmo >= FNIC_LS_REQ_MIN_TMO_SECS) && \
(tmo <= FNIC_LS_REQ_MAX_TMO_SECS)) ? \
(tmo * 1000) : (FNIC_LS_REQ_MIN_TMO_SECS * 1000))
#define IS_ADMIN_IO(_io_req) \
(NVME_CMD_FLAGS(_io_req) & FNIC_NVME_ADMIN_IO_TIMER_PENDING)
extern unsigned int nvme_max_ios_to_process;
extern unsigned int nvme_dev_loss_tmo;
extern spinlock_t fnic_list_lock;
enum nvfnic_lsreq_state_e {
FNIC_LS_REQ_CMD_INIT = 0,
FNIC_LS_REQ_CMD_PENDING,
FNIC_LS_REQ_CMD_ABTS_PENDING,
FNIC_LS_REQ_CMD_COMPLETE,
FNIC_LS_REQ_ABTS_COMPLETE,
FNIC_LS_REQ_CMD_ABTS_STARTED,
};
struct fnic_nvme_tag {
struct list_head free_list;
int tag_id;
};
struct nvfnic_ls_req {
struct list_head list;
struct nvmefc_ls_req *ls_req;
uint16_t oxid;
struct timer_list ls_req_timer;
struct fnic *fnic;
struct fnic_tport_s *tport;
int state;
unsigned int flags;
};
#if IS_ENABLED(CONFIG_NVME_FC)
int nvfnic_nvme_io_done_handler(void *arg);
struct fnic_io_req *nvfnic_find_io_req_by_tag(struct fnic *fnic, uint16_t tag);
void nvfnic_reset_fcpio_tag_pool(struct fnic_iport_s *iport);
int nvfnic_add_lport(struct fnic *fnic);
void nvfnic_fcpio_abort(struct nvme_fc_local_port *lport,
struct nvme_fc_remote_port *rport,
void *hw_queue_handle, struct nvmefc_fcp_req *fcp_req);
void nvfnic_remote_port_delete(struct nvme_fc_remote_port *rport);
void nvfnic_local_port_delete(struct nvme_fc_local_port *lport);
int nvfnic_dma_map_sgl(struct fnic *fnic, struct fnic_io_req *io_req,
int sg_count);
void nvfnic_dma_unmap_sgl(struct fnic *fnic, struct fnic_io_req *io_req);
int nvfnic_get_sg_count(struct fnic_io_req *io_req);
void nvfnic_release_nvme_ioreq_buf(struct fnic_iport_s *iport,
struct fnic_io_req *io_req);
void nvfnic_dump_nvcmd(struct fnic_io_req *io_req, uint8_t flags);
bool _cleanup_tport_io(struct sbitmap *map, unsigned int tag, void *data);
void nvfnic_flush_nvme_io_list(struct fnic *fnic);
void nvfnic_fcpio_cmpl(struct fnic_io_req *io_req);
bool nvfnic_transport_ready(struct fnic_iport_s *iport,
struct fnic_tport_s *tport);
int nvfnic_alloc_fcpio_tag(struct fnic_iport_s *iport,
struct fnic_io_req *io_req);
int nvfnic_queuecommand(struct fnic_io_req *io_req);
void nvfnic_free_fcpio_tag(struct fnic_iport_s *iport,
struct fnic_io_req *io_req);
void nvfnic_delete_lport(struct fnic_iport_s *iport);
int nvfnic_add_tport(struct fnic *fnic, struct fnic_tport_s *tport,
unsigned long flags);
void nvfnic_cleanup_all_nvme_ios(struct fnic *fnic);
void nvfnic_delete_tport_work(struct work_struct *work);
void nvfnic_delete_tport(struct fnic_iport_s *iport,
struct fnic_tport_s *tport, unsigned long flags);
void nvfnic_fcpio_nvme_fast_cmpl_handler(struct fnic *fnic,
struct fcpio_fw_req *desc);
void nvfnic_ls_rsp_recv(struct fnic_iport_s *iport,
struct fc_frame_header *fchdr, int len);
void nvfnic_process_ls_abts_rsp(struct fnic_iport_s *iport,
struct fc_frame_header *fchdr);
void nvfnic_admin_io_timeout(struct timer_list *t);
void nvfnic_fcpio_nvme_itmf_cmpl_handler(struct fnic *fnic,
struct fcpio_fw_req *desc);
void nvfnic_nvme_zero_devloss_tports(struct fnic *fnic);
bool nvfnic_queue_abort_io_req(struct fnic *fnic, int tag, u32 task_req,
struct fnic_io_req *io_req);
void nvfnic_ls_req_abort(struct nvme_fc_local_port *lport,
struct nvme_fc_remote_port *rport,
struct nvmefc_ls_req *lsreq);
int nvfnic_create_queue(struct nvme_fc_local_port *lport, unsigned int idx,
u16 size, void **handle);
void nvfnic_ls_req_timeout(struct timer_list *t);
uint16_t nvfnic_alloc_ls_req_oxid(struct fnic_iport_s *iport);
struct nvfnic_ls_req *nvfnic_find_ls_req(struct fnic_tport_s *tport,
uint16_t oxid);
void nvfnic_terminate_tport_ios(struct fnic *fnic, struct fnic_tport_s *tport);
bool _terminate_tport_ios(struct sbitmap *map, unsigned int tag, void *data);
bool _cleanup_all_nvme_io(struct sbitmap *map, unsigned int tag, void *data);
void nvfnic_cleanup_all_nvme_ios(struct fnic *fnic);
int nvfnic_fcpio_send(struct nvme_fc_local_port *lport,
struct nvme_fc_remote_port *rport, void *hw_queue_handle,
struct nvmefc_fcp_req *fcp_req);
void nvfnic_fcpio_ersp_cmpl_handler(struct fnic *fnic,
struct fcpio_fw_req *desc, int sw_flag);
void nvfnic_terminate_tport_ls_reqs(struct fnic *fnic,
struct fnic_tport_s *tport);
void nvfnic_terminate_tport_admin_ios(struct fnic *fnic,
struct fnic_tport_s *tport);
void nvfnic_cleanup_tport_io(struct fnic *fnic, struct fnic_tport_s *tport);
void nvfnic_nvme_unload(struct fnic *fnic);
void nvfnic_exch_reset(struct fnic_iport_s *iport, struct fnic_tport_s *tport);
void nvfnic_nvme_iodone_work(struct work_struct *work);
#else
static inline int nvfnic_add_lport(struct fnic *fnic)
{
return -EOPNOTSUPP;
}
static inline void nvfnic_nvme_unload(struct fnic *fnic)
{
}
static inline void nvfnic_flush_nvme_io_list(struct fnic *fnic)
{
}
static inline void nvfnic_nvme_iodone_work(struct work_struct *work)
{
}
static inline void nvfnic_exch_reset(struct fnic_iport_s *iport,
struct fnic_tport_s *tport)
{
}
static inline void nvfnic_process_ls_abts_rsp(struct fnic_iport_s *iport,
struct fc_frame_header *fchdr)
{
}
static inline void nvfnic_ls_rsp_recv(struct fnic_iport_s *iport,
struct fc_frame_header *fchdr, int len)
{
}
static inline int nvfnic_add_tport(struct fnic *fnic,
struct fnic_tport_s *tport,
unsigned long flags)
{
return 0;
}
static inline void nvfnic_delete_tport(struct fnic_iport_s *iport,
struct fnic_tport_s *tport,
unsigned long flags)
{
}
static inline void nvfnic_cleanup_all_nvme_ios(struct fnic *fnic)
{
}
static inline void nvfnic_fcpio_nvme_fast_cmpl_handler(struct fnic *fnic,
struct fcpio_fw_req *desc)
{
}
static inline void nvfnic_fcpio_ersp_cmpl_handler(struct fnic *fnic,
struct fcpio_fw_req *desc,
int sw_flag)
{
}
static inline void nvfnic_fcpio_nvme_itmf_cmpl_handler(struct fnic *fnic,
struct fcpio_fw_req *desc)
{
}
static inline int nvfnic_get_nvmef_info(struct fnic *fnic,
struct fnic_nvmef_info *info)
{
return 0;
}
#endif
extern const char *fnic_fcpio_status_to_str(unsigned int status);
#endif /* _FNIC_NVME_H */

View File

@@ -126,7 +126,8 @@ static inline void fnic_queue_wq_copy_desc_itmf(struct vnic_wq_copy *wq,
desc->u.itmf.tm_req = tm_req; /* SCSI Task Management request */
desc->u.itmf.t_tag = tm_id; /* tag of fcpio to be aborted */
desc->u.itmf._resvd = 0;
memcpy(desc->u.itmf.lun, lun, LUN_ADDRESS); /* LUN address */
if (lun)
memcpy(desc->u.itmf.lun, lun, LUN_ADDRESS); /* LUN address */
desc->u.itmf._resvd1 = 0;
hton24(desc->u.itmf.d_id, d_id); /* FC vNIC only: Target D_ID */
desc->u.itmf.r_a_tov = r_a_tov; /* FC vNIC only: R_A_TOV in msec */
@@ -222,6 +223,35 @@ static inline void fnic_queue_rq_desc(struct vnic_rq *rq,
vnic_rq_post(rq, os_buf, 0, dma_addr, len);
}
static inline void fnic_queue_wq_copy_desc_nvme_io(struct vnic_wq_copy *wq,
u32 req_id,
u8 spl_flags,
u32 sgl_cnt,
u64 sgl_addr,
u8 flags, u8 *nvme_cmd_iu,
u16 cmd_len,
u32 data_len,
u32 d_id, u32 mss,
u32 ratov, u32 edtov)
{
struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq);
desc->hdr.type = FCPIO_NVME_CMD; /* enum fcpio_type */
desc->hdr.status = 0; /* header status entry */
desc->hdr._resvd = 0; /* reserved */
desc->hdr.tag.u.req_id = req_id; /* id for this request */
desc->u.nvcmnd.sgl_cnt = sgl_cnt; /* scatter-gather list count */
desc->u.nvcmnd.sgl_addr = sgl_addr; /* scatter-gather list addr */
desc->u.nvcmnd._resvd1 = 0; /* reserved: should be 0 */
desc->u.nvcmnd.flags = flags; /* command flags */
memset(desc->u.nvcmnd.nvme_cmnd, 0, NVME_CMD_SZ);
memcpy(desc->u.nvcmnd.nvme_cmnd, nvme_cmd_iu, cmd_len); /* SCSI CDB */
desc->u.nvcmnd.cmd_len = cmd_len;
desc->u.nvcmnd.data_len = data_len; /* length of data expected */
hton24(desc->u.nvcmnd.d_id, d_id); /* FC vNIC only: Target D_ID */
vnic_wq_copy_post(wq);
}
struct fnic;

View File

@@ -96,7 +96,7 @@ static const char *fnic_ioreq_state_to_str(unsigned int state)
return fnic_ioreq_state_str[state];
}
static const char *fnic_fcpio_status_to_str(unsigned int status)
const char *fnic_fcpio_status_to_str(unsigned int status)
{
if (status >= ARRAY_SIZE(fcpio_status_str) || !fcpio_status_str[status])
return "unknown";
@@ -186,7 +186,7 @@ fnic_count_lun_ioreqs(struct fnic *fnic, struct scsi_device *scsi_device)
}
/* Free up Copy Wq descriptors. Called with copy_wq lock held */
static int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq, unsigned int hwq)
int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq, unsigned int hwq)
{
/* if no Ack received from firmware, then nothing to clean */
if (!fnic->fw_ack_recd[hwq])

View File

@@ -430,7 +430,7 @@ struct vnic_devcmd_notify {
struct vnic_devcmd_provinfo {
u8 oui[3];
u8 type;
u8 data[];
u8 data[0];
};
/*