mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 08:15:07 -04:00
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:
committed by
Martin K. Petersen
parent
188dfadf02
commit
5efdd5cf92
@@ -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 \
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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)
|
||||
|
||||
1890
drivers/scsi/fnic/fnic_nvme.c
Normal file
1890
drivers/scsi/fnic/fnic_nvme.c
Normal file
File diff suppressed because it is too large
Load Diff
210
drivers/scsi/fnic/fnic_nvme.h
Normal file
210
drivers/scsi/fnic/fnic_nvme.h
Normal 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 */
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -430,7 +430,7 @@ struct vnic_devcmd_notify {
|
||||
struct vnic_devcmd_provinfo {
|
||||
u8 oui[3];
|
||||
u8 type;
|
||||
u8 data[];
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user