diff options
author | Jing Huang <huangj@brocade.com> | 2010-07-08 23:02:55 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-27 13:04:32 -0400 |
commit | ab2a9ba189e889b3e8990e52e90d2cd9606b2aa1 (patch) | |
tree | 0114a0fcb8caf0daee0fa23a8d9b788ad1eef0f2 /drivers/scsi/bfa | |
parent | 08a17ced7a78064f4f03de7d68b8cd32581f0510 (diff) |
[SCSI] bfa: add debugfs support
- Add debugfs support to obtain firmware trace, driver trace
and read/write to registers.
- debugfs hierarchy:
/sys/kernel/debug/bfa/host#
where the host number corresponds to the one under /sys/class/scsi_host/host#
- Following are the new debugfs entries added:
drvtrc: collect current driver trace
fwtrc: collect current firmware trace.
fwsave: collect last saved fw trace as a result of firmware crash.
regwr: write one word to chip register
regrd: read one or more words from chip register.
Signed-off-by: Jing Huang <huangj@brocade.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/bfa')
-rw-r--r-- | drivers/scsi/bfa/Makefile | 2 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfad.c | 12 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfad_debugfs.c | 547 | ||||
-rw-r--r-- | drivers/scsi/bfa/bfad_drv.h | 12 |
4 files changed, 571 insertions, 2 deletions
diff --git a/drivers/scsi/bfa/Makefile b/drivers/scsi/bfa/Makefile index 17e06cae71b2..ac3fdf02d5f6 100644 --- a/drivers/scsi/bfa/Makefile +++ b/drivers/scsi/bfa/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | obj-$(CONFIG_SCSI_BFA_FC) := bfa.o | 1 | obj-$(CONFIG_SCSI_BFA_FC) := bfa.o |
2 | 2 | ||
3 | bfa-y := bfad.o bfad_intr.o bfad_os.o bfad_im.o bfad_attr.o bfad_fwimg.o | 3 | bfa-y := bfad.o bfad_intr.o bfad_os.o bfad_im.o bfad_attr.o bfad_fwimg.o |
4 | 4 | bfa-y += bfad_debugfs.o | |
5 | bfa-y += bfa_core.o bfa_ioc.o bfa_ioc_ct.o bfa_ioc_cb.o bfa_iocfc.o bfa_fcxp.o | 5 | bfa-y += bfa_core.o bfa_ioc.o bfa_ioc_ct.o bfa_ioc_cb.o bfa_iocfc.o bfa_fcxp.o |
6 | bfa-y += bfa_lps.o bfa_hw_cb.o bfa_hw_ct.o bfa_intr.o bfa_timer.o bfa_rport.o | 6 | bfa-y += bfa_lps.o bfa_hw_cb.o bfa_hw_ct.o bfa_intr.o bfa_timer.o bfa_rport.o |
7 | bfa-y += bfa_fcport.o bfa_port.o bfa_uf.o bfa_sgpg.o bfa_module.o bfa_ioim.o | 7 | bfa-y += bfa_fcport.o bfa_port.o bfa_uf.o bfa_sgpg.o bfa_module.o bfa_ioim.o |
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index a17800e6277d..915a29d6c7ad 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c | |||
@@ -57,6 +57,7 @@ static int ipfc_enable = BFA_FALSE; | |||
57 | static int fdmi_enable = BFA_TRUE; | 57 | static int fdmi_enable = BFA_TRUE; |
58 | int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH; | 58 | int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH; |
59 | int bfa_linkup_delay = -1; | 59 | int bfa_linkup_delay = -1; |
60 | int bfa_debugfs_enable = 1; | ||
60 | 61 | ||
61 | module_param(os_name, charp, S_IRUGO | S_IWUSR); | 62 | module_param(os_name, charp, S_IRUGO | S_IWUSR); |
62 | MODULE_PARM_DESC(os_name, "OS name of the hba host machine"); | 63 | MODULE_PARM_DESC(os_name, "OS name of the hba host machine"); |
@@ -106,6 +107,9 @@ MODULE_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for boot" | |||
106 | module_param(fdmi_enable, int, S_IRUGO | S_IWUSR); | 107 | module_param(fdmi_enable, int, S_IRUGO | S_IWUSR); |
107 | MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1," | 108 | MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1," |
108 | " Range[false:0|true:1]"); | 109 | " Range[false:0|true:1]"); |
110 | module_param(bfa_debugfs_enable, int, S_IRUGO | S_IWUSR); | ||
111 | MODULE_PARM_DESC(bfa_debugfs_enable, "Enables debugfs feature, default=1," | ||
112 | " Range[false:0|true:1]"); | ||
109 | 113 | ||
110 | /* | 114 | /* |
111 | * Stores the module parm num_sgpgs value; | 115 | * Stores the module parm num_sgpgs value; |
@@ -903,6 +907,10 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role) | |||
903 | bfad->pport.roles |= BFA_PORT_ROLE_FCP_IM; | 907 | bfad->pport.roles |= BFA_PORT_ROLE_FCP_IM; |
904 | } | 908 | } |
905 | 909 | ||
910 | /* Setup the debugfs node for this scsi_host */ | ||
911 | if (bfa_debugfs_enable) | ||
912 | bfad_debugfs_init(&bfad->pport); | ||
913 | |||
906 | bfad->bfad_flags |= BFAD_CFG_PPORT_DONE; | 914 | bfad->bfad_flags |= BFAD_CFG_PPORT_DONE; |
907 | 915 | ||
908 | out: | 916 | out: |
@@ -912,6 +920,10 @@ out: | |||
912 | void | 920 | void |
913 | bfad_uncfg_pport(struct bfad_s *bfad) | 921 | bfad_uncfg_pport(struct bfad_s *bfad) |
914 | { | 922 | { |
923 | /* Remove the debugfs node for this scsi_host */ | ||
924 | kfree(bfad->regdata); | ||
925 | bfad_debugfs_exit(&bfad->pport); | ||
926 | |||
915 | if ((bfad->pport.roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) { | 927 | if ((bfad->pport.roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) { |
916 | bfad_ipfc_port_delete(bfad, &bfad->pport); | 928 | bfad_ipfc_port_delete(bfad, &bfad->pport); |
917 | bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IPFC; | 929 | bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IPFC; |
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c new file mode 100644 index 000000000000..4b82f12aad62 --- /dev/null +++ b/drivers/scsi/bfa/bfad_debugfs.c | |||
@@ -0,0 +1,547 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. | ||
3 | * All rights reserved | ||
4 | * www.brocade.com | ||
5 | * | ||
6 | * Linux driver for Brocade Fibre Channel Host Bus Adapter. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License (GPL) Version 2 as | ||
10 | * published by the Free Software Foundation | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/debugfs.h> | ||
19 | |||
20 | #include <bfad_drv.h> | ||
21 | #include <bfad_im.h> | ||
22 | |||
23 | /* | ||
24 | * BFA debufs interface | ||
25 | * | ||
26 | * To access the interface, debugfs file system should be mounted | ||
27 | * if not already mounted using: | ||
28 | * mount -t debugfs none /sys/kernel/debug | ||
29 | * | ||
30 | * BFA Hierarchy: | ||
31 | * - bfa/host# | ||
32 | * where the host number corresponds to the one under /sys/class/scsi_host/host# | ||
33 | * | ||
34 | * Debugging service available per host: | ||
35 | * fwtrc: To collect current firmware trace. | ||
36 | * drvtrc: To collect current driver trace | ||
37 | * fwsave: To collect last saved fw trace as a result of firmware crash. | ||
38 | * regwr: To write one word to chip register | ||
39 | * regrd: To read one or more words from chip register. | ||
40 | */ | ||
41 | |||
42 | struct bfad_debug_info { | ||
43 | char *debug_buffer; | ||
44 | void *i_private; | ||
45 | int buffer_len; | ||
46 | }; | ||
47 | |||
48 | static int | ||
49 | bfad_debugfs_open_drvtrc(struct inode *inode, struct file *file) | ||
50 | { | ||
51 | struct bfad_port_s *port = inode->i_private; | ||
52 | struct bfad_s *bfad = port->bfad; | ||
53 | struct bfad_debug_info *debug; | ||
54 | |||
55 | debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); | ||
56 | if (!debug) | ||
57 | return -ENOMEM; | ||
58 | |||
59 | debug->debug_buffer = (void *) bfad->trcmod; | ||
60 | debug->buffer_len = sizeof(struct bfa_trc_mod_s); | ||
61 | |||
62 | file->private_data = debug; | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int | ||
68 | bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file) | ||
69 | { | ||
70 | struct bfad_port_s *port = inode->i_private; | ||
71 | struct bfad_s *bfad = port->bfad; | ||
72 | struct bfad_debug_info *fw_debug; | ||
73 | unsigned long flags; | ||
74 | int rc; | ||
75 | |||
76 | fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); | ||
77 | if (!fw_debug) | ||
78 | return -ENOMEM; | ||
79 | |||
80 | fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s); | ||
81 | |||
82 | fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len); | ||
83 | if (!fw_debug->debug_buffer) { | ||
84 | kfree(fw_debug); | ||
85 | printk(KERN_INFO "bfad[%d]: Failed to allocate fwtrc buffer\n", | ||
86 | bfad->inst_no); | ||
87 | return -ENOMEM; | ||
88 | } | ||
89 | |||
90 | memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len); | ||
91 | |||
92 | spin_lock_irqsave(&bfad->bfad_lock, flags); | ||
93 | rc = bfa_debug_fwtrc(&bfad->bfa, | ||
94 | fw_debug->debug_buffer, | ||
95 | &fw_debug->buffer_len); | ||
96 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | ||
97 | if (rc != BFA_STATUS_OK) { | ||
98 | vfree(fw_debug->debug_buffer); | ||
99 | fw_debug->debug_buffer = NULL; | ||
100 | kfree(fw_debug); | ||
101 | printk(KERN_INFO "bfad[%d]: Failed to collect fwtrc\n", | ||
102 | bfad->inst_no); | ||
103 | return -ENOMEM; | ||
104 | } | ||
105 | |||
106 | file->private_data = fw_debug; | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int | ||
112 | bfad_debugfs_open_fwsave(struct inode *inode, struct file *file) | ||
113 | { | ||
114 | struct bfad_port_s *port = inode->i_private; | ||
115 | struct bfad_s *bfad = port->bfad; | ||
116 | struct bfad_debug_info *fw_debug; | ||
117 | unsigned long flags; | ||
118 | int rc; | ||
119 | |||
120 | fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); | ||
121 | if (!fw_debug) | ||
122 | return -ENOMEM; | ||
123 | |||
124 | fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s); | ||
125 | |||
126 | fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len); | ||
127 | if (!fw_debug->debug_buffer) { | ||
128 | kfree(fw_debug); | ||
129 | printk(KERN_INFO "bfad[%d]: Failed to allocate fwsave buffer\n", | ||
130 | bfad->inst_no); | ||
131 | return -ENOMEM; | ||
132 | } | ||
133 | |||
134 | memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len); | ||
135 | |||
136 | spin_lock_irqsave(&bfad->bfad_lock, flags); | ||
137 | rc = bfa_debug_fwsave(&bfad->bfa, | ||
138 | fw_debug->debug_buffer, | ||
139 | &fw_debug->buffer_len); | ||
140 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | ||
141 | if (rc != BFA_STATUS_OK) { | ||
142 | vfree(fw_debug->debug_buffer); | ||
143 | fw_debug->debug_buffer = NULL; | ||
144 | kfree(fw_debug); | ||
145 | printk(KERN_INFO "bfad[%d]: Failed to collect fwsave\n", | ||
146 | bfad->inst_no); | ||
147 | return -ENOMEM; | ||
148 | } | ||
149 | |||
150 | file->private_data = fw_debug; | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static int | ||
156 | bfad_debugfs_open_reg(struct inode *inode, struct file *file) | ||
157 | { | ||
158 | struct bfad_debug_info *reg_debug; | ||
159 | |||
160 | reg_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); | ||
161 | if (!reg_debug) | ||
162 | return -ENOMEM; | ||
163 | |||
164 | reg_debug->i_private = inode->i_private; | ||
165 | |||
166 | file->private_data = reg_debug; | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | /* Changes the current file position */ | ||
172 | static loff_t | ||
173 | bfad_debugfs_lseek(struct file *file, loff_t offset, int orig) | ||
174 | { | ||
175 | struct bfad_debug_info *debug; | ||
176 | loff_t pos = file->f_pos; | ||
177 | |||
178 | debug = file->private_data; | ||
179 | |||
180 | switch (orig) { | ||
181 | case 0: | ||
182 | file->f_pos = offset; | ||
183 | break; | ||
184 | case 1: | ||
185 | file->f_pos += offset; | ||
186 | break; | ||
187 | case 2: | ||
188 | file->f_pos = debug->buffer_len - offset; | ||
189 | break; | ||
190 | default: | ||
191 | return -EINVAL; | ||
192 | } | ||
193 | |||
194 | if (file->f_pos < 0 || file->f_pos > debug->buffer_len) { | ||
195 | file->f_pos = pos; | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | |||
199 | return file->f_pos; | ||
200 | } | ||
201 | |||
202 | static ssize_t | ||
203 | bfad_debugfs_read(struct file *file, char __user *buf, | ||
204 | size_t nbytes, loff_t *pos) | ||
205 | { | ||
206 | struct bfad_debug_info *debug = file->private_data; | ||
207 | |||
208 | if (!debug || !debug->debug_buffer) | ||
209 | return 0; | ||
210 | |||
211 | return memory_read_from_buffer(buf, nbytes, pos, | ||
212 | debug->debug_buffer, debug->buffer_len); | ||
213 | } | ||
214 | |||
215 | #define BFA_REG_CT_ADDRSZ (0x40000) | ||
216 | #define BFA_REG_CB_ADDRSZ (0x20000) | ||
217 | #define BFA_REG_ADDRSZ(__bfa) \ | ||
218 | ((bfa_ioc_devid(&(__bfa)->ioc) == BFA_PCI_DEVICE_ID_CT) ? \ | ||
219 | BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ) | ||
220 | #define BFA_REG_ADDRMSK(__bfa) ((uint32_t)(BFA_REG_ADDRSZ(__bfa) - 1)) | ||
221 | |||
222 | static bfa_status_t | ||
223 | bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len) | ||
224 | { | ||
225 | u8 area; | ||
226 | |||
227 | /* check [16:15] */ | ||
228 | area = (offset >> 15) & 0x7; | ||
229 | if (area == 0) { | ||
230 | /* PCIe core register */ | ||
231 | if ((offset + (len<<2)) > 0x8000) /* 8k dwords or 32KB */ | ||
232 | return BFA_STATUS_EINVAL; | ||
233 | } else if (area == 0x1) { | ||
234 | /* CB 32 KB memory page */ | ||
235 | if ((offset + (len<<2)) > 0x10000) /* 8k dwords or 32KB */ | ||
236 | return BFA_STATUS_EINVAL; | ||
237 | } else { | ||
238 | /* CB register space 64KB */ | ||
239 | if ((offset + (len<<2)) > BFA_REG_ADDRMSK(bfa)) | ||
240 | return BFA_STATUS_EINVAL; | ||
241 | } | ||
242 | return BFA_STATUS_OK; | ||
243 | } | ||
244 | |||
245 | static ssize_t | ||
246 | bfad_debugfs_read_regrd(struct file *file, char __user *buf, | ||
247 | size_t nbytes, loff_t *pos) | ||
248 | { | ||
249 | struct bfad_debug_info *regrd_debug = file->private_data; | ||
250 | struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private; | ||
251 | struct bfad_s *bfad = port->bfad; | ||
252 | ssize_t rc; | ||
253 | |||
254 | if (!bfad->regdata) | ||
255 | return 0; | ||
256 | |||
257 | rc = memory_read_from_buffer(buf, nbytes, pos, | ||
258 | bfad->regdata, bfad->reglen); | ||
259 | |||
260 | if ((*pos + nbytes) >= bfad->reglen) { | ||
261 | kfree(bfad->regdata); | ||
262 | bfad->regdata = NULL; | ||
263 | bfad->reglen = 0; | ||
264 | } | ||
265 | |||
266 | return rc; | ||
267 | } | ||
268 | |||
269 | static ssize_t | ||
270 | bfad_debugfs_write_regrd(struct file *file, const char __user *buf, | ||
271 | size_t nbytes, loff_t *ppos) | ||
272 | { | ||
273 | struct bfad_debug_info *regrd_debug = file->private_data; | ||
274 | struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private; | ||
275 | struct bfad_s *bfad = port->bfad; | ||
276 | struct bfa_s *bfa = &bfad->bfa; | ||
277 | struct bfa_ioc_s *ioc = &bfa->ioc; | ||
278 | int addr, len, rc, i; | ||
279 | u32 *regbuf; | ||
280 | void __iomem *rb, *reg_addr; | ||
281 | unsigned long flags; | ||
282 | |||
283 | rc = sscanf(buf, "%x:%x", &addr, &len); | ||
284 | if (rc < 2) { | ||
285 | printk(KERN_INFO | ||
286 | "bfad[%d]: %s failed to read user buf\n", | ||
287 | bfad->inst_no, __func__); | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | |||
291 | kfree(bfad->regdata); | ||
292 | bfad->regdata = NULL; | ||
293 | bfad->reglen = 0; | ||
294 | |||
295 | bfad->regdata = kzalloc(len << 2, GFP_KERNEL); | ||
296 | if (!bfad->regdata) { | ||
297 | printk(KERN_INFO "bfad[%d]: Failed to allocate regrd buffer\n", | ||
298 | bfad->inst_no); | ||
299 | return -ENOMEM; | ||
300 | } | ||
301 | |||
302 | bfad->reglen = len << 2; | ||
303 | rb = bfa_ioc_bar0(ioc); | ||
304 | addr &= BFA_REG_ADDRMSK(bfa); | ||
305 | |||
306 | /* offset and len sanity check */ | ||
307 | rc = bfad_reg_offset_check(bfa, addr, len); | ||
308 | if (rc) { | ||
309 | printk(KERN_INFO "bfad[%d]: Failed reg offset check\n", | ||
310 | bfad->inst_no); | ||
311 | kfree(bfad->regdata); | ||
312 | bfad->regdata = NULL; | ||
313 | bfad->reglen = 0; | ||
314 | return -EINVAL; | ||
315 | } | ||
316 | |||
317 | reg_addr = rb + addr; | ||
318 | regbuf = (u32 *)bfad->regdata; | ||
319 | spin_lock_irqsave(&bfad->bfad_lock, flags); | ||
320 | for (i = 0; i < len; i++) { | ||
321 | *regbuf = bfa_reg_read(reg_addr); | ||
322 | regbuf++; | ||
323 | reg_addr += sizeof(u32); | ||
324 | } | ||
325 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | ||
326 | |||
327 | return nbytes; | ||
328 | } | ||
329 | |||
330 | static ssize_t | ||
331 | bfad_debugfs_write_regwr(struct file *file, const char __user *buf, | ||
332 | size_t nbytes, loff_t *ppos) | ||
333 | { | ||
334 | struct bfad_debug_info *debug = file->private_data; | ||
335 | struct bfad_port_s *port = (struct bfad_port_s *)debug->i_private; | ||
336 | struct bfad_s *bfad = port->bfad; | ||
337 | struct bfa_s *bfa = &bfad->bfa; | ||
338 | struct bfa_ioc_s *ioc = &bfa->ioc; | ||
339 | int addr, val, rc; | ||
340 | void __iomem *reg_addr; | ||
341 | unsigned long flags; | ||
342 | |||
343 | rc = sscanf(buf, "%x:%x", &addr, &val); | ||
344 | if (rc < 2) { | ||
345 | printk(KERN_INFO | ||
346 | "bfad[%d]: %s failed to read user buf\n", | ||
347 | bfad->inst_no, __func__); | ||
348 | return -EINVAL; | ||
349 | } | ||
350 | |||
351 | addr &= BFA_REG_ADDRMSK(bfa); /* offset only 17 bit and word align */ | ||
352 | |||
353 | /* offset and len sanity check */ | ||
354 | rc = bfad_reg_offset_check(bfa, addr, 1); | ||
355 | if (rc) { | ||
356 | printk(KERN_INFO | ||
357 | "bfad[%d]: Failed reg offset check\n", | ||
358 | bfad->inst_no); | ||
359 | return -EINVAL; | ||
360 | } | ||
361 | |||
362 | reg_addr = (uint32_t *) ((uint8_t *) bfa_ioc_bar0(ioc) + addr); | ||
363 | spin_lock_irqsave(&bfad->bfad_lock, flags); | ||
364 | bfa_reg_write(reg_addr, val); | ||
365 | spin_unlock_irqrestore(&bfad->bfad_lock, flags); | ||
366 | |||
367 | return nbytes; | ||
368 | } | ||
369 | |||
370 | static int | ||
371 | bfad_debugfs_release(struct inode *inode, struct file *file) | ||
372 | { | ||
373 | struct bfad_debug_info *debug = file->private_data; | ||
374 | |||
375 | if (!debug) | ||
376 | return 0; | ||
377 | |||
378 | file->private_data = NULL; | ||
379 | kfree(debug); | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static int | ||
384 | bfad_debugfs_release_fwtrc(struct inode *inode, struct file *file) | ||
385 | { | ||
386 | struct bfad_debug_info *fw_debug = file->private_data; | ||
387 | |||
388 | if (!fw_debug) | ||
389 | return 0; | ||
390 | |||
391 | if (fw_debug->debug_buffer) | ||
392 | vfree(fw_debug->debug_buffer); | ||
393 | |||
394 | file->private_data = NULL; | ||
395 | kfree(fw_debug); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static const struct file_operations bfad_debugfs_op_drvtrc = { | ||
400 | .owner = THIS_MODULE, | ||
401 | .open = bfad_debugfs_open_drvtrc, | ||
402 | .llseek = bfad_debugfs_lseek, | ||
403 | .read = bfad_debugfs_read, | ||
404 | .release = bfad_debugfs_release, | ||
405 | }; | ||
406 | |||
407 | static const struct file_operations bfad_debugfs_op_fwtrc = { | ||
408 | .owner = THIS_MODULE, | ||
409 | .open = bfad_debugfs_open_fwtrc, | ||
410 | .llseek = bfad_debugfs_lseek, | ||
411 | .read = bfad_debugfs_read, | ||
412 | .release = bfad_debugfs_release_fwtrc, | ||
413 | }; | ||
414 | |||
415 | static const struct file_operations bfad_debugfs_op_fwsave = { | ||
416 | .owner = THIS_MODULE, | ||
417 | .open = bfad_debugfs_open_fwsave, | ||
418 | .llseek = bfad_debugfs_lseek, | ||
419 | .read = bfad_debugfs_read, | ||
420 | .release = bfad_debugfs_release_fwtrc, | ||
421 | }; | ||
422 | |||
423 | static const struct file_operations bfad_debugfs_op_regrd = { | ||
424 | .owner = THIS_MODULE, | ||
425 | .open = bfad_debugfs_open_reg, | ||
426 | .llseek = bfad_debugfs_lseek, | ||
427 | .read = bfad_debugfs_read_regrd, | ||
428 | .write = bfad_debugfs_write_regrd, | ||
429 | .release = bfad_debugfs_release, | ||
430 | }; | ||
431 | |||
432 | static const struct file_operations bfad_debugfs_op_regwr = { | ||
433 | .owner = THIS_MODULE, | ||
434 | .open = bfad_debugfs_open_reg, | ||
435 | .llseek = bfad_debugfs_lseek, | ||
436 | .write = bfad_debugfs_write_regwr, | ||
437 | .release = bfad_debugfs_release, | ||
438 | }; | ||
439 | |||
440 | struct bfad_debugfs_entry { | ||
441 | const char *name; | ||
442 | mode_t mode; | ||
443 | const struct file_operations *fops; | ||
444 | }; | ||
445 | |||
446 | static const struct bfad_debugfs_entry bfad_debugfs_files[] = { | ||
447 | { "drvtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_drvtrc, }, | ||
448 | { "fwtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwtrc, }, | ||
449 | { "fwsave", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwsave, }, | ||
450 | { "regrd", S_IFREG|S_IRUGO|S_IWUSR, &bfad_debugfs_op_regrd, }, | ||
451 | { "regwr", S_IFREG|S_IWUSR, &bfad_debugfs_op_regwr, }, | ||
452 | }; | ||
453 | |||
454 | static struct dentry *bfa_debugfs_root; | ||
455 | static atomic_t bfa_debugfs_port_count; | ||
456 | |||
457 | inline void | ||
458 | bfad_debugfs_init(struct bfad_port_s *port) | ||
459 | { | ||
460 | struct bfad_im_port_s *im_port = port->im_port; | ||
461 | struct bfad_s *bfad = im_port->bfad; | ||
462 | struct Scsi_Host *shost = im_port->shost; | ||
463 | const struct bfad_debugfs_entry *file; | ||
464 | char name[16]; | ||
465 | int i; | ||
466 | |||
467 | if (!bfa_debugfs_enable) | ||
468 | return; | ||
469 | |||
470 | /* Setup the BFA debugfs root directory*/ | ||
471 | if (!bfa_debugfs_root) { | ||
472 | bfa_debugfs_root = debugfs_create_dir("bfa", NULL); | ||
473 | atomic_set(&bfa_debugfs_port_count, 0); | ||
474 | if (!bfa_debugfs_root) { | ||
475 | printk(KERN_WARNING | ||
476 | "BFA debugfs root dir creation failed\n"); | ||
477 | goto err; | ||
478 | } | ||
479 | } | ||
480 | |||
481 | /* | ||
482 | * Setup the host# directory for the port, | ||
483 | * corresponds to the scsi_host num of this port. | ||
484 | */ | ||
485 | snprintf(name, sizeof(name), "host%d", shost->host_no); | ||
486 | if (!port->port_debugfs_root) { | ||
487 | port->port_debugfs_root = | ||
488 | debugfs_create_dir(name, bfa_debugfs_root); | ||
489 | if (!port->port_debugfs_root) { | ||
490 | printk(KERN_WARNING | ||
491 | "BFA host root dir creation failed\n"); | ||
492 | goto err; | ||
493 | } | ||
494 | |||
495 | atomic_inc(&bfa_debugfs_port_count); | ||
496 | |||
497 | for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) { | ||
498 | file = &bfad_debugfs_files[i]; | ||
499 | bfad->bfad_dentry_files[i] = | ||
500 | debugfs_create_file(file->name, | ||
501 | file->mode, | ||
502 | port->port_debugfs_root, | ||
503 | port, | ||
504 | file->fops); | ||
505 | if (!bfad->bfad_dentry_files[i]) { | ||
506 | printk(KERN_WARNING | ||
507 | "BFA host%d: create %s entry failed\n", | ||
508 | shost->host_no, file->name); | ||
509 | goto err; | ||
510 | } | ||
511 | } | ||
512 | } | ||
513 | |||
514 | err: | ||
515 | return; | ||
516 | } | ||
517 | |||
518 | inline void | ||
519 | bfad_debugfs_exit(struct bfad_port_s *port) | ||
520 | { | ||
521 | struct bfad_im_port_s *im_port = port->im_port; | ||
522 | struct bfad_s *bfad = im_port->bfad; | ||
523 | int i; | ||
524 | |||
525 | for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) { | ||
526 | if (bfad->bfad_dentry_files[i]) { | ||
527 | debugfs_remove(bfad->bfad_dentry_files[i]); | ||
528 | bfad->bfad_dentry_files[i] = NULL; | ||
529 | } | ||
530 | } | ||
531 | |||
532 | /* | ||
533 | * Remove the host# directory for the port, | ||
534 | * corresponds to the scsi_host num of this port. | ||
535 | */ | ||
536 | if (port->port_debugfs_root) { | ||
537 | debugfs_remove(port->port_debugfs_root); | ||
538 | port->port_debugfs_root = NULL; | ||
539 | atomic_dec(&bfa_debugfs_port_count); | ||
540 | } | ||
541 | |||
542 | /* Remove the BFA debugfs root directory */ | ||
543 | if (atomic_read(&bfa_debugfs_port_count) == 0) { | ||
544 | debugfs_remove(bfa_debugfs_root); | ||
545 | bfa_debugfs_root = NULL; | ||
546 | } | ||
547 | } | ||
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index fb6ac1d3fd17..465b8b86ec9c 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h | |||
@@ -111,6 +111,9 @@ struct bfad_port_s { | |||
111 | struct bfad_im_port_s *im_port; /* IM specific data */ | 111 | struct bfad_im_port_s *im_port; /* IM specific data */ |
112 | struct bfad_tm_port_s *tm_port; /* TM specific data */ | 112 | struct bfad_tm_port_s *tm_port; /* TM specific data */ |
113 | struct bfad_ipfc_port_s *ipfc_port; /* IPFC specific data */ | 113 | struct bfad_ipfc_port_s *ipfc_port; /* IPFC specific data */ |
114 | |||
115 | /* port debugfs specific data */ | ||
116 | struct dentry *port_debugfs_root; | ||
114 | }; | 117 | }; |
115 | 118 | ||
116 | /* | 119 | /* |
@@ -186,6 +189,10 @@ struct bfad_s { | |||
186 | struct fc_host_statistics link_stats; | 189 | struct fc_host_statistics link_stats; |
187 | struct list_head pbc_pcfg_list; | 190 | struct list_head pbc_pcfg_list; |
188 | atomic_t wq_reqcnt; | 191 | atomic_t wq_reqcnt; |
192 | /* debugfs specific data */ | ||
193 | char *regdata; | ||
194 | u32 reglen; | ||
195 | struct dentry *bfad_dentry_files[5]; | ||
189 | }; | 196 | }; |
190 | 197 | ||
191 | struct bfad_pcfg_s { | 198 | struct bfad_pcfg_s { |
@@ -276,7 +283,9 @@ void bfad_drv_uninit(struct bfad_s *bfad); | |||
276 | void bfad_drv_log_level_set(struct bfad_s *bfad); | 283 | void bfad_drv_log_level_set(struct bfad_s *bfad); |
277 | bfa_status_t bfad_fc4_module_init(void); | 284 | bfa_status_t bfad_fc4_module_init(void); |
278 | void bfad_fc4_module_exit(void); | 285 | void bfad_fc4_module_exit(void); |
279 | int bfad_worker (void *ptr); | 286 | int bfad_worker(void *ptr); |
287 | void bfad_debugfs_init(struct bfad_port_s *port); | ||
288 | void bfad_debugfs_exit(struct bfad_port_s *port); | ||
280 | 289 | ||
281 | void bfad_pci_remove(struct pci_dev *pdev); | 290 | void bfad_pci_remove(struct pci_dev *pdev); |
282 | int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid); | 291 | int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid); |
@@ -289,6 +298,7 @@ extern struct list_head bfad_list; | |||
289 | extern int bfa_lun_queue_depth; | 298 | extern int bfa_lun_queue_depth; |
290 | extern int bfad_supported_fc4s; | 299 | extern int bfad_supported_fc4s; |
291 | extern int bfa_linkup_delay; | 300 | extern int bfa_linkup_delay; |
301 | extern int bfa_debugfs_enable; | ||
292 | extern struct mutex bfad_mutex; | 302 | extern struct mutex bfad_mutex; |
293 | 303 | ||
294 | #endif /* __BFAD_DRV_H__ */ | 304 | #endif /* __BFAD_DRV_H__ */ |