#ifndef _PMCS_DEF_H
#define _PMCS_DEF_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
NOTHING,
SATA,
SAS,
EXPANDER,
NEW
} pmcs_dtype_t;
#define PMCS_HW_MIN_LINK_RATE SAS_LINK_RATE_1_5GBIT
#define PMCS_HW_MAX_LINK_RATE SAS_LINK_RATE_6GBIT
#define PMCS_INVALID_DEVICE_ID 0xffffffff
#define PMCS_DEVICE_ID_MASK 0xffff
#define PMCS_PHY_INVALID_PORT_ID 0xf
#define PMCS_PM_MAX_NAMELEN 16
#define PMCS_MAX_REENUMERATE 2
#define PMCS_REDISCOVERY_DELAY (5 * MICROSEC)
struct pmcs_phy {
pmcs_phy_t *sibling;
pmcs_phy_t *parent;
pmcs_phy_t *children;
pmcs_phy_t *dead_next;
list_node_t list_node;
uint32_t device_id;
uint32_t
ncphy : 8,
hw_event_ack : 24;
uint8_t phynum;
uint8_t width;
uint8_t ds_recovery_retries;
uint8_t ds_prev_good_recoveries;
clock_t prev_recovery;
clock_t last_good_recovery;
pmcs_dtype_t dtype;
pmcs_dtype_t pend_dtype;
uint32_t
level : 8,
tolerates_sas2 : 1,
spinup_hold : 1,
atdt : 3,
portid : 4,
link_rate : 4,
valid_device_id : 1,
abort_sent : 1,
abort_pending : 1,
need_rl_ext : 1,
subsidiary : 1,
configured : 1,
dead : 1,
changed : 1,
reenumerate : 1,
virtual : 1,
deregister_wait : 1;
clock_t config_stop;
hrtime_t abort_all_start;
kcondvar_t abort_all_cv;
kmutex_t phy_lock;
volatile uint32_t ref_count;
uint32_t enum_attempts;
uint8_t sas_address[8];
struct {
uint32_t
prog_min_rate :4,
hw_min_rate :4,
prog_max_rate :4,
hw_max_rate :4,
reserved :16;
} state;
char path[32];
pmcs_hw_t *pwp;
pmcs_iport_t *iport;
pmcs_iport_t *last_iport;
pmcs_xscsi_t *target;
pmcs_xscsi_t **target_addr;
kstat_t *phy_stats;
uint64_t att_port_pm;
uint64_t att_port_pm_tmp;
char att_port_pm_str[PMCS_PM_MAX_NAMELEN + 1];
uint64_t tgt_port_pm;
uint64_t tgt_port_pm_tmp;
char tgt_port_pm_str[PMCS_PM_MAX_NAMELEN + 1];
smp_routing_attr_t routing_attr;
smp_routing_attr_t routing_method;
smp_report_general_resp_t rg_resp;
smp_discover_resp_t disc_resp;
};
#define PMCS_MAX_DS_RECOVERY_RETRIES 10
#define PMCS_MAX_DS_RECOVERY_TIME (60 * 1000000)
#define PMCS_DS_RECOVERY_INTERVAL (1000000)
#define IQCI_BASE_OFFSET 0
#define IQ_OFFSET(qnum) (IQCI_BASE_OFFSET + (qnum << 2))
#define OQPI_BASE_OFFSET 256
#define OQ_OFFSET(qnum) (OQPI_BASE_OFFSET + (qnum << 2))
typedef enum {
PMCS_WORK_STATE_NIL = 0,
PMCS_WORK_STATE_READY,
PMCS_WORK_STATE_ONCHIP,
PMCS_WORK_STATE_INTR,
PMCS_WORK_STATE_IOCOMPQ,
PMCS_WORK_STATE_ABORTED,
PMCS_WORK_STATE_TIMED_OUT
} pmcs_work_state_t;
struct pmcwork {
STAILQ_ENTRY(pmcwork) next;
kmutex_t lock;
kcondvar_t sleep_cv;
void *ptr;
void *arg;
pmcs_phy_t *phy;
pmcs_xscsi_t *xp;
volatile uint32_t htag;
uint32_t abt_htag;
uint32_t
timer : 27,
onwire : 1,
dead : 1,
state : 3;
hrtime_t start;
uint32_t ssp_event;
pmcs_dtype_t dtype;
void *last_ptr;
void *last_arg;
pmcs_phy_t *last_phy;
pmcs_xscsi_t *last_xp;
uint32_t last_htag;
pmcs_work_state_t last_state;
hrtime_t finish;
};
#define PMCS_ABT_HTAG_ALL 0xffffffff
#define PMCS_REC_EVENT 0xffffffff
#pragma pack(4)
typedef struct {
char vendor_id[8];
uint8_t product_id;
uint8_t hwrev;
uint8_t destination_partition;
uint8_t reserved0;
uint8_t fwrev[4];
uint32_t firmware_length;
uint32_t crc;
uint32_t start_address;
uint8_t data[];
} pmcs_fw_hdr_t;
#pragma pack()
#define PMCS_WORK_DISCOVER 0
#define PMCS_WORK_ABORT_HANDLE 3
#define PMCS_WORK_SPINUP_RELEASE 4
#define PMCS_WORK_SAS_HW_ACK 5
#define PMCS_WORK_SATA_RUN 6
#define PMCS_WORK_RUN_QUEUES 7
#define PMCS_WORK_ADD_DMA_CHUNKS 8
#define PMCS_WORK_DS_ERR_RECOVERY 9
#define PMCS_WORK_SSP_EVT_RECOVERY 10
#define PMCS_WORK_DEREGISTER_DEV 11
#define PMCS_WORK_DUMP_REGS 12
#define PMCS_WORK_FLAG_DISCOVER (1 << 0)
#define PMCS_WORK_FLAG_ABORT_HANDLE (1 << 3)
#define PMCS_WORK_FLAG_SPINUP_RELEASE (1 << 4)
#define PMCS_WORK_FLAG_SAS_HW_ACK (1 << 5)
#define PMCS_WORK_FLAG_SATA_RUN (1 << 6)
#define PMCS_WORK_FLAG_RUN_QUEUES (1 << 7)
#define PMCS_WORK_FLAG_ADD_DMA_CHUNKS (1 << 8)
#define PMCS_WORK_FLAG_DS_ERR_RECOVERY (1 << 9)
#define PMCS_WORK_FLAG_SSP_EVT_RECOVERY (1 << 10)
#define PMCS_WORK_FLAG_DEREGISTER_DEV (1 << 11)
#define PMCS_WORK_FLAG_DUMP_REGS (1 << 12)
typedef struct {
uint32_t signature;
uint32_t count;
uint32_t *ptr;
} echo_test_t;
#define ECHO_SIGNATURE 0xbebebeef
#define PMCS_TAG_TYPE_FREE 0
#define PMCS_TAG_TYPE_NONE 1
#define PMCS_TAG_TYPE_CBACK 2
#define PMCS_TAG_TYPE_WAIT 3
#define PMCS_TAG_TYPE_SHIFT 28
#define PMCS_TAG_SERNO_SHIFT 12
#define PMCS_TAG_INDEX_SHIFT 0
#define PMCS_TAG_TYPE_MASK 0x30000000
#define PMCS_TAG_NONIO_CMD 0x40000000
#define PMCS_TAG_DONE 0x80000000
#define PMCS_TAG_SERNO_MASK 0x0ffff000
#define PMCS_TAG_INDEX_MASK 0x00000fff
#define PMCS_TAG_TYPE(x) \
(((x) & PMCS_TAG_TYPE_MASK) >> PMCS_TAG_TYPE_SHIFT)
#define PMCS_TAG_SERNO(x) \
(((x) & PMCS_TAG_SERNO_MASK) >> PMCS_TAG_SERNO_SHIFT)
#define PMCS_TAG_INDEX(x) \
(((x) & PMCS_TAG_INDEX_MASK) >> PMCS_TAG_INDEX_SHIFT)
#define PMCS_TAG_FREE 0
#define PMCS_COMMAND_DONE(x) \
(((x)->htag == PMCS_TAG_FREE) || (((x)->htag & PMCS_TAG_DONE) != 0))
#define PMCS_COMMAND_ACTIVE(x) \
((x)->htag != PMCS_TAG_FREE && (x)->state == PMCS_WORK_STATE_ONCHIP)
#define CLEAN_MESSAGE(m, x) { \
int _j = x; \
while (_j < PMCS_MSG_SIZE) { \
m[_j++] = 0; \
} \
}
#define COPY_MESSAGE(t, f, a) { \
int _j; \
for (_j = 0; _j < a; _j++) { \
t[_j] = f[_j]; \
} \
while (_j < PMCS_MSG_SIZE) { \
t[_j++] = 0; \
} \
}
#define PMCS_PHY_ADDRESSABLE(pp) \
((pp)->level == 0 && (pp)->dtype == SATA && \
((pp)->sas_address[0] >> 4) != 5)
#define RESTART_DISCOVERY(pwp) \
ASSERT(!mutex_owned(&pwp->config_lock)); \
mutex_enter(&pwp->config_lock); \
pwp->config_changed = B_TRUE; \
mutex_exit(&pwp->config_lock); \
SCHEDULE_WORK(pwp, PMCS_WORK_DISCOVER);
#define RESTART_DISCOVERY_LOCKED(pwp) \
ASSERT(mutex_owned(&pwp->config_lock)); \
pwp->config_changed = B_TRUE; \
SCHEDULE_WORK(pwp, PMCS_WORK_DISCOVER);
#define PHY_CHANGED(pwp, p) \
pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, p, NULL, "%s changed in " \
"%s line %d", p->path, __func__, __LINE__); \
p->changed = 1; \
p->enum_attempts = 0
#define PHY_CHANGED_AT_LOCATION(pwp, p, func, line) \
pmcs_prt(pwp, PMCS_PRT_DEBUG_CONFIG, p, NULL, "%s changed in " \
"%s line %d", p->path, func, line); \
p->changed = 1; \
p->enum_attempts = 0
#define PHY_TYPE(pptr) \
(((pptr)->dtype == NOTHING)? "NOTHING" : \
(((pptr)->dtype == SATA)? "SATA" : \
(((pptr)->dtype == SAS)? "SAS" : "EXPANDER")))
#define IS_ROOT_PHY(pptr) (pptr->parent == NULL)
#define PMCS_HIPRI(pwp, oq, c) \
(pwp->hipri_queue & (1 << PMCS_IQ_OTHER)) ? \
(PMCS_IOMB_HIPRI | PMCS_IOMB_IN_SAS(oq, c)) : \
(PMCS_IOMB_IN_SAS(oq, c))
#define SCHEDULE_WORK(hwp, wrk) \
(void) atomic_set_long_excl(&hwp->work_flags, wrk)
#define WORK_SCHEDULED(hwp, wrk) \
(atomic_clear_long_excl(&hwp->work_flags, wrk) == 0)
#define WORK_IS_SCHEDULED(hwp, wrk) \
((atomic_and_ulong_nv(&hwp->work_flags, (ulong_t)-1) & (1 << wrk)) != 0)
#define WAIT_FOR(p, t, r) \
clock_t _lb = ddi_get_lbolt(); \
r = 0; \
while (!PMCS_COMMAND_DONE(p)) { \
clock_t _ret = cv_timedwait(&p->sleep_cv, \
&p->lock, _lb + drv_usectohz(t * 1000)); \
if (!PMCS_COMMAND_DONE(p) && _ret < 0) { \
r = 1; \
break; \
} \
}
#define PMCS_CQ_RUN_LOCKED(hwp) \
if (!STAILQ_EMPTY(&hwp->cq) || hwp->iocomp_cb_head) { \
pmcs_cq_thr_info_t *cqti; \
cqti = &hwp->cq_info.cq_thr_info \
[hwp->cq_info.cq_next_disp_thr]; \
hwp->cq_info.cq_next_disp_thr++; \
if (hwp->cq_info.cq_next_disp_thr == \
hwp->cq_info.cq_threads) { \
hwp->cq_info.cq_next_disp_thr = 0; \
} \
mutex_enter(&cqti->cq_thr_lock); \
cv_signal(&cqti->cq_cv); \
mutex_exit(&cqti->cq_thr_lock); \
}
#define PMCS_CQ_RUN(hwp) \
mutex_enter(&hwp->cq_lock); \
PMCS_CQ_RUN_LOCKED(hwp); \
mutex_exit(&hwp->cq_lock);
#define US2WT(x) (x)/10
#define BYTE0(x) (((x) >> 0) & 0xff)
#define BYTE1(x) (((x) >> 8) & 0xff)
#define BYTE2(x) (((x) >> 16) & 0xff)
#define BYTE3(x) (((x) >> 24) & 0xff)
#define BYTE4(x) (((x) >> 32) & 0xff)
#define BYTE5(x) (((x) >> 40) & 0xff)
#define BYTE6(x) (((x) >> 48) & 0xff)
#define BYTE7(x) (((x) >> 56) & 0xff)
#define WORD0(x) (((x) >> 0) & 0xffff)
#define WORD1(x) (((x) >> 16) & 0xffff)
#define WORD2(x) (((x) >> 32) & 0xffff)
#define WORD3(x) (((x) >> 48) & 0xffff)
#define DWORD0(x) ((uint32_t)(x))
#define DWORD1(x) ((uint32_t)(((uint64_t)x) >> 32))
#define SAS_ADDR_FMT "0x%02x%02x%02x%02x%02x%02x%02x%02x"
#define SAS_ADDR_PRT(x) x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7]
#define PMCS_VALID_LINK_RATE(r) \
((r == SAS_LINK_RATE_1_5GBIT) || (r == SAS_LINK_RATE_3GBIT) || \
(r == SAS_LINK_RATE_6GBIT))
#define HEXDIGIT(x) (((x) >= '0' && (x) <= '9') || \
((x) >= 'a' && (x) <= 'f') || ((x) >= 'A' && (x) <= 'F'))
#define NSECS_PER_SEC 1000000000UL
typedef void (*pmcs_cb_t) (pmcs_hw_t *, pmcwork_t *, uint32_t *);
#define PMCS_TBUF_ELEM_SIZE 120
#define PMCS_TBUF_NUM_ELEMS_DEF 100000
#define PMCS_TBUF_UA_MAX_SIZE 32
typedef struct {
uint16_t target_num;
char target_ua[PMCS_TBUF_UA_MAX_SIZE];
uint8_t phy_sas_address[8];
char phy_path[32];
pmcs_dtype_t phy_dtype;
timespec_t timestamp;
uint64_t fw_timestamp;
char buf[PMCS_TBUF_ELEM_SIZE];
} pmcs_tbuf_t;
typedef struct pmcs_fw_event_hdr_s {
uint32_t fw_el_signature;
uint32_t fw_el_entry_start_offset;
uint32_t fw_el_rsvd1;
uint32_t fw_el_buf_size;
uint32_t fw_el_rsvd2;
uint32_t fw_el_oldest_idx;
uint32_t fw_el_latest_idx;
uint32_t fw_el_entry_size;
} pmcs_fw_event_hdr_t;
typedef struct pmcs_fw_event_entry_s {
uint32_t num_words : 3,
reserved : 25,
severity: 4;
uint32_t ts_upper;
uint32_t ts_lower;
uint32_t seq_num;
uint32_t logw0;
uint32_t logw1;
uint32_t logw2;
uint32_t logw3;
} pmcs_fw_event_entry_t;
#define PMCS_FWLOG_TIMER_DIV 8
#define PMCS_FWLOG_AAP1_SIG 0x1234AAAA
#define PMCS_FWLOG_IOP_SIG 0x5678CCCC
#define PMCS_NUM_RECEPTACLES 2
#define PMCS_RECEPT_LABEL_0 "SAS0"
#define PMCS_RECEPT_LABEL_1 "SAS1"
#define PMCS_RECEPT_PM_0 "f0"
#define PMCS_RECEPT_PM_1 "f"
#ifdef __cplusplus
}
#endif
#endif