diff options
Diffstat (limited to '')
-rw-r--r-- | drivers/scsi/snic/snic.h | 416 |
1 files changed, 416 insertions, 0 deletions
diff --git a/drivers/scsi/snic/snic.h b/drivers/scsi/snic/snic.h new file mode 100644 index 000000000..de0ab5fc8 --- /dev/null +++ b/drivers/scsi/snic/snic.h @@ -0,0 +1,416 @@ +/* + * Copyright 2014 Cisco Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _SNIC_H_ +#define _SNIC_H_ + +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/workqueue.h> +#include <linux/bitops.h> +#include <linux/mempool.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi.h> +#include <scsi/scsi_host.h> + +#include "snic_disc.h" +#include "snic_io.h" +#include "snic_res.h" +#include "snic_trc.h" +#include "snic_stats.h" +#include "vnic_dev.h" +#include "vnic_wq.h" +#include "vnic_cq.h" +#include "vnic_intr.h" +#include "vnic_stats.h" +#include "vnic_snic.h" + +#define SNIC_DRV_NAME "snic" +#define SNIC_DRV_DESCRIPTION "Cisco SCSI NIC Driver" +#define SNIC_DRV_VERSION "0.0.1.18" +#define PFX SNIC_DRV_NAME ":" +#define DFX SNIC_DRV_NAME "%d: " + +#define DESC_CLEAN_LOW_WATERMARK 8 +#define SNIC_UCSM_DFLT_THROTTLE_CNT_BLD 16 /* UCSM default throttle count */ +#define SNIC_MAX_IO_REQ 50 /* scsi_cmnd tag map entries */ +#define SNIC_MIN_IO_REQ 8 /* Min IO throttle count */ +#define SNIC_IO_LOCKS 64 /* IO locks: power of 2 */ +#define SNIC_DFLT_QUEUE_DEPTH 32 /* Default Queue Depth */ +#define SNIC_MAX_QUEUE_DEPTH 64 /* Max Queue Depth */ +#define SNIC_DFLT_CMD_TIMEOUT 90 /* Extended tmo for FW */ + +/* + * Tag bits used for special requests. + */ +#define SNIC_TAG_ABORT BIT(30) /* Tag indicating abort */ +#define SNIC_TAG_DEV_RST BIT(29) /* Tag for device reset */ +#define SNIC_TAG_IOCTL_DEV_RST BIT(28) /* Tag for User Device Reset */ +#define SNIC_TAG_MASK (BIT(24) - 1) /* Mask for lookup */ +#define SNIC_NO_TAG -1 + +/* + * Command flags to identify the type of command and for other future use + */ +#define SNIC_NO_FLAGS 0 +#define SNIC_IO_INITIALIZED BIT(0) +#define SNIC_IO_ISSUED BIT(1) +#define SNIC_IO_DONE BIT(2) +#define SNIC_IO_REQ_NULL BIT(3) +#define SNIC_IO_ABTS_PENDING BIT(4) +#define SNIC_IO_ABORTED BIT(5) +#define SNIC_IO_ABTS_ISSUED BIT(6) +#define SNIC_IO_TERM_ISSUED BIT(7) +#define SNIC_IO_ABTS_TIMEDOUT BIT(8) +#define SNIC_IO_ABTS_TERM_DONE BIT(9) +#define SNIC_IO_ABTS_TERM_REQ_NULL BIT(10) +#define SNIC_IO_ABTS_TERM_TIMEDOUT BIT(11) +#define SNIC_IO_INTERNAL_TERM_PENDING BIT(12) +#define SNIC_IO_INTERNAL_TERM_ISSUED BIT(13) +#define SNIC_DEVICE_RESET BIT(14) +#define SNIC_DEV_RST_ISSUED BIT(15) +#define SNIC_DEV_RST_TIMEDOUT BIT(16) +#define SNIC_DEV_RST_ABTS_ISSUED BIT(17) +#define SNIC_DEV_RST_TERM_ISSUED BIT(18) +#define SNIC_DEV_RST_DONE BIT(19) +#define SNIC_DEV_RST_REQ_NULL BIT(20) +#define SNIC_DEV_RST_ABTS_DONE BIT(21) +#define SNIC_DEV_RST_TERM_DONE BIT(22) +#define SNIC_DEV_RST_ABTS_PENDING BIT(23) +#define SNIC_DEV_RST_PENDING BIT(24) +#define SNIC_DEV_RST_NOTSUP BIT(25) +#define SNIC_SCSI_CLEANUP BIT(26) +#define SNIC_HOST_RESET_ISSUED BIT(27) +#define SNIC_HOST_RESET_CMD_TERM \ + (SNIC_DEV_RST_NOTSUP | SNIC_SCSI_CLEANUP | SNIC_HOST_RESET_ISSUED) + +#define SNIC_ABTS_TIMEOUT 30000 /* msec */ +#define SNIC_LUN_RESET_TIMEOUT 30000 /* msec */ +#define SNIC_HOST_RESET_TIMEOUT 30000 /* msec */ + + +/* + * These are protected by the hashed req_lock. + */ +#define CMD_SP(Cmnd) \ + (((struct snic_internal_io_state *)scsi_cmd_priv(Cmnd))->rqi) +#define CMD_STATE(Cmnd) \ + (((struct snic_internal_io_state *)scsi_cmd_priv(Cmnd))->state) +#define CMD_ABTS_STATUS(Cmnd) \ + (((struct snic_internal_io_state *)scsi_cmd_priv(Cmnd))->abts_status) +#define CMD_LR_STATUS(Cmnd) \ + (((struct snic_internal_io_state *)scsi_cmd_priv(Cmnd))->lr_status) +#define CMD_FLAGS(Cmnd) \ + (((struct snic_internal_io_state *)scsi_cmd_priv(Cmnd))->flags) + +#define SNIC_INVALID_CODE 0x100 /* Hdr Status val unused by firmware */ + +#define SNIC_MAX_TARGET 256 +#define SNIC_FLAGS_NONE (0) + +/* snic module params */ +extern unsigned int snic_max_qdepth; + +/* snic debugging */ +extern unsigned int snic_log_level; + +#define SNIC_MAIN_LOGGING 0x1 +#define SNIC_SCSI_LOGGING 0x2 +#define SNIC_ISR_LOGGING 0x8 +#define SNIC_DESC_LOGGING 0x10 + +#define SNIC_CHECK_LOGGING(LEVEL, CMD) \ +do { \ + if (unlikely(snic_log_level & LEVEL)) \ + do { \ + CMD; \ + } while (0); \ +} while (0) + +#define SNIC_MAIN_DBG(host, fmt, args...) \ + SNIC_CHECK_LOGGING(SNIC_MAIN_LOGGING, \ + shost_printk(KERN_INFO, host, fmt, ## args);) + +#define SNIC_SCSI_DBG(host, fmt, args...) \ + SNIC_CHECK_LOGGING(SNIC_SCSI_LOGGING, \ + shost_printk(KERN_INFO, host, fmt, ##args);) + +#define SNIC_DISC_DBG(host, fmt, args...) \ + SNIC_CHECK_LOGGING(SNIC_SCSI_LOGGING, \ + shost_printk(KERN_INFO, host, fmt, ##args);) + +#define SNIC_ISR_DBG(host, fmt, args...) \ + SNIC_CHECK_LOGGING(SNIC_ISR_LOGGING, \ + shost_printk(KERN_INFO, host, fmt, ##args);) + +#define SNIC_HOST_ERR(host, fmt, args...) \ + shost_printk(KERN_ERR, host, fmt, ##args) + +#define SNIC_HOST_INFO(host, fmt, args...) \ + shost_printk(KERN_INFO, host, fmt, ##args) + +#define SNIC_INFO(fmt, args...) \ + pr_info(PFX fmt, ## args) + +#define SNIC_DBG(fmt, args...) \ + pr_info(PFX fmt, ## args) + +#define SNIC_ERR(fmt, args...) \ + pr_err(PFX fmt, ## args) + +#ifdef DEBUG +#define SNIC_BUG_ON(EXPR) \ + ({ \ + if (EXPR) { \ + SNIC_ERR("SNIC BUG(%s)\n", #EXPR); \ + BUG_ON(EXPR); \ + } \ + }) +#else +#define SNIC_BUG_ON(EXPR) \ + ({ \ + if (EXPR) { \ + SNIC_ERR("SNIC BUG(%s) at %s : %d\n", \ + #EXPR, __func__, __LINE__); \ + WARN_ON_ONCE(EXPR); \ + } \ + }) +#endif + +/* Soft assert */ +#define SNIC_ASSERT_NOT_IMPL(EXPR) \ + ({ \ + if (EXPR) {\ + SNIC_INFO("Functionality not impl'ed at %s:%d\n", \ + __func__, __LINE__); \ + WARN_ON_ONCE(EXPR); \ + } \ + }) + + +extern const char *snic_state_str[]; + +enum snic_intx_intr_index { + SNIC_INTX_WQ_RQ_COPYWQ, + SNIC_INTX_ERR, + SNIC_INTX_NOTIFY, + SNIC_INTX_INTR_MAX, +}; + +enum snic_msix_intr_index { + SNIC_MSIX_WQ, + SNIC_MSIX_IO_CMPL, + SNIC_MSIX_ERR_NOTIFY, + SNIC_MSIX_INTR_MAX, +}; + +#define SNIC_INTRHDLR_NAMSZ (2 * IFNAMSIZ) +struct snic_msix_entry { + int requested; + char devname[SNIC_INTRHDLR_NAMSZ]; + irqreturn_t (*isr)(int, void *); + void *devid; +}; + +enum snic_state { + SNIC_INIT = 0, + SNIC_ERROR, + SNIC_ONLINE, + SNIC_OFFLINE, + SNIC_FWRESET, +}; + +#define SNIC_WQ_MAX 1 +#define SNIC_CQ_IO_CMPL_MAX 1 +#define SNIC_CQ_MAX (SNIC_WQ_MAX + SNIC_CQ_IO_CMPL_MAX) + +/* firmware version information */ +struct snic_fw_info { + u32 fw_ver; + u32 hid; /* u16 hid | u16 vnic id */ + u32 max_concur_ios; /* max concurrent ios */ + u32 max_sgs_per_cmd; /* max sgls per IO */ + u32 max_io_sz; /* max io size supported */ + u32 hba_cap; /* hba capabilities */ + u32 max_tgts; /* max tgts supported */ + u16 io_tmo; /* FW Extended timeout */ + struct completion *wait; /* protected by snic lock*/ +}; + +/* + * snic_work item : defined to process asynchronous events + */ +struct snic_work { + struct work_struct work; + u16 ev_id; + u64 *ev_data; +}; + +/* + * snic structure to represent SCSI vNIC + */ +struct snic { + /* snic specific members */ + struct list_head list; + char name[IFNAMSIZ]; + atomic_t state; + spinlock_t snic_lock; + struct completion *remove_wait; + bool in_remove; + bool stop_link_events; /* stop processing link events */ + + /* discovery related */ + struct snic_disc disc; + + /* Scsi Host info */ + struct Scsi_Host *shost; + + /* vnic related structures */ + struct vnic_dev_bar bar0; + + struct vnic_stats *stats; + unsigned long stats_time; + unsigned long stats_reset_time; + + struct vnic_dev *vdev; + + /* hw resource info */ + unsigned int wq_count; + unsigned int cq_count; + unsigned int intr_count; + unsigned int err_intr_offset; + + int link_status; /* retrieved from svnic_dev_link_status() */ + u32 link_down_cnt; + + /* pci related */ + struct pci_dev *pdev; + struct snic_msix_entry msix[SNIC_MSIX_INTR_MAX]; + + /* io related info */ + mempool_t *req_pool[SNIC_REQ_MAX_CACHES]; /* (??) */ + ____cacheline_aligned spinlock_t io_req_lock[SNIC_IO_LOCKS]; + + /* Maintain snic specific commands, cmds with no tag in spl_cmd_list */ + ____cacheline_aligned spinlock_t spl_cmd_lock; + struct list_head spl_cmd_list; + + unsigned int max_tag_id; + atomic_t ios_inflight; /* io in flight counter */ + + struct vnic_snic_config config; + + struct work_struct link_work; + + /* firmware information */ + struct snic_fw_info fwinfo; + + /* Work for processing Target related work */ + struct work_struct tgt_work; + + /* Work for processing Discovery */ + struct work_struct disc_work; + + /* stats related */ + unsigned int reset_stats; + atomic64_t io_cmpl_skip; + struct snic_stats s_stats; /* Per SNIC driver stats */ + + /* platform specific */ +#ifdef CONFIG_SCSI_SNIC_DEBUG_FS + struct dentry *stats_host; /* Per snic debugfs root */ + struct dentry *stats_file; /* Per snic debugfs file */ + struct dentry *reset_stats_file;/* Per snic reset stats file */ +#endif + + /* completion queue cache line section */ + ____cacheline_aligned struct vnic_cq cq[SNIC_CQ_MAX]; + + /* work queue cache line section */ + ____cacheline_aligned struct vnic_wq wq[SNIC_WQ_MAX]; + spinlock_t wq_lock[SNIC_WQ_MAX]; + + /* interrupt resource cache line section */ + ____cacheline_aligned struct vnic_intr intr[SNIC_MSIX_INTR_MAX]; +}; /* end of snic structure */ + +/* + * SNIC Driver's Global Data + */ +struct snic_global { + struct list_head snic_list; + spinlock_t snic_list_lock; + + struct kmem_cache *req_cache[SNIC_REQ_MAX_CACHES]; + + struct workqueue_struct *event_q; + +#ifdef CONFIG_SCSI_SNIC_DEBUG_FS + /* debugfs related global data */ + struct dentry *trc_root; + struct dentry *stats_root; + + struct snic_trc trc ____cacheline_aligned; +#endif +}; + +extern struct snic_global *snic_glob; + +int snic_glob_init(void); +void snic_glob_cleanup(void); + +extern struct workqueue_struct *snic_event_queue; +extern struct device_attribute *snic_attrs[]; + +int snic_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); +int snic_abort_cmd(struct scsi_cmnd *); +int snic_device_reset(struct scsi_cmnd *); +int snic_host_reset(struct scsi_cmnd *); +int snic_reset(struct Scsi_Host *, struct scsi_cmnd *); +void snic_shutdown_scsi_cleanup(struct snic *); + + +int snic_request_intr(struct snic *); +void snic_free_intr(struct snic *); +int snic_set_intr_mode(struct snic *); +void snic_clear_intr_mode(struct snic *); + +int snic_fwcq_cmpl_handler(struct snic *, int); +int snic_wq_cmpl_handler(struct snic *, int); +void snic_free_wq_buf(struct vnic_wq *, struct vnic_wq_buf *); + + +void snic_log_q_error(struct snic *); +void snic_handle_link_event(struct snic *); +void snic_handle_link(struct work_struct *); + +int snic_queue_exch_ver_req(struct snic *); +int snic_io_exch_ver_cmpl_handler(struct snic *, struct snic_fw_req *); + +int snic_queue_wq_desc(struct snic *, void *os_buf, u16 len); + +void snic_handle_untagged_req(struct snic *, struct snic_req_info *); +void snic_release_untagged_req(struct snic *, struct snic_req_info *); +void snic_free_all_untagged_reqs(struct snic *); +int snic_get_conf(struct snic *); +void snic_set_state(struct snic *, enum snic_state); +int snic_get_state(struct snic *); +const char *snic_state_to_str(unsigned int); +void snic_hex_dump(char *, char *, int); +void snic_print_desc(const char *fn, char *os_buf, int len); +const char *show_opcode_name(int val); +#endif /* _SNIC_H */ |