linux/drivers/scsi/bfa/bfa_cs.h
Arnd Bergmann 37126399da scsi: bfa: Fix function pointer type mismatch for state machines
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>
2024-02-26 21:16:48 -05:00

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__ */