diff options
Diffstat (limited to 'drivers/scsi/fnic/fnic_debugfs.c')
-rw-r--r-- | drivers/scsi/fnic/fnic_debugfs.c | 390 |
1 files changed, 379 insertions, 11 deletions
diff --git a/drivers/scsi/fnic/fnic_debugfs.c b/drivers/scsi/fnic/fnic_debugfs.c index cbcb0121c84d..b6073f875761 100644 --- a/drivers/scsi/fnic/fnic_debugfs.c +++ b/drivers/scsi/fnic/fnic_debugfs.c | |||
@@ -23,6 +23,58 @@ | |||
23 | static struct dentry *fnic_trace_debugfs_root; | 23 | static struct dentry *fnic_trace_debugfs_root; |
24 | static struct dentry *fnic_trace_debugfs_file; | 24 | static struct dentry *fnic_trace_debugfs_file; |
25 | static struct dentry *fnic_trace_enable; | 25 | static struct dentry *fnic_trace_enable; |
26 | static struct dentry *fnic_stats_debugfs_root; | ||
27 | |||
28 | /* | ||
29 | * fnic_debugfs_init - Initialize debugfs for fnic debug logging | ||
30 | * | ||
31 | * Description: | ||
32 | * When Debugfs is configured this routine sets up the fnic debugfs | ||
33 | * file system. If not already created, this routine will create the | ||
34 | * fnic directory and statistics directory for trace buffer and | ||
35 | * stats logging. | ||
36 | */ | ||
37 | int fnic_debugfs_init(void) | ||
38 | { | ||
39 | int rc = -1; | ||
40 | fnic_trace_debugfs_root = debugfs_create_dir("fnic", NULL); | ||
41 | if (!fnic_trace_debugfs_root) { | ||
42 | printk(KERN_DEBUG "Cannot create debugfs root\n"); | ||
43 | return rc; | ||
44 | } | ||
45 | |||
46 | if (!fnic_trace_debugfs_root) { | ||
47 | printk(KERN_DEBUG | ||
48 | "fnic root directory doesn't exist in debugfs\n"); | ||
49 | return rc; | ||
50 | } | ||
51 | |||
52 | fnic_stats_debugfs_root = debugfs_create_dir("statistics", | ||
53 | fnic_trace_debugfs_root); | ||
54 | if (!fnic_stats_debugfs_root) { | ||
55 | printk(KERN_DEBUG "Cannot create Statistics directory\n"); | ||
56 | return rc; | ||
57 | } | ||
58 | |||
59 | rc = 0; | ||
60 | return rc; | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * fnic_debugfs_terminate - Tear down debugfs infrastructure | ||
65 | * | ||
66 | * Description: | ||
67 | * When Debugfs is configured this routine removes debugfs file system | ||
68 | * elements that are specific to fnic. | ||
69 | */ | ||
70 | void fnic_debugfs_terminate(void) | ||
71 | { | ||
72 | debugfs_remove(fnic_stats_debugfs_root); | ||
73 | fnic_stats_debugfs_root = NULL; | ||
74 | |||
75 | debugfs_remove(fnic_trace_debugfs_root); | ||
76 | fnic_trace_debugfs_root = NULL; | ||
77 | } | ||
26 | 78 | ||
27 | /* | 79 | /* |
28 | * fnic_trace_ctrl_open - Open the trace_enable file | 80 | * fnic_trace_ctrl_open - Open the trace_enable file |
@@ -241,16 +293,16 @@ static const struct file_operations fnic_trace_debugfs_fops = { | |||
241 | * Description: | 293 | * Description: |
242 | * When Debugfs is configured this routine sets up the fnic debugfs | 294 | * When Debugfs is configured this routine sets up the fnic debugfs |
243 | * file system. If not already created, this routine will create the | 295 | * file system. If not already created, this routine will create the |
244 | * fnic directory. It will create file trace to log fnic trace buffer | 296 | * create file trace to log fnic trace buffer output into debugfs and |
245 | * output into debugfs and it will also create file trace_enable to | 297 | * it will also create file trace_enable to control enable/disable of |
246 | * control enable/disable of trace logging into trace buffer. | 298 | * trace logging into trace buffer. |
247 | */ | 299 | */ |
248 | int fnic_trace_debugfs_init(void) | 300 | int fnic_trace_debugfs_init(void) |
249 | { | 301 | { |
250 | int rc = -1; | 302 | int rc = -1; |
251 | fnic_trace_debugfs_root = debugfs_create_dir("fnic", NULL); | ||
252 | if (!fnic_trace_debugfs_root) { | 303 | if (!fnic_trace_debugfs_root) { |
253 | printk(KERN_DEBUG "Cannot create debugfs root\n"); | 304 | printk(KERN_DEBUG |
305 | "FNIC Debugfs root directory doesn't exist\n"); | ||
254 | return rc; | 306 | return rc; |
255 | } | 307 | } |
256 | fnic_trace_enable = debugfs_create_file("tracing_enable", | 308 | fnic_trace_enable = debugfs_create_file("tracing_enable", |
@@ -259,8 +311,8 @@ int fnic_trace_debugfs_init(void) | |||
259 | NULL, &fnic_trace_ctrl_fops); | 311 | NULL, &fnic_trace_ctrl_fops); |
260 | 312 | ||
261 | if (!fnic_trace_enable) { | 313 | if (!fnic_trace_enable) { |
262 | printk(KERN_DEBUG "Cannot create trace_enable file" | 314 | printk(KERN_DEBUG |
263 | " under debugfs"); | 315 | "Cannot create trace_enable file under debugfs\n"); |
264 | return rc; | 316 | return rc; |
265 | } | 317 | } |
266 | 318 | ||
@@ -271,7 +323,8 @@ int fnic_trace_debugfs_init(void) | |||
271 | &fnic_trace_debugfs_fops); | 323 | &fnic_trace_debugfs_fops); |
272 | 324 | ||
273 | if (!fnic_trace_debugfs_file) { | 325 | if (!fnic_trace_debugfs_file) { |
274 | printk(KERN_DEBUG "Cannot create trace file under debugfs"); | 326 | printk(KERN_DEBUG |
327 | "Cannot create trace file under debugfs\n"); | ||
275 | return rc; | 328 | return rc; |
276 | } | 329 | } |
277 | rc = 0; | 330 | rc = 0; |
@@ -295,8 +348,323 @@ void fnic_trace_debugfs_terminate(void) | |||
295 | debugfs_remove(fnic_trace_enable); | 348 | debugfs_remove(fnic_trace_enable); |
296 | fnic_trace_enable = NULL; | 349 | fnic_trace_enable = NULL; |
297 | } | 350 | } |
298 | if (fnic_trace_debugfs_root) { | 351 | } |
299 | debugfs_remove(fnic_trace_debugfs_root); | 352 | |
300 | fnic_trace_debugfs_root = NULL; | 353 | /* |
354 | * fnic_reset_stats_open - Open the reset_stats file | ||
355 | * @inode: The inode pointer. | ||
356 | * @file: The file pointer to attach the stats reset flag. | ||
357 | * | ||
358 | * Description: | ||
359 | * This routine opens a debugsfs file reset_stats and stores i_private data | ||
360 | * to debug structure to retrieve later for while performing other | ||
361 | * file oprations. | ||
362 | * | ||
363 | * Returns: | ||
364 | * This function returns zero if successful. | ||
365 | */ | ||
366 | static int fnic_reset_stats_open(struct inode *inode, struct file *file) | ||
367 | { | ||
368 | struct stats_debug_info *debug; | ||
369 | |||
370 | debug = kzalloc(sizeof(struct stats_debug_info), GFP_KERNEL); | ||
371 | if (!debug) | ||
372 | return -ENOMEM; | ||
373 | |||
374 | debug->i_private = inode->i_private; | ||
375 | |||
376 | file->private_data = debug; | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * fnic_reset_stats_read - Read a reset_stats debugfs file | ||
383 | * @filp: The file pointer to read from. | ||
384 | * @ubuf: The buffer to copy the data to. | ||
385 | * @cnt: The number of bytes to read. | ||
386 | * @ppos: The position in the file to start reading from. | ||
387 | * | ||
388 | * Description: | ||
389 | * This routine reads value of variable reset_stats | ||
390 | * and stores into local @buf. It will start reading file at @ppos and | ||
391 | * copy up to @cnt of data to @ubuf from @buf. | ||
392 | * | ||
393 | * Returns: | ||
394 | * This function returns the amount of data that was read. | ||
395 | */ | ||
396 | static ssize_t fnic_reset_stats_read(struct file *file, | ||
397 | char __user *ubuf, | ||
398 | size_t cnt, loff_t *ppos) | ||
399 | { | ||
400 | struct stats_debug_info *debug = file->private_data; | ||
401 | struct fnic *fnic = (struct fnic *)debug->i_private; | ||
402 | char buf[64]; | ||
403 | int len; | ||
404 | |||
405 | len = sprintf(buf, "%u\n", fnic->reset_stats); | ||
406 | |||
407 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, len); | ||
408 | } | ||
409 | |||
410 | /* | ||
411 | * fnic_reset_stats_write - Write to reset_stats debugfs file | ||
412 | * @filp: The file pointer to write from. | ||
413 | * @ubuf: The buffer to copy the data from. | ||
414 | * @cnt: The number of bytes to write. | ||
415 | * @ppos: The position in the file to start writing to. | ||
416 | * | ||
417 | * Description: | ||
418 | * This routine writes data from user buffer @ubuf to buffer @buf and | ||
419 | * resets cumulative stats of fnic. | ||
420 | * | ||
421 | * Returns: | ||
422 | * This function returns the amount of data that was written. | ||
423 | */ | ||
424 | static ssize_t fnic_reset_stats_write(struct file *file, | ||
425 | const char __user *ubuf, | ||
426 | size_t cnt, loff_t *ppos) | ||
427 | { | ||
428 | struct stats_debug_info *debug = file->private_data; | ||
429 | struct fnic *fnic = (struct fnic *)debug->i_private; | ||
430 | struct fnic_stats *stats = &fnic->fnic_stats; | ||
431 | u64 *io_stats_p = (u64 *)&stats->io_stats; | ||
432 | u64 *fw_stats_p = (u64 *)&stats->fw_stats; | ||
433 | char buf[64]; | ||
434 | unsigned long val; | ||
435 | int ret; | ||
436 | |||
437 | if (cnt >= sizeof(buf)) | ||
438 | return -EINVAL; | ||
439 | |||
440 | if (copy_from_user(&buf, ubuf, cnt)) | ||
441 | return -EFAULT; | ||
442 | |||
443 | buf[cnt] = 0; | ||
444 | |||
445 | ret = kstrtoul(buf, 10, &val); | ||
446 | if (ret < 0) | ||
447 | return ret; | ||
448 | |||
449 | fnic->reset_stats = val; | ||
450 | |||
451 | if (fnic->reset_stats) { | ||
452 | /* Skip variable is used to avoid descrepancies to Num IOs | ||
453 | * and IO Completions stats. Skip incrementing No IO Compls | ||
454 | * for pending active IOs after reset stats | ||
455 | */ | ||
456 | atomic64_set(&fnic->io_cmpl_skip, | ||
457 | atomic64_read(&stats->io_stats.active_ios)); | ||
458 | memset(&stats->abts_stats, 0, sizeof(struct abort_stats)); | ||
459 | memset(&stats->term_stats, 0, | ||
460 | sizeof(struct terminate_stats)); | ||
461 | memset(&stats->reset_stats, 0, sizeof(struct reset_stats)); | ||
462 | memset(&stats->misc_stats, 0, sizeof(struct misc_stats)); | ||
463 | memset(&stats->vlan_stats, 0, sizeof(struct vlan_stats)); | ||
464 | memset(io_stats_p+1, 0, | ||
465 | sizeof(struct io_path_stats) - sizeof(u64)); | ||
466 | memset(fw_stats_p+1, 0, | ||
467 | sizeof(struct fw_stats) - sizeof(u64)); | ||
301 | } | 468 | } |
469 | |||
470 | (*ppos)++; | ||
471 | return cnt; | ||
472 | } | ||
473 | |||
474 | /* | ||
475 | * fnic_reset_stats_release - Release the buffer used to store | ||
476 | * debugfs file data | ||
477 | * @inode: The inode pointer | ||
478 | * @file: The file pointer that contains the buffer to release | ||
479 | * | ||
480 | * Description: | ||
481 | * This routine frees the buffer that was allocated when the debugfs | ||
482 | * file was opened. | ||
483 | * | ||
484 | * Returns: | ||
485 | * This function returns zero. | ||
486 | */ | ||
487 | static int fnic_reset_stats_release(struct inode *inode, | ||
488 | struct file *file) | ||
489 | { | ||
490 | struct stats_debug_info *debug = file->private_data; | ||
491 | kfree(debug); | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | /* | ||
496 | * fnic_stats_debugfs_open - Open the stats file for specific host | ||
497 | * and get fnic stats. | ||
498 | * @inode: The inode pointer. | ||
499 | * @file: The file pointer to attach the specific host statistics. | ||
500 | * | ||
501 | * Description: | ||
502 | * This routine opens a debugsfs file stats of specific host and print | ||
503 | * fnic stats. | ||
504 | * | ||
505 | * Returns: | ||
506 | * This function returns zero if successful. | ||
507 | */ | ||
508 | static int fnic_stats_debugfs_open(struct inode *inode, | ||
509 | struct file *file) | ||
510 | { | ||
511 | struct fnic *fnic = inode->i_private; | ||
512 | struct fnic_stats *fnic_stats = &fnic->fnic_stats; | ||
513 | struct stats_debug_info *debug; | ||
514 | int buf_size = 2 * PAGE_SIZE; | ||
515 | |||
516 | debug = kzalloc(sizeof(struct stats_debug_info), GFP_KERNEL); | ||
517 | if (!debug) | ||
518 | return -ENOMEM; | ||
519 | |||
520 | debug->debug_buffer = vmalloc(buf_size); | ||
521 | if (!debug->debug_buffer) { | ||
522 | kfree(debug); | ||
523 | return -ENOMEM; | ||
524 | } | ||
525 | |||
526 | debug->buf_size = buf_size; | ||
527 | memset((void *)debug->debug_buffer, 0, buf_size); | ||
528 | debug->buffer_len = fnic_get_stats_data(debug, fnic_stats); | ||
529 | |||
530 | file->private_data = debug; | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | /* | ||
536 | * fnic_stats_debugfs_read - Read a debugfs file | ||
537 | * @file: The file pointer to read from. | ||
538 | * @ubuf: The buffer to copy the data to. | ||
539 | * @nbytes: The number of bytes to read. | ||
540 | * @pos: The position in the file to start reading from. | ||
541 | * | ||
542 | * Description: | ||
543 | * This routine reads data from the buffer indicated in the private_data | ||
544 | * field of @file. It will start reading at @pos and copy up to @nbytes of | ||
545 | * data to @ubuf. | ||
546 | * | ||
547 | * Returns: | ||
548 | * This function returns the amount of data that was read (this could be | ||
549 | * less than @nbytes if the end of the file was reached). | ||
550 | */ | ||
551 | static ssize_t fnic_stats_debugfs_read(struct file *file, | ||
552 | char __user *ubuf, | ||
553 | size_t nbytes, | ||
554 | loff_t *pos) | ||
555 | { | ||
556 | struct stats_debug_info *debug = file->private_data; | ||
557 | int rc = 0; | ||
558 | rc = simple_read_from_buffer(ubuf, nbytes, pos, | ||
559 | debug->debug_buffer, | ||
560 | debug->buffer_len); | ||
561 | return rc; | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | * fnic_stats_stats_release - Release the buffer used to store | ||
566 | * debugfs file data | ||
567 | * @inode: The inode pointer | ||
568 | * @file: The file pointer that contains the buffer to release | ||
569 | * | ||
570 | * Description: | ||
571 | * This routine frees the buffer that was allocated when the debugfs | ||
572 | * file was opened. | ||
573 | * | ||
574 | * Returns: | ||
575 | * This function returns zero. | ||
576 | */ | ||
577 | static int fnic_stats_debugfs_release(struct inode *inode, | ||
578 | struct file *file) | ||
579 | { | ||
580 | struct stats_debug_info *debug = file->private_data; | ||
581 | vfree(debug->debug_buffer); | ||
582 | kfree(debug); | ||
583 | return 0; | ||
584 | } | ||
585 | |||
586 | static const struct file_operations fnic_stats_debugfs_fops = { | ||
587 | .owner = THIS_MODULE, | ||
588 | .open = fnic_stats_debugfs_open, | ||
589 | .read = fnic_stats_debugfs_read, | ||
590 | .release = fnic_stats_debugfs_release, | ||
591 | }; | ||
592 | |||
593 | static const struct file_operations fnic_reset_debugfs_fops = { | ||
594 | .owner = THIS_MODULE, | ||
595 | .open = fnic_reset_stats_open, | ||
596 | .read = fnic_reset_stats_read, | ||
597 | .write = fnic_reset_stats_write, | ||
598 | .release = fnic_reset_stats_release, | ||
599 | }; | ||
600 | |||
601 | /* | ||
602 | * fnic_stats_init - Initialize stats struct and create stats file per fnic | ||
603 | * | ||
604 | * Description: | ||
605 | * When Debugfs is configured this routine sets up the stats file per fnic | ||
606 | * It will create file stats and reset_stats under statistics/host# directory | ||
607 | * to log per fnic stats. | ||
608 | */ | ||
609 | int fnic_stats_debugfs_init(struct fnic *fnic) | ||
610 | { | ||
611 | int rc = -1; | ||
612 | char name[16]; | ||
613 | |||
614 | snprintf(name, sizeof(name), "host%d", fnic->lport->host->host_no); | ||
615 | |||
616 | if (!fnic_stats_debugfs_root) { | ||
617 | printk(KERN_DEBUG "fnic_stats root doesn't exist\n"); | ||
618 | return rc; | ||
619 | } | ||
620 | fnic->fnic_stats_debugfs_host = debugfs_create_dir(name, | ||
621 | fnic_stats_debugfs_root); | ||
622 | if (!fnic->fnic_stats_debugfs_host) { | ||
623 | printk(KERN_DEBUG "Cannot create host directory\n"); | ||
624 | return rc; | ||
625 | } | ||
626 | |||
627 | fnic->fnic_stats_debugfs_file = debugfs_create_file("stats", | ||
628 | S_IFREG|S_IRUGO|S_IWUSR, | ||
629 | fnic->fnic_stats_debugfs_host, | ||
630 | fnic, | ||
631 | &fnic_stats_debugfs_fops); | ||
632 | if (!fnic->fnic_stats_debugfs_file) { | ||
633 | printk(KERN_DEBUG "Cannot create host stats file\n"); | ||
634 | return rc; | ||
635 | } | ||
636 | |||
637 | fnic->fnic_reset_debugfs_file = debugfs_create_file("reset_stats", | ||
638 | S_IFREG|S_IRUGO|S_IWUSR, | ||
639 | fnic->fnic_stats_debugfs_host, | ||
640 | fnic, | ||
641 | &fnic_reset_debugfs_fops); | ||
642 | if (!fnic->fnic_reset_debugfs_file) { | ||
643 | printk(KERN_DEBUG "Cannot create host stats file\n"); | ||
644 | return rc; | ||
645 | } | ||
646 | rc = 0; | ||
647 | return rc; | ||
648 | } | ||
649 | |||
650 | /* | ||
651 | * fnic_stats_debugfs_remove - Tear down debugfs infrastructure of stats | ||
652 | * | ||
653 | * Description: | ||
654 | * When Debugfs is configured this routine removes debugfs file system | ||
655 | * elements that are specific to fnic stats. | ||
656 | */ | ||
657 | void fnic_stats_debugfs_remove(struct fnic *fnic) | ||
658 | { | ||
659 | if (!fnic) | ||
660 | return; | ||
661 | |||
662 | debugfs_remove(fnic->fnic_stats_debugfs_file); | ||
663 | fnic->fnic_stats_debugfs_file = NULL; | ||
664 | |||
665 | debugfs_remove(fnic->fnic_reset_debugfs_file); | ||
666 | fnic->fnic_reset_debugfs_file = NULL; | ||
667 | |||
668 | debugfs_remove(fnic->fnic_stats_debugfs_host); | ||
669 | fnic->fnic_stats_debugfs_host = NULL; | ||
302 | } | 670 | } |