Hi [adding Steven Rostedt] On Thu, Jul 14, 2022 at 11:02:23PM -0700, Nilesh Javali wrote: > From: Arun Easi <aeasi@xxxxxxxxxxx> > > Adding a message based tracing mechanism where > a rotating number of messages are captured in > a trace structure. Disable/enable/resize > operations are allowed via debugfs interfaces. I really wonder why you need to this kind of infrastructure to your driver? As far I know the qla2xxx is already able to log into ftrace. Why can't we just use this infrastructure? Thanks, Daniel > > Signed-off-by: Arun Easi <aeasi@xxxxxxxxxxx> > Signed-off-by: Nilesh Javali <njavali@xxxxxxxxxxx> > --- > drivers/scsi/qla2xxx/qla_dbg.c | 12 +++ > drivers/scsi/qla2xxx/qla_dbg.h | 140 +++++++++++++++++++++++++++++++++ > drivers/scsi/qla2xxx/qla_def.h | 31 ++++++++ > drivers/scsi/qla2xxx/qla_dfs.c | 102 ++++++++++++++++++++++++ > drivers/scsi/qla2xxx/qla_os.c | 5 ++ > 5 files changed, 290 insertions(+) > > diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c > index 7cf1f78cbaee..c4ba8ac51d27 100644 > --- a/drivers/scsi/qla2xxx/qla_dbg.c > +++ b/drivers/scsi/qla2xxx/qla_dbg.c > @@ -2777,3 +2777,15 @@ ql_dbg_qp(uint32_t level, struct qla_qpair *qpair, int32_t id, > va_end(va); > > } > + > +#ifdef QLA_TRACING > +void qla_tracing_init(void) > +{ > + if (is_kdump_kernel()) > + return; > +} > + > +void qla_tracing_exit(void) > +{ > +} > +#endif /* QLA_TRACING */ > diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h > index feeb1666227f..e0d91a1f81c0 100644 > --- a/drivers/scsi/qla2xxx/qla_dbg.h > +++ b/drivers/scsi/qla2xxx/qla_dbg.h > @@ -5,6 +5,7 @@ > */ > > #include "qla_def.h" > +#include <linux/delay.h> > > /* > * Firmware Dump structure definition > @@ -321,6 +322,145 @@ struct qla2xxx_fw_dump { > > extern uint ql_errlev; > > +#ifdef QLA_TRACING > +#include <linux/crash_dump.h> > + > +extern void qla_tracing_init(void); > +extern void qla_tracing_exit(void); > + > +static inline int > +ql_mask_match_ext(uint level, int *log_tunable) > +{ > + if (*log_tunable == 1) > + *log_tunable = QL_DBG_DEFAULT1_MASK; > + > + return (level & *log_tunable) == level; > +} > + > +static inline int > +__qla_trace_get(struct qla_trace *trc) > +{ > + if (test_bit(QLA_TRACE_QUIESCE, &trc->flags)) > + return -EIO; > + atomic_inc(&trc->ref_count); > + return 0; > +} > + > +static inline int > +qla_trace_get(struct qla_trace *trc) > +{ > + unsigned long flags; > + int ret; > + > + spin_lock_irqsave(&trc->trc_lock, flags); > + ret = __qla_trace_get(trc); > + spin_unlock_irqrestore(&trc->trc_lock, flags); > + > + return ret; > +} > + > +static inline void > +qla_trace_put(struct qla_trace *trc) > +{ > + wmb(); > + atomic_dec(&trc->ref_count); > +} > + > +static inline char * > +qla_get_trace_next(struct qla_trace *trc) > +{ > + uint32_t t_ind; > + char *buf; > + unsigned long flags; > + > + spin_lock_irqsave(&trc->trc_lock, flags); > + if (!test_bit(QLA_TRACE_ENABLED, &trc->flags) || > + __qla_trace_get(trc)) { > + spin_unlock_irqrestore(&trc->trc_lock, flags); > + return NULL; > + } > + t_ind = trc->trace_ind = qla_trace_ind_norm(trc, trc->trace_ind + 1); > + spin_unlock_irqrestore(&trc->trc_lock, flags); > + > + if (!t_ind) > + set_bit(QLA_TRACE_WRAPPED, &trc->flags); > + > + buf = qla_trace_record(trc, t_ind); > + /* Put an end marker '>' for the next record. */ > + qla_trace_record(trc, qla_trace_ind_norm(trc, t_ind + 1))[0] = '>'; > + > + return buf; > +} > + > +static inline int > +qla_trace_quiesce(struct qla_trace *trc) > +{ > + unsigned long flags; > + u32 cnt = 0; > + int ret = 0; > + > + set_bit(QLA_TRACE_QUIESCE, &trc->flags); > + > + spin_lock_irqsave(&trc->trc_lock, flags); > + while (atomic_read(&trc->ref_count)) { > + spin_unlock_irqrestore(&trc->trc_lock, flags); > + > + msleep(1); > + > + spin_lock_irqsave(&trc->trc_lock, flags); > + cnt++; > + if (cnt > 10 * 1000) { > + pr_info("qla2xxx: Trace could not be quiesced now (count=%d).", > + atomic_read(&trc->ref_count)); > + /* Leave trace enabled */ > + clear_bit(QLA_TRACE_QUIESCE, &trc->flags); > + ret = -EIO; > + break; > + } > + } > + spin_unlock_irqrestore(&trc->trc_lock, flags); > + return ret; > +} > + > +static inline void > +qla_trace_init(struct qla_trace *trc, char *name, u32 num_entries) > +{ > + if (trc->recs) > + return; > + > + memset(trc, 0, sizeof(*trc)); > + > + trc->name = name; > + spin_lock_init(&trc->trc_lock); > + if (!num_entries) > + return; > + trc->num_entries = num_entries; > + trc->recs = vzalloc(trc->num_entries * > + sizeof(struct qla_trace_rec)); > + if (!trc->recs) > + return; > + > + set_bit(QLA_TRACE_ENABLED, &trc->flags); > +} > + > +static inline void > +qla_trace_uninit(struct qla_trace *trc) > +{ > + if (!trc->recs) > + return; > + > + vfree(trc->recs); > + trc->recs = NULL; > + clear_bit(QLA_TRACE_ENABLED, &trc->flags); > +} > + > +#else /* QLA_TRACING */ > +#define qla_trace_init(trc, name, num) > +#define qla_trace_uninit(trc) > +#define qla_tracing_init() > +#define qla_tracing_exit() > +#endif /* QLA_TRACING */ > + > void __attribute__((format (printf, 4, 5))) > ql_dbg(uint, scsi_qla_host_t *vha, uint, const char *fmt, ...); > void __attribute__((format (printf, 4, 5))) > diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h > index 22274b405d01..39322105e7be 100644 > --- a/drivers/scsi/qla2xxx/qla_def.h > +++ b/drivers/scsi/qla2xxx/qla_def.h > @@ -35,6 +35,37 @@ > > #include <uapi/scsi/fc/fc_els.h> > > +#define QLA_TRACING /* Captures driver messages to buffer */ > + > +#ifdef QLA_TRACING > +#define QLA_TRACE_LINE_SIZE 256 /* Biggest so far is ~215 */ > +#define qla_trace_ind_norm(_trc, _ind) ((_ind) >= (_trc)->num_entries ? \ > + 0 : (_ind)) > +#define qla_trace_record(_trc, __ind) ((_trc)->recs[__ind].buf) > +#define qla_trace_record_len (sizeof(struct qla_trace_rec)) > +#define qla_trace_start(_trc) qla_trace_record(_trc, 0) > +#define qla_trace_len(_trc) ((_trc)->num_entries) > +#define qla_trace_size(_trc) (qla_trace_record_len * \ > + (_trc)->num_entries) > +#define qla_trace_cur_ind(_trc) ((_trc)->trace_ind) > +struct qla_trace_rec { > + char buf[QLA_TRACE_LINE_SIZE]; > +}; > + > +struct qla_trace { > +#define QLA_TRACE_ENABLED 0 /* allow trace writes or not */ > +#define QLA_TRACE_WRAPPED 1 > +#define QLA_TRACE_QUIESCE 2 > + unsigned long flags; > + atomic_t ref_count; > + u32 num_entries; > + u32 trace_ind; > + spinlock_t trc_lock; > + char *name; > + struct qla_trace_rec *recs; > +}; > +#endif /* QLA_TRACING */ > + > #define QLA_DFS_DEFINE_DENTRY(_debugfs_file_name) \ > struct dentry *dfs_##_debugfs_file_name > #define QLA_DFS_ROOT_DEFINE_DENTRY(_debugfs_file_name) \ > diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c > index c3c8b9536ef6..98c6390ad1f1 100644 > --- a/drivers/scsi/qla2xxx/qla_dfs.c > +++ b/drivers/scsi/qla2xxx/qla_dfs.c > @@ -489,6 +489,108 @@ qla_dfs_naqp_show(struct seq_file *s, void *unused) > return 0; > } > > +#ifdef QLA_TRACING > +static char *trace_help = "\ > +# Format:\n\ > +# <msec> <cpu#> <message>\n\ > +#\n\ > +# Trace control by writing:\n\ > +# 'enable' - to enable this trace\n\ > +# 'disable' - to disable this trace\n\ > +# 'resize=<nlines>' - to resize this trace to <nlines>\n\ > +#\n"; > + > +static int > +qla_dfs_trace_show(struct seq_file *s, void *unused) > +{ > + struct qla_trace *trc = s->private; > + char *buf; > + u32 t_ind = 0, i; > + > + seq_puts(s, trace_help); > + > + if (qla_trace_get(trc)) > + return 0; > + > + seq_printf(s, "# Trace max lines = %d, writes = %s\n#\n", > + trc->num_entries, test_bit(QLA_TRACE_ENABLED, > + &trc->flags) ? "enabled" : "disabled"); > + > + if (test_bit(QLA_TRACE_WRAPPED, &trc->flags)) > + t_ind = qla_trace_cur_ind(trc) + 1; > + > + for (i = 0; i < qla_trace_len(trc); i++, t_ind++) { > + t_ind = qla_trace_ind_norm(trc, t_ind); > + buf = qla_trace_record(trc, t_ind); > + if (!buf[0]) > + continue; > + seq_puts(s, buf); > + } > + > + mb(); > + qla_trace_put(trc); > + return 0; > +} > + > +#define string_is(_buf, _str_val) \ > + (strncmp(_str_val, _buf, strlen(_str_val)) == 0) > + > +static ssize_t > +qla_dfs_trace_write(struct file *file, const char __user *buffer, > + size_t count, loff_t *pos) > +{ > + struct seq_file *s = file->private_data; > + struct qla_trace *trc = s->private; > + char buf[32]; > + ssize_t ret = count; > + > + memset(buf, 0, sizeof(buf)); > + if (copy_from_user(buf, buffer, min(sizeof(buf), count))) > + return -EFAULT; > + > + if (string_is(buf, "enable")) { > + if (!trc->recs) { > + pr_warn("qla2xxx: '%s' is empty, resize before enabling.\n", > + trc->name); > + return -EINVAL; > + } > + pr_info("qla2xxx: Enabling trace '%s'\n", trc->name); > + set_bit(QLA_TRACE_ENABLED, &trc->flags); > + } else if (string_is(buf, "disable")) { > + pr_info("qla2xxx: Disabling trace '%s'\n", trc->name); > + clear_bit(QLA_TRACE_ENABLED, &trc->flags); > + } else if (string_is(buf, "resize")) { > + u32 new_len; > + > + if (sscanf(buf, "resize=%d", &new_len) != 1) > + return -EINVAL; > + if (new_len == trc->num_entries) { > + pr_info("qla2xxx: New trace size is same as old.\n"); > + return count; > + } > + pr_info("qla2xxx: Changing trace '%s' size to %d\n", > + trc->name, new_len); > + if (qla_trace_quiesce(trc)) { > + ret = -EBUSY; > + goto done; > + } > + qla_trace_uninit(trc); > + /* > + * Go through init once again to start creating traces > + * based on the respective tunable. > + */ > + qla_trace_init(trc, trc->name, new_len); > + if (!trc->recs) { > + pr_warn("qla2xxx: Trace allocation failed for '%s'\n", > + trc->name); > + ret = -ENOMEM; > + } > + } > +done: > + return ret; > +} > +#endif /* QLA_TRACING */ > + > /* > * Helper macros for setting up debugfs entries. > * _name: The name of the debugfs entry > diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c > index 0bd0fd1042df..0d2397069cac 100644 > --- a/drivers/scsi/qla2xxx/qla_os.c > +++ b/drivers/scsi/qla2xxx/qla_os.c > @@ -8191,6 +8191,8 @@ qla2x00_module_init(void) > BUILD_BUG_ON(sizeof(sw_info_t) != 32); > BUILD_BUG_ON(sizeof(target_id_t) != 2); > > + qla_tracing_init(); > + > /* Allocate cache for SRBs. */ > srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0, > SLAB_HWCACHE_ALIGN, NULL); > @@ -8269,6 +8271,7 @@ qla2x00_module_init(void) > > destroy_cache: > kmem_cache_destroy(srb_cachep); > + qla_tracing_exit(); > return ret; > } > > @@ -8287,6 +8290,8 @@ qla2x00_module_exit(void) > fc_release_transport(qla2xxx_transport_template); > qlt_exit(); > kmem_cache_destroy(srb_cachep); > + > + qla_tracing_exit(); > } > > module_init(qla2x00_module_init); > -- > 2.19.0.rc0 >