#include "ocs.h"
#include "ocs_os.h"
#define DEFAULT_SLAB_LEN (64*1024)
struct ocs_array_s {
ocs_os_handle_t os;
uint32_t size;
uint32_t count;
uint32_t n_rows;
uint32_t elems_per_row;
uint32_t bytes_per_row;
void **array_rows;
uint32_t array_rows_len;
};
static uint32_t slab_len = DEFAULT_SLAB_LEN;
void
ocs_array_set_slablen(uint32_t len)
{
slab_len = len;
}
ocs_array_t *
ocs_array_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count)
{
ocs_array_t *array = NULL;
uint32_t i;
if (size > slab_len) {
ocs_log_err(NULL, "Error: size exceeds slab length\n");
return NULL;
}
array = ocs_malloc(os, sizeof(*array), OCS_M_ZERO | OCS_M_NOWAIT);
if (array == NULL) {
return NULL;
}
array->os = os;
array->size = size;
array->count = count;
array->elems_per_row = slab_len / size;
array->n_rows = (count + array->elems_per_row - 1) / array->elems_per_row;
array->bytes_per_row = array->elems_per_row * array->size;
array->array_rows_len = array->n_rows * sizeof(*array->array_rows);
array->array_rows = ocs_malloc(os, array->array_rows_len, OCS_M_ZERO | OCS_M_NOWAIT);
if (array->array_rows == NULL) {
ocs_array_free(array);
return NULL;
}
for (i = 0; i < array->n_rows; i++) {
array->array_rows[i] = ocs_malloc(os, array->bytes_per_row, OCS_M_ZERO | OCS_M_NOWAIT);
if (array->array_rows[i] == NULL) {
ocs_array_free(array);
return NULL;
}
}
return array;
}
void
ocs_array_free(ocs_array_t *array)
{
uint32_t i;
if (array != NULL) {
if (array->array_rows != NULL) {
for (i = 0; i < array->n_rows; i++) {
if (array->array_rows[i] != NULL) {
ocs_free(array->os, array->array_rows[i], array->bytes_per_row);
}
}
ocs_free(array->os, array->array_rows, array->array_rows_len);
}
ocs_free(array->os, array, sizeof(*array));
}
}
void *ocs_array_get(ocs_array_t *array, uint32_t idx)
{
void *entry = NULL;
if (idx < array->count) {
uint32_t row = idx / array->elems_per_row;
uint32_t offset = idx % array->elems_per_row;
entry = ((uint8_t*)array->array_rows[row]) + (offset * array->size);
}
return entry;
}
uint32_t
ocs_array_get_count(ocs_array_t *array)
{
return array->count;
}
uint32_t
ocs_array_get_size(ocs_array_t *array)
{
return array->size;
}
struct ocs_varray_s {
ocs_os_handle_t os;
uint32_t array_count;
void **array;
uint32_t entry_count;
uint32_t next_index;
ocs_lock_t lock;
};
ocs_varray_t *
ocs_varray_alloc(ocs_os_handle_t os, uint32_t array_count)
{
ocs_varray_t *va;
va = ocs_malloc(os, sizeof(*va), OCS_M_ZERO | OCS_M_NOWAIT);
if (va != NULL) {
va->os = os;
va->array_count = array_count;
va->array = ocs_malloc(os, sizeof(*va->array) * va->array_count, OCS_M_ZERO | OCS_M_NOWAIT);
if (va->array != NULL) {
va->next_index = 0;
ocs_lock_init(os, &va->lock, "varray:%p", va);
} else {
ocs_free(os, va, sizeof(*va));
va = NULL;
}
}
return va;
}
void
ocs_varray_free(ocs_varray_t *va)
{
if (va != NULL) {
ocs_lock_free(&va->lock);
if (va->array != NULL) {
ocs_free(va->os, va->array, sizeof(*va->array) * va->array_count);
}
ocs_free(va->os, va, sizeof(*va));
}
}
int32_t
ocs_varray_add(ocs_varray_t *va, void *entry)
{
uint32_t rc = -1;
ocs_lock(&va->lock);
if (va->entry_count < va->array_count) {
va->array[va->entry_count++] = entry;
rc = 0;
}
ocs_unlock(&va->lock);
return rc;
}
void
ocs_varray_iter_reset(ocs_varray_t *va)
{
ocs_lock(&va->lock);
va->next_index = 0;
ocs_unlock(&va->lock);
}
void *
ocs_varray_iter_next(ocs_varray_t *va)
{
void *rval = NULL;
if (va != NULL) {
ocs_lock(&va->lock);
rval = _ocs_varray_iter_next(va);
ocs_unlock(&va->lock);
}
return rval;
}
void *
_ocs_varray_iter_next(ocs_varray_t *va)
{
void *rval;
rval = va->array[va->next_index];
if (++va->next_index >= va->entry_count) {
va->next_index = 0;
}
return rval;
}
void
ocs_varray_lock(ocs_varray_t *va)
{
ocs_lock(&va->lock);
}
void
ocs_varray_unlock(ocs_varray_t *va)
{
ocs_unlock(&va->lock);
}
uint32_t
ocs_varray_get_count(ocs_varray_t *va)
{
uint32_t rc;
ocs_lock(&va->lock);
rc = va->entry_count;
ocs_unlock(&va->lock);
return rc;
}
struct ocs_cbuf_s {
ocs_os_handle_t os;
uint32_t entry_count;
void **array;
uint32_t pidx;
uint32_t cidx;
ocs_lock_t cbuf_plock;
ocs_lock_t cbuf_clock;
ocs_sem_t cbuf_psem;
ocs_sem_t cbuf_csem;
};
ocs_cbuf_t*
ocs_cbuf_alloc(ocs_os_handle_t os, uint32_t entry_count)
{
ocs_cbuf_t *cbuf;
cbuf = ocs_malloc(os, sizeof(*cbuf), OCS_M_NOWAIT | OCS_M_ZERO);
if (cbuf == NULL) {
return NULL;
}
cbuf->os = os;
cbuf->entry_count = entry_count;
cbuf->pidx = 0;
cbuf->cidx = 0;
ocs_lock_init(NULL, &cbuf->cbuf_clock, "cbuf_c:%p", cbuf);
ocs_lock_init(NULL, &cbuf->cbuf_plock, "cbuf_p:%p", cbuf);
ocs_sem_init(&cbuf->cbuf_csem, 0, "cbuf:%p", cbuf);
ocs_sem_init(&cbuf->cbuf_psem, cbuf->entry_count, "cbuf:%p", cbuf);
cbuf->array = ocs_malloc(os, entry_count * sizeof(*cbuf->array), OCS_M_NOWAIT | OCS_M_ZERO);
if (cbuf->array == NULL) {
ocs_cbuf_free(cbuf);
return NULL;
}
return cbuf;
}
void
ocs_cbuf_free(ocs_cbuf_t *cbuf)
{
if (cbuf != NULL) {
if (cbuf->array != NULL) {
ocs_free(cbuf->os, cbuf->array, sizeof(*cbuf->array) * cbuf->entry_count);
}
ocs_lock_free(&cbuf->cbuf_clock);
ocs_lock_free(&cbuf->cbuf_plock);
ocs_free(cbuf->os, cbuf, sizeof(*cbuf));
}
}
void*
ocs_cbuf_get(ocs_cbuf_t *cbuf, int32_t timeout_usec)
{
void *ret = NULL;
if (likely(ocs_sem_p(&cbuf->cbuf_csem, timeout_usec) == 0)) {
ocs_lock(&cbuf->cbuf_clock);
ret = cbuf->array[cbuf->cidx];
if (unlikely(++cbuf->cidx >= cbuf->entry_count)) {
cbuf->cidx = 0;
}
ocs_unlock(&cbuf->cbuf_clock);
ocs_sem_v(&cbuf->cbuf_psem);
}
return ret;
}
int32_t
ocs_cbuf_put(ocs_cbuf_t *cbuf, void *elem)
{
int32_t rc = 0;
if (likely(ocs_sem_p(&cbuf->cbuf_psem, -1) == 0)) {
ocs_lock(&cbuf->cbuf_plock);
cbuf->array[cbuf->pidx] = elem;
if (unlikely(++cbuf->pidx >= cbuf->entry_count)) {
cbuf->pidx = 0;
}
ocs_unlock(&cbuf->cbuf_plock);
ocs_sem_v(&cbuf->cbuf_csem);
} else {
rc = -1;
}
return rc;
}
int32_t
ocs_cbuf_prime(ocs_cbuf_t *cbuf, ocs_array_t *array)
{
uint32_t i;
uint32_t count = MIN(ocs_array_get_count(array), cbuf->entry_count);
for (i = 0; i < count; i++) {
ocs_cbuf_put(cbuf, ocs_array_get(array, i));
}
return 0;
}
void
ocs_ddump_startfile(ocs_textbuf_t *textbuf)
{
ocs_textbuf_printf(textbuf, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n");
}
void
ocs_ddump_endfile(ocs_textbuf_t *textbuf)
{
}
void
ocs_ddump_section(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
{
ocs_textbuf_printf(textbuf, "<%s type=\"section\" instance=\"%d\">\n", name, instance);
}
void
ocs_ddump_endsection(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
{
ocs_textbuf_printf(textbuf, "</%s>\n", name);
}
void
ocs_ddump_value(ocs_textbuf_t *textbuf, const char *name, const char *fmt, ...)
{
va_list ap;
char valuebuf[64];
va_start(ap, fmt);
vsnprintf(valuebuf, sizeof(valuebuf), fmt, ap);
va_end(ap);
ocs_textbuf_printf(textbuf, "<%s>%s</%s>\n", name, valuebuf, name);
}
void
ocs_ddump_buffer(ocs_textbuf_t *textbuf, const char *name, uint32_t instance, void *buffer, uint32_t size)
{
uint32_t *dword;
uint32_t i;
uint32_t count;
count = size / sizeof(uint32_t);
if (count == 0) {
return;
}
ocs_textbuf_printf(textbuf, "<%s type=\"buffer\" instance=\"%d\">\n", name, instance);
dword = buffer;
for (i = 0; i < count; i++) {
#define OCS_NEWLINE_MOD 8
ocs_textbuf_printf(textbuf, "%08x ", *dword++);
if ((i % OCS_NEWLINE_MOD) == (OCS_NEWLINE_MOD - 1)) {
ocs_textbuf_printf(textbuf, "\n");
}
}
ocs_textbuf_printf(textbuf, "</%s>\n", name);
}
void
ocs_ddump_queue_entries(ocs_textbuf_t *textbuf, void *q_addr, uint32_t size,
uint32_t length, int32_t index, uint32_t qentries)
{
uint32_t i;
uint32_t j;
uint8_t *entry;
uint32_t *dword;
uint32_t entry_count = 0;
uint32_t entry_words = size / sizeof(uint32_t);
if ((qentries == (uint32_t)-1) || (qentries > length)) {
entry_count = length;
index = 0;
} else {
entry_count = qentries;
index -= (qentries - 1);
if (index < 0) {
index += length;
}
}
#define OCS_NEWLINE_MOD 8
ocs_textbuf_printf(textbuf, "<qentries>\n");
for (i = 0; i < entry_count; i++){
entry = q_addr;
entry += index * size;
dword = (uint32_t *)entry;
ocs_textbuf_printf(textbuf, "[%04x] ", index);
for (j = 0; j < entry_words; j++) {
ocs_textbuf_printf(textbuf, "%08x ", *dword++);
if (((j+1) == entry_words) ||
((j % OCS_NEWLINE_MOD) == (OCS_NEWLINE_MOD - 1))) {
ocs_textbuf_printf(textbuf, "\n");
if ((j+1) < entry_words) {
ocs_textbuf_printf(textbuf, " ");
}
}
}
index++;
if ((uint32_t)index >= length) {
index = 0;
}
}
ocs_textbuf_printf(textbuf, "</qentries>\n");
}
#define OCS_DEBUG_ENABLE(x) (x ? ~0 : 0)
#define OCS_DEBUG_MASK \
(OCS_DEBUG_ENABLE(1) & OCS_DEBUG_ALWAYS) | \
(OCS_DEBUG_ENABLE(0) & OCS_DEBUG_ENABLE_MQ_DUMP) | \
(OCS_DEBUG_ENABLE(0) & OCS_DEBUG_ENABLE_CQ_DUMP) | \
(OCS_DEBUG_ENABLE(0) & OCS_DEBUG_ENABLE_WQ_DUMP) | \
(OCS_DEBUG_ENABLE(0) & OCS_DEBUG_ENABLE_EQ_DUMP) | \
(OCS_DEBUG_ENABLE(0) & OCS_DEBUG_ENABLE_SPARAM_DUMP)
static uint32_t ocs_debug_mask = OCS_DEBUG_MASK;
static int
_isprint(int c) {
return ((c > 32) && (c < 127));
}
void ocs_debug_enable(uint32_t mask) {
ocs_debug_mask |= mask;
}
void ocs_debug_disable(uint32_t mask) {
ocs_debug_mask &= ~mask;
}
int ocs_debug_is_enabled(uint32_t mask) {
return (ocs_debug_mask & mask) == mask;
}
void
ocs_dump32(uint32_t mask, ocs_os_handle_t os, const char *label, void *buf, uint32_t buf_length)
{
uint32_t word_count = buf_length / sizeof(uint32_t);
uint32_t i;
uint32_t columns = 8;
uint32_t n;
uint32_t *wbuf;
char *cbuf;
uint32_t addr = 0;
char linebuf[200];
char *pbuf = linebuf;
if (!ocs_debug_is_enabled(mask))
return;
if (label)
ocs_log_debug(os, "%s\n", label);
wbuf = buf;
while (word_count > 0) {
pbuf = linebuf;
pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%08X: ", addr);
n = word_count;
if (n > columns)
n = columns;
for (i = 0; i < n; i ++)
pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%08X ", wbuf[i]);
for (; i < columns; i ++)
pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%8s ", "");
pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), " ");
cbuf = (char*)wbuf;
for (i = 0; i < n*sizeof(uint32_t); i ++)
pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "%c", _isprint(cbuf[i]) ? cbuf[i] : '.');
pbuf += ocs_snprintf(pbuf, sizeof(linebuf) - (pbuf-linebuf), "\n");
ocs_log_debug(os, "%s", linebuf);
wbuf += n;
word_count -= n;
addr += n*sizeof(uint32_t);
}
}
#if defined(OCS_DEBUG_QUEUE_HISTORY)
#define OCS_Q_HIST_WQE_WORD_MASK_DEFAULT (BIT(4) | BIT(6) | BIT(7) | BIT(9) | BIT(12))
#define OCS_Q_HIST_TRECV_CONT_WQE_WORD_MASK (BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(9) | BIT(12))
#define OCS_Q_HIST_IWRITE_WQE_WORD_MASK (BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(9))
#define OCS_Q_HIST_IREAD_WQE_WORD_MASK (BIT(4) | BIT(6) | BIT(7) | BIT(9))
#define OCS_Q_HIST_ABORT_WQE_WORD_MASK (BIT(3) | BIT(7) | BIT(8) | BIT(9))
#define OCS_Q_HIST_WCQE_WORD_MASK (BIT(0) | BIT(3))
#define OCS_Q_HIST_WCQE_WORD_MASK_ERR (BIT(0) | BIT(1) | BIT(2) | BIT(3))
#define OCS_Q_HIST_CQXABT_WORD_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
#define OCS_Q_HIST_ENABLE_Q_INFO 0
uint8_t ocs_queue_history_q_info_enabled(void)
{
return OCS_Q_HIST_ENABLE_Q_INFO;
}
#define OCS_Q_HIST_ENABLE_TIMESTAMPS 0
uint8_t ocs_queue_history_timestamp_enabled(void)
{
return OCS_Q_HIST_ENABLE_TIMESTAMPS;
}
ocs_q_hist_wqe_mask_t ocs_q_hist_wqe_masks[] = {
{SLI4_WQE_ABORT, OCS_Q_HIST_ABORT_WQE_WORD_MASK},
{SLI4_WQE_FCP_IREAD64, OCS_Q_HIST_IREAD_WQE_WORD_MASK},
{SLI4_WQE_FCP_IWRITE64, OCS_Q_HIST_IWRITE_WQE_WORD_MASK},
{SLI4_WQE_FCP_CONT_TRECEIVE64, OCS_Q_HIST_TRECV_CONT_WQE_WORD_MASK},
};
ocs_q_hist_cqe_mask_t ocs_q_hist_cqe_masks[] = {
{SLI_QENTRY_WQ, OCS_Q_HIST_TYPE_CWQE, OCS_Q_HIST_WCQE_WORD_MASK, OCS_Q_HIST_WCQE_WORD_MASK_ERR},
{SLI_QENTRY_XABT, OCS_Q_HIST_TYPE_CXABT, OCS_Q_HIST_CQXABT_WORD_MASK, OCS_Q_HIST_WCQE_WORD_MASK},
};
static uint32_t ocs_q_hist_get_wqe_mask(sli4_generic_wqe_t *wqe)
{
uint32_t i;
for (i = 0; i < ARRAY_SIZE(ocs_q_hist_wqe_masks); i++) {
if (ocs_q_hist_wqe_masks[i].command == wqe->command) {
return ocs_q_hist_wqe_masks[i].mask;
}
}
return OCS_Q_HIST_WQE_WORD_MASK_DEFAULT;
}
void
ocs_queue_history_init(ocs_t *ocs, ocs_hw_q_hist_t *q_hist)
{
q_hist->ocs = ocs;
if (q_hist->q_hist != NULL) {
ocs_log_debug(ocs, "q_hist not NULL, skipping init\n");
return;
}
q_hist->q_hist = ocs_malloc(ocs, sizeof(*q_hist->q_hist)*OCS_Q_HIST_SIZE, OCS_M_ZERO | OCS_M_NOWAIT);
if (q_hist->q_hist == NULL) {
ocs_log_err(ocs, "Could not allocate queue history buffer\n");
} else {
ocs_lock_init(ocs, &q_hist->q_hist_lock, "queue history lock[%d]", ocs_instance(ocs));
}
q_hist->q_hist_index = 0;
}
void
ocs_queue_history_free(ocs_hw_q_hist_t *q_hist)
{
ocs_t *ocs = q_hist->ocs;
if (q_hist->q_hist != NULL) {
ocs_free(ocs, q_hist->q_hist, sizeof(*q_hist->q_hist)*OCS_Q_HIST_SIZE);
ocs_lock_free(&q_hist->q_hist_lock);
q_hist->q_hist = NULL;
}
}
static void
ocs_queue_history_add_q_info(ocs_hw_q_hist_t *q_hist, uint32_t qid, uint32_t qindex)
{
if (ocs_queue_history_q_info_enabled()) {
q_hist->q_hist[q_hist->q_hist_index] = (qid << 16) | qindex;
q_hist->q_hist_index++;
q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
}
}
static void
ocs_queue_history_add_timestamp(ocs_hw_q_hist_t *q_hist)
{
if (ocs_queue_history_timestamp_enabled()) {
uint64_t tsc_value;
tsc_value = get_cyclecount();
q_hist->q_hist[q_hist->q_hist_index] = ((tsc_value >> 32 ) & 0xFFFFFFFF);
q_hist->q_hist_index++;
q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
q_hist->q_hist[q_hist->q_hist_index] = (tsc_value & 0xFFFFFFFF);
q_hist->q_hist_index++;
q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
}
}
void
ocs_queue_history_wq(ocs_hw_q_hist_t *q_hist, uint32_t *entryw, uint32_t qid, uint32_t qindex)
{
int i;
ocs_q_hist_ftr_t ftr;
uint32_t wqe_word_mask = ocs_q_hist_get_wqe_mask((sli4_generic_wqe_t *)entryw);
if (q_hist->q_hist == NULL) {
return;
}
ftr.word = 0;
ftr.s.type = OCS_Q_HIST_TYPE_WQE;
ocs_lock(&q_hist->q_hist_lock);
for (i = ((sizeof(wqe_word_mask)*8) - 1); i >= 0; i--){
if ((wqe_word_mask >> i) & 1) {
q_hist->q_hist[q_hist->q_hist_index] = entryw[i];
q_hist->q_hist_index++;
q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
}
}
ocs_queue_history_add_q_info(q_hist, qid, qindex);
ocs_queue_history_add_timestamp(q_hist);
if (wqe_word_mask) {
ftr.s.mask = wqe_word_mask;
q_hist->q_hist[q_hist->q_hist_index] = ftr.word;
q_hist->q_hist_index++;
q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
}
ocs_unlock(&q_hist->q_hist_lock);
}
void
ocs_queue_history_misc(ocs_hw_q_hist_t *q_hist, uint32_t *entryw, uint32_t num_words)
{
int i;
ocs_q_hist_ftr_t ftr;
uint32_t mask = 0;
if (q_hist->q_hist == NULL) {
return;
}
ftr.word = 0;
ftr.s.type = OCS_Q_HIST_TYPE_MISC;
ocs_lock(&q_hist->q_hist_lock);
for (i = num_words-1; i >= 0; i--) {
q_hist->q_hist[q_hist->q_hist_index] = entryw[i];
q_hist->q_hist_index++;
q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
mask |= BIT(i);
}
ocs_queue_history_add_timestamp(q_hist);
if (num_words) {
ftr.s.mask = mask;
q_hist->q_hist[q_hist->q_hist_index] = ftr.word;
q_hist->q_hist_index++;
q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
}
ocs_unlock(&q_hist->q_hist_lock);
}
void
ocs_queue_history_cqe(ocs_hw_q_hist_t *q_hist, uint8_t ctype, uint32_t *entryw, uint8_t status, uint32_t qid, uint32_t qindex)
{
int i;
unsigned j;
uint32_t cqe_word_mask = 0;
ocs_q_hist_ftr_t ftr;
if (q_hist->q_hist == NULL) {
return;
}
ftr.word = 0;
for (j = 0; j < ARRAY_SIZE(ocs_q_hist_cqe_masks); j++) {
if (ocs_q_hist_cqe_masks[j].ctype == ctype) {
ftr.s.type = ocs_q_hist_cqe_masks[j].type;
if (status != 0) {
cqe_word_mask = ocs_q_hist_cqe_masks[j].mask_err;
} else {
cqe_word_mask = ocs_q_hist_cqe_masks[j].mask;
}
}
}
ocs_lock(&q_hist->q_hist_lock);
for (i = ((sizeof(cqe_word_mask)*8) - 1); i >= 0; i--){
if ((cqe_word_mask >> i) & 1) {
q_hist->q_hist[q_hist->q_hist_index] = entryw[i];
q_hist->q_hist_index++;
q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
}
}
ocs_queue_history_add_q_info(q_hist, qid, qindex);
ocs_queue_history_add_timestamp(q_hist);
if (cqe_word_mask) {
ftr.s.mask = cqe_word_mask;
q_hist->q_hist[q_hist->q_hist_index] = ftr.word;
q_hist->q_hist_index++;
q_hist->q_hist_index = q_hist->q_hist_index % OCS_Q_HIST_SIZE;
}
ocs_unlock(&q_hist->q_hist_lock);
}
uint32_t
ocs_queue_history_prev_index(uint32_t index)
{
if (index == 0) {
return OCS_Q_HIST_SIZE - 1;
} else {
return index - 1;
}
}
#endif
void
ocs_display_sparams(const char *prelabel, const char *reqlabel, int dest, void *textbuf, void *sparams)
{
char label[64];
if (sparams == NULL) {
return;
}
switch(dest) {
case 0:
if (prelabel != NULL) {
ocs_snprintf(label, sizeof(label), "[%s] sparam: %s", prelabel, reqlabel);
} else {
ocs_snprintf(label, sizeof(label), "sparam: %s", reqlabel);
}
ocs_dump32(OCS_DEBUG_ENABLE_SPARAM_DUMP, NULL, label, sparams, sizeof(fc_plogi_payload_t));
break;
case 1:
ocs_ddump_buffer((ocs_textbuf_t*) textbuf, reqlabel, 0, sparams, sizeof(fc_plogi_payload_t));
break;
}
}
uint16_t
ocs_scsi_dif_calc_crc(const uint8_t *buffer, uint32_t size, uint16_t crc)
{
return t10crc16(buffer, size, crc);
}
uint16_t
ocs_scsi_dif_calc_checksum(ocs_scsi_vaddr_len_t addrlen[], uint32_t addrlen_count)
{
uint32_t i, j;
uint16_t checksum;
uint32_t intermediate;
uint32_t count;
uint16_t *buffer;
intermediate = 0;
for (j = 0; j < addrlen_count; j++) {
buffer = addrlen[j].vaddr;
count = addrlen[j].length / 2;
for (i=0; i < count; i++) {
intermediate += buffer[i];
}
}
intermediate += ((intermediate & 0xffff0000) >> 16);
intermediate = ~intermediate;
checksum = intermediate;
return checksum;
}
uint32_t
ocs_scsi_dif_blocksize(ocs_scsi_dif_info_t *dif_info)
{
uint32_t blocksize = 0;
switch(dif_info->blk_size) {
case OCS_SCSI_DIF_BK_SIZE_512: blocksize = 512; break;
case OCS_SCSI_DIF_BK_SIZE_1024: blocksize = 1024; break;
case OCS_SCSI_DIF_BK_SIZE_2048: blocksize = 2048; break;
case OCS_SCSI_DIF_BK_SIZE_4096: blocksize = 4096; break;
case OCS_SCSI_DIF_BK_SIZE_520: blocksize = 520; break;
case OCS_SCSI_DIF_BK_SIZE_4104: blocksize = 4104; break;
default:
break;
}
return blocksize;
}
int32_t
ocs_scsi_dif_set_blocksize(ocs_scsi_dif_info_t *dif_info, uint32_t blocksize)
{
int32_t rc = 0;
switch(blocksize) {
case 512: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_512; break;
case 1024: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_1024; break;
case 2048: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_2048; break;
case 4096: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_4096; break;
case 520: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_520; break;
case 4104: dif_info->blk_size = OCS_SCSI_DIF_BK_SIZE_4104; break;
default:
rc = -1;
break;
}
return rc;
}
int32_t
ocs_scsi_dif_mem_blocksize(ocs_scsi_dif_info_t *dif_info, int wiretomem)
{
uint32_t blocksize;
uint8_t wiretomem_adj[] = {
0,
DIF_SIZE,
0,
DIF_SIZE,
0,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE};
uint8_t memtowire_adj[] = {
0,
0,
DIF_SIZE,
0,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE};
blocksize = ocs_scsi_dif_blocksize(dif_info);
if (blocksize == 0) {
return -1;
}
if (wiretomem) {
ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
blocksize += wiretomem_adj[dif_info->dif_oper];
} else {
ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
blocksize += memtowire_adj[dif_info->dif_oper];
}
return blocksize;
}
int32_t
ocs_scsi_dif_wire_blocksize(ocs_scsi_dif_info_t *dif_info, int wiretomem)
{
uint32_t blocksize;
uint8_t wiretomem_adj[] = {
0,
0,
DIF_SIZE,
0,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE};
uint8_t memtowire_adj[] = {
0,
DIF_SIZE,
0,
DIF_SIZE,
0,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE};
blocksize = ocs_scsi_dif_blocksize(dif_info);
if (blocksize == 0) {
return -1;
}
if (wiretomem) {
ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
blocksize += wiretomem_adj[dif_info->dif_oper];
} else {
ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
blocksize += memtowire_adj[dif_info->dif_oper];
}
return blocksize;
}
uint32_t
ocs_hw_dif_blocksize(ocs_hw_dif_info_t *dif_info)
{
uint32_t blocksize = 0;
switch(dif_info->blk_size) {
case OCS_HW_DIF_BK_SIZE_512: blocksize = 512; break;
case OCS_HW_DIF_BK_SIZE_1024: blocksize = 1024; break;
case OCS_HW_DIF_BK_SIZE_2048: blocksize = 2048; break;
case OCS_HW_DIF_BK_SIZE_4096: blocksize = 4096; break;
case OCS_HW_DIF_BK_SIZE_520: blocksize = 520; break;
case OCS_HW_DIF_BK_SIZE_4104: blocksize = 4104; break;
default:
break;
}
return blocksize;
}
int32_t
ocs_hw_dif_mem_blocksize(ocs_hw_dif_info_t *dif_info, int wiretomem)
{
uint32_t blocksize;
uint8_t wiretomem_adj[] = {
0,
DIF_SIZE,
0,
DIF_SIZE,
0,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE};
uint8_t memtowire_adj[] = {
0,
0,
DIF_SIZE,
0,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE};
blocksize = ocs_hw_dif_blocksize(dif_info);
if (blocksize == 0) {
return -1;
}
if (wiretomem) {
ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
blocksize += wiretomem_adj[dif_info->dif_oper];
} else {
ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
blocksize += memtowire_adj[dif_info->dif_oper];
}
return blocksize;
}
int32_t
ocs_hw_dif_wire_blocksize(ocs_hw_dif_info_t *dif_info, int wiretomem)
{
uint32_t blocksize;
uint8_t wiretomem_adj[] = {
0,
0,
DIF_SIZE,
0,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE};
uint8_t memtowire_adj[] = {
0,
DIF_SIZE,
0,
DIF_SIZE,
0,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE,
DIF_SIZE};
blocksize = ocs_hw_dif_blocksize(dif_info);
if (blocksize == 0) {
return -1;
}
if (wiretomem) {
ocs_assert(dif_info->dif_oper < ARRAY_SIZE(wiretomem_adj), 0);
blocksize += wiretomem_adj[dif_info->dif_oper];
} else {
ocs_assert(dif_info->dif_oper < ARRAY_SIZE(memtowire_adj), 0);
blocksize += memtowire_adj[dif_info->dif_oper];
}
return blocksize;
}
static int32_t ocs_segment_remaining(ocs_textbuf_segment_t *segment);
static ocs_textbuf_segment_t *ocs_textbuf_segment_alloc(ocs_textbuf_t *textbuf);
static void ocs_textbuf_segment_free(ocs_t *ocs, ocs_textbuf_segment_t *segment);
static ocs_textbuf_segment_t *ocs_textbuf_get_segment(ocs_textbuf_t *textbuf, uint32_t idx);
uint8_t *
ocs_textbuf_get_buffer(ocs_textbuf_t *textbuf)
{
return ocs_textbuf_ext_get_buffer(textbuf, 0);
}
int32_t
ocs_textbuf_get_length(ocs_textbuf_t *textbuf)
{
return ocs_textbuf_ext_get_length(textbuf, 0);
}
int32_t
ocs_textbuf_get_written(ocs_textbuf_t *textbuf)
{
uint32_t idx;
int32_t n;
int32_t total = 0;
for (idx = 0; (n = ocs_textbuf_ext_get_written(textbuf, idx)) >= 0; idx++) {
total += n;
}
return total;
}
uint8_t *ocs_textbuf_ext_get_buffer(ocs_textbuf_t *textbuf, uint32_t idx)
{
ocs_textbuf_segment_t *segment = ocs_textbuf_get_segment(textbuf, idx);
if (segment == NULL) {
return NULL;
}
return segment->buffer;
}
int32_t ocs_textbuf_ext_get_length(ocs_textbuf_t *textbuf, uint32_t idx)
{
ocs_textbuf_segment_t *segment = ocs_textbuf_get_segment(textbuf, idx);
if (segment == NULL) {
return -1;
}
return segment->buffer_length;
}
int32_t ocs_textbuf_ext_get_written(ocs_textbuf_t *textbuf, uint32_t idx)
{
ocs_textbuf_segment_t *segment = ocs_textbuf_get_segment(textbuf, idx);
if (segment == NULL) {
return -1;
}
return segment->buffer_written;
}
uint32_t
ocs_textbuf_initialized(ocs_textbuf_t *textbuf)
{
return (textbuf->ocs != NULL);
}
int32_t
ocs_textbuf_alloc(ocs_t *ocs, ocs_textbuf_t *textbuf, uint32_t length)
{
ocs_memset(textbuf, 0, sizeof(*textbuf));
textbuf->ocs = ocs;
ocs_list_init(&textbuf->segment_list, ocs_textbuf_segment_t, link);
if (length > OCS_TEXTBUF_MAX_ALLOC_LEN) {
textbuf->allocation_length = OCS_TEXTBUF_MAX_ALLOC_LEN;
} else {
textbuf->allocation_length = length;
}
textbuf->extendable = TRUE;
textbuf->max_allocation_length = length;
return (ocs_textbuf_segment_alloc(textbuf) == NULL) ? -1 : 0;
}
static ocs_textbuf_segment_t *
ocs_textbuf_segment_alloc(ocs_textbuf_t *textbuf)
{
ocs_textbuf_segment_t *segment = NULL;
if (textbuf->extendable) {
segment = ocs_malloc(textbuf->ocs, sizeof(*segment), OCS_M_ZERO | OCS_M_NOWAIT);
if (segment != NULL) {
segment->buffer = ocs_malloc(textbuf->ocs, textbuf->allocation_length, OCS_M_ZERO | OCS_M_NOWAIT);
if (segment->buffer != NULL) {
segment->buffer_length = textbuf->allocation_length;
segment->buffer_written = 0;
ocs_list_add_tail(&textbuf->segment_list, segment);
textbuf->total_allocation_length += textbuf->allocation_length;
if (textbuf->total_allocation_length >= textbuf->max_allocation_length) {
textbuf->extendable = 0;
}
} else {
ocs_textbuf_segment_free(textbuf->ocs, segment);
segment = NULL;
}
}
}
return segment;
}
static void
ocs_textbuf_segment_free(ocs_t *ocs, ocs_textbuf_segment_t *segment)
{
if (segment) {
if (segment->buffer && !segment->user_allocated) {
ocs_free(ocs, segment->buffer, segment->buffer_length);
}
ocs_free(ocs, segment, sizeof(*segment));
}
}
static ocs_textbuf_segment_t *
ocs_textbuf_get_segment(ocs_textbuf_t *textbuf, uint32_t idx)
{
uint32_t i;
ocs_textbuf_segment_t *segment;
if (ocs_textbuf_initialized(textbuf)) {
i = 0;
ocs_list_foreach(&textbuf->segment_list, segment) {
if (i == idx) {
return segment;
}
i++;
}
}
return NULL;
}
int32_t
ocs_textbuf_init(ocs_t *ocs, ocs_textbuf_t *textbuf, void *buffer, uint32_t length)
{
int32_t rc = -1;
ocs_textbuf_segment_t *segment;
ocs_memset(textbuf, 0, sizeof(*textbuf));
textbuf->ocs = ocs;
ocs_list_init(&textbuf->segment_list, ocs_textbuf_segment_t, link);
segment = ocs_malloc(ocs, sizeof(*segment), OCS_M_ZERO | OCS_M_NOWAIT);
if (segment) {
segment->buffer = buffer;
segment->buffer_length = length;
segment->buffer_written = 0;
segment->user_allocated = 1;
ocs_list_add_tail(&textbuf->segment_list, segment);
rc = 0;
}
return rc;
}
void
ocs_textbuf_free(ocs_t *ocs, ocs_textbuf_t *textbuf)
{
ocs_textbuf_segment_t *segment;
ocs_textbuf_segment_t *n;
if (ocs_textbuf_initialized(textbuf)) {
ocs_list_foreach_safe(&textbuf->segment_list, segment, n) {
ocs_list_remove(&textbuf->segment_list, segment);
ocs_textbuf_segment_free(ocs, segment);
}
ocs_memset(textbuf, 0, sizeof(*textbuf));
}
}
void
ocs_textbuf_printf(ocs_textbuf_t *textbuf, const char *fmt, ...)
{
va_list ap;
if (ocs_textbuf_initialized(textbuf)) {
va_start(ap, fmt);
ocs_textbuf_vprintf(textbuf, fmt, ap);
va_end(ap);
}
}
void
ocs_textbuf_vprintf(ocs_textbuf_t *textbuf, const char *fmt, va_list ap)
{
int avail;
int written;
ocs_textbuf_segment_t *segment;
va_list save_ap;
if (!ocs_textbuf_initialized(textbuf)) {
return;
}
va_copy(save_ap, ap);
segment = ocs_list_get_tail(&textbuf->segment_list);
avail = ocs_segment_remaining(segment);
if (avail == 0) {
if ((segment = ocs_textbuf_segment_alloc(textbuf)) == NULL) {
goto out;
}
avail = ocs_segment_remaining(segment);
}
written = ocs_vsnprintf(segment->buffer + segment->buffer_written, avail, fmt, ap);
if (written >= avail) {
written = avail;
if (textbuf->extendable) {
*(segment->buffer + segment->buffer_written) = 0;
if ((segment = ocs_textbuf_segment_alloc(textbuf)) == NULL) {
ocs_log_err(textbuf->ocs, "alloc segment failed\n");
goto out;
}
avail = ocs_segment_remaining(segment);
written = ocs_vsnprintf(segment->buffer + segment->buffer_written, avail, fmt, save_ap);
}
}
segment->buffer_written += written;
out:
va_end(save_ap);
}
void
ocs_textbuf_putc(ocs_textbuf_t *textbuf, uint8_t c)
{
ocs_textbuf_segment_t *segment;
if (ocs_textbuf_initialized(textbuf)) {
segment = ocs_list_get_tail(&textbuf->segment_list);
if (ocs_segment_remaining(segment)) {
*(segment->buffer + segment->buffer_written++) = c;
}
if (ocs_segment_remaining(segment) == 0) {
ocs_textbuf_segment_alloc(textbuf);
}
}
}
void
ocs_textbuf_puts(ocs_textbuf_t *textbuf, char *s)
{
if (ocs_textbuf_initialized(textbuf)) {
while(*s) {
ocs_textbuf_putc(textbuf, *s++);
}
}
}
void
ocs_textbuf_buffer(ocs_textbuf_t *textbuf, uint8_t *buffer, uint32_t buffer_length)
{
char *s;
if (!ocs_textbuf_initialized(textbuf)) {
return;
}
s = (char*) buffer;
while(*s) {
switch(*s) {
case '"': ocs_textbuf_puts(textbuf, """); break;
case '\'': ocs_textbuf_puts(textbuf, "'"); break;
case '<': ocs_textbuf_puts(textbuf, "<"); break;
case '>': ocs_textbuf_puts(textbuf, ">"); break;
case '&': ocs_textbuf_puts(textbuf, "&"); break;
default: ocs_textbuf_putc(textbuf, *s); break;
}
s++;
}
}
void
ocs_textbuf_copy(ocs_textbuf_t *textbuf, uint8_t *buffer, uint32_t buffer_length)
{
char *s;
if (!ocs_textbuf_initialized(textbuf)) {
return;
}
s = (char*) buffer;
while(*s) {
ocs_textbuf_putc(textbuf, *s++);
}
}
int32_t
ocs_textbuf_remaining(ocs_textbuf_t *textbuf)
{
if (ocs_textbuf_initialized(textbuf)) {
return ocs_segment_remaining(ocs_list_get_head(&textbuf->segment_list));
} else {
return 0;
}
}
static int32_t
ocs_segment_remaining(ocs_textbuf_segment_t *segment)
{
return segment->buffer_length - segment->buffer_written;
}
void
ocs_textbuf_reset(ocs_textbuf_t *textbuf)
{
uint32_t i = 0;
ocs_textbuf_segment_t *segment;
ocs_textbuf_segment_t *n;
if (ocs_textbuf_initialized(textbuf)) {
ocs_list_foreach_safe(&textbuf->segment_list, segment, n) {
if (i++ == 0) {
segment->buffer_written = 0;
} else {
ocs_list_remove(&textbuf->segment_list, segment);
ocs_textbuf_segment_free(textbuf->ocs, segment);
}
}
}
}
static void
**spv_new_row(ocs_os_handle_t os, uint32_t rowcount)
{
return ocs_malloc(os, sizeof(void*) * rowcount, OCS_M_ZERO | OCS_M_NOWAIT);
}
static void
_spv_del(ocs_os_handle_t os, void **a, uint32_t n, uint32_t depth)
{
if (a) {
if (depth) {
uint32_t i;
for (i = 0; i < n; i ++) {
_spv_del(os, a[i], n, depth-1);
}
ocs_free(os, a, SPV_ROWLEN*sizeof(*a));
}
}
}
void
spv_del(sparse_vector_t spv)
{
if (spv) {
_spv_del(spv->os, spv->array, SPV_ROWLEN, SPV_DIM);
ocs_free(spv->os, spv, sizeof(*spv));
}
}
sparse_vector_t
spv_new(ocs_os_handle_t os)
{
sparse_vector_t spv;
uint32_t i;
spv = ocs_malloc(os, sizeof(*spv), OCS_M_ZERO | OCS_M_NOWAIT);
if (!spv) {
return NULL;
}
spv->os = os;
spv->max_idx = 1;
for (i = 0; i < SPV_DIM; i ++) {
spv->max_idx *= SPV_ROWLEN;
}
return spv;
}
static void
*spv_new_cell(sparse_vector_t sv, uint32_t idx, uint8_t alloc_new_rows)
{
uint32_t a = (idx >> 16) & 0xff;
uint32_t b = (idx >> 8) & 0xff;
uint32_t c = (idx >> 0) & 0xff;
void **p;
if (idx >= sv->max_idx) {
return NULL;
}
if (sv->array == NULL) {
sv->array = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
if (sv->array == NULL) {
return NULL;
}
}
p = sv->array;
if (p[a] == NULL) {
p[a] = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
if (p[a] == NULL) {
return NULL;
}
}
p = p[a];
if (p[b] == NULL) {
p[b] = (alloc_new_rows ? spv_new_row(sv->os, SPV_ROWLEN) : NULL);
if (p[b] == NULL) {
return NULL;
}
}
p = p[b];
return &p[c];
}
void
spv_set(sparse_vector_t sv, uint32_t idx, void *value)
{
void **ref = spv_new_cell(sv, idx, TRUE);
if (ref) {
*ref = value;
}
}
void
*spv_get(sparse_vector_t sv, uint32_t idx)
{
void **ref = spv_new_cell(sv, idx, FALSE);
if (ref) {
return *ref;
}
return NULL;
}
static unsigned short crctable[256] =
{
0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B,
0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6,
0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6,
0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B,
0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1,
0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C,
0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C,
0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781,
0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8,
0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255,
0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925,
0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698,
0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472,
0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF,
0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF,
0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02,
0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA,
0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067,
0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17,
0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA,
0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640,
0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD,
0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D,
0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30,
0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759,
0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4,
0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394,
0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29,
0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3,
0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E,
0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E,
0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3
};
unsigned short
t10crc16(const unsigned char *blk_adr, unsigned long blk_len, unsigned short crc)
{
if (blk_len > 0) {
while (blk_len--) {
crc = crctable[((crc>>8) ^ *blk_adr++) & 0xFFL] ^ (crc << 8);
}
}
return crc;
}
struct ocs_ramlog_s {
uint32_t initialized;
uint32_t textbuf_count;
uint32_t textbuf_base;
ocs_textbuf_t *textbufs;
uint32_t cur_textbuf_idx;
ocs_textbuf_t *cur_textbuf;
ocs_lock_t lock;
};
static uint32_t ocs_ramlog_next_idx(ocs_ramlog_t *ramlog, uint32_t idx);
ocs_ramlog_t *
ocs_ramlog_init(ocs_t *ocs, uint32_t buffer_len, uint32_t buffer_count)
{
uint32_t i;
uint32_t rc;
ocs_ramlog_t *ramlog;
ramlog = ocs_malloc(ocs, sizeof(*ramlog), OCS_M_ZERO | OCS_M_NOWAIT);
if (ramlog == NULL) {
ocs_log_err(ocs, "ocs_malloc ramlog failed\n");
return NULL;
}
ramlog->textbuf_count = buffer_count;
ramlog->textbufs = ocs_malloc(ocs, sizeof(*ramlog->textbufs)*buffer_count, OCS_M_ZERO | OCS_M_NOWAIT);
if (ramlog->textbufs == NULL) {
ocs_log_err(ocs, "ocs_malloc textbufs failed\n");
ocs_ramlog_free(ocs, ramlog);
return NULL;
}
for (i = 0; i < buffer_count; i ++) {
rc = ocs_textbuf_alloc(ocs, &ramlog->textbufs[i], buffer_len);
if (rc) {
ocs_log_err(ocs, "ocs_textbuf_alloc failed\n");
ocs_ramlog_free(ocs, ramlog);
return NULL;
}
}
ramlog->cur_textbuf_idx = 0;
ramlog->textbuf_base = 1;
ramlog->cur_textbuf = &ramlog->textbufs[0];
ramlog->initialized = TRUE;
ocs_lock_init(ocs, &ramlog->lock, "ramlog_lock[%d]", ocs_instance(ocs));
return ramlog;
}
void
ocs_ramlog_free(ocs_t *ocs, ocs_ramlog_t *ramlog)
{
uint32_t i;
if (ramlog != NULL) {
ocs_lock_free(&ramlog->lock);
if (ramlog->textbufs) {
for (i = 0; i < ramlog->textbuf_count; i ++) {
ocs_textbuf_free(ocs, &ramlog->textbufs[i]);
}
ocs_free(ocs, ramlog->textbufs, ramlog->textbuf_count*sizeof(*ramlog->textbufs));
ramlog->textbufs = NULL;
}
ocs_free(ocs, ramlog, sizeof(*ramlog));
}
}
void
ocs_ramlog_clear(ocs_t *ocs, ocs_ramlog_t *ramlog, int clear_start_of_day, int clear_recent)
{
uint32_t i;
if (clear_recent) {
for (i = ramlog->textbuf_base; i < ramlog->textbuf_count; i ++) {
ocs_textbuf_reset(&ramlog->textbufs[i]);
}
ramlog->cur_textbuf_idx = 1;
}
if (clear_start_of_day && ramlog->textbuf_base) {
ocs_textbuf_reset(&ramlog->textbufs[0]);
ramlog->textbuf_base = 0;
}
}
int32_t
ocs_ramlog_printf(void *os, const char *fmt, ...)
{
ocs_t *ocs = os;
va_list ap;
int32_t res;
if (ocs == NULL || ocs->ramlog == NULL) {
return -1;
}
va_start(ap, fmt);
res = ocs_ramlog_vprintf(ocs->ramlog, fmt, ap);
va_end(ap);
return res;
}
int32_t
ocs_ramlog_vprintf(ocs_ramlog_t *ramlog, const char *fmt, va_list ap)
{
if (ramlog == NULL || !ramlog->initialized) {
return -1;
}
ocs_lock(&ramlog->lock);
if (ocs_textbuf_remaining(ramlog->cur_textbuf) < 120) {
ramlog->cur_textbuf_idx = ocs_ramlog_next_idx(ramlog, ramlog->cur_textbuf_idx);
ramlog->cur_textbuf = &ramlog->textbufs[ramlog->cur_textbuf_idx];
ocs_textbuf_reset(ramlog->cur_textbuf);
}
ocs_textbuf_vprintf(ramlog->cur_textbuf, fmt, ap);
ocs_unlock(&ramlog->lock);
return 0;
}
static uint32_t
ocs_ramlog_next_idx(ocs_ramlog_t *ramlog, uint32_t idx)
{
idx = idx + 1;
if (idx >= ramlog->textbuf_count) {
idx = ramlog->textbuf_base;
}
return idx;
}
int32_t
ocs_ddump_ramlog(ocs_textbuf_t *textbuf, ocs_ramlog_t *ramlog)
{
uint32_t i;
ocs_textbuf_t *rltextbuf;
int idx;
if ((ramlog == NULL) || (ramlog->textbufs == NULL)) {
return -1;
}
ocs_ddump_section(textbuf, "driver-log", 0);
ocs_ddump_section(textbuf, "startofday", 0);
if (ramlog->textbuf_base) {
rltextbuf = &ramlog->textbufs[0];
ocs_textbuf_buffer(textbuf, ocs_textbuf_get_buffer(rltextbuf), ocs_textbuf_get_written(rltextbuf));
}
ocs_ddump_endsection(textbuf, "startofday", 0);
ocs_ddump_section(textbuf, "recent", 0);
idx = ocs_ramlog_next_idx(ramlog, ramlog->textbuf_count);
for (i = ramlog->textbuf_base; i < ramlog->textbuf_count; i ++) {
rltextbuf = &ramlog->textbufs[idx];
ocs_textbuf_buffer(textbuf, ocs_textbuf_get_buffer(rltextbuf), ocs_textbuf_get_written(rltextbuf));
idx = ocs_ramlog_next_idx(ramlog, idx);
}
ocs_ddump_endsection(textbuf, "recent", 0);
ocs_ddump_endsection(textbuf, "driver-log", 0);
return 0;
}
struct ocs_pool_s {
ocs_os_handle_t os;
ocs_array_t *a;
ocs_list_t freelist;
uint32_t use_lock:1;
ocs_lock_t lock;
};
typedef struct {
ocs_list_link_t link;
} pool_hdr_t;
ocs_pool_t *
ocs_pool_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count, uint32_t use_lock)
{
ocs_pool_t *pool;
uint32_t i;
pool = ocs_malloc(os, sizeof(*pool), OCS_M_ZERO | OCS_M_NOWAIT);
if (pool == NULL) {
return NULL;
}
pool->os = os;
pool->use_lock = use_lock;
pool->a = ocs_array_alloc(os, size + sizeof(pool_hdr_t), count);
if (pool->a == NULL) {
ocs_pool_free(pool);
return NULL;
}
ocs_list_init(&pool->freelist, pool_hdr_t, link);
for (i = 0; i < count; i++) {
ocs_list_add_tail(&pool->freelist, ocs_array_get(pool->a, i));
}
if (pool->use_lock) {
ocs_lock_init(os, &pool->lock, "ocs_pool:%p", pool);
}
return pool;
}
void
ocs_pool_reset(ocs_pool_t *pool)
{
uint32_t i;
uint32_t count = ocs_array_get_count(pool->a);
uint32_t size = ocs_array_get_size(pool->a);
if (pool->use_lock) {
ocs_lock(&pool->lock);
}
while (!ocs_list_empty(&pool->freelist)) {
ocs_list_remove_head(&pool->freelist);
}
ocs_list_init(&pool->freelist, pool_hdr_t, link);
for (i = 0; i < count; i++) {
ocs_memset(ocs_pool_get_instance(pool, i), 0, size - sizeof(pool_hdr_t));
ocs_list_add_tail(&pool->freelist, ocs_array_get(pool->a, i));
}
if (pool->use_lock) {
ocs_unlock(&pool->lock);
}
}
void
ocs_pool_free(ocs_pool_t *pool)
{
if (pool != NULL) {
if (pool->a != NULL) {
ocs_array_free(pool->a);
}
if (pool->use_lock) {
ocs_lock_free(&pool->lock);
}
ocs_free(pool->os, pool, sizeof(*pool));
}
}
void *
ocs_pool_get(ocs_pool_t *pool)
{
pool_hdr_t *h;
void *item = NULL;
if (pool->use_lock) {
ocs_lock(&pool->lock);
}
h = ocs_list_remove_head(&pool->freelist);
if (h != NULL) {
item = &h[1];
}
if (pool->use_lock) {
ocs_unlock(&pool->lock);
}
return item;
}
void
ocs_pool_put(ocs_pool_t *pool, void *item)
{
pool_hdr_t *h;
if (pool->use_lock) {
ocs_lock(&pool->lock);
}
h = &((pool_hdr_t*)item)[-1];
ocs_list_add_tail(&pool->freelist, h);
if (pool->use_lock) {
ocs_unlock(&pool->lock);
}
}
uint32_t
ocs_pool_get_count(ocs_pool_t *pool)
{
uint32_t count;
if (pool->use_lock) {
ocs_lock(&pool->lock);
}
count = ocs_array_get_count(pool->a);
if (pool->use_lock) {
ocs_unlock(&pool->lock);
}
return count;
}
void *
ocs_pool_get_instance(ocs_pool_t *pool, uint32_t idx)
{
pool_hdr_t *h = ocs_array_get(pool->a, idx);
if (h == NULL) {
return NULL;
}
return &h[1];
}
uint32_t
ocs_pool_get_freelist_count(ocs_pool_t *pool)
{
uint32_t count = 0;
void *item;
if (pool->use_lock) {
ocs_lock(&pool->lock);
}
ocs_list_foreach(&pool->freelist, item) {
count++;
}
if (pool->use_lock) {
ocs_unlock(&pool->lock);
}
return count;
}