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