Commit ace7f46b authored by Manish Rangankar's avatar Manish Rangankar Committed by Martin K. Petersen

scsi: qedi: Add QLogic FastLinQ offload iSCSI driver framework.

The QLogic FastLinQ Driver for iSCSI (qedi) is the iSCSI specific module
for 41000 Series Converged Network Adapters by QLogic.

This patch consists of following changes:

  - MAINTAINERS Makefile and Kconfig changes for qedi,
  - PCI driver registration,
  - iSCSI host level initialization,
  - Debugfs and log level infrastructure.

The following indiviual changes are merged into this commit:

  qedi: Add LL2 iSCSI interface for offload iSCSI.
  qedi: Add support for iSCSI session management.
  qedi: Add support for data path.
Signed-off-by: default avatarNilesh Javali <nilesh.javali@cavium.com>
Signed-off-by: default avatarAdheer Chandravanshi <adheer.chandravanshi@qlogic.com>
Signed-off-by: default avatarChad Dupuis <chad.dupuis@cavium.com>
Signed-off-by: default avatarSaurav Kashyap <saurav.kashyap@cavium.com>
Signed-off-by: default avatarArun Easi <arun.easi@cavium.com>
Signed-off-by: default avatarManish Rangankar <manish.rangankar@cavium.com>
Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Reviewed-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 775a2e29
...@@ -10079,6 +10079,12 @@ F: drivers/net/ethernet/qlogic/qed/ ...@@ -10079,6 +10079,12 @@ F: drivers/net/ethernet/qlogic/qed/
F: include/linux/qed/ F: include/linux/qed/
F: drivers/net/ethernet/qlogic/qede/ F: drivers/net/ethernet/qlogic/qede/
QLOGIC QL41xxx ISCSI DRIVER
M: QLogic-Storage-Upstream@cavium.com
L: linux-scsi@vger.kernel.org
S: Supported
F: drivers/scsi/qedi/
QNX4 FILESYSTEM QNX4 FILESYSTEM
M: Anders Larsen <al@alarsen.net> M: Anders Larsen <al@alarsen.net>
W: http://www.alarsen.net/linux/qnx4fs/ W: http://www.alarsen.net/linux/qnx4fs/
......
...@@ -1233,6 +1233,7 @@ config SCSI_QLOGICPTI ...@@ -1233,6 +1233,7 @@ config SCSI_QLOGICPTI
source "drivers/scsi/qla2xxx/Kconfig" source "drivers/scsi/qla2xxx/Kconfig"
source "drivers/scsi/qla4xxx/Kconfig" source "drivers/scsi/qla4xxx/Kconfig"
source "drivers/scsi/qedi/Kconfig"
config SCSI_LPFC config SCSI_LPFC
tristate "Emulex LightPulse Fibre Channel Support" tristate "Emulex LightPulse Fibre Channel Support"
......
...@@ -131,6 +131,7 @@ obj-$(CONFIG_PS3_ROM) += ps3rom.o ...@@ -131,6 +131,7 @@ obj-$(CONFIG_PS3_ROM) += ps3rom.o
obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/ obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/
obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/ obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/
obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/ obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
obj-$(CONFIG_QEDI) += libiscsi.o qedi/
obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/ obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/
obj-$(CONFIG_SCSI_ESAS2R) += esas2r/ obj-$(CONFIG_SCSI_ESAS2R) += esas2r/
obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
......
config QEDI
tristate "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver Support"
depends on PCI && SCSI
depends on QED
select SCSI_ISCSI_ATTRS
select QED_LL2
select QED_ISCSI
---help---
This driver supports iSCSI offload for the QLogic FastLinQ
41000 Series Converged Network Adapters.
obj-$(CONFIG_QEDI) := qedi.o
qedi-y := qedi_main.o qedi_iscsi.o qedi_fw.o qedi_sysfs.o \
qedi_dbg.o
qedi-$(CONFIG_DEBUG_FS) += qedi_debugfs.o
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
*
* This software is available under the terms of the GNU General Public License
* (GPL) Version 2, available from the file COPYING in the main directory of
* this source tree.
*/
#ifndef _QEDI_H_
#define _QEDI_H_
#define __PREVENT_QED_HSI__
#include <scsi/scsi_transport_iscsi.h>
#include <scsi/libiscsi.h>
#include <scsi/scsi_host.h>
#include <linux/uio_driver.h>
#include "qedi_hsi.h"
#include <linux/qed/qed_if.h>
#include "qedi_dbg.h"
#include <linux/qed/qed_iscsi_if.h>
#include <linux/qed/qed_ll2_if.h>
#include "qedi_version.h"
#define QEDI_MODULE_NAME "qedi"
struct qedi_endpoint;
/*
* PCI function probe defines
*/
#define QEDI_MODE_NORMAL 0
#define QEDI_MODE_RECOVERY 1
#define ISCSI_WQE_SET_PTU_INVALIDATE 1
#define QEDI_MAX_ISCSI_TASK 4096
#define QEDI_MAX_TASK_NUM 0x0FFF
#define QEDI_MAX_ISCSI_CONNS_PER_HBA 1024
#define QEDI_ISCSI_MAX_BDS_PER_CMD 256 /* Firmware max BDs is 256 */
#define MAX_OUSTANDING_TASKS_PER_CON 1024
#define QEDI_MAX_BD_LEN 0xffff
#define QEDI_BD_SPLIT_SZ 0x1000
#define QEDI_PAGE_SIZE 4096
#define QEDI_FAST_SGE_COUNT 4
/* MAX Length for cached SGL */
#define MAX_SGLEN_FOR_CACHESGL ((1U << 16) - 1)
#define MAX_NUM_MSIX_PF 8
#define MIN_NUM_CPUS_MSIX(x) min((x)->msix_count, num_online_cpus())
#define QEDI_LOCAL_PORT_MIN 60000
#define QEDI_LOCAL_PORT_MAX 61024
#define QEDI_LOCAL_PORT_RANGE (QEDI_LOCAL_PORT_MAX - QEDI_LOCAL_PORT_MIN)
#define QEDI_LOCAL_PORT_INVALID 0xffff
#define TX_RX_RING 16
#define RX_RING (TX_RX_RING - 1)
#define LL2_SINGLE_BUF_SIZE 0x400
#define QEDI_PAGE_SIZE 4096
#define QEDI_PAGE_ALIGN(addr) ALIGN(addr, QEDI_PAGE_SIZE)
#define QEDI_PAGE_MASK (~((QEDI_PAGE_SIZE) - 1))
#define QEDI_PAGE_SIZE 4096
#define QEDI_PATH_HANDLE 0xFE0000000UL
struct qedi_uio_ctrl {
/* meta data */
u32 uio_hsi_version;
/* user writes */
u32 host_tx_prod;
u32 host_rx_cons;
u32 host_rx_bd_cons;
u32 host_tx_pkt_len;
u32 host_rx_cons_cnt;
/* driver writes */
u32 hw_tx_cons;
u32 hw_rx_prod;
u32 hw_rx_bd_prod;
u32 hw_rx_prod_cnt;
/* other */
u8 mac_addr[6];
u8 reserve[2];
};
struct qedi_rx_bd {
u32 rx_pkt_index;
u32 rx_pkt_len;
u16 vlan_id;
};
#define QEDI_RX_DESC_CNT (QEDI_PAGE_SIZE / sizeof(struct qedi_rx_bd))
#define QEDI_MAX_RX_DESC_CNT (QEDI_RX_DESC_CNT - 1)
#define QEDI_NUM_RX_BD (QEDI_RX_DESC_CNT * 1)
#define QEDI_MAX_RX_BD (QEDI_NUM_RX_BD - 1)
#define QEDI_NEXT_RX_IDX(x) ((((x) & (QEDI_MAX_RX_DESC_CNT)) == \
(QEDI_MAX_RX_DESC_CNT - 1)) ? \
(x) + 2 : (x) + 1)
struct qedi_uio_dev {
struct uio_info qedi_uinfo;
u32 uio_dev;
struct list_head list;
u32 ll2_ring_size;
void *ll2_ring;
u32 ll2_buf_size;
void *ll2_buf;
void *rx_pkt;
void *tx_pkt;
struct qedi_ctx *qedi;
struct pci_dev *pdev;
void *uctrl;
};
/* List to maintain the skb pointers */
struct skb_work_list {
struct list_head list;
struct sk_buff *skb;
u16 vlan_id;
};
/* Queue sizes in number of elements */
#define QEDI_SQ_SIZE MAX_OUSTANDING_TASKS_PER_CON
#define QEDI_CQ_SIZE 2048
#define QEDI_CMDQ_SIZE QEDI_MAX_ISCSI_TASK
#define QEDI_PROTO_CQ_PROD_IDX 0
struct qedi_glbl_q_params {
u64 hw_p_cq; /* Completion queue PBL */
u64 hw_p_rq; /* Request queue PBL */
u64 hw_p_cmdq; /* Command queue PBL */
};
struct global_queue {
union iscsi_cqe *cq;
dma_addr_t cq_dma;
u32 cq_mem_size;
u32 cq_cons_idx; /* Completion queue consumer index */
void *cq_pbl;
dma_addr_t cq_pbl_dma;
u32 cq_pbl_size;
};
struct qedi_fastpath {
struct qed_sb_info *sb_info;
u16 sb_id;
#define QEDI_NAME_SIZE 16
char name[QEDI_NAME_SIZE];
struct qedi_ctx *qedi;
};
/* Used to pass fastpath information needed to process CQEs */
struct qedi_io_work {
struct list_head list;
struct iscsi_cqe_solicited cqe;
u16 que_idx;
};
/**
* struct iscsi_cid_queue - Per adapter iscsi cid queue
*
* @cid_que_base: queue base memory
* @cid_que: queue memory pointer
* @cid_q_prod_idx: produce index
* @cid_q_cons_idx: consumer index
* @cid_q_max_idx: max index. used to detect wrap around condition
* @cid_free_cnt: queue size
* @conn_cid_tbl: iscsi cid to conn structure mapping table
*
* Per adapter iSCSI CID Queue
*/
struct iscsi_cid_queue {
void *cid_que_base;
u32 *cid_que;
u32 cid_q_prod_idx;
u32 cid_q_cons_idx;
u32 cid_q_max_idx;
u32 cid_free_cnt;
struct qedi_conn **conn_cid_tbl;
};
struct qedi_portid_tbl {
spinlock_t lock; /* Port id lock */
u16 start;
u16 max;
u16 next;
unsigned long *table;
};
struct qedi_itt_map {
__le32 itt;
struct qedi_cmd *p_cmd;
};
/* I/O tracing entry */
#define QEDI_IO_TRACE_SIZE 2048
struct qedi_io_log {
#define QEDI_IO_TRACE_REQ 0
#define QEDI_IO_TRACE_RSP 1
u8 direction;
u16 task_id;
u32 cid;
u32 port_id; /* Remote port fabric ID */
int lun;
u8 op; /* SCSI CDB */
u8 lba[4];
unsigned int bufflen; /* SCSI buffer length */
unsigned int sg_count; /* Number of SG elements */
u8 fast_sgs; /* number of fast sgls */
u8 slow_sgs; /* number of slow sgls */
u8 cached_sgs; /* number of cached sgls */
int result; /* Result passed back to mid-layer */
unsigned long jiffies; /* Time stamp when I/O logged */
int refcount; /* Reference count for task id */
unsigned int blk_req_cpu; /* CPU that the task is queued on by
* blk layer
*/
unsigned int req_cpu; /* CPU that the task is queued on */
unsigned int intr_cpu; /* Interrupt CPU that the task is received on */
unsigned int blk_rsp_cpu;/* CPU that task is actually processed and
* returned to blk layer
*/
bool cached_sge;
bool slow_sge;
bool fast_sge;
};
/* Number of entries in BDQ */
#define QEDI_BDQ_NUM 256
#define QEDI_BDQ_BUF_SIZE 256
/* DMA coherent buffers for BDQ */
struct qedi_bdq_buf {
void *buf_addr;
dma_addr_t buf_dma;
};
/* Main port level struct */
struct qedi_ctx {
struct qedi_dbg_ctx dbg_ctx;
struct Scsi_Host *shost;
struct pci_dev *pdev;
struct qed_dev *cdev;
struct qed_dev_iscsi_info dev_info;
struct qed_int_info int_info;
struct qedi_glbl_q_params *p_cpuq;
struct global_queue **global_queues;
/* uio declaration */
struct qedi_uio_dev *udev;
struct list_head ll2_skb_list;
spinlock_t ll2_lock; /* Light L2 lock */
spinlock_t hba_lock; /* per port lock */
struct task_struct *ll2_recv_thread;
unsigned long flags;
#define UIO_DEV_OPENED 1
#define QEDI_IOTHREAD_WAKE 2
#define QEDI_IN_RECOVERY 5
#define QEDI_IN_OFFLINE 6
u8 mac[ETH_ALEN];
u32 src_ip[4];
u8 ip_type;
/* Physical address of above array */
dma_addr_t hw_p_cpuq;
struct qedi_bdq_buf bdq[QEDI_BDQ_NUM];
void *bdq_pbl;
dma_addr_t bdq_pbl_dma;
size_t bdq_pbl_mem_size;
void *bdq_pbl_list;
dma_addr_t bdq_pbl_list_dma;
u8 bdq_pbl_list_num_entries;
void __iomem *bdq_primary_prod;
void __iomem *bdq_secondary_prod;
u16 bdq_prod_idx;
u16 rq_num_entries;
u32 msix_count;
u32 max_sqes;
u8 num_queues;
u32 max_active_conns;
struct iscsi_cid_queue cid_que;
struct qedi_endpoint **ep_tbl;
struct qedi_portid_tbl lcl_port_tbl;
/* Rx fast path intr context */
struct qed_sb_info *sb_array;
struct qedi_fastpath *fp_array;
struct qed_iscsi_tid tasks;
#define QEDI_LINK_DOWN 0
#define QEDI_LINK_UP 1
atomic_t link_state;
#define QEDI_RESERVE_TASK_ID 0
#define MAX_ISCSI_TASK_ENTRIES 4096
#define QEDI_INVALID_TASK_ID (MAX_ISCSI_TASK_ENTRIES + 1)
unsigned long task_idx_map[MAX_ISCSI_TASK_ENTRIES / BITS_PER_LONG];
struct qedi_itt_map *itt_map;
u16 tid_reuse_count[QEDI_MAX_ISCSI_TASK];
struct qed_pf_params pf_params;
struct workqueue_struct *tmf_thread;
struct workqueue_struct *offload_thread;
u16 ll2_mtu;
struct workqueue_struct *dpc_wq;
spinlock_t task_idx_lock; /* To protect gbl context */
s32 last_tidx_alloc;
s32 last_tidx_clear;
struct qedi_io_log io_trace_buf[QEDI_IO_TRACE_SIZE];
spinlock_t io_trace_lock; /* prtect trace Log buf */
u16 io_trace_idx;
unsigned int intr_cpu;
u32 cached_sgls;
bool use_cached_sge;
u32 slow_sgls;
bool use_slow_sge;
u32 fast_sgls;
bool use_fast_sge;
atomic_t num_offloads;
};
struct qedi_work {
struct list_head list;
struct qedi_ctx *qedi;
union iscsi_cqe cqe;
u16 que_idx;
bool is_solicited;
};
struct qedi_percpu_s {
struct task_struct *iothread;
struct list_head work_list;
spinlock_t p_work_lock; /* Per cpu worker lock */
};
static inline void *qedi_get_task_mem(struct qed_iscsi_tid *info, u32 tid)
{
return (info->blocks[tid / info->num_tids_per_block] +
(tid % info->num_tids_per_block) * info->size);
}
#define QEDI_U64_HI(val) ((u32)(((u64)(val)) >> 32))
#define QEDI_U64_LO(val) ((u32)(((u64)(val)) & 0xffffffff))
#endif /* _QEDI_H_ */
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
*
* This software is available under the terms of the GNU General Public License
* (GPL) Version 2, available from the file COPYING in the main directory of
* this source tree.
*/
#include "qedi_dbg.h"
#include <linux/vmalloc.h>
void
qedi_dbg_err(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
const char *fmt, ...)
{
va_list va;
struct va_format vaf;
char nfunc[32];
memset(nfunc, 0, sizeof(nfunc));
memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
vaf.fmt = fmt;
vaf.va = &va;
if (likely(qedi) && likely(qedi->pdev))
pr_err("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
nfunc, line, qedi->host_no, &vaf);
else
pr_err("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
va_end(va);
}
void
qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
const char *fmt, ...)
{
va_list va;
struct va_format vaf;
char nfunc[32];
memset(nfunc, 0, sizeof(nfunc));
memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
vaf.fmt = fmt;
vaf.va = &va;
if (!(qedi_dbg_log & QEDI_LOG_WARN))
return;
if (likely(qedi) && likely(qedi->pdev))
pr_warn("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
nfunc, line, qedi->host_no, &vaf);
else
pr_warn("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
va_end(va);
}
void
qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
const char *fmt, ...)
{
va_list va;
struct va_format vaf;
char nfunc[32];
memset(nfunc, 0, sizeof(nfunc));
memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
vaf.fmt = fmt;
vaf.va = &va;
if (!(qedi_dbg_log & QEDI_LOG_NOTICE))
return;
if (likely(qedi) && likely(qedi->pdev))
pr_notice("[%s]:[%s:%d]:%d: %pV",
dev_name(&qedi->pdev->dev), nfunc, line,
qedi->host_no, &vaf);
else
pr_notice("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
va_end(va);
}
void
qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
u32 level, const char *fmt, ...)
{
va_list va;
struct va_format vaf;
char nfunc[32];
memset(nfunc, 0, sizeof(nfunc));
memcpy(nfunc, func, sizeof(nfunc) - 1);
va_start(va, fmt);
vaf.fmt = fmt;
vaf.va = &va;
if (!(qedi_dbg_log & level))
return;
if (likely(qedi) && likely(qedi->pdev))
pr_info("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
nfunc, line, qedi->host_no, &vaf);
else
pr_info("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf);
va_end(va);
}
int
qedi_create_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter)
{
int ret = 0;
for (; iter->name; iter++) {
ret = sysfs_create_bin_file(&shost->shost_gendev.kobj,
iter->attr);
if (ret)
pr_err("Unable to create sysfs %s attr, err(%d).\n",
iter->name, ret);
}
return ret;
}
void
qedi_remove_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter)
{
for (; iter->name; iter++)
sysfs_remove_bin_file(&shost->shost_gendev.kobj, iter->attr);
}
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
*
* This software is available under the terms of the GNU General Public License
* (GPL) Version 2, available from the file COPYING in the main directory of
* this source tree.
*/
#ifndef _QEDI_DBG_H_
#define _QEDI_DBG_H_
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/compiler.h>
#include <linux/string.h>
#include <linux/version.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_iscsi.h>
#include <linux/fs.h>
#define __PREVENT_QED_HSI__
#include <linux/qed/common_hsi.h>
#include <linux/qed/qed_if.h>
extern uint qedi_dbg_log;
/* Debug print level definitions */
#define QEDI_LOG_DEFAULT 0x1 /* Set default logging mask */
#define QEDI_LOG_INFO 0x2 /* Informational logs,
* MAC address, WWPN, WWNN
*/
#define QEDI_LOG_DISC 0x4 /* Init, discovery, rport */
#define QEDI_LOG_LL2 0x8 /* LL2, VLAN logs */
#define QEDI_LOG_CONN 0x10 /* Connection setup, cleanup */
#define QEDI_LOG_EVT 0x20 /* Events, link, mtu */
#define QEDI_LOG_TIMER 0x40 /* Timer events */
#define QEDI_LOG_MP_REQ 0x80 /* Middle Path (MP) logs */
#define QEDI_LOG_SCSI_TM 0x100 /* SCSI Aborts, Task Mgmt */
#define QEDI_LOG_UNSOL 0x200 /* unsolicited event logs */
#define QEDI_LOG_IO 0x400 /* scsi cmd, completion */
#define QEDI_LOG_MQ 0x800 /* Multi Queue logs */
#define QEDI_LOG_BSG 0x1000 /* BSG logs */
#define QEDI_LOG_DEBUGFS 0x2000 /* debugFS logs */
#define QEDI_LOG_LPORT 0x4000 /* lport logs */
#define QEDI_LOG_ELS 0x8000 /* ELS logs */
#define QEDI_LOG_NPIV 0x10000 /* NPIV logs */
#define QEDI_LOG_SESS 0x20000 /* Conection setup, cleanup */
#define QEDI_LOG_UIO 0x40000 /* iSCSI UIO logs */
#define QEDI_LOG_TID 0x80000 /* FW TID context acquire,
* free
*/
#define QEDI_TRACK_TID 0x100000 /* Track TID state. To be
* enabled only at module load
* and not run-time.
*/
#define QEDI_TRACK_CMD_LIST 0x300000 /* Track active cmd list nodes,
* done with reference to TID,
* hence TRACK_TID also enabled.
*/
#define QEDI_LOG_NOTICE 0x40000000 /* Notice logs */
#define QEDI_LOG_WARN 0x80000000 /* Warning logs */
/* Debug context structure */
struct qedi_dbg_ctx {
unsigned int host_no;
struct pci_dev *pdev;
#ifdef CONFIG_DEBUG_FS
struct dentry *bdf_dentry;
#endif
};
#define QEDI_ERR(pdev, fmt, ...) \
qedi_dbg_err(pdev, __func__, __LINE__, fmt, ## __VA_ARGS__)
#define QEDI_WARN(pdev, fmt, ...) \
qedi_dbg_warn(pdev, __func__, __LINE__, fmt, ## __VA_ARGS__)
#define QEDI_NOTICE(pdev, fmt, ...) \
qedi_dbg_notice(pdev, __func__, __LINE__, fmt, ## __VA_ARGS__)
#define QEDI_INFO(pdev, level, fmt, ...) \
qedi_dbg_info(pdev, __func__, __LINE__, level, fmt, \
## __VA_ARGS__)
void qedi_dbg_err(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
const char *fmt, ...);
void qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
const char *fmt, ...);
void qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
const char *fmt, ...);
void qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line,
u32 info, const char *fmt, ...);
struct Scsi_Host;
struct sysfs_bin_attrs {
char *name;
struct bin_attribute *attr;
};
int qedi_create_sysfs_attr(struct Scsi_Host *shost,
struct sysfs_bin_attrs *iter);
void qedi_remove_sysfs_attr(struct Scsi_Host *shost,
struct sysfs_bin_attrs *iter);
#ifdef CONFIG_DEBUG_FS
/* DebugFS related code */
struct qedi_list_of_funcs {
char *oper_str;
ssize_t (*oper_func)(struct qedi_dbg_ctx *qedi);
};
struct qedi_debugfs_ops {
char *name;
struct qedi_list_of_funcs *qedi_funcs;
};
#define qedi_dbg_fileops(drv, ops) \
{ \
.owner = THIS_MODULE, \
.open = simple_open, \
.read = drv##_dbg_##ops##_cmd_read, \
.write = drv##_dbg_##ops##_cmd_write \
}
/* Used for debugfs sequential files */
#define qedi_dbg_fileops_seq(drv, ops) \
{ \
.owner = THIS_MODULE, \
.open = drv##_dbg_##ops##_open, \
.read = seq_read, \
.llseek = seq_lseek, \
.release = single_release, \
}
void qedi_dbg_host_init(struct qedi_dbg_ctx *qedi,
struct qedi_debugfs_ops *dops,
const struct file_operations *fops);
void qedi_dbg_host_exit(struct qedi_dbg_ctx *qedi);
void qedi_dbg_init(char *drv_name);
void qedi_dbg_exit(void);
#endif /* CONFIG_DEBUG_FS */
#endif /* _QEDI_DBG_H_ */
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
*
* This software is available under the terms of the GNU General Public License
* (GPL) Version 2, available from the file COPYING in the main directory of
* this source tree.
*/
#include "qedi.h"
#include "qedi_dbg.h"
#include <linux/uaccess.h>
#include <linux/debugfs.h>
#include <linux/module.h>
int do_not_recover;
static struct dentry *qedi_dbg_root;
void
qedi_dbg_host_init(struct qedi_dbg_ctx *qedi,
struct qedi_debugfs_ops *dops,
const struct file_operations *fops)
{
char host_dirname[32];
struct dentry *file_dentry = NULL;
sprintf(host_dirname, "host%u", qedi->host_no);
qedi->bdf_dentry = debugfs_create_dir(host_dirname, qedi_dbg_root);
if (!qedi->bdf_dentry)
return;
while (dops) {
if (!(dops->name))
break;
file_dentry = debugfs_create_file(dops->name, 0600,
qedi->bdf_dentry, qedi,
fops);
if (!file_dentry) {
QEDI_INFO(qedi, QEDI_LOG_DEBUGFS,
"Debugfs entry %s creation failed\n",
dops->name);
debugfs_remove_recursive(qedi->bdf_dentry);
return;
}
dops++;
fops++;
}
}
void
qedi_dbg_host_exit(struct qedi_dbg_ctx *qedi)
{
debugfs_remove_recursive(qedi->bdf_dentry);
qedi->bdf_dentry = NULL;
}
void
qedi_dbg_init(char *drv_name)
{
qedi_dbg_root = debugfs_create_dir(drv_name, NULL);
if (!qedi_dbg_root)
QEDI_INFO(NULL, QEDI_LOG_DEBUGFS, "Init of debugfs failed\n");
}
void
qedi_dbg_exit(void)
{
debugfs_remove_recursive(qedi_dbg_root);
qedi_dbg_root = NULL;
}
static ssize_t
qedi_dbg_do_not_recover_enable(struct qedi_dbg_ctx *qedi_dbg)
{
if (!do_not_recover)
do_not_recover = 1;
QEDI_INFO(qedi_dbg, QEDI_LOG_DEBUGFS, "do_not_recover=%d\n",
do_not_recover);
return 0;
}
static ssize_t
qedi_dbg_do_not_recover_disable(struct qedi_dbg_ctx *qedi_dbg)
{
if (do_not_recover)
do_not_recover = 0;
QEDI_INFO(qedi_dbg, QEDI_LOG_DEBUGFS, "do_not_recover=%d\n",
do_not_recover);
return 0;
}
static struct qedi_list_of_funcs qedi_dbg_do_not_recover_ops[] = {
{ "enable", qedi_dbg_do_not_recover_enable },
{ "disable", qedi_dbg_do_not_recover_disable },
{ NULL, NULL }
};
struct qedi_debugfs_ops qedi_debugfs_ops[] = {
{ "gbl_ctx", NULL },
{ "do_not_recover", qedi_dbg_do_not_recover_ops},
{ "io_trace", NULL },
{ NULL, NULL }
};
static ssize_t
qedi_dbg_do_not_recover_cmd_write(struct file *filp, const char __user *buffer,
size_t count, loff_t *ppos)
{
size_t cnt = 0;
struct qedi_dbg_ctx *qedi_dbg =
(struct qedi_dbg_ctx *)filp->private_data;
struct qedi_list_of_funcs *lof = qedi_dbg_do_not_recover_ops;
if (*ppos)
return 0;
while (lof) {
if (!(lof->oper_str))
break;
if (!strncmp(lof->oper_str, buffer, strlen(lof->oper_str))) {
cnt = lof->oper_func(qedi_dbg);
break;
}
lof++;
}
return (count - cnt);
}
static ssize_t
qedi_dbg_do_not_recover_cmd_read(struct file *filp, char __user *buffer,
size_t count, loff_t *ppos)
{
size_t cnt = 0;
if (*ppos)
return 0;
cnt = sprintf(buffer, "do_not_recover=%d\n", do_not_recover);
cnt = min_t(int, count, cnt - *ppos);
*ppos += cnt;
return cnt;
}
static int
qedi_gbl_ctx_show(struct seq_file *s, void *unused)
{
struct qedi_fastpath *fp = NULL;
struct qed_sb_info *sb_info = NULL;
struct status_block *sb = NULL;
struct global_queue *que = NULL;
int id;
u16 prod_idx;
struct qedi_ctx *qedi = s->private;
unsigned long flags;
seq_puts(s, " DUMP CQ CONTEXT:\n");
for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) {
spin_lock_irqsave(&qedi->hba_lock, flags);
seq_printf(s, "=========FAST CQ PATH [%d] ==========\n", id);
fp = &qedi->fp_array[id];
sb_info = fp->sb_info;
sb = sb_info->sb_virt;
prod_idx = (sb->pi_array[QEDI_PROTO_CQ_PROD_IDX] &
STATUS_BLOCK_PROD_INDEX_MASK);
seq_printf(s, "SB PROD IDX: %d\n", prod_idx);
que = qedi->global_queues[fp->sb_id];
seq_printf(s, "DRV CONS IDX: %d\n", que->cq_cons_idx);
seq_printf(s, "CQ complete host memory: %d\n", fp->sb_id);
seq_puts(s, "=========== END ==================\n\n\n");
spin_unlock_irqrestore(&qedi->hba_lock, flags);
}
return 0;
}
static int
qedi_dbg_gbl_ctx_open(struct inode *inode, struct file *file)
{
struct qedi_dbg_ctx *qedi_dbg = inode->i_private;
struct qedi_ctx *qedi = container_of(qedi_dbg, struct qedi_ctx,
dbg_ctx);
return single_open(file, qedi_gbl_ctx_show, qedi);
}
static int
qedi_io_trace_show(struct seq_file *s, void *unused)
{
int id, idx = 0;
struct qedi_ctx *qedi = s->private;
struct qedi_io_log *io_log;
unsigned long flags;
seq_puts(s, " DUMP IO LOGS:\n");
spin_lock_irqsave(&qedi->io_trace_lock, flags);
idx = qedi->io_trace_idx;
for (id = 0; id < QEDI_IO_TRACE_SIZE; id++) {
io_log = &qedi->io_trace_buf[idx];
seq_printf(s, "iodir-%d:", io_log->direction);
seq_printf(s, "tid-0x%x:", io_log->task_id);
seq_printf(s, "cid-0x%x:", io_log->cid);
seq_printf(s, "lun-%d:", io_log->lun);
seq_printf(s, "op-0x%02x:", io_log->op);
seq_printf(s, "0x%02x%02x%02x%02x:", io_log->lba[0],
io_log->lba[1], io_log->lba[2], io_log->lba[3]);
seq_printf(s, "buflen-%d:", io_log->bufflen);
seq_printf(s, "sgcnt-%d:", io_log->sg_count);
seq_printf(s, "res-0x%08x:", io_log->result);
seq_printf(s, "jif-%lu:", io_log->jiffies);
seq_printf(s, "blk_req_cpu-%d:", io_log->blk_req_cpu);
seq_printf(s, "req_cpu-%d:", io_log->req_cpu);
seq_printf(s, "intr_cpu-%d:", io_log->intr_cpu);
seq_printf(s, "blk_rsp_cpu-%d\n", io_log->blk_rsp_cpu);
idx++;
if (idx == QEDI_IO_TRACE_SIZE)
idx = 0;
}
spin_unlock_irqrestore(&qedi->io_trace_lock, flags);
return 0;
}
static int
qedi_dbg_io_trace_open(struct inode *inode, struct file *file)
{
struct qedi_dbg_ctx *qedi_dbg = inode->i_private;
struct qedi_ctx *qedi = container_of(qedi_dbg, struct qedi_ctx,
dbg_ctx);
return single_open(file, qedi_io_trace_show, qedi);
}
const struct file_operations qedi_dbg_fops[] = {
qedi_dbg_fileops_seq(qedi, gbl_ctx),
qedi_dbg_fileops(qedi, do_not_recover),
qedi_dbg_fileops_seq(qedi, io_trace),
{ NULL, NULL },
};
This diff is collapsed.
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
*
* This software is available under the terms of the GNU General Public License
* (GPL) Version 2, available from the file COPYING in the main directory of
* this source tree.
*/
#ifndef _QEDI_GBL_H_
#define _QEDI_GBL_H_
#include "qedi_iscsi.h"
extern uint qedi_io_tracing;
extern int do_not_recover;
extern struct scsi_host_template qedi_host_template;
extern struct iscsi_transport qedi_iscsi_transport;
extern const struct qed_iscsi_ops *qedi_ops;
extern struct qedi_debugfs_ops qedi_debugfs_ops;
extern const struct file_operations qedi_dbg_fops;
extern struct device_attribute *qedi_shost_attrs[];
int qedi_alloc_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep);
void qedi_free_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep);
int qedi_send_iscsi_login(struct qedi_conn *qedi_conn,
struct iscsi_task *task);
int qedi_send_iscsi_logout(struct qedi_conn *qedi_conn,
struct iscsi_task *task);
int qedi_iscsi_abort_work(struct qedi_conn *qedi_conn,
struct iscsi_task *mtask);
int qedi_send_iscsi_text(struct qedi_conn *qedi_conn,
struct iscsi_task *task);
int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn,
struct iscsi_task *task,
char *datap, int data_len, int unsol);
int qedi_iscsi_send_ioreq(struct iscsi_task *task);
int qedi_get_task_idx(struct qedi_ctx *qedi);
void qedi_clear_task_idx(struct qedi_ctx *qedi, int idx);
int qedi_iscsi_cleanup_task(struct iscsi_task *task,
bool mark_cmd_node_deleted);
void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd);
void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt,
struct qedi_cmd *qedi_cmd);
void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt);
void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, int16_t *tid);
void qedi_process_iscsi_error(struct qedi_endpoint *ep,
struct async_data *data);
void qedi_start_conn_recovery(struct qedi_ctx *qedi,
struct qedi_conn *qedi_conn);
struct qedi_conn *qedi_get_conn_from_id(struct qedi_ctx *qedi, u32 iscsi_cid);
void qedi_process_tcp_error(struct qedi_endpoint *ep, struct async_data *data);
void qedi_mark_device_missing(struct iscsi_cls_session *cls_session);
void qedi_mark_device_available(struct iscsi_cls_session *cls_session);
void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu);
int qedi_recover_all_conns(struct qedi_ctx *qedi);
void qedi_fp_process_cqes(struct qedi_work *work);
int qedi_cleanup_all_io(struct qedi_ctx *qedi,
struct qedi_conn *qedi_conn,
struct iscsi_task *task, bool in_recovery);
void qedi_trace_io(struct qedi_ctx *qedi, struct iscsi_task *task,
u16 tid, int8_t direction);
int qedi_alloc_id(struct qedi_portid_tbl *id_tbl, u16 id);
u16 qedi_alloc_new_id(struct qedi_portid_tbl *id_tbl);
void qedi_free_id(struct qedi_portid_tbl *id_tbl, u16 id);
int qedi_create_sysfs_ctx_attr(struct qedi_ctx *qedi);
void qedi_remove_sysfs_ctx_attr(struct qedi_ctx *qedi);
void qedi_clearsq(struct qedi_ctx *qedi,
struct qedi_conn *qedi_conn,
struct iscsi_task *task);
#endif
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
*
* This software is available under the terms of the GNU General Public License
* (GPL) Version 2, available from the file COPYING in the main directory of
* this source tree.
*/
#ifndef __QEDI_HSI__
#define __QEDI_HSI__
/*
* Add include to common target
*/
#include <linux/qed/common_hsi.h>
/*
* Add include to common storage target
*/
#include <linux/qed/storage_common.h>
/*
* Add include to common TCP target
*/
#include <linux/qed/tcp_common.h>
/*
* Add include to common iSCSI target for both eCore and protocol driver
*/
#include <linux/qed/iscsi_common.h>
/*
* iSCSI CMDQ element
*/
struct iscsi_cmdqe {
__le16 conn_id;
u8 invalid_command;
u8 cmd_hdr_type;
__le32 reserved1[2];
__le32 cmd_payload[13];
};
/*
* iSCSI CMD header type
*/
enum iscsi_cmd_hdr_type {
ISCSI_CMD_HDR_TYPE_BHS_ONLY /* iSCSI BHS with no expected AHS */,
ISCSI_CMD_HDR_TYPE_BHS_W_AHS /* iSCSI BHS with expected AHS */,
ISCSI_CMD_HDR_TYPE_AHS /* iSCSI AHS */,
MAX_ISCSI_CMD_HDR_TYPE
};
#endif /* __QEDI_HSI__ */
This diff is collapsed.
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
*
* This software is available under the terms of the GNU General Public License
* (GPL) Version 2, available from the file COPYING in the main directory of
* this source tree.
*/
#ifndef _QEDI_ISCSI_H_
#define _QEDI_ISCSI_H_
#include <linux/socket.h>
#include <linux/completion.h>
#include "qedi.h"
#define ISCSI_MAX_SESS_PER_HBA 4096
#define DEF_KA_TIMEOUT 7200000
#define DEF_KA_INTERVAL 10000
#define DEF_KA_MAX_PROBE_COUNT 10
#define DEF_TOS 0
#define DEF_TTL 0xfe
#define DEF_SND_SEQ_SCALE 0
#define DEF_RCV_BUF 0xffff
#define DEF_SND_BUF 0xffff
#define DEF_SEED 0
#define DEF_MAX_RT_TIME 8000
#define DEF_MAX_DA_COUNT 2
#define DEF_SWS_TIMER 1000
#define DEF_MAX_CWND 2
#define DEF_PATH_MTU 1500
#define DEF_MSS 1460
#define DEF_LL2_MTU 1560
#define JUMBO_MTU 9000
#define MIN_MTU 576 /* rfc 793 */
#define IPV4_HDR_LEN 20
#define IPV6_HDR_LEN 40
#define TCP_HDR_LEN 20
#define TCP_OPTION_LEN 12
#define VLAN_LEN 4
enum {
EP_STATE_IDLE = 0x0,
EP_STATE_ACQRCONN_START = 0x1,
EP_STATE_ACQRCONN_COMPL = 0x2,
EP_STATE_OFLDCONN_START = 0x4,
EP_STATE_OFLDCONN_COMPL = 0x8,
EP_STATE_DISCONN_START = 0x10,
EP_STATE_DISCONN_COMPL = 0x20,
EP_STATE_CLEANUP_START = 0x40,
EP_STATE_CLEANUP_CMPL = 0x80,
EP_STATE_TCP_FIN_RCVD = 0x100,
EP_STATE_TCP_RST_RCVD = 0x200,
EP_STATE_LOGOUT_SENT = 0x400,
EP_STATE_LOGOUT_RESP_RCVD = 0x800,
EP_STATE_CLEANUP_FAILED = 0x1000,
EP_STATE_OFLDCONN_FAILED = 0x2000,
EP_STATE_CONNECT_FAILED = 0x4000,
EP_STATE_DISCONN_TIMEDOUT = 0x8000,
};
struct qedi_conn;
struct qedi_endpoint {
struct qedi_ctx *qedi;
u32 dst_addr[4];
u32 src_addr[4];
u16 src_port;
u16 dst_port;
u16 vlan_id;
u16 pmtu;
u8 src_mac[ETH_ALEN];
u8 dst_mac[ETH_ALEN];
u8 ip_type;
int state;
wait_queue_head_t ofld_wait;
wait_queue_head_t tcp_ofld_wait;
u32 iscsi_cid;
/* identifier of the connection from qed */
u32 handle;
u32 fw_cid;
void __iomem *p_doorbell;
/* Send queue management */
struct iscsi_wqe *sq;
dma_addr_t sq_dma;
u16 sq_prod_idx;
u16 fw_sq_prod_idx;
u16 sq_con_idx;
u32 sq_mem_size;
void *sq_pbl;
dma_addr_t sq_pbl_dma;
u32 sq_pbl_size;
struct qedi_conn *conn;
struct work_struct offload_work;
};
#define QEDI_SQ_WQES_MIN 16
struct qedi_io_bdt {
struct iscsi_sge *sge_tbl;
dma_addr_t sge_tbl_dma;
u16 sge_valid;
};
/**
* struct generic_pdu_resc - login pdu resource structure
*
* @req_buf: driver buffer used to stage payload associated with
* the login request
* @req_dma_addr: dma address for iscsi login request payload buffer
* @req_buf_size: actual login request payload length
* @req_wr_ptr: pointer into login request buffer when next data is
* to be written
* @resp_hdr: iscsi header where iscsi login response header is to
* be recreated
* @resp_buf: buffer to stage login response payload
* @resp_dma_addr: login response payload buffer dma address
* @resp_buf_size: login response paylod length
* @resp_wr_ptr: pointer into login response buffer when next data is
* to be written
* @req_bd_tbl: iscsi login request payload BD table
* @req_bd_dma: login request BD table dma address
* @resp_bd_tbl: iscsi login response payload BD table
* @resp_bd_dma: login request BD table dma address
*
* following structure defines buffer info for generic pdus such as iSCSI Login,
* Logout and NOP
*/
struct generic_pdu_resc {
char *req_buf;
dma_addr_t req_dma_addr;
u32 req_buf_size;
char *req_wr_ptr;
struct iscsi_hdr resp_hdr;
char *resp_buf;
dma_addr_t resp_dma_addr;
u32 resp_buf_size;
char *resp_wr_ptr;
char *req_bd_tbl;
dma_addr_t req_bd_dma;
char *resp_bd_tbl;
dma_addr_t resp_bd_dma;
};
struct qedi_conn {
struct iscsi_cls_conn *cls_conn;
struct qedi_ctx *qedi;
struct qedi_endpoint *ep;
struct list_head active_cmd_list;
spinlock_t list_lock; /* internal conn lock */
u32 active_cmd_count;
u32 cmd_cleanup_req;
u32 cmd_cleanup_cmpl;
u32 iscsi_conn_id;
int itt;
int abrt_conn;
#define QEDI_CID_RESERVED 0x5AFF
u32 fw_cid;
/*
* Buffer for login negotiation process
*/
struct generic_pdu_resc gen_pdu;
struct list_head tmf_work_list;
wait_queue_head_t wait_queue;
spinlock_t tmf_work_lock; /* tmf work lock */
unsigned long flags;
#define QEDI_CONN_FW_CLEANUP 1
};
struct qedi_cmd {
struct list_head io_cmd;
bool io_cmd_in_list;
struct iscsi_hdr hdr;
struct qedi_conn *conn;
struct scsi_cmnd *scsi_cmd;
struct scatterlist *sg;
struct qedi_io_bdt io_tbl;
struct iscsi_task_context request;
unsigned char *sense_buffer;
dma_addr_t sense_buffer_dma;
u16 task_id;
/* field populated for tmf work queue */
struct iscsi_task *task;
struct work_struct tmf_work;
int state;
#define CLEANUP_WAIT 1
#define CLEANUP_RECV 2
#define CLEANUP_WAIT_FAILED 3
#define CLEANUP_NOT_REQUIRED 4
#define LUN_RESET_RESPONSE_RECEIVED 5
#define RESPONSE_RECEIVED 6
int type;
#define TYPEIO 1
#define TYPERESET 2
struct qedi_work_map *list_tmf_work;
/* slowpath management */
bool use_slowpath;
struct iscsi_tm_rsp *tmf_resp_buf;
struct qedi_work cqe_work;
};
struct qedi_work_map {
struct list_head list;
struct qedi_cmd *qedi_cmd;
int rtid;
int state;
#define QEDI_WORK_QUEUED 1
#define QEDI_WORK_SCHEDULED 2
#define QEDI_WORK_EXIT 3
struct work_struct *ptr_tmf_work;
};
#define qedi_set_itt(task_id, itt) ((u32)(((task_id) & 0xffff) | ((itt) << 16)))
#define qedi_get_itt(cqe) (cqe.iscsi_hdr.cmd.itt >> 16)
#define QEDI_OFLD_WAIT_STATE(q) ((q)->state == EP_STATE_OFLDCONN_FAILED || \
(q)->state == EP_STATE_OFLDCONN_COMPL)
#endif /* _QEDI_ISCSI_H_ */
This diff is collapsed.
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
*
* This software is available under the terms of the GNU General Public License
* (GPL) Version 2, available from the file COPYING in the main directory of
* this source tree.
*/
#include "qedi.h"
#include "qedi_gbl.h"
#include "qedi_iscsi.h"
#include "qedi_dbg.h"
static inline struct qedi_ctx *qedi_dev_to_hba(struct device *dev)
{
struct Scsi_Host *shost = class_to_shost(dev);
return iscsi_host_priv(shost);
}
static ssize_t qedi_show_port_state(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct qedi_ctx *qedi = qedi_dev_to_hba(dev);
if (atomic_read(&qedi->link_state) == QEDI_LINK_UP)
return sprintf(buf, "Online\n");
else
return sprintf(buf, "Linkdown\n");
}
static ssize_t qedi_show_speed(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct qedi_ctx *qedi = qedi_dev_to_hba(dev);
struct qed_link_output if_link;
qedi_ops->common->get_link(qedi->cdev, &if_link);
return sprintf(buf, "%d Gbit\n", if_link.speed / 1000);
}
static DEVICE_ATTR(port_state, 0444, qedi_show_port_state, NULL);
static DEVICE_ATTR(speed, 0444, qedi_show_speed, NULL);
struct device_attribute *qedi_shost_attrs[] = {
&dev_attr_port_state,
&dev_attr_speed,
NULL
};
/*
* QLogic iSCSI Offload Driver
* Copyright (c) 2016 Cavium Inc.
*
* This software is available under the terms of the GNU General Public License
* (GPL) Version 2, available from the file COPYING in the main directory of
* this source tree.
*/
#define QEDI_MODULE_VERSION "8.10.3.0"
#define QEDI_DRIVER_MAJOR_VER 8
#define QEDI_DRIVER_MINOR_VER 10
#define QEDI_DRIVER_REV_VER 3
#define QEDI_DRIVER_ENG_VER 0
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment