#ifndef _NVME_VAR_H
#define _NVME_VAR_H
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/blkdev.h>
#include <sys/taskq_impl.h>
#include <sys/list.h>
#include <sys/ddi_ufm.h>
#include <nvme_common.h>
#ifdef __cplusplus
extern "C" {
#endif
#define NVME_MODULE_NAME "nvme"
typedef enum {
NVME_PCI_CONFIG = 1 << 0,
NVME_FMA_INIT = 1 << 1,
NVME_REGS_MAPPED = 1 << 2,
NVME_ADMIN_QUEUE = 1 << 3,
NVME_CTRL_LIMITS = 1 << 4,
NVME_INTERRUPTS = 1 << 5,
NVME_UFM_INIT = 1 << 6,
NVME_MUTEX_INIT = 1 << 7,
NVME_MGMT_INIT = 1 << 8,
NVME_STAT_INIT = 1 << 9,
NVME_NS_INIT = 1 << 10
} nvme_progress_t;
typedef enum {
NVME_NS_LOCK = 1 << 0,
NVME_NS_MINOR = 1 << 1
} nvme_ns_progress_t;
typedef enum {
NVME_QUIRK_START_CID = 1 << 0,
} nvme_quirk_t;
#define NVME_MIN_ADMIN_QUEUE_LEN 16
#define NVME_MIN_IO_QUEUE_LEN 16
#define NVME_DEFAULT_ADMIN_QUEUE_LEN 256
#define NVME_DEFAULT_IO_QUEUE_LEN 1024
#define NVME_DEFAULT_ASYNC_EVENT_LIMIT 10
#define NVME_MIN_ASYNC_EVENT_LIMIT 1
#define NVME_DEFAULT_MIN_BLOCK_SIZE 512
typedef struct nvme nvme_t;
typedef struct nvme_namespace nvme_namespace_t;
typedef struct nvme_minor nvme_minor_t;
typedef struct nvme_lock nvme_lock_t;
typedef struct nvme_minor_lock_info nvme_minor_lock_info_t;
typedef struct nvme_dma nvme_dma_t;
typedef struct nvme_cmd nvme_cmd_t;
typedef struct nvme_cq nvme_cq_t;
typedef struct nvme_qpair nvme_qpair_t;
typedef struct nvme_task_arg nvme_task_arg_t;
typedef struct nvme_device_stat nvme_device_stat_t;
typedef struct nvme_admin_stat nvme_admin_stat_t;
typedef enum {
NVME_LOCK_STATE_UNLOCKED = 0,
NVME_LOCK_STATE_BLOCKED,
NVME_LOCK_STATE_ACQUIRED
} nvme_minor_lock_state_t;
struct nvme_minor_lock_info {
list_node_t nli_node;
nvme_lock_t *nli_lock;
nvme_minor_lock_state_t nli_state;
nvme_lock_level_t nli_curlevel;
nvme_minor_t *nli_minor;
nvme_t *nli_nvme;
nvme_namespace_t *nli_ns;
nvme_ioctl_common_t *nli_ioc;
hrtime_t nli_last_change;
uintptr_t nli_acq_kthread;
pid_t nli_acq_pid;
};
struct nvme_minor {
id_t nm_minor;
nvme_t *nm_ctrl;
nvme_namespace_t *nm_ns;
avl_node_t nm_avl;
kcondvar_t nm_cv;
nvme_minor_lock_info_t nm_ctrl_lock;
nvme_minor_lock_info_t nm_ns_lock;
};
struct nvme_lock {
nvme_minor_lock_info_t *nl_writer;
list_t nl_readers;
list_t nl_pend_readers;
list_t nl_pend_writers;
uint32_t nl_nwrite_locks;
uint32_t nl_nread_locks;
uint32_t nl_npend_writes;
uint32_t nl_npend_reads;
uint32_t nl_nnonblock;
uint32_t nl_nsignals;
uint32_t nl_nsig_unlock;
uint32_t nl_nsig_blocks;
uint32_t nl_nsig_acq;
};
struct nvme_dma {
ddi_dma_handle_t nd_dmah;
ddi_acc_handle_t nd_acch;
ddi_dma_cookie_t nd_cookie;
uint_t nd_ncookie;
caddr_t nd_memp;
size_t nd_len;
boolean_t nd_cached;
};
typedef enum {
NVME_CMD_ALLOCATED = 0,
NVME_CMD_SUBMITTED,
NVME_CMD_QUEUED,
NVME_CMD_COMPLETED,
NVME_CMD_LOST
} nvme_cmd_state_t;
typedef enum {
NVME_CMD_F_DONTPANIC = 1 << 0,
NVME_CMD_F_USELOCK = 1 << 1,
} nvme_cmd_flag_t;
struct nvme_cmd {
struct list_node nc_list;
nvme_sqe_t nc_sqe;
nvme_cqe_t nc_cqe;
void (*nc_callback)(void *);
bd_xfer_t *nc_xfer;
uint32_t nc_timeout;
nvme_cmd_flag_t nc_flags;
nvme_cmd_state_t nc_state;
uint16_t nc_sqid;
hrtime_t nc_submit_ts;
hrtime_t nc_queue_ts;
nvme_dma_t *nc_dma;
nvme_dma_t *nc_prp;
kmutex_t nc_mutex;
kcondvar_t nc_cv;
taskq_ent_t nc_tqent;
nvme_t *nc_nvme;
};
struct nvme_cq {
size_t ncq_nentry;
uint16_t ncq_id;
nvme_dma_t *ncq_dma;
nvme_cqe_t *ncq_cq;
uint_t ncq_head;
uintptr_t ncq_hdbl;
int ncq_phase;
taskq_t *ncq_cmd_taskq;
kmutex_t ncq_mutex;
};
struct nvme_qpair {
size_t nq_nentry;
nvme_dma_t *nq_sqdma;
nvme_sqe_t *nq_sq;
uint_t nq_sqhead;
uint_t nq_sqtail;
uintptr_t nq_sqtdbl;
nvme_cq_t *nq_cq;
nvme_cmd_t **nq_cmd;
uint16_t nq_next_cmd;
uint_t nq_active_cmds;
uint32_t nq_active_timeout;
kmutex_t nq_mutex;
ksema_t nq_sema;
};
typedef struct nvme_mgmt_lock {
kmutex_t nml_lock;
kcondvar_t nml_cv;
uintptr_t nml_bd_own;
} nvme_mgmt_lock_t;
struct nvme_device_stat {
kstat_named_t nds_dma_bind_err;
kstat_named_t nds_abort_timeout;
kstat_named_t nds_abort_failed;
kstat_named_t nds_abort_successful;
kstat_named_t nds_abort_unsuccessful;
kstat_named_t nds_cmd_timeout;
kstat_named_t nds_wrong_logpage;
kstat_named_t nds_unknown_logpage;
kstat_named_t nds_too_many_cookies;
kstat_named_t nds_unknown_cid;
kstat_named_t nds_inv_cmd_err;
kstat_named_t nds_inv_field_err;
kstat_named_t nds_inv_nsfmt_err;
kstat_named_t nds_data_xfr_err;
kstat_named_t nds_internal_err;
kstat_named_t nds_abort_rq_err;
kstat_named_t nds_abort_pwrloss_err;
kstat_named_t nds_abort_sq_del;
kstat_named_t nds_nvm_cap_exc;
kstat_named_t nds_nvm_ns_notrdy;
kstat_named_t nds_nvm_ns_formatting;
kstat_named_t nds_inv_cq_err;
kstat_named_t nds_inv_qid_err;
kstat_named_t nds_max_qsz_exc;
kstat_named_t nds_inv_int_vect;
kstat_named_t nds_inv_log_page;
kstat_named_t nds_inv_format;
kstat_named_t nds_inv_q_del;
kstat_named_t nds_cnfl_attr;
kstat_named_t nds_inv_prot;
kstat_named_t nds_readonly;
kstat_named_t nds_inv_fwslot;
kstat_named_t nds_inv_fwimg;
kstat_named_t nds_fwact_creset;
kstat_named_t nds_fwact_nssr;
kstat_named_t nds_fwact_reset;
kstat_named_t nds_fwact_mtfa;
kstat_named_t nds_fwact_prohibited;
kstat_named_t nds_fw_overlap;
kstat_named_t nds_inv_cmdseq_err;
kstat_named_t nds_ns_attached;
kstat_named_t nds_ns_priv;
kstat_named_t nds_ns_not_attached;
kstat_named_t nds_inc_ctrl_list;
kstat_named_t nds_ana_attach;
kstat_named_t nds_ns_attach_lim;
kstat_named_t nds_diagfail_event;
kstat_named_t nds_persistent_event;
kstat_named_t nds_transient_event;
kstat_named_t nds_fw_load_event;
kstat_named_t nds_reliability_event;
kstat_named_t nds_temperature_event;
kstat_named_t nds_spare_event;
kstat_named_t nds_vendor_event;
kstat_named_t nds_notice_event;
kstat_named_t nds_unknown_event;
};
#define NAS_CNT 0
#define NAS_AVG 1
#define NAS_MAX 2
struct nvme_admin_stat {
kstat_named_t nas_getlogpage[3];
kstat_named_t nas_identify[3];
kstat_named_t nas_abort[3];
kstat_named_t nas_fwactivate[3];
kstat_named_t nas_fwimgload[3];
kstat_named_t nas_nsformat[3];
kstat_named_t nas_vendor[3];
kstat_named_t nas_other[3];
};
struct nvme {
dev_info_t *n_dip;
nvme_progress_t n_progress;
nvme_quirk_t n_quirks;
caddr_t n_regs;
ddi_acc_handle_t n_regh;
kmem_cache_t *n_cmd_cache;
kmem_cache_t *n_prp_cache;
size_t n_inth_sz;
ddi_intr_handle_t *n_inth;
int n_intr_cnt;
uint_t n_intr_pri;
int n_intr_cap;
int n_intr_type;
int n_intr_types;
ddi_acc_handle_t n_pcicfg_handle;
uint16_t n_vendor_id;
uint16_t n_device_id;
uint16_t n_subsystem_vendor_id;
uint16_t n_subsystem_device_id;
uint8_t n_revision_id;
char *n_product;
char *n_vendor;
nvme_version_t n_version;
boolean_t n_dead;
nvme_ioctl_errno_t n_dead_status;
taskq_ent_t n_dead_tqent;
boolean_t n_strict_version;
boolean_t n_ignore_unknown_vendor_status;
uint32_t n_admin_queue_len;
uint32_t n_io_squeue_len;
uint32_t n_io_cqueue_len;
uint16_t n_async_event_limit;
uint_t n_min_block_size;
uint16_t n_abort_command_limit;
uint64_t n_max_data_transfer_size;
boolean_t n_write_cache_present;
boolean_t n_write_cache_enabled;
int n_error_log_len;
boolean_t n_async_event_supported;
int n_submission_queues_supported;
int n_completion_queues_supported;
int n_submission_queues;
int n_completion_queues;
int n_nssr_supported;
int n_doorbell_stride;
int n_timeout;
int n_arbitration_mechanisms;
int n_cont_queues_reqd;
int n_max_queue_entries;
int n_pageshift;
int n_pagesize;
uint32_t n_namespace_count;
uint_t n_namespaces_attachable;
uint_t n_ioq_count;
uint_t n_cq_count;
nvme_identify_ctrl_t *n_idctl;
nvme_identify_nsid_t *n_idcomns;
nvme_qpair_t *n_adminq;
nvme_qpair_t **n_ioq;
nvme_cq_t **n_cq;
nvme_namespace_t *n_ns;
ddi_dma_attr_t n_queue_dma_attr;
ddi_dma_attr_t n_prp_dma_attr;
ddi_dma_attr_t n_sgl_dma_attr;
ddi_device_acc_attr_t n_reg_acc_attr;
ddi_iblock_cookie_t n_fm_ibc;
int n_fm_cap;
ksema_t n_abort_sema;
nvme_mgmt_lock_t n_mgmt;
kmutex_t n_minor_mutex;
nvme_lock_t n_lock;
kstat_t *n_device_kstat;
nvme_device_stat_t n_device_stat;
kstat_t *n_admin_kstat;
kmutex_t n_admin_stat_mutex;
nvme_admin_stat_t n_admin_stat;
ddi_eventcookie_t n_rm_cookie;
ddi_callback_id_t n_ev_rm_cb_id;
ddi_ufm_handle_t *n_ufmh;
nvme_fwslot_log_t *n_fwslot;
kmutex_t n_fwslot_mutex;
};
struct nvme_namespace {
nvme_t *ns_nvme;
nvme_ns_progress_t ns_progress;
uint8_t ns_eui64[8];
uint8_t ns_nguid[16];
char ns_name[11];
bd_handle_t ns_bd_hdl;
uint32_t ns_id;
size_t ns_block_count;
size_t ns_block_size;
size_t ns_best_block_size;
nvme_ns_state_t ns_state;
nvme_identify_nsid_t *ns_idns;
nvme_lock_t ns_lock;
char *ns_devid;
};
struct nvme_task_arg {
nvme_t *nt_nvme;
nvme_cmd_t *nt_cmd;
};
typedef enum {
NVME_IOCTL_EXCL_NONE = 0,
NVME_IOCTL_EXCL_WRITE,
NVME_IOCTL_EXCL_CTRL,
NVME_IOCTL_EXCL_SKIP
} nvme_ioctl_excl_t;
typedef struct nvme_ioctl_check {
boolean_t nck_ns_ok;
boolean_t nck_ns_minor_ok;
boolean_t nck_skip_ctrl;
boolean_t nck_ctrl_rewrite;
boolean_t nck_bcast_ok;
nvme_ioctl_excl_t nck_excl;
} nvme_ioctl_check_t;
extern uint_t nvme_vendor_specific_admin_cmd_max_timeout;
extern uint32_t nvme_vendor_specific_admin_cmd_size;
extern nvme_namespace_t *nvme_nsid2ns(nvme_t *, uint32_t);
extern boolean_t nvme_ioctl_error(nvme_ioctl_common_t *, nvme_ioctl_errno_t,
uint32_t, uint32_t);
extern boolean_t nvme_ctrl_atleast(nvme_t *, const nvme_version_t *);
extern void nvme_ioctl_success(nvme_ioctl_common_t *);
extern boolean_t nvme_validate_logpage(nvme_t *, nvme_ioctl_get_logpage_t *);
extern boolean_t nvme_validate_identify(nvme_t *, nvme_ioctl_identify_t *,
boolean_t);
extern boolean_t nvme_validate_get_feature(nvme_t *,
nvme_ioctl_get_feature_t *);
extern boolean_t nvme_validate_vuc(nvme_t *, nvme_ioctl_passthru_t *);
extern boolean_t nvme_validate_format(nvme_t *, nvme_ioctl_format_t *);
extern boolean_t nvme_validate_fw_load(nvme_t *, nvme_ioctl_fw_load_t *);
extern boolean_t nvme_validate_fw_commit(nvme_t *, nvme_ioctl_fw_commit_t *);
extern boolean_t nvme_validate_ctrl_attach_detach_ns(nvme_t *,
nvme_ioctl_common_t *);
extern boolean_t nvme_validate_ns_delete(nvme_t *, nvme_ioctl_common_t *);
extern boolean_t nvme_validate_ns_create(nvme_t *, nvme_ioctl_ns_create_t *);
extern void nvme_rwlock(nvme_minor_t *, nvme_ioctl_lock_t *);
extern void nvme_rwunlock(nvme_minor_lock_info_t *, nvme_lock_t *);
extern void nvme_rwlock_ctrl_dead(void *);
extern void nvme_lock_init(nvme_lock_t *);
extern void nvme_lock_fini(nvme_lock_t *);
extern boolean_t nvme_stat_init(nvme_t *);
extern void nvme_stat_cleanup(nvme_t *);
extern void nvme_admin_stat_cmd(nvme_t *, nvme_cmd_t *);
#ifdef __cplusplus
}
#endif
#endif