#ifndef _STMF_IMPL_H
#define _STMF_IMPL_H
#include <sys/stmf_defines.h>
#include <sys/stmf_ioctl.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef uint32_t stmf_event_handle_t;
#define STMF_MAX_NUM_EVENTS (sizeof (stmf_event_handle_t) * 8)
#define STMF_EVENT_ADD(h, e) (atomic_or_32(&(h), \
((uint32_t)1) << (e)))
#define STMF_EVENT_REMOVE(h, e) (atomic_and_32(&(h), \
~(((uint32_t)1) << (e))))
#define STMF_EVENT_ENABLED(h, e) (((h) & ((uint32_t)1) << (e)) != 0)
#define STMF_EVENT_CLEAR_ALL(h) ((h) = 0)
#define STMF_EVENT_ALLOC_HANDLE(h) ((h) = 0)
#define STMF_EVENT_FREE_HANDLE(h) ((h) = 0)
#define STMF_TGT_NAME_LEN 256
#define STMF_GUID_INPUT 32
#define STMF_UPDATE_KSTAT_IO(kip, dbuf) \
if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) { \
kip->reads++; \
kip->nread += dbuf->db_data_size; \
} else { \
kip->writes++; \
kip->nwritten += dbuf->db_data_size; \
}
struct stmf_i_scsi_task;
struct stmf_itl_data;
typedef struct stmf_i_lu_provider {
stmf_lu_provider_t *ilp_lp;
uint32_t ilp_alloc_size;
uint32_t ilp_nlus;
uint32_t ilp_cb_in_progress:1,
ilp_rsvd:31;
struct stmf_i_lu_provider *ilp_next;
struct stmf_pp_data *ilp_ppd;
} stmf_i_lu_provider_t;
typedef struct stmf_i_lu {
stmf_lu_t *ilu_lu;
uint32_t ilu_alloc_size;
uint32_t ilu_flags;
uint32_t ilu_ref_cnt;
uint8_t ilu_state;
uint8_t ilu_prev_state;
uint8_t ilu_access;
uint8_t ilu_alua;
stmf_event_handle_t ilu_event_hdl;
struct stmf_i_lu *ilu_next;
struct stmf_i_lu *ilu_prev;
char *ilu_alias;
char ilu_ascii_hex_guid[STMF_GUID_INPUT + 1];
kmutex_t ilu_task_lock;
uint32_t ilu_task_cntr1;
uint32_t ilu_task_cntr2;
uint32_t *ilu_cur_task_cntr;
uint32_t ilu_ntasks;
uint32_t ilu_ntasks_free;
uint32_t ilu_ntasks_min_free;
uint32_t ilu_additional_ref;
uint32_t ilu_proxy_registered;
uint64_t ilu_reg_msgid;
struct stmf_i_scsi_task *ilu_tasks;
struct stmf_i_scsi_task *ilu_free_tasks;
struct stmf_itl_data *ilu_itl_list;
kstat_t *ilu_kstat_info;
kstat_t *ilu_kstat_io;
kmutex_t ilu_kstat_lock;
kcondvar_t ilu_offline_pending_cv;
void *ilu_luid;
} stmf_i_lu_t;
#define ILU_STALL_DEREGISTER 0x0001
#define ILU_RESET_ACTIVE 0x0002
typedef struct stmf_i_port_provider {
stmf_port_provider_t *ipp_pp;
uint32_t ipp_alloc_size;
uint32_t ipp_npps;
uint32_t ipp_cb_in_progress:1,
ipp_rsvd:31;
struct stmf_i_port_provider *ipp_next;
struct stmf_pp_data *ipp_ppd;
} stmf_i_port_provider_t;
#define MAX_ILPORT 0x10000
typedef struct stmf_i_local_port {
stmf_local_port_t *ilport_lport;
uint32_t ilport_alloc_size;
uint32_t ilport_nsessions;
struct stmf_i_scsi_session *ilport_ss_list;
krwlock_t ilport_lock;
struct stmf_i_local_port *ilport_next;
struct stmf_i_local_port *ilport_prev;
uint8_t ilport_state;
uint8_t ilport_prev_state;
uint8_t ilport_standby;
uint8_t ilport_alua;
uint16_t ilport_rtpid;
uint16_t ilport_proxy_registered;
uint64_t ilport_reg_msgid;
uint8_t ilport_no_standby_lu;
uint32_t ilport_unexpected_comp;
stmf_event_handle_t ilport_event_hdl;
clock_t ilport_last_online_clock;
clock_t ilport_avg_interval;
uint32_t ilport_online_times;
uint32_t ilport_flags;
kstat_t *ilport_kstat_info;
kstat_t *ilport_kstat_io;
kmutex_t ilport_kstat_lock;
char ilport_kstat_tgt_name[STMF_TGT_NAME_LEN];
void *ilport_tg;
id_t ilport_instance;
} stmf_i_local_port_t;
#define STMF_AVG_ONLINE_INTERVAL (30 * drv_usectohz(1000000))
#define MAX_IRPORT 0x10000
typedef struct stmf_i_remote_port {
struct scsi_devid_desc *irport_id;
kmutex_t irport_mutex;
int irport_refcnt;
id_t irport_instance;
avl_node_t irport_ln;
uint32_t irport_nread_tasks;
uint32_t irport_nwrite_tasks;
hrtime_t irport_rdstart_timestamp;
hrtime_t irport_rddone_timestamp;
hrtime_t irport_wrstart_timestamp;
hrtime_t irport_wrdone_timestamp;
kstat_t *irport_kstat_info;
kstat_t *irport_kstat_io;
kstat_t *irport_kstat_estat;
boolean_t irport_info_dirty;
} stmf_i_remote_port_t;
#define ILPORT_FORCED_OFFLINE 0x01
#define ILPORT_SS_GOT_INITIAL_LUNS 0x02
typedef struct stmf_i_scsi_session {
stmf_scsi_session_t *iss_ss;
uint32_t iss_alloc_size;
uint32_t iss_flags;
stmf_i_remote_port_t *iss_irport;
struct stmf_i_scsi_session *iss_next;
struct stmf_lun_map *iss_sm;
void *iss_hg;
krwlock_t *iss_lockp;
time_t iss_creation_time;
} stmf_i_scsi_session_t;
#define ISS_LUN_INVENTORY_CHANGED 0x0001
#define ISS_RESET_ACTIVE 0x0002
#define ISS_BEING_CREATED 0x0004
#define ISS_GOT_INITIAL_LUNS 0x0008
#define ISS_EVENT_ACTIVE 0x0010
#define ISS_NULL_TPTID 0x0020
#define ITASK_MAX_NCMDS 14
#define ITASK_DEFAULT_POLL_TIMEOUT 0
#define ITASK_TASK_AUDIT_DEPTH 32
typedef enum {
TE_UNDEFINED,
TE_TASK_START,
TE_XFER_START,
TE_XFER_DONE,
TE_SEND_STATUS,
TE_SEND_STATUS_DONE,
TE_TASK_FREE,
TE_TASK_ABORT,
TE_TASK_LPORT_ABORTED,
TE_TASK_LU_ABORTED,
TE_PROCESS_CMD
} task_audit_event_t;
#define CMD_OR_IOF_NA 0xffffffff
typedef struct stmf_task_audit_rec {
task_audit_event_t ta_event;
uint32_t ta_cmd_or_iof;
uint32_t ta_itask_flags;
stmf_data_buf_t *ta_dbuf;
timespec_t ta_timestamp;
} stmf_task_audit_rec_t;
struct stmf_worker;
typedef struct stmf_i_scsi_task {
scsi_task_t *itask_task;
uint32_t itask_alloc_size;
uint32_t itask_flags;
kmutex_t itask_mutex;
uint64_t itask_proxy_msg_id;
stmf_data_buf_t *itask_proxy_dbuf;
struct stmf_worker *itask_worker;
uint32_t *itask_ilu_task_cntr;
struct stmf_i_scsi_task *itask_worker_next;
struct stmf_i_scsi_task *itask_lu_next;
struct stmf_i_scsi_task *itask_lu_prev;
struct stmf_i_scsi_task *itask_lu_free_next;
struct stmf_itl_data *itask_itl_datap;
clock_t itask_start_time;
stmf_data_buf_t *itask_dbufs[4];
clock_t itask_poll_timeout;
uint8_t itask_cmd_stack[ITASK_MAX_NCMDS];
uint8_t itask_ncmds;
uint8_t itask_allocated_buf_map;
uint16_t itask_cdb_buf_size;
hrtime_t itask_start_timestamp;
hrtime_t itask_done_timestamp;
hrtime_t itask_xfer_done_timestamp;
hrtime_t itask_waitq_enter_timestamp;
hrtime_t itask_waitq_time;
hrtime_t itask_lu_read_time;
hrtime_t itask_lu_write_time;
hrtime_t itask_lport_read_time;
hrtime_t itask_lport_write_time;
uint64_t itask_read_xfer;
uint64_t itask_write_xfer;
kmutex_t itask_audit_mutex;
uint8_t itask_audit_index;
stmf_task_audit_rec_t itask_audit_records[ITASK_TASK_AUDIT_DEPTH];
} stmf_i_scsi_task_t;
#define ITASK_DEFAULT_ABORT_TIMEOUT 5
#define STMF_ENQUEUE_ITASK(w, i) \
ASSERT((itask->itask_flags & ITASK_IN_FREE_LIST) == 0); \
ASSERT(mutex_owned(&itask->itask_mutex)); \
ASSERT(mutex_owned(&w->worker_lock)); \
i->itask_worker_next = NULL; \
if (w->worker_task_tail) { \
w->worker_task_tail->itask_worker_next = i; \
} else { \
w->worker_task_head = i; \
} \
w->worker_task_tail = i; \
if (++(w->worker_queue_depth) > w->worker_max_qdepth_pu) { \
w->worker_max_qdepth_pu = w->worker_queue_depth; \
} \
atomic_inc_32(&w->worker_ref_count); \
atomic_or_32(&itask->itask_flags, ITASK_IN_WORKER_QUEUE); \
i->itask_waitq_enter_timestamp = gethrtime(); \
if ((w->worker_flags & STMF_WORKER_ACTIVE) == 0) \
cv_signal(&w->worker_cv);
#define STMF_DEQUEUE_ITASK(w, itask) \
ASSERT(mutex_owned(&w->worker_lock)); \
if ((itask = w->worker_task_head) != NULL) { \
w->worker_task_head = itask->itask_worker_next; \
if (w->worker_task_head == NULL) { \
w->worker_task_tail = NULL; \
} \
} else { \
w->worker_task_tail = NULL; \
}
#define ITASK_IN_FREE_LIST 0x0001
#define ITASK_IN_TRANSITION 0x0002
#define ITASK_IN_WORKER_QUEUE 0x0004
#define ITASK_BEING_ABORTED 0x0008
#define ITASK_BEING_COMPLETED 0x0010
#define ITASK_KNOWN_TO_TGT_PORT 0x0020
#define ITASK_KNOWN_TO_LU 0x0040
#define ITASK_LU_ABORT_CALLED 0x0080
#define ITASK_TGT_PORT_ABORT_CALLED 0x0100
#define ITASK_DEFAULT_HANDLING 0x0200
#define ITASK_CAUSING_LU_RESET 0x0400
#define ITASK_CAUSING_TARGET_RESET 0x0800
#define ITASK_KSTAT_IN_RUNQ 0x1000
#define ITASK_PROXY_TASK 0x2000
#define ITASK_CMD_MASK 0x1F
#define ITASK_CMD_BUF_NDX(cmd) (((uint8_t)(cmd)) >> 5)
#define ITASK_CMD_NEW_TASK 0x1
#define ITASK_CMD_DATA_XFER_DONE 0x2
#define ITASK_CMD_STATUS_DONE 0x3
#define ITASK_CMD_ABORT 0x4
#define ITASK_CMD_SEND_STATUS 0x5
#define ITASK_CMD_POLL 0x10
#define ITASK_CMD_POLL_LU (ITASK_CMD_POLL | 1)
#define ITASK_CMD_POLL_LPORT (ITASK_CMD_POLL | 2)
typedef struct stmf_itl_data {
uint32_t itl_counter;
uint8_t itl_flags;
uint8_t itl_hdlrm_reason;
uint16_t itl_lun;
void *itl_handle;
struct stmf_i_lu *itl_ilu;
struct stmf_i_scsi_session *itl_session;
struct stmf_itl_data *itl_next;
} stmf_itl_data_t;
#define STMF_ITL_BEING_TERMINATED 0x01
typedef struct stmf_pp_data {
struct stmf_pp_data *ppd_next;
void *ppd_provider;
nvlist_t *ppd_nv;
uint32_t ppd_lu_provider:1,
ppd_port_provider:1,
ppd_rsvd:30;
uint32_t ppd_alloc_size;
uint64_t ppd_token;
char ppd_name[8];
} stmf_pp_data_t;
typedef struct stmf_worker {
kthread_t *worker_tid;
stmf_i_scsi_task_t *worker_task_head;
stmf_i_scsi_task_t *worker_task_tail;
stmf_i_scsi_task_t *worker_wait_head;
stmf_i_scsi_task_t *worker_wait_tail;
kmutex_t worker_lock;
kcondvar_t worker_cv;
uint32_t worker_flags;
uint32_t worker_queue_depth;
uint32_t worker_max_qdepth_pu;
uint32_t worker_max_sys_qdepth_pu;
uint32_t worker_ref_count;
hrtime_t worker_signal_timestamp;
} stmf_worker_t;
#define STMF_WORKER_STARTED 1
#define STMF_WORKER_ACTIVE 2
#define STMF_WORKER_TERMINATE 4
typedef struct stmf_xfer_data {
uint32_t alloc_size;
uint32_t size_done;
uint32_t size_left;
uint8_t buf[4];
} stmf_xfer_data_t;
#define TASK_TO_ITASK(x_task) \
((stmf_i_scsi_task_t *)(x_task)->task_stmf_private)
void stmf_dlun_init();
stmf_status_t stmf_dlun_fini();
void stmf_worker_init();
stmf_status_t stmf_worker_fini();
void stmf_task_free(scsi_task_t *task);
void stmf_do_task_abort(scsi_task_t *task);
void stmf_do_itl_dereg(stmf_lu_t *lu, stmf_itl_data_t *itl,
uint8_t hdlrm_reason);
void stmf_generate_lu_event(stmf_i_lu_t *ilu, int eventid,
void *arg, uint32_t flags);
void stmf_generate_lport_event(stmf_i_local_port_t *ilport, int eventid,
void *arg, uint32_t flags);
#ifdef __cplusplus
}
#endif
#endif