mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
37126399da
The bfa driver is full of state machines and a generic abstraction layer for them. This relies on casting function pointers, but that is no longer allowed when CONFIG_CFI_CLANG is enabled and causes a huge number of warnings like: drivers/scsi/bfa/bfad.c:169:3: error: cast from 'void (*)(struct bfad_s *, enum bfad_sm_event)' to 'bfa_sm_t' (aka 'void (*)(void *, int)') converts to incompatible function type [-Werror,-Wcast-function-type-strict] bfa_sm_set_state(bfad, bfad_sm_created); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Rework the mechanism to no longer require the function pointer casts, by having separate types for each individual state machine. This in turn requires moving the enum definitions for each state machine into the header files in order to define the typedef. Reviewed-by: Kees Cook <keescook@chromium.org> Signed-off-by: Arnd Bergmann <arnd@arndb.de> Link: https://lore.kernel.org/r/20240222124433.2046570-2-arnd@kernel.org Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
316 lines
6.9 KiB
C
316 lines
6.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
|
|
* Copyright (c) 2014- QLogic Corporation.
|
|
* All rights reserved
|
|
* www.qlogic.com
|
|
*
|
|
* Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
|
|
*/
|
|
|
|
/*
|
|
* bfa_cs.h BFA common services
|
|
*/
|
|
|
|
#ifndef __BFA_CS_H__
|
|
#define __BFA_CS_H__
|
|
|
|
#include "bfad_drv.h"
|
|
|
|
/*
|
|
* BFA TRC
|
|
*/
|
|
|
|
#ifndef BFA_TRC_MAX
|
|
#define BFA_TRC_MAX (4 * 1024)
|
|
#endif
|
|
|
|
#define BFA_TRC_TS(_trcm) \
|
|
({ \
|
|
struct timespec64 ts; \
|
|
\
|
|
ktime_get_ts64(&ts); \
|
|
(ts.tv_sec*1000000+ts.tv_nsec / 1000); \
|
|
})
|
|
|
|
#ifndef BFA_TRC_TS
|
|
#define BFA_TRC_TS(_trcm) ((_trcm)->ticks++)
|
|
#endif
|
|
|
|
struct bfa_trc_s {
|
|
#ifdef __BIG_ENDIAN
|
|
u16 fileno;
|
|
u16 line;
|
|
#else
|
|
u16 line;
|
|
u16 fileno;
|
|
#endif
|
|
u32 timestamp;
|
|
union {
|
|
struct {
|
|
u32 rsvd;
|
|
u32 u32;
|
|
} u32;
|
|
u64 u64;
|
|
} data;
|
|
};
|
|
|
|
struct bfa_trc_mod_s {
|
|
u32 head;
|
|
u32 tail;
|
|
u32 ntrc;
|
|
u32 stopped;
|
|
u32 ticks;
|
|
u32 rsvd[3];
|
|
struct bfa_trc_s trc[BFA_TRC_MAX];
|
|
};
|
|
|
|
enum {
|
|
BFA_TRC_HAL = 1, /* BFA modules */
|
|
BFA_TRC_FCS = 2, /* BFA FCS modules */
|
|
BFA_TRC_LDRV = 3, /* Linux driver modules */
|
|
BFA_TRC_CNA = 4, /* Common modules */
|
|
};
|
|
#define BFA_TRC_MOD_SH 10
|
|
#define BFA_TRC_MOD(__mod) ((BFA_TRC_ ## __mod) << BFA_TRC_MOD_SH)
|
|
|
|
/*
|
|
* Define a new tracing file (module). Module should match one defined above.
|
|
*/
|
|
#define BFA_TRC_FILE(__mod, __submod) \
|
|
static int __trc_fileno = ((BFA_TRC_ ## __mod ## _ ## __submod) | \
|
|
BFA_TRC_MOD(__mod))
|
|
|
|
|
|
#define bfa_trc32(_trcp, _data) \
|
|
__bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data)
|
|
#define bfa_trc(_trcp, _data) \
|
|
__bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u64)_data)
|
|
|
|
static inline void
|
|
bfa_trc_init(struct bfa_trc_mod_s *trcm)
|
|
{
|
|
trcm->head = trcm->tail = trcm->stopped = 0;
|
|
trcm->ntrc = BFA_TRC_MAX;
|
|
}
|
|
|
|
static inline void
|
|
bfa_trc_stop(struct bfa_trc_mod_s *trcm)
|
|
{
|
|
trcm->stopped = 1;
|
|
}
|
|
|
|
void
|
|
__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data);
|
|
|
|
void
|
|
__bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data);
|
|
|
|
#define bfa_sm_fault(__mod, __event) do { \
|
|
bfa_trc(__mod, (((u32)0xDEAD << 16) | __event)); \
|
|
printk(KERN_ERR "Assertion failure: %s:%d: %d", \
|
|
__FILE__, __LINE__, (__event)); \
|
|
} while (0)
|
|
|
|
/* BFA queue definitions */
|
|
#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next))
|
|
#define bfa_q_next(_qe) (((struct list_head *) (_qe))->next)
|
|
#define bfa_q_prev(_qe) (((struct list_head *) (_qe))->prev)
|
|
|
|
/*
|
|
* bfa_q_qe_init - to initialize a queue element
|
|
*/
|
|
#define bfa_q_qe_init(_qe) { \
|
|
bfa_q_next(_qe) = (struct list_head *) NULL; \
|
|
bfa_q_prev(_qe) = (struct list_head *) NULL; \
|
|
}
|
|
|
|
/*
|
|
* bfa_q_deq - dequeue an element from head of the queue
|
|
*/
|
|
#define bfa_q_deq(_q, _qe) do { \
|
|
if (!list_empty(_q)) { \
|
|
(*((struct list_head **) (_qe))) = bfa_q_next(_q); \
|
|
bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) = \
|
|
(struct list_head *) (_q); \
|
|
bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe));\
|
|
} else { \
|
|
*((struct list_head **) (_qe)) = (struct list_head *) NULL;\
|
|
} \
|
|
} while (0)
|
|
|
|
/*
|
|
* bfa_q_deq_tail - dequeue an element from tail of the queue
|
|
*/
|
|
#define bfa_q_deq_tail(_q, _qe) { \
|
|
if (!list_empty(_q)) { \
|
|
*((struct list_head **) (_qe)) = bfa_q_prev(_q); \
|
|
bfa_q_next(bfa_q_prev(*((struct list_head **) _qe))) = \
|
|
(struct list_head *) (_q); \
|
|
bfa_q_prev(_q) = bfa_q_prev(*(struct list_head **) _qe);\
|
|
} else { \
|
|
*((struct list_head **) (_qe)) = (struct list_head *) NULL;\
|
|
} \
|
|
}
|
|
|
|
static inline int
|
|
bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe)
|
|
{
|
|
struct list_head *tqe;
|
|
|
|
tqe = bfa_q_next(q);
|
|
while (tqe != q) {
|
|
if (tqe == qe)
|
|
return 1;
|
|
tqe = bfa_q_next(tqe);
|
|
if (tqe == NULL)
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define bfa_q_is_on_q(_q, _qe) \
|
|
bfa_q_is_on_q_func(_q, (struct list_head *)(_qe))
|
|
|
|
/*
|
|
* @ BFA state machine interfaces
|
|
*/
|
|
|
|
typedef void (*bfa_sm_t)(void *sm, int event);
|
|
|
|
/*
|
|
* oc - object class eg. bfa_ioc
|
|
* st - state, eg. reset
|
|
* otype - object type, eg. struct bfa_ioc_s
|
|
* etype - object type, eg. enum ioc_event
|
|
*/
|
|
#define bfa_sm_state_decl(oc, st, otype, etype) \
|
|
static void oc ## _sm_ ## st(otype * fsm, etype event)
|
|
|
|
#define bfa_sm_set_state(_sm, _state) ((_sm)->sm = (_state))
|
|
#define bfa_sm_send_event(_sm, _event) ((_sm)->sm((_sm), (_event)))
|
|
#define bfa_sm_get_state(_sm) ((_sm)->sm)
|
|
#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (_state))
|
|
|
|
/*
|
|
* For converting from state machine function to state encoding.
|
|
*/
|
|
struct bfa_sm_table_s {
|
|
bfa_sm_t sm; /* state machine function */
|
|
int state; /* state machine encoding */
|
|
char *name; /* state name for display */
|
|
};
|
|
#define BFA_SM(_sm) (_sm)
|
|
|
|
/*
|
|
* State machine with entry actions.
|
|
*/
|
|
typedef void (*bfa_fsm_t)(void *fsm, int event);
|
|
|
|
/*
|
|
* oc - object class eg. bfa_ioc
|
|
* st - state, eg. reset
|
|
* otype - object type, eg. struct bfa_ioc_s
|
|
* etype - object type, eg. enum ioc_event
|
|
*/
|
|
#define bfa_fsm_state_decl(oc, st, otype, etype) \
|
|
static void oc ## _sm_ ## st(otype * fsm, etype event); \
|
|
static void oc ## _sm_ ## st ## _entry(otype * fsm)
|
|
|
|
#define bfa_fsm_set_state(_fsm, _state) do { \
|
|
(_fsm)->fsm = (_state); \
|
|
_state ## _entry(_fsm); \
|
|
} while (0)
|
|
|
|
#define bfa_fsm_send_event(_fsm, _event) ((_fsm)->fsm((_fsm), (_event)))
|
|
#define bfa_fsm_get_state(_fsm) ((_fsm)->fsm)
|
|
#define bfa_fsm_cmp_state(_fsm, _state) ((_fsm)->fsm == (_state))
|
|
|
|
/*
|
|
* @ Generic wait counter.
|
|
*/
|
|
|
|
typedef void (*bfa_wc_resume_t) (void *cbarg);
|
|
|
|
struct bfa_wc_s {
|
|
bfa_wc_resume_t wc_resume;
|
|
void *wc_cbarg;
|
|
int wc_count;
|
|
};
|
|
|
|
static inline void
|
|
bfa_wc_up(struct bfa_wc_s *wc)
|
|
{
|
|
wc->wc_count++;
|
|
}
|
|
|
|
static inline void
|
|
bfa_wc_down(struct bfa_wc_s *wc)
|
|
{
|
|
wc->wc_count--;
|
|
if (wc->wc_count == 0)
|
|
wc->wc_resume(wc->wc_cbarg);
|
|
}
|
|
|
|
/*
|
|
* Initialize a waiting counter.
|
|
*/
|
|
static inline void
|
|
bfa_wc_init(struct bfa_wc_s *wc, bfa_wc_resume_t wc_resume, void *wc_cbarg)
|
|
{
|
|
wc->wc_resume = wc_resume;
|
|
wc->wc_cbarg = wc_cbarg;
|
|
wc->wc_count = 0;
|
|
bfa_wc_up(wc);
|
|
}
|
|
|
|
/*
|
|
* Wait for counter to reach zero
|
|
*/
|
|
static inline void
|
|
bfa_wc_wait(struct bfa_wc_s *wc)
|
|
{
|
|
bfa_wc_down(wc);
|
|
}
|
|
|
|
static inline void
|
|
wwn2str(char *wwn_str, u64 wwn)
|
|
{
|
|
union {
|
|
u64 wwn;
|
|
u8 byte[8];
|
|
} w;
|
|
|
|
w.wwn = wwn;
|
|
sprintf(wwn_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", w.byte[0],
|
|
w.byte[1], w.byte[2], w.byte[3], w.byte[4], w.byte[5],
|
|
w.byte[6], w.byte[7]);
|
|
}
|
|
|
|
static inline void
|
|
fcid2str(char *fcid_str, u32 fcid)
|
|
{
|
|
union {
|
|
u32 fcid;
|
|
u8 byte[4];
|
|
} f;
|
|
|
|
f.fcid = fcid;
|
|
sprintf(fcid_str, "%02x:%02x:%02x", f.byte[1], f.byte[2], f.byte[3]);
|
|
}
|
|
|
|
#define bfa_swap_3b(_x) \
|
|
((((_x) & 0xff) << 16) | \
|
|
((_x) & 0x00ff00) | \
|
|
(((_x) & 0xff0000) >> 16))
|
|
|
|
#ifndef __BIG_ENDIAN
|
|
#define bfa_hton3b(_x) bfa_swap_3b(_x)
|
|
#else
|
|
#define bfa_hton3b(_x) (_x)
|
|
#endif
|
|
|
|
#define bfa_ntoh3b(_x) bfa_hton3b(_x)
|
|
|
|
#endif /* __BFA_CS_H__ */
|