#ifndef _PMCS_H
#define _PMCS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/cpuvar.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/pci.h>
#include <sys/pcie.h>
#include <sys/file.h>
#include <sys/isa_defs.h>
#include <sys/sunmdi.h>
#include <sys/mdi_impldefs.h>
#include <sys/scsi/scsi.h>
#include <sys/scsi/impl/scsi_reset_notify.h>
#include <sys/scsi/impl/scsi_sas.h>
#include <sys/scsi/impl/smp_transport.h>
#include <sys/scsi/generic/sas.h>
#include <sys/scsi/generic/smp_frames.h>
#include <sys/atomic.h>
#include <sys/byteorder.h>
#include <sys/sysmacros.h>
#include <sys/bitmap.h>
#include <sys/queue.h>
#include <sys/sdt.h>
#include <sys/ddifm.h>
#include <sys/fm/protocol.h>
#include <sys/fm/util.h>
#include <sys/fm/io/ddi.h>
#include <sys/scsi/impl/spc3_types.h>
typedef struct pmcs_hw pmcs_hw_t;
typedef struct pmcs_iport pmcs_iport_t;
typedef struct pmcs_phy pmcs_phy_t;
typedef struct lsas_cmd lsas_cmd_t;
typedef struct lsas_result lsas_result_t;
typedef struct lsata_cmd lsata_cmd_t;
typedef struct lsata_result lsata_result_t;
typedef struct pmcwork pmcwork_t;
typedef struct pmcs_cmd pmcs_cmd_t;
typedef struct pmcs_xscsi pmcs_xscsi_t;
typedef struct pmcs_lun pmcs_lun_t;
typedef struct pmcs_chunk pmcs_chunk_t;
#include <sys/scsi/adapters/pmcs/pmcs_param.h>
#include <sys/scsi/adapters/pmcs/pmcs_reg.h>
#include <sys/scsi/adapters/pmcs/pmcs_mpi.h>
#include <sys/scsi/adapters/pmcs/pmcs_iomb.h>
#include <sys/scsi/adapters/pmcs/pmcs_sgl.h>
#include <sys/scsi/adapters/pmcs/ata.h>
#include <sys/scsi/adapters/pmcs/pmcs_def.h>
#include <sys/scsi/adapters/pmcs/pmcs_proto.h>
#include <sys/scsi/adapters/pmcs/pmcs_scsa.h>
#include <sys/scsi/adapters/pmcs/pmcs_smhba.h>
#define PMCS_MAX_UA_SIZE 32
struct pmcs_xscsi {
uint32_t
ca : 1,
ncq : 1,
pio : 1,
special_needed : 1,
special_running : 1,
reset_success : 1,
reset_wait : 1,
resetting : 1,
recover_wait : 1,
recovering : 1,
event_recovery : 1,
draining : 1,
new : 1,
assigned : 1,
dev_gone : 1,
phy_addressable : 1,
dev_state : 4;
uint16_t maxdepth;
uint16_t qdepth;
uint16_t actv_cnt;
uint16_t actv_pkts;
uint16_t target_num;
kmutex_t statlock;
int32_t ref_count;
dev_info_t *dip;
pmcs_phy_t *phy;
STAILQ_HEAD(wqh, pmcs_cmd) wq;
pmcs_cmd_t *wq_recovery_tail;
kmutex_t wqlock;
STAILQ_HEAD(aqh, pmcs_cmd) aq;
kmutex_t aqlock;
STAILQ_HEAD(sqh, pmcs_cmd) sq;
uint32_t tagmap;
pmcs_hw_t *pwp;
ddi_soft_state_bystr *lun_sstate;
uint64_t capacity;
char unit_address[PMCS_MAX_UA_SIZE];
kcondvar_t reset_cv;
kcondvar_t abort_cv;
char *ua;
pmcs_dtype_t dtype;
list_t lun_list;
struct smp_device *smpd;
};
#define PMCS_INVALID_TARGET_NUM (uint16_t)-1
#define PMCS_TGT_WAIT_QUEUE 0x01
#define PMCS_TGT_ACTIVE_QUEUE 0x02
#define PMCS_TGT_SPECIAL_QUEUE 0x04
#define PMCS_TGT_ALL_QUEUES 0xff
struct pmcs_lun {
list_node_t lun_list_next;
pmcs_xscsi_t *target;
struct scsi_device *sd;
uint64_t lun_num;
scsi_lun_t scsi_lun;
char unit_address[PMCS_MAX_UA_SIZE];
};
#define PMCS_MAX_IO_COMPS_PER_INTR 12
#define PMCS_MAX_IO_COMPS_HIWAT_SHIFT 6
#define PMCS_MAX_IO_COMPS_LOWAT_SHIFT 10
#define PMCS_QUANTUM_TIME_USECS (1000000 / 10)
#define PMCS_MAX_COAL_TIMER 0x200
#define PMCS_MAX_CQ_THREADS 4
#define PMCS_COAL_TIMER_GRAN 2
#define PMCS_INTR_THRESHOLD(x) ((x) * 6 / 10)
typedef struct pmcs_io_intr_coal_s {
hrtime_t nsecs_between_intrs;
hrtime_t last_io_comp;
clock_t quantum;
uint32_t num_io_completions;
uint32_t num_intrs;
uint32_t max_io_completions;
uint32_t intr_latency;
uint32_t intr_threshold;
uint16_t intr_coal_timer;
boolean_t timer_on;
boolean_t stop_thread;
boolean_t int_cleared;
} pmcs_io_intr_coal_t;
typedef struct pmcs_cq_thr_info_s {
kthread_t *cq_thread;
kmutex_t cq_thr_lock;
kcondvar_t cq_cv;
pmcs_hw_t *cq_pwp;
} pmcs_cq_thr_info_t;
typedef struct pmcs_cq_info_s {
uint32_t cq_threads;
uint32_t cq_next_disp_thr;
boolean_t cq_stop;
pmcs_cq_thr_info_t *cq_thr_info;
} pmcs_cq_info_t;
typedef struct pmcs_iocomp_cb_s {
pmcwork_t *pwrk;
char iomb[PMCS_QENTRY_SIZE << 1];
struct pmcs_iocomp_cb_s *next;
} pmcs_iocomp_cb_t;
typedef struct pmcs_iqp_trace_s {
char *head;
char *curpos;
uint32_t size_left;
} pmcs_iqp_trace_t;
#define PMCS_TGT_SSTATE_SZ 64
#define PMCS_LUN_SSTATE_SZ 4
#define PMCS_IPORT_INVALID_PORT_ID 0xf
struct pmcs_iport {
kmutex_t lock;
list_node_t list_node;
kmutex_t refcnt_lock;
kcondvar_t refcnt_cv;
int refcnt;
dev_info_t *dip;
pmcs_hw_t *pwp;
pmcs_phy_t *pptr;
enum {
UA_INACTIVE,
UA_PEND_ACTIVATE,
UA_ACTIVE,
UA_PEND_DEACTIVATE
} ua_state;
char *ua;
int portid;
int report_skip;
list_t phys;
int nphy;
scsi_hba_tgtmap_t *iss_tgtmap;
ddi_soft_state_bystr *tgt_sstate;
kmutex_t smp_lock;
kcondvar_t smp_cv;
boolean_t smp_active;
kthread_t *smp_active_thread;
};
struct pmcs_chunk {
pmcs_chunk_t *next;
ddi_acc_handle_t acc_handle;
ddi_dma_handle_t dma_handle;
uint8_t *addrp;
uint64_t dma_addr;
};
struct pmcs_hw {
dev_info_t *dip;
uint64_t sas_wwns[PMCS_MAX_PORTS];
enum pwpstate {
STATE_NIL,
STATE_PROBING,
STATE_RUNNING,
STATE_UNPROBING,
STATE_IN_RESET,
STATE_DEAD
} state;
enum pwp_last_reset_reason {
PMCS_LAST_RST_UNINIT,
PMCS_LAST_RST_ATTACH,
PMCS_LAST_RST_FW_UPGRADE,
PMCS_LAST_RST_FATAL_ERROR,
PMCS_LAST_RST_STALL,
PMCS_LAST_RST_QUIESCE,
PMCS_LAST_RST_DETACH
} last_reset_reason;
uint32_t
fw_disable_update : 1,
fw_force_update : 1,
blocked : 1,
stuck : 1,
locks_initted : 1,
mpi_table_setup : 1,
hba_attached : 1,
iports_attached : 1,
suspended : 1,
separate_ports : 1,
fwlog : 4,
phymode : 3,
physpeed : 3,
resource_limited : 1,
configuring : 1,
ds_err_recovering : 1,
quiesced : 1,
fwlog_file : 1,
fw_active_img : 1;
krwlock_t iports_lock;
scsi_hba_iportmap_t *hss_iportmap;
list_t iports;
int num_iports;
sas_phymap_t *hss_phymap;
int phymap_active;
kmutex_t lock;
kmutex_t dma_lock;
kmutex_t axil_lock;
kcondvar_t drain_cv;
int fm_capabilities;
ddi_device_acc_attr_t dev_acc_attr;
ddi_device_acc_attr_t reg_acc_attr;
ddi_acc_handle_t pci_acc_handle;
ddi_acc_handle_t msg_acc_handle;
ddi_acc_handle_t top_acc_handle;
ddi_acc_handle_t mpi_acc_handle;
ddi_acc_handle_t gsm_acc_handle;
ddi_acc_handle_t iqp_acchdls[PMCS_MAX_IQ];
ddi_acc_handle_t oqp_acchdls[PMCS_MAX_IQ];
ddi_acc_handle_t cip_acchdls;
ddi_acc_handle_t fwlog_acchdl;
ddi_acc_handle_t regdump_acchdl;
ddi_dma_attr_t iqp_dma_attr;
ddi_dma_attr_t oqp_dma_attr;
ddi_dma_attr_t cip_dma_attr;
ddi_dma_attr_t fwlog_dma_attr;
ddi_dma_attr_t regdump_dma_attr;
ddi_dma_handle_t iqp_handles[PMCS_MAX_IQ];
ddi_dma_handle_t oqp_handles[PMCS_MAX_OQ];
ddi_dma_handle_t cip_handles;
ddi_dma_handle_t fwlog_hndl;
ddi_dma_handle_t regdump_hndl;
uint32_t *msg_regs;
uint32_t *top_regs;
uint32_t *mpi_regs;
uint32_t *gsm_regs;
uint32_t mpi_offset;
uint32_t mpi_gst_offset;
uint32_t mpi_iqc_offset;
uint32_t mpi_oqc_offset;
uint32_t ioq_depth;
uint32_t shadow_iqpi[PMCS_MAX_IQ];
uint32_t iqpi_offset[PMCS_MAX_IQ];
uint32_t last_iqci[PMCS_MAX_IQ];
uint32_t last_htag[PMCS_MAX_IQ];
uint32_t *iqp[PMCS_MAX_IQ];
kmutex_t iqp_lock[PMCS_NIQ];
pmcs_iqp_trace_t *iqpt;
uint32_t *oqp[PMCS_MAX_OQ];
uint32_t oqci_offset[PMCS_MAX_OQ];
uint32_t oqci[PMCS_NOQ];
uint32_t oqpi[PMCS_NOQ];
uint64_t oqaddr[PMCS_MAX_OQ];
uint64_t iqaddr[PMCS_MAX_IQ];
uint8_t *cip;
uint64_t ciaddr;
void *scratch;
uint64_t scratch_dma;
volatile uint8_t scratch_locked;
uint32_t *fwlogp;
pmcs_fw_event_hdr_t *fwlogp_aap1;
pmcs_fw_event_hdr_t *fwlogp_iop;
uint64_t fwaddr;
char fwlogfile_aap1[MAXPATHLEN + 1];
uint32_t fwlog_max_entries_aap1;
uint32_t fwlog_oldest_idx_aap1;
uint32_t fwlog_latest_idx_aap1;
uint32_t fwlog_threshold_aap1;
uint32_t fwlog_findex_aap1;
char fwlogfile_iop[MAXPATHLEN + 1];
uint32_t fwlog_max_entries_iop;
uint32_t fwlog_oldest_idx_iop;
uint32_t fwlog_latest_idx_iop;
uint32_t fwlog_threshold_iop;
uint32_t fwlog_findex_iop;
caddr_t regdumpp;
uint32_t *flash_chunkp;
uint64_t flash_chunk_addr;
uint32_t last_msgu_tick;
uint32_t last_iop_tick;
uint32_t fw;
uint32_t ila_ver;
uint8_t max_iq;
uint8_t max_oq;
uint8_t nphy;
uint8_t chiprev;
uint16_t max_cmd;
uint16_t max_dev;
uint16_t last_wq_dev;
uint8_t watchdog_count;
enum {
PMCS_INT_NONE,
PMCS_INT_TIMER,
PMCS_INT_MSI,
PMCS_INT_MSIX,
PMCS_INT_FIXED
} int_type;
uint8_t oqvec[PMCS_NOQ];
ddi_intr_handle_t *ih_table;
size_t ih_table_size;
timeout_id_t wdhandle;
uint32_t intr_mask;
int intr_cnt;
int intr_cap;
uint32_t odb_auto_clear;
int nchunks;
pmcs_chunk_t *dma_chunklist;
pmcs_dmachunk_t *dma_freelist;
pmcs_phy_t *root_phys;
pmcs_phy_t *ports[PMCS_MAX_PORTS];
kmutex_t dead_phylist_lock;
pmcs_phy_t *dead_phys;
kmem_cache_t *phy_cache;
kmutex_t config_lock;
volatile boolean_t config_changed;
boolean_t config_restart;
clock_t config_restart_time;
kcondvar_t config_cv;
pmcwork_t *work;
STAILQ_HEAD(wfh, pmcwork) wf;
STAILQ_HEAD(pfh, pmcwork) pf;
uint16_t wserno;
kmutex_t wfree_lock;
kmutex_t pfree_lock;
scsi_hba_tran_t *tran;
smp_hba_tran_t *smp_tran;
struct scsi_reset_notify_entry *reset_notify_listf;
ddi_taskq_t *tq;
volatile ulong_t work_flags;
pmcs_xscsi_t **targets;
STAILQ_HEAD(dqh, pmcs_cmd) dq;
STAILQ_HEAD(cqh, pmcs_cmd) cq;
kmutex_t cq_lock;
kmem_cache_t *iocomp_cb_cache;
pmcs_iocomp_cb_t *iocomp_cb_head;
pmcs_iocomp_cb_t *iocomp_cb_tail;
uint16_t debug_mask;
uint16_t phyid_block_mask;
uint16_t phys_started;
uint16_t open_retry_interval;
uint32_t hipri_queue;
uint32_t mpibar;
uint32_t intr_pri;
pmcs_io_intr_coal_t io_intr_coal;
pmcs_cq_info_t cq_info;
kmutex_t ict_lock;
kcondvar_t ict_cv;
kthread_t *ict_thread;
char *recept_labels[PMCS_NUM_RECEPTACLES];
char *recept_pm[PMCS_NUM_RECEPTACLES];
uint64_t fw_timestamp;
timespec_t sys_timestamp;
hrtime_t hrtimestamp;
#ifdef DEBUG
kmutex_t dbglock;
uint32_t ltags[256];
uint32_t ftags[256];
hrtime_t ltime[256];
hrtime_t ftime[256];
uint16_t ftag_lines[256];
uint8_t lti;
uint8_t fti;
#endif
};
extern void *pmcs_softc_state;
extern void *pmcs_iport_softstate;
extern const char pmcs_nowrk[];
extern const char pmcs_nomsg[];
extern const char pmcs_timeo[];
extern int modrootloaded;
#ifdef __cplusplus
}
#endif
#endif