1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * QLogic iSCSI Offload Driver |
4 | * Copyright (c) 2016 Cavium Inc. |
5 | */ |
6 | |
7 | #include "qedi.h" |
8 | #include "qedi_dbg.h" |
9 | |
10 | #include <linux/uaccess.h> |
11 | #include <linux/debugfs.h> |
12 | #include <linux/module.h> |
13 | |
14 | int qedi_do_not_recover; |
15 | static struct dentry *qedi_dbg_root; |
16 | |
17 | void |
18 | qedi_dbg_host_init(struct qedi_dbg_ctx *qedi, |
19 | const struct qedi_debugfs_ops *dops, |
20 | const struct file_operations *fops) |
21 | { |
22 | char host_dirname[32]; |
23 | |
24 | sprintf(buf: host_dirname, fmt: "host%u" , qedi->host_no); |
25 | qedi->bdf_dentry = debugfs_create_dir(name: host_dirname, parent: qedi_dbg_root); |
26 | |
27 | while (dops) { |
28 | if (!(dops->name)) |
29 | break; |
30 | |
31 | debugfs_create_file(name: dops->name, mode: 0600, parent: qedi->bdf_dentry, data: qedi, |
32 | fops); |
33 | dops++; |
34 | fops++; |
35 | } |
36 | } |
37 | |
38 | void |
39 | qedi_dbg_host_exit(struct qedi_dbg_ctx *qedi) |
40 | { |
41 | debugfs_remove_recursive(dentry: qedi->bdf_dentry); |
42 | qedi->bdf_dentry = NULL; |
43 | } |
44 | |
45 | void |
46 | qedi_dbg_init(char *drv_name) |
47 | { |
48 | qedi_dbg_root = debugfs_create_dir(name: drv_name, NULL); |
49 | } |
50 | |
51 | void |
52 | qedi_dbg_exit(void) |
53 | { |
54 | debugfs_remove_recursive(dentry: qedi_dbg_root); |
55 | qedi_dbg_root = NULL; |
56 | } |
57 | |
58 | static ssize_t |
59 | qedi_dbg_do_not_recover_enable(struct qedi_dbg_ctx *qedi_dbg) |
60 | { |
61 | if (!qedi_do_not_recover) |
62 | qedi_do_not_recover = 1; |
63 | |
64 | QEDI_INFO(qedi_dbg, QEDI_LOG_DEBUGFS, "do_not_recover=%d\n" , |
65 | qedi_do_not_recover); |
66 | return 0; |
67 | } |
68 | |
69 | static ssize_t |
70 | qedi_dbg_do_not_recover_disable(struct qedi_dbg_ctx *qedi_dbg) |
71 | { |
72 | if (qedi_do_not_recover) |
73 | qedi_do_not_recover = 0; |
74 | |
75 | QEDI_INFO(qedi_dbg, QEDI_LOG_DEBUGFS, "do_not_recover=%d\n" , |
76 | qedi_do_not_recover); |
77 | return 0; |
78 | } |
79 | |
80 | static struct qedi_list_of_funcs qedi_dbg_do_not_recover_ops[] = { |
81 | { "enable" , qedi_dbg_do_not_recover_enable }, |
82 | { "disable" , qedi_dbg_do_not_recover_disable }, |
83 | { NULL, NULL } |
84 | }; |
85 | |
86 | const struct qedi_debugfs_ops qedi_debugfs_ops[] = { |
87 | { "gbl_ctx" , NULL }, |
88 | { "do_not_recover" , qedi_dbg_do_not_recover_ops}, |
89 | { "io_trace" , NULL }, |
90 | { NULL, NULL } |
91 | }; |
92 | |
93 | static ssize_t |
94 | qedi_dbg_do_not_recover_cmd_write(struct file *filp, const char __user *buffer, |
95 | size_t count, loff_t *ppos) |
96 | { |
97 | size_t cnt = 0; |
98 | struct qedi_dbg_ctx *qedi_dbg = |
99 | (struct qedi_dbg_ctx *)filp->private_data; |
100 | struct qedi_list_of_funcs *lof = qedi_dbg_do_not_recover_ops; |
101 | |
102 | if (*ppos) |
103 | return 0; |
104 | |
105 | while (lof) { |
106 | if (!(lof->oper_str)) |
107 | break; |
108 | |
109 | if (!strncmp(lof->oper_str, buffer, strlen(lof->oper_str))) { |
110 | cnt = lof->oper_func(qedi_dbg); |
111 | break; |
112 | } |
113 | |
114 | lof++; |
115 | } |
116 | return (count - cnt); |
117 | } |
118 | |
119 | static ssize_t |
120 | qedi_dbg_do_not_recover_cmd_read(struct file *filp, char __user *buffer, |
121 | size_t count, loff_t *ppos) |
122 | { |
123 | size_t cnt = 0; |
124 | |
125 | if (*ppos) |
126 | return 0; |
127 | |
128 | cnt = sprintf(buf: buffer, fmt: "do_not_recover=%d\n" , qedi_do_not_recover); |
129 | cnt = min_t(int, count, cnt - *ppos); |
130 | *ppos += cnt; |
131 | return cnt; |
132 | } |
133 | |
134 | static int |
135 | qedi_gbl_ctx_show(struct seq_file *s, void *unused) |
136 | { |
137 | struct qedi_fastpath *fp = NULL; |
138 | struct qed_sb_info *sb_info = NULL; |
139 | struct status_block *sb = NULL; |
140 | struct global_queue *que = NULL; |
141 | int id; |
142 | u16 prod_idx; |
143 | struct qedi_ctx *qedi = s->private; |
144 | unsigned long flags; |
145 | |
146 | seq_puts(m: s, s: " DUMP CQ CONTEXT:\n" ); |
147 | |
148 | for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { |
149 | spin_lock_irqsave(&qedi->hba_lock, flags); |
150 | seq_printf(m: s, fmt: "=========FAST CQ PATH [%d] ==========\n" , id); |
151 | fp = &qedi->fp_array[id]; |
152 | sb_info = fp->sb_info; |
153 | sb = sb_info->sb_virt; |
154 | prod_idx = (sb->pi_array[QEDI_PROTO_CQ_PROD_IDX] & |
155 | STATUS_BLOCK_PROD_INDEX_MASK); |
156 | seq_printf(m: s, fmt: "SB PROD IDX: %d\n" , prod_idx); |
157 | que = qedi->global_queues[fp->sb_id]; |
158 | seq_printf(m: s, fmt: "DRV CONS IDX: %d\n" , que->cq_cons_idx); |
159 | seq_printf(m: s, fmt: "CQ complete host memory: %d\n" , fp->sb_id); |
160 | seq_puts(m: s, s: "=========== END ==================\n\n\n" ); |
161 | spin_unlock_irqrestore(lock: &qedi->hba_lock, flags); |
162 | } |
163 | return 0; |
164 | } |
165 | |
166 | static int |
167 | qedi_dbg_gbl_ctx_open(struct inode *inode, struct file *file) |
168 | { |
169 | struct qedi_dbg_ctx *qedi_dbg = inode->i_private; |
170 | struct qedi_ctx *qedi = container_of(qedi_dbg, struct qedi_ctx, |
171 | dbg_ctx); |
172 | |
173 | return single_open(file, qedi_gbl_ctx_show, qedi); |
174 | } |
175 | |
176 | static int |
177 | qedi_io_trace_show(struct seq_file *s, void *unused) |
178 | { |
179 | int id, idx = 0; |
180 | struct qedi_ctx *qedi = s->private; |
181 | struct qedi_io_log *io_log; |
182 | unsigned long flags; |
183 | |
184 | seq_puts(m: s, s: " DUMP IO LOGS:\n" ); |
185 | spin_lock_irqsave(&qedi->io_trace_lock, flags); |
186 | idx = qedi->io_trace_idx; |
187 | for (id = 0; id < QEDI_IO_TRACE_SIZE; id++) { |
188 | io_log = &qedi->io_trace_buf[idx]; |
189 | seq_printf(m: s, fmt: "iodir-%d:" , io_log->direction); |
190 | seq_printf(m: s, fmt: "tid-0x%x:" , io_log->task_id); |
191 | seq_printf(m: s, fmt: "cid-0x%x:" , io_log->cid); |
192 | seq_printf(m: s, fmt: "lun-%d:" , io_log->lun); |
193 | seq_printf(m: s, fmt: "op-0x%02x:" , io_log->op); |
194 | seq_printf(m: s, fmt: "0x%02x%02x%02x%02x:" , io_log->lba[0], |
195 | io_log->lba[1], io_log->lba[2], io_log->lba[3]); |
196 | seq_printf(m: s, fmt: "buflen-%d:" , io_log->bufflen); |
197 | seq_printf(m: s, fmt: "sgcnt-%d:" , io_log->sg_count); |
198 | seq_printf(m: s, fmt: "res-0x%08x:" , io_log->result); |
199 | seq_printf(m: s, fmt: "jif-%lu:" , io_log->jiffies); |
200 | seq_printf(m: s, fmt: "blk_req_cpu-%d:" , io_log->blk_req_cpu); |
201 | seq_printf(m: s, fmt: "req_cpu-%d:" , io_log->req_cpu); |
202 | seq_printf(m: s, fmt: "intr_cpu-%d:" , io_log->intr_cpu); |
203 | seq_printf(m: s, fmt: "blk_rsp_cpu-%d\n" , io_log->blk_rsp_cpu); |
204 | |
205 | idx++; |
206 | if (idx == QEDI_IO_TRACE_SIZE) |
207 | idx = 0; |
208 | } |
209 | spin_unlock_irqrestore(lock: &qedi->io_trace_lock, flags); |
210 | return 0; |
211 | } |
212 | |
213 | static int |
214 | qedi_dbg_io_trace_open(struct inode *inode, struct file *file) |
215 | { |
216 | struct qedi_dbg_ctx *qedi_dbg = inode->i_private; |
217 | struct qedi_ctx *qedi = container_of(qedi_dbg, struct qedi_ctx, |
218 | dbg_ctx); |
219 | |
220 | return single_open(file, qedi_io_trace_show, qedi); |
221 | } |
222 | |
223 | const struct file_operations qedi_dbg_fops[] = { |
224 | qedi_dbg_fileops_seq(qedi, gbl_ctx), |
225 | qedi_dbg_fileops(qedi, do_not_recover), |
226 | qedi_dbg_fileops_seq(qedi, io_trace), |
227 | { }, |
228 | }; |
229 | |