1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Debugfs interface Support for MPT (Message Passing Technology) based |
4 | * controllers. |
5 | * |
6 | * Copyright (C) 2020 Broadcom Inc. |
7 | * |
8 | * Authors: Broadcom Inc. |
9 | * Sreekanth Reddy <sreekanth.reddy@broadcom.com> |
10 | * Suganath Prabu <suganath-prabu.subramani@broadcom.com> |
11 | * |
12 | * Send feedback to : MPT-FusionLinux.pdl@broadcom.com) |
13 | * |
14 | **/ |
15 | |
16 | #include <linux/kernel.h> |
17 | #include <linux/types.h> |
18 | #include <linux/pci.h> |
19 | #include <linux/interrupt.h> |
20 | #include <linux/compat.h> |
21 | #include <linux/uio.h> |
22 | |
23 | #include <scsi/scsi.h> |
24 | #include <scsi/scsi_device.h> |
25 | #include <scsi/scsi_host.h> |
26 | #include "mpt3sas_base.h" |
27 | #include <linux/debugfs.h> |
28 | |
29 | static struct dentry *mpt3sas_debugfs_root; |
30 | |
31 | /* |
32 | * _debugfs_iocdump_read - copy ioc dump from debugfs buffer |
33 | * @filep: File Pointer |
34 | * @ubuf: Buffer to fill data |
35 | * @cnt: Length of the buffer |
36 | * @ppos: Offset in the file |
37 | */ |
38 | |
39 | static ssize_t |
40 | _debugfs_iocdump_read(struct file *filp, char __user *ubuf, size_t cnt, |
41 | loff_t *ppos) |
42 | |
43 | { |
44 | struct mpt3sas_debugfs_buffer *debug = filp->private_data; |
45 | |
46 | if (!debug || !debug->buf) |
47 | return 0; |
48 | |
49 | return simple_read_from_buffer(to: ubuf, count: cnt, ppos, from: debug->buf, available: debug->len); |
50 | } |
51 | |
52 | /* |
53 | * _debugfs_iocdump_open : open the ioc_dump debugfs attribute file |
54 | */ |
55 | static int |
56 | _debugfs_iocdump_open(struct inode *inode, struct file *file) |
57 | { |
58 | struct MPT3SAS_ADAPTER *ioc = inode->i_private; |
59 | struct mpt3sas_debugfs_buffer *debug; |
60 | |
61 | debug = kzalloc(size: sizeof(struct mpt3sas_debugfs_buffer), GFP_KERNEL); |
62 | if (!debug) |
63 | return -ENOMEM; |
64 | |
65 | debug->buf = (void *)ioc; |
66 | debug->len = sizeof(struct MPT3SAS_ADAPTER); |
67 | file->private_data = debug; |
68 | return 0; |
69 | } |
70 | |
71 | /* |
72 | * _debugfs_iocdump_release : release the ioc_dump debugfs attribute |
73 | * @inode: inode structure to the corresponds device |
74 | * @file: File pointer |
75 | */ |
76 | static int |
77 | _debugfs_iocdump_release(struct inode *inode, struct file *file) |
78 | { |
79 | struct mpt3sas_debugfs_buffer *debug = file->private_data; |
80 | |
81 | if (!debug) |
82 | return 0; |
83 | |
84 | file->private_data = NULL; |
85 | kfree(objp: debug); |
86 | return 0; |
87 | } |
88 | |
89 | static const struct file_operations mpt3sas_debugfs_iocdump_fops = { |
90 | .owner = THIS_MODULE, |
91 | .open = _debugfs_iocdump_open, |
92 | .read = _debugfs_iocdump_read, |
93 | .release = _debugfs_iocdump_release, |
94 | }; |
95 | |
96 | /* |
97 | * mpt3sas_init_debugfs : Create debugfs root for mpt3sas driver |
98 | */ |
99 | void mpt3sas_init_debugfs(void) |
100 | { |
101 | mpt3sas_debugfs_root = debugfs_create_dir(name: "mpt3sas" , NULL); |
102 | if (!mpt3sas_debugfs_root) |
103 | pr_info("mpt3sas: Cannot create debugfs root\n" ); |
104 | } |
105 | |
106 | /* |
107 | * mpt3sas_exit_debugfs : Remove debugfs root for mpt3sas driver |
108 | */ |
109 | void mpt3sas_exit_debugfs(void) |
110 | { |
111 | debugfs_remove_recursive(dentry: mpt3sas_debugfs_root); |
112 | } |
113 | |
114 | /* |
115 | * mpt3sas_setup_debugfs : Setup debugfs per HBA adapter |
116 | * ioc: MPT3SAS_ADAPTER object |
117 | */ |
118 | void |
119 | mpt3sas_setup_debugfs(struct MPT3SAS_ADAPTER *ioc) |
120 | { |
121 | char name[64]; |
122 | |
123 | snprintf(buf: name, size: sizeof(name), fmt: "scsi_host%d" , ioc->shost->host_no); |
124 | if (!ioc->debugfs_root) { |
125 | ioc->debugfs_root = |
126 | debugfs_create_dir(name, parent: mpt3sas_debugfs_root); |
127 | if (!ioc->debugfs_root) { |
128 | dev_err(&ioc->pdev->dev, |
129 | "Cannot create per adapter debugfs directory\n" ); |
130 | return; |
131 | } |
132 | } |
133 | |
134 | snprintf(buf: name, size: sizeof(name), fmt: "ioc_dump" ); |
135 | ioc->ioc_dump = debugfs_create_file(name, mode: 0444, |
136 | parent: ioc->debugfs_root, data: ioc, fops: &mpt3sas_debugfs_iocdump_fops); |
137 | if (!ioc->ioc_dump) { |
138 | dev_err(&ioc->pdev->dev, |
139 | "Cannot create ioc_dump debugfs file\n" ); |
140 | debugfs_remove(dentry: ioc->debugfs_root); |
141 | return; |
142 | } |
143 | |
144 | snprintf(buf: name, size: sizeof(name), fmt: "host_recovery" ); |
145 | debugfs_create_u8(name, mode: 0444, parent: ioc->debugfs_root, value: &ioc->shost_recovery); |
146 | |
147 | } |
148 | |
149 | /* |
150 | * mpt3sas_destroy_debugfs : Destroy debugfs per HBA adapter |
151 | * @ioc: MPT3SAS_ADAPTER object |
152 | */ |
153 | void mpt3sas_destroy_debugfs(struct MPT3SAS_ADAPTER *ioc) |
154 | { |
155 | debugfs_remove_recursive(dentry: ioc->debugfs_root); |
156 | } |
157 | |
158 | |