1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | // Copyright 2012 Cisco Systems, Inc. All rights reserved. |
3 | |
4 | #include <linux/module.h> |
5 | #include <linux/errno.h> |
6 | #include <linux/debugfs.h> |
7 | #include <linux/vmalloc.h> |
8 | #include "fnic.h" |
9 | |
10 | static struct dentry *fnic_trace_debugfs_root; |
11 | static struct dentry *fnic_trace_debugfs_file; |
12 | static struct dentry *fnic_trace_enable; |
13 | static struct dentry *fnic_stats_debugfs_root; |
14 | |
15 | static struct dentry *fnic_fc_trace_debugfs_file; |
16 | static struct dentry *fnic_fc_rdata_trace_debugfs_file; |
17 | static struct dentry *fnic_fc_trace_enable; |
18 | static struct dentry *fnic_fc_trace_clear; |
19 | |
20 | struct fc_trace_flag_type { |
21 | u8 fc_row_file; |
22 | u8 fc_normal_file; |
23 | u8 fnic_trace; |
24 | u8 fc_trace; |
25 | u8 fc_clear; |
26 | }; |
27 | |
28 | static struct fc_trace_flag_type *fc_trc_flag; |
29 | |
30 | /* |
31 | * fnic_debugfs_init - Initialize debugfs for fnic debug logging |
32 | * |
33 | * Description: |
34 | * When Debugfs is configured this routine sets up the fnic debugfs |
35 | * file system. If not already created, this routine will create the |
36 | * fnic directory and statistics directory for trace buffer and |
37 | * stats logging. |
38 | */ |
39 | int fnic_debugfs_init(void) |
40 | { |
41 | fnic_trace_debugfs_root = debugfs_create_dir(name: "fnic" , NULL); |
42 | |
43 | fnic_stats_debugfs_root = debugfs_create_dir(name: "statistics" , |
44 | parent: fnic_trace_debugfs_root); |
45 | |
46 | /* Allocate memory to structure */ |
47 | fc_trc_flag = vmalloc(size: sizeof(struct fc_trace_flag_type)); |
48 | |
49 | if (fc_trc_flag) { |
50 | fc_trc_flag->fc_row_file = 0; |
51 | fc_trc_flag->fc_normal_file = 1; |
52 | fc_trc_flag->fnic_trace = 2; |
53 | fc_trc_flag->fc_trace = 3; |
54 | fc_trc_flag->fc_clear = 4; |
55 | } |
56 | |
57 | return 0; |
58 | } |
59 | |
60 | /* |
61 | * fnic_debugfs_terminate - Tear down debugfs infrastructure |
62 | * |
63 | * Description: |
64 | * When Debugfs is configured this routine removes debugfs file system |
65 | * elements that are specific to fnic. |
66 | */ |
67 | void fnic_debugfs_terminate(void) |
68 | { |
69 | debugfs_remove(dentry: fnic_stats_debugfs_root); |
70 | fnic_stats_debugfs_root = NULL; |
71 | |
72 | debugfs_remove(dentry: fnic_trace_debugfs_root); |
73 | fnic_trace_debugfs_root = NULL; |
74 | |
75 | vfree(addr: fc_trc_flag); |
76 | } |
77 | |
78 | /* |
79 | * fnic_trace_ctrl_read - |
80 | * Read trace_enable ,fc_trace_enable |
81 | * or fc_trace_clear debugfs file |
82 | * @filp: The file pointer to read from. |
83 | * @ubuf: The buffer to copy the data to. |
84 | * @cnt: The number of bytes to read. |
85 | * @ppos: The position in the file to start reading from. |
86 | * |
87 | * Description: |
88 | * This routine reads value of variable fnic_tracing_enabled or |
89 | * fnic_fc_tracing_enabled or fnic_fc_trace_cleared |
90 | * and stores into local @buf. |
91 | * It will start reading file at @ppos and |
92 | * copy up to @cnt of data to @ubuf from @buf. |
93 | * |
94 | * Returns: |
95 | * This function returns the amount of data that was read. |
96 | */ |
97 | static ssize_t fnic_trace_ctrl_read(struct file *filp, |
98 | char __user *ubuf, |
99 | size_t cnt, loff_t *ppos) |
100 | { |
101 | char buf[64]; |
102 | int len; |
103 | u8 *trace_type; |
104 | len = 0; |
105 | trace_type = (u8 *)filp->private_data; |
106 | if (*trace_type == fc_trc_flag->fnic_trace) |
107 | len = sprintf(buf, fmt: "%d\n" , fnic_tracing_enabled); |
108 | else if (*trace_type == fc_trc_flag->fc_trace) |
109 | len = sprintf(buf, fmt: "%d\n" , fnic_fc_tracing_enabled); |
110 | else if (*trace_type == fc_trc_flag->fc_clear) |
111 | len = sprintf(buf, fmt: "%d\n" , fnic_fc_trace_cleared); |
112 | else |
113 | pr_err("fnic: Cannot read to any debugfs file\n" ); |
114 | |
115 | return simple_read_from_buffer(to: ubuf, count: cnt, ppos, from: buf, available: len); |
116 | } |
117 | |
118 | /* |
119 | * fnic_trace_ctrl_write - |
120 | * Write to trace_enable, fc_trace_enable or |
121 | * fc_trace_clear debugfs file |
122 | * @filp: The file pointer to write from. |
123 | * @ubuf: The buffer to copy the data from. |
124 | * @cnt: The number of bytes to write. |
125 | * @ppos: The position in the file to start writing to. |
126 | * |
127 | * Description: |
128 | * This routine writes data from user buffer @ubuf to buffer @buf and |
129 | * sets fc_trace_enable ,tracing_enable or fnic_fc_trace_cleared |
130 | * value as per user input. |
131 | * |
132 | * Returns: |
133 | * This function returns the amount of data that was written. |
134 | */ |
135 | static ssize_t fnic_trace_ctrl_write(struct file *filp, |
136 | const char __user *ubuf, |
137 | size_t cnt, loff_t *ppos) |
138 | { |
139 | char buf[64]; |
140 | unsigned long val; |
141 | int ret; |
142 | u8 *trace_type; |
143 | trace_type = (u8 *)filp->private_data; |
144 | |
145 | if (cnt >= sizeof(buf)) |
146 | return -EINVAL; |
147 | |
148 | if (copy_from_user(to: &buf, from: ubuf, n: cnt)) |
149 | return -EFAULT; |
150 | |
151 | buf[cnt] = 0; |
152 | |
153 | ret = kstrtoul(s: buf, base: 10, res: &val); |
154 | if (ret < 0) |
155 | return ret; |
156 | |
157 | if (*trace_type == fc_trc_flag->fnic_trace) |
158 | fnic_tracing_enabled = val; |
159 | else if (*trace_type == fc_trc_flag->fc_trace) |
160 | fnic_fc_tracing_enabled = val; |
161 | else if (*trace_type == fc_trc_flag->fc_clear) |
162 | fnic_fc_trace_cleared = val; |
163 | else |
164 | pr_err("fnic: cannot write to any debugfs file\n" ); |
165 | |
166 | (*ppos)++; |
167 | |
168 | return cnt; |
169 | } |
170 | |
171 | static const struct file_operations fnic_trace_ctrl_fops = { |
172 | .owner = THIS_MODULE, |
173 | .open = simple_open, |
174 | .read = fnic_trace_ctrl_read, |
175 | .write = fnic_trace_ctrl_write, |
176 | }; |
177 | |
178 | /* |
179 | * fnic_trace_debugfs_open - Open the fnic trace log |
180 | * @inode: The inode pointer |
181 | * @file: The file pointer to attach the log output |
182 | * |
183 | * Description: |
184 | * This routine is the entry point for the debugfs open file operation. |
185 | * It allocates the necessary buffer for the log, fills the buffer from |
186 | * the in-memory log and then returns a pointer to that log in |
187 | * the private_data field in @file. |
188 | * |
189 | * Returns: |
190 | * This function returns zero if successful. On error it will return |
191 | * a negative error value. |
192 | */ |
193 | static int fnic_trace_debugfs_open(struct inode *inode, |
194 | struct file *file) |
195 | { |
196 | fnic_dbgfs_t *fnic_dbg_prt; |
197 | u8 *rdata_ptr; |
198 | rdata_ptr = (u8 *)inode->i_private; |
199 | fnic_dbg_prt = kzalloc(size: sizeof(fnic_dbgfs_t), GFP_KERNEL); |
200 | if (!fnic_dbg_prt) |
201 | return -ENOMEM; |
202 | |
203 | if (*rdata_ptr == fc_trc_flag->fnic_trace) { |
204 | fnic_dbg_prt->buffer = vzalloc(array3_size(3, trace_max_pages, |
205 | PAGE_SIZE)); |
206 | if (!fnic_dbg_prt->buffer) { |
207 | kfree(objp: fnic_dbg_prt); |
208 | return -ENOMEM; |
209 | } |
210 | fnic_dbg_prt->buffer_len = fnic_get_trace_data(fnic_dbg_prt); |
211 | } else { |
212 | fnic_dbg_prt->buffer = |
213 | vzalloc(array3_size(3, fnic_fc_trace_max_pages, |
214 | PAGE_SIZE)); |
215 | if (!fnic_dbg_prt->buffer) { |
216 | kfree(objp: fnic_dbg_prt); |
217 | return -ENOMEM; |
218 | } |
219 | fnic_dbg_prt->buffer_len = |
220 | fnic_fc_trace_get_data(fnic_dbgfs_prt: fnic_dbg_prt, rdata_flag: *rdata_ptr); |
221 | } |
222 | file->private_data = fnic_dbg_prt; |
223 | |
224 | return 0; |
225 | } |
226 | |
227 | /* |
228 | * fnic_trace_debugfs_lseek - Seek through a debugfs file |
229 | * @file: The file pointer to seek through. |
230 | * @offset: The offset to seek to or the amount to seek by. |
231 | * @howto: Indicates how to seek. |
232 | * |
233 | * Description: |
234 | * This routine is the entry point for the debugfs lseek file operation. |
235 | * The @howto parameter indicates whether @offset is the offset to directly |
236 | * seek to, or if it is a value to seek forward or reverse by. This function |
237 | * figures out what the new offset of the debugfs file will be and assigns |
238 | * that value to the f_pos field of @file. |
239 | * |
240 | * Returns: |
241 | * This function returns the new offset if successful and returns a negative |
242 | * error if unable to process the seek. |
243 | */ |
244 | static loff_t fnic_trace_debugfs_lseek(struct file *file, |
245 | loff_t offset, |
246 | int howto) |
247 | { |
248 | fnic_dbgfs_t *fnic_dbg_prt = file->private_data; |
249 | return fixed_size_llseek(file, offset, whence: howto, |
250 | size: fnic_dbg_prt->buffer_len); |
251 | } |
252 | |
253 | /* |
254 | * fnic_trace_debugfs_read - Read a debugfs file |
255 | * @file: The file pointer to read from. |
256 | * @ubuf: The buffer to copy the data to. |
257 | * @nbytes: The number of bytes to read. |
258 | * @pos: The position in the file to start reading from. |
259 | * |
260 | * Description: |
261 | * This routine reads data from the buffer indicated in the private_data |
262 | * field of @file. It will start reading at @pos and copy up to @nbytes of |
263 | * data to @ubuf. |
264 | * |
265 | * Returns: |
266 | * This function returns the amount of data that was read (this could be |
267 | * less than @nbytes if the end of the file was reached). |
268 | */ |
269 | static ssize_t fnic_trace_debugfs_read(struct file *file, |
270 | char __user *ubuf, |
271 | size_t nbytes, |
272 | loff_t *pos) |
273 | { |
274 | fnic_dbgfs_t *fnic_dbg_prt = file->private_data; |
275 | int rc = 0; |
276 | rc = simple_read_from_buffer(to: ubuf, count: nbytes, ppos: pos, |
277 | from: fnic_dbg_prt->buffer, |
278 | available: fnic_dbg_prt->buffer_len); |
279 | return rc; |
280 | } |
281 | |
282 | /* |
283 | * fnic_trace_debugfs_release - Release the buffer used to store |
284 | * debugfs file data |
285 | * @inode: The inode pointer |
286 | * @file: The file pointer that contains the buffer to release |
287 | * |
288 | * Description: |
289 | * This routine frees the buffer that was allocated when the debugfs |
290 | * file was opened. |
291 | * |
292 | * Returns: |
293 | * This function returns zero. |
294 | */ |
295 | static int fnic_trace_debugfs_release(struct inode *inode, |
296 | struct file *file) |
297 | { |
298 | fnic_dbgfs_t *fnic_dbg_prt = file->private_data; |
299 | |
300 | vfree(addr: fnic_dbg_prt->buffer); |
301 | kfree(objp: fnic_dbg_prt); |
302 | return 0; |
303 | } |
304 | |
305 | static const struct file_operations fnic_trace_debugfs_fops = { |
306 | .owner = THIS_MODULE, |
307 | .open = fnic_trace_debugfs_open, |
308 | .llseek = fnic_trace_debugfs_lseek, |
309 | .read = fnic_trace_debugfs_read, |
310 | .release = fnic_trace_debugfs_release, |
311 | }; |
312 | |
313 | /* |
314 | * fnic_trace_debugfs_init - Initialize debugfs for fnic trace logging |
315 | * |
316 | * Description: |
317 | * When Debugfs is configured this routine sets up the fnic debugfs |
318 | * file system. If not already created, this routine will create the |
319 | * create file trace to log fnic trace buffer output into debugfs and |
320 | * it will also create file trace_enable to control enable/disable of |
321 | * trace logging into trace buffer. |
322 | */ |
323 | void fnic_trace_debugfs_init(void) |
324 | { |
325 | fnic_trace_enable = debugfs_create_file(name: "tracing_enable" , |
326 | S_IFREG|S_IRUGO|S_IWUSR, |
327 | parent: fnic_trace_debugfs_root, |
328 | data: &(fc_trc_flag->fnic_trace), |
329 | fops: &fnic_trace_ctrl_fops); |
330 | |
331 | fnic_trace_debugfs_file = debugfs_create_file(name: "trace" , |
332 | S_IFREG|S_IRUGO|S_IWUSR, |
333 | parent: fnic_trace_debugfs_root, |
334 | data: &(fc_trc_flag->fnic_trace), |
335 | fops: &fnic_trace_debugfs_fops); |
336 | } |
337 | |
338 | /* |
339 | * fnic_trace_debugfs_terminate - Tear down debugfs infrastructure |
340 | * |
341 | * Description: |
342 | * When Debugfs is configured this routine removes debugfs file system |
343 | * elements that are specific to fnic trace logging. |
344 | */ |
345 | void fnic_trace_debugfs_terminate(void) |
346 | { |
347 | debugfs_remove(dentry: fnic_trace_debugfs_file); |
348 | fnic_trace_debugfs_file = NULL; |
349 | |
350 | debugfs_remove(dentry: fnic_trace_enable); |
351 | fnic_trace_enable = NULL; |
352 | } |
353 | |
354 | /* |
355 | * fnic_fc_trace_debugfs_init - |
356 | * Initialize debugfs for fnic control frame trace logging |
357 | * |
358 | * Description: |
359 | * When Debugfs is configured this routine sets up the fnic_fc debugfs |
360 | * file system. If not already created, this routine will create the |
361 | * create file trace to log fnic fc trace buffer output into debugfs and |
362 | * it will also create file fc_trace_enable to control enable/disable of |
363 | * trace logging into trace buffer. |
364 | */ |
365 | |
366 | void fnic_fc_trace_debugfs_init(void) |
367 | { |
368 | fnic_fc_trace_enable = debugfs_create_file(name: "fc_trace_enable" , |
369 | S_IFREG|S_IRUGO|S_IWUSR, |
370 | parent: fnic_trace_debugfs_root, |
371 | data: &(fc_trc_flag->fc_trace), |
372 | fops: &fnic_trace_ctrl_fops); |
373 | |
374 | fnic_fc_trace_clear = debugfs_create_file(name: "fc_trace_clear" , |
375 | S_IFREG|S_IRUGO|S_IWUSR, |
376 | parent: fnic_trace_debugfs_root, |
377 | data: &(fc_trc_flag->fc_clear), |
378 | fops: &fnic_trace_ctrl_fops); |
379 | |
380 | fnic_fc_rdata_trace_debugfs_file = |
381 | debugfs_create_file(name: "fc_trace_rdata" , |
382 | S_IFREG|S_IRUGO|S_IWUSR, |
383 | parent: fnic_trace_debugfs_root, |
384 | data: &(fc_trc_flag->fc_normal_file), |
385 | fops: &fnic_trace_debugfs_fops); |
386 | |
387 | fnic_fc_trace_debugfs_file = |
388 | debugfs_create_file(name: "fc_trace" , |
389 | S_IFREG|S_IRUGO|S_IWUSR, |
390 | parent: fnic_trace_debugfs_root, |
391 | data: &(fc_trc_flag->fc_row_file), |
392 | fops: &fnic_trace_debugfs_fops); |
393 | } |
394 | |
395 | /* |
396 | * fnic_fc_trace_debugfs_terminate - Tear down debugfs infrastructure |
397 | * |
398 | * Description: |
399 | * When Debugfs is configured this routine removes debugfs file system |
400 | * elements that are specific to fnic_fc trace logging. |
401 | */ |
402 | |
403 | void fnic_fc_trace_debugfs_terminate(void) |
404 | { |
405 | debugfs_remove(dentry: fnic_fc_trace_debugfs_file); |
406 | fnic_fc_trace_debugfs_file = NULL; |
407 | |
408 | debugfs_remove(dentry: fnic_fc_rdata_trace_debugfs_file); |
409 | fnic_fc_rdata_trace_debugfs_file = NULL; |
410 | |
411 | debugfs_remove(dentry: fnic_fc_trace_enable); |
412 | fnic_fc_trace_enable = NULL; |
413 | |
414 | debugfs_remove(dentry: fnic_fc_trace_clear); |
415 | fnic_fc_trace_clear = NULL; |
416 | } |
417 | |
418 | /* |
419 | * fnic_reset_stats_open - Open the reset_stats file |
420 | * @inode: The inode pointer. |
421 | * @file: The file pointer to attach the stats reset flag. |
422 | * |
423 | * Description: |
424 | * This routine opens a debugsfs file reset_stats and stores i_private data |
425 | * to debug structure to retrieve later for while performing other |
426 | * file oprations. |
427 | * |
428 | * Returns: |
429 | * This function returns zero if successful. |
430 | */ |
431 | static int fnic_reset_stats_open(struct inode *inode, struct file *file) |
432 | { |
433 | struct stats_debug_info *debug; |
434 | |
435 | debug = kzalloc(size: sizeof(struct stats_debug_info), GFP_KERNEL); |
436 | if (!debug) |
437 | return -ENOMEM; |
438 | |
439 | debug->i_private = inode->i_private; |
440 | |
441 | file->private_data = debug; |
442 | |
443 | return 0; |
444 | } |
445 | |
446 | /* |
447 | * fnic_reset_stats_read - Read a reset_stats debugfs file |
448 | * @filp: The file pointer to read from. |
449 | * @ubuf: The buffer to copy the data to. |
450 | * @cnt: The number of bytes to read. |
451 | * @ppos: The position in the file to start reading from. |
452 | * |
453 | * Description: |
454 | * This routine reads value of variable reset_stats |
455 | * and stores into local @buf. It will start reading file at @ppos and |
456 | * copy up to @cnt of data to @ubuf from @buf. |
457 | * |
458 | * Returns: |
459 | * This function returns the amount of data that was read. |
460 | */ |
461 | static ssize_t fnic_reset_stats_read(struct file *file, |
462 | char __user *ubuf, |
463 | size_t cnt, loff_t *ppos) |
464 | { |
465 | struct stats_debug_info *debug = file->private_data; |
466 | struct fnic *fnic = (struct fnic *)debug->i_private; |
467 | char buf[64]; |
468 | int len; |
469 | |
470 | len = sprintf(buf, fmt: "%u\n" , fnic->reset_stats); |
471 | |
472 | return simple_read_from_buffer(to: ubuf, count: cnt, ppos, from: buf, available: len); |
473 | } |
474 | |
475 | /* |
476 | * fnic_reset_stats_write - Write to reset_stats debugfs file |
477 | * @filp: The file pointer to write from. |
478 | * @ubuf: The buffer to copy the data from. |
479 | * @cnt: The number of bytes to write. |
480 | * @ppos: The position in the file to start writing to. |
481 | * |
482 | * Description: |
483 | * This routine writes data from user buffer @ubuf to buffer @buf and |
484 | * resets cumulative stats of fnic. |
485 | * |
486 | * Returns: |
487 | * This function returns the amount of data that was written. |
488 | */ |
489 | static ssize_t fnic_reset_stats_write(struct file *file, |
490 | const char __user *ubuf, |
491 | size_t cnt, loff_t *ppos) |
492 | { |
493 | struct stats_debug_info *debug = file->private_data; |
494 | struct fnic *fnic = (struct fnic *)debug->i_private; |
495 | struct fnic_stats *stats = &fnic->fnic_stats; |
496 | u64 *io_stats_p = (u64 *)&stats->io_stats; |
497 | u64 *fw_stats_p = (u64 *)&stats->fw_stats; |
498 | char buf[64]; |
499 | unsigned long val; |
500 | int ret; |
501 | |
502 | if (cnt >= sizeof(buf)) |
503 | return -EINVAL; |
504 | |
505 | if (copy_from_user(to: &buf, from: ubuf, n: cnt)) |
506 | return -EFAULT; |
507 | |
508 | buf[cnt] = 0; |
509 | |
510 | ret = kstrtoul(s: buf, base: 10, res: &val); |
511 | if (ret < 0) |
512 | return ret; |
513 | |
514 | fnic->reset_stats = val; |
515 | |
516 | if (fnic->reset_stats) { |
517 | /* Skip variable is used to avoid descrepancies to Num IOs |
518 | * and IO Completions stats. Skip incrementing No IO Compls |
519 | * for pending active IOs after reset stats |
520 | */ |
521 | atomic64_set(v: &fnic->io_cmpl_skip, |
522 | i: atomic64_read(v: &stats->io_stats.active_ios)); |
523 | memset(&stats->abts_stats, 0, sizeof(struct abort_stats)); |
524 | memset(&stats->term_stats, 0, |
525 | sizeof(struct terminate_stats)); |
526 | memset(&stats->reset_stats, 0, sizeof(struct reset_stats)); |
527 | memset(&stats->misc_stats, 0, sizeof(struct misc_stats)); |
528 | memset(&stats->vlan_stats, 0, sizeof(struct vlan_stats)); |
529 | memset(io_stats_p+1, 0, |
530 | sizeof(struct io_path_stats) - sizeof(u64)); |
531 | memset(fw_stats_p+1, 0, |
532 | sizeof(struct fw_stats) - sizeof(u64)); |
533 | ktime_get_real_ts64(tv: &stats->stats_timestamps.last_reset_time); |
534 | } |
535 | |
536 | (*ppos)++; |
537 | return cnt; |
538 | } |
539 | |
540 | /* |
541 | * fnic_reset_stats_release - Release the buffer used to store |
542 | * debugfs file data |
543 | * @inode: The inode pointer |
544 | * @file: The file pointer that contains the buffer to release |
545 | * |
546 | * Description: |
547 | * This routine frees the buffer that was allocated when the debugfs |
548 | * file was opened. |
549 | * |
550 | * Returns: |
551 | * This function returns zero. |
552 | */ |
553 | static int fnic_reset_stats_release(struct inode *inode, |
554 | struct file *file) |
555 | { |
556 | struct stats_debug_info *debug = file->private_data; |
557 | kfree(objp: debug); |
558 | return 0; |
559 | } |
560 | |
561 | /* |
562 | * fnic_stats_debugfs_open - Open the stats file for specific host |
563 | * and get fnic stats. |
564 | * @inode: The inode pointer. |
565 | * @file: The file pointer to attach the specific host statistics. |
566 | * |
567 | * Description: |
568 | * This routine opens a debugsfs file stats of specific host and print |
569 | * fnic stats. |
570 | * |
571 | * Returns: |
572 | * This function returns zero if successful. |
573 | */ |
574 | static int fnic_stats_debugfs_open(struct inode *inode, |
575 | struct file *file) |
576 | { |
577 | struct fnic *fnic = inode->i_private; |
578 | struct fnic_stats *fnic_stats = &fnic->fnic_stats; |
579 | struct stats_debug_info *debug; |
580 | int buf_size = 2 * PAGE_SIZE; |
581 | |
582 | debug = kzalloc(size: sizeof(struct stats_debug_info), GFP_KERNEL); |
583 | if (!debug) |
584 | return -ENOMEM; |
585 | |
586 | debug->debug_buffer = vmalloc(size: buf_size); |
587 | if (!debug->debug_buffer) { |
588 | kfree(objp: debug); |
589 | return -ENOMEM; |
590 | } |
591 | |
592 | debug->buf_size = buf_size; |
593 | memset((void *)debug->debug_buffer, 0, buf_size); |
594 | debug->buffer_len = fnic_get_stats_data(debug, fnic_stats); |
595 | |
596 | file->private_data = debug; |
597 | |
598 | return 0; |
599 | } |
600 | |
601 | /* |
602 | * fnic_stats_debugfs_read - Read a debugfs file |
603 | * @file: The file pointer to read from. |
604 | * @ubuf: The buffer to copy the data to. |
605 | * @nbytes: The number of bytes to read. |
606 | * @pos: The position in the file to start reading from. |
607 | * |
608 | * Description: |
609 | * This routine reads data from the buffer indicated in the private_data |
610 | * field of @file. It will start reading at @pos and copy up to @nbytes of |
611 | * data to @ubuf. |
612 | * |
613 | * Returns: |
614 | * This function returns the amount of data that was read (this could be |
615 | * less than @nbytes if the end of the file was reached). |
616 | */ |
617 | static ssize_t fnic_stats_debugfs_read(struct file *file, |
618 | char __user *ubuf, |
619 | size_t nbytes, |
620 | loff_t *pos) |
621 | { |
622 | struct stats_debug_info *debug = file->private_data; |
623 | int rc = 0; |
624 | rc = simple_read_from_buffer(to: ubuf, count: nbytes, ppos: pos, |
625 | from: debug->debug_buffer, |
626 | available: debug->buffer_len); |
627 | return rc; |
628 | } |
629 | |
630 | /* |
631 | * fnic_stats_stats_release - Release the buffer used to store |
632 | * debugfs file data |
633 | * @inode: The inode pointer |
634 | * @file: The file pointer that contains the buffer to release |
635 | * |
636 | * Description: |
637 | * This routine frees the buffer that was allocated when the debugfs |
638 | * file was opened. |
639 | * |
640 | * Returns: |
641 | * This function returns zero. |
642 | */ |
643 | static int fnic_stats_debugfs_release(struct inode *inode, |
644 | struct file *file) |
645 | { |
646 | struct stats_debug_info *debug = file->private_data; |
647 | vfree(addr: debug->debug_buffer); |
648 | kfree(objp: debug); |
649 | return 0; |
650 | } |
651 | |
652 | static const struct file_operations fnic_stats_debugfs_fops = { |
653 | .owner = THIS_MODULE, |
654 | .open = fnic_stats_debugfs_open, |
655 | .read = fnic_stats_debugfs_read, |
656 | .release = fnic_stats_debugfs_release, |
657 | }; |
658 | |
659 | static const struct file_operations fnic_reset_debugfs_fops = { |
660 | .owner = THIS_MODULE, |
661 | .open = fnic_reset_stats_open, |
662 | .read = fnic_reset_stats_read, |
663 | .write = fnic_reset_stats_write, |
664 | .release = fnic_reset_stats_release, |
665 | }; |
666 | |
667 | /* |
668 | * fnic_stats_init - Initialize stats struct and create stats file per fnic |
669 | * |
670 | * Description: |
671 | * When Debugfs is configured this routine sets up the stats file per fnic |
672 | * It will create file stats and reset_stats under statistics/host# directory |
673 | * to log per fnic stats. |
674 | */ |
675 | void fnic_stats_debugfs_init(struct fnic *fnic) |
676 | { |
677 | char name[16]; |
678 | |
679 | snprintf(buf: name, size: sizeof(name), fmt: "host%d" , fnic->lport->host->host_no); |
680 | |
681 | fnic->fnic_stats_debugfs_host = debugfs_create_dir(name, |
682 | parent: fnic_stats_debugfs_root); |
683 | |
684 | fnic->fnic_stats_debugfs_file = debugfs_create_file(name: "stats" , |
685 | S_IFREG|S_IRUGO|S_IWUSR, |
686 | parent: fnic->fnic_stats_debugfs_host, |
687 | data: fnic, |
688 | fops: &fnic_stats_debugfs_fops); |
689 | |
690 | fnic->fnic_reset_debugfs_file = debugfs_create_file(name: "reset_stats" , |
691 | S_IFREG|S_IRUGO|S_IWUSR, |
692 | parent: fnic->fnic_stats_debugfs_host, |
693 | data: fnic, |
694 | fops: &fnic_reset_debugfs_fops); |
695 | } |
696 | |
697 | /* |
698 | * fnic_stats_debugfs_remove - Tear down debugfs infrastructure of stats |
699 | * |
700 | * Description: |
701 | * When Debugfs is configured this routine removes debugfs file system |
702 | * elements that are specific to fnic stats. |
703 | */ |
704 | void fnic_stats_debugfs_remove(struct fnic *fnic) |
705 | { |
706 | if (!fnic) |
707 | return; |
708 | |
709 | debugfs_remove(dentry: fnic->fnic_stats_debugfs_file); |
710 | fnic->fnic_stats_debugfs_file = NULL; |
711 | |
712 | debugfs_remove(dentry: fnic->fnic_reset_debugfs_file); |
713 | fnic->fnic_reset_debugfs_file = NULL; |
714 | |
715 | debugfs_remove(dentry: fnic->fnic_stats_debugfs_host); |
716 | fnic->fnic_stats_debugfs_host = NULL; |
717 | } |
718 | |