aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_dfs.c
diff options
context:
space:
mode:
authorAndrew Vasquez <andrew.vasquez@qlogic.com>2008-01-17 12:02:17 -0500
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-23 12:29:32 -0500
commitdf613b96077cee826b14089ae6e75eeabf71faa3 (patch)
tree262f0b96f1dc94da58f837e5446b02da52d80471 /drivers/scsi/qla2xxx/qla_dfs.c
parent00b6bd25166e2a4bad23c614c10c55993bb2489e (diff)
[SCSI] qla2xxx: Add Fibre Channel Event (FCE) tracing support.
FCE support enables the firmware to record FC extended link services and basic link services frames which have been transmitted and received by the ISP. This allows for a limited view of the FC traffic through the ISP without using a FC analyzer. This can be useful in situations where a physical connection to the FC bus is not possible. The driver exports this information in two ways -- first, via a debugfs node exported for all supported ISPs under: <debugfs_mount_point>/qla2xxx/qla2xxx_<host_no>/fce where a read of the 'fce' file will provide a snapshot of the firmware's FCE buffer; and finally, the FCE buffer will be extracted during a firmware-dump scenario. Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_dfs.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
new file mode 100644
index 000000000000..1479c60441c8
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -0,0 +1,175 @@
1/*
2 * QLogic Fibre Channel HBA Driver
3 * Copyright (c) 2003-2005 QLogic Corporation
4 *
5 * See LICENSE.qla2xxx for copyright and licensing details.
6 */
7#include "qla_def.h"
8
9#include <linux/debugfs.h>
10#include <linux/seq_file.h>
11
12static struct dentry *qla2x00_dfs_root;
13static atomic_t qla2x00_dfs_root_count;
14
15static int
16qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
17{
18 scsi_qla_host_t *ha = s->private;
19 uint32_t cnt;
20 uint32_t *fce;
21 uint64_t fce_start;
22
23 mutex_lock(&ha->fce_mutex);
24
25 seq_printf(s, "FCE Trace Buffer\n");
26 seq_printf(s, "In Pointer = %llx\n\n", ha->fce_wr);
27 seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma);
28 seq_printf(s, "FCE Enable Registers\n");
29 seq_printf(s, "%08x %08x %08x %08x %08x %08x\n",
30 ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4],
31 ha->fce_mb[5], ha->fce_mb[6]);
32
33 fce = (uint32_t *) ha->fce;
34 fce_start = (unsigned long long) ha->fce_dma;
35 for (cnt = 0; cnt < fce_calc_size(ha->fce_bufs) / 4; cnt++) {
36 if (cnt % 8 == 0)
37 seq_printf(s, "\n%llx: ",
38 (unsigned long long)((cnt * 4) + fce_start));
39 else
40 seq_printf(s, " ");
41 seq_printf(s, "%08x", *fce++);
42 }
43
44 seq_printf(s, "\nEnd\n");
45
46 mutex_unlock(&ha->fce_mutex);
47
48 return 0;
49}
50
51static int
52qla2x00_dfs_fce_open(struct inode *inode, struct file *file)
53{
54 scsi_qla_host_t *ha = inode->i_private;
55 int rval;
56
57 if (!ha->flags.fce_enabled)
58 goto out;
59
60 mutex_lock(&ha->fce_mutex);
61
62 /* Pause tracing to flush FCE buffers. */
63 rval = qla2x00_disable_fce_trace(ha, &ha->fce_wr, &ha->fce_rd);
64 if (rval)
65 qla_printk(KERN_WARNING, ha,
66 "DebugFS: Unable to disable FCE (%d).\n", rval);
67
68 ha->flags.fce_enabled = 0;
69
70 mutex_unlock(&ha->fce_mutex);
71out:
72 return single_open(file, qla2x00_dfs_fce_show, ha);
73}
74
75static int
76qla2x00_dfs_fce_release(struct inode *inode, struct file *file)
77{
78 scsi_qla_host_t *ha = inode->i_private;
79 int rval;
80
81 if (ha->flags.fce_enabled)
82 goto out;
83
84 mutex_lock(&ha->fce_mutex);
85
86 /* Re-enable FCE tracing. */
87 ha->flags.fce_enabled = 1;
88 memset(ha->fce, 0, fce_calc_size(ha->fce_bufs));
89 rval = qla2x00_enable_fce_trace(ha, ha->fce_dma, ha->fce_bufs,
90 ha->fce_mb, &ha->fce_bufs);
91 if (rval) {
92 qla_printk(KERN_WARNING, ha,
93 "DebugFS: Unable to reinitialize FCE (%d).\n", rval);
94 ha->flags.fce_enabled = 0;
95 }
96
97 mutex_unlock(&ha->fce_mutex);
98out:
99 return single_release(inode, file);
100}
101
102static const struct file_operations dfs_fce_ops = {
103 .open = qla2x00_dfs_fce_open,
104 .read = seq_read,
105 .llseek = seq_lseek,
106 .release = qla2x00_dfs_fce_release,
107};
108
109int
110qla2x00_dfs_setup(scsi_qla_host_t *ha)
111{
112 if (!IS_QLA25XX(ha))
113 goto out;
114 if (!ha->fce)
115 goto out;
116
117 if (qla2x00_dfs_root)
118 goto create_dir;
119
120 atomic_set(&qla2x00_dfs_root_count, 0);
121 qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL);
122 if (!qla2x00_dfs_root) {
123 qla_printk(KERN_NOTICE, ha,
124 "DebugFS: Unable to create root directory.\n");
125 goto out;
126 }
127
128create_dir:
129 if (ha->dfs_dir)
130 goto create_nodes;
131
132 mutex_init(&ha->fce_mutex);
133 ha->dfs_dir = debugfs_create_dir(ha->host_str, qla2x00_dfs_root);
134 if (!ha->dfs_dir) {
135 qla_printk(KERN_NOTICE, ha,
136 "DebugFS: Unable to create ha directory.\n");
137 goto out;
138 }
139
140 atomic_inc(&qla2x00_dfs_root_count);
141
142create_nodes:
143 ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, ha,
144 &dfs_fce_ops);
145 if (!ha->dfs_fce) {
146 qla_printk(KERN_NOTICE, ha,
147 "DebugFS: Unable to fce node.\n");
148 goto out;
149 }
150out:
151 return 0;
152}
153
154int
155qla2x00_dfs_remove(scsi_qla_host_t *ha)
156{
157 if (ha->dfs_fce) {
158 debugfs_remove(ha->dfs_fce);
159 ha->dfs_fce = NULL;
160 }
161
162 if (ha->dfs_dir) {
163 debugfs_remove(ha->dfs_dir);
164 ha->dfs_dir = NULL;
165 atomic_dec(&qla2x00_dfs_root_count);
166 }
167
168 if (atomic_read(&qla2x00_dfs_root_count) == 0 &&
169 qla2x00_dfs_root) {
170 debugfs_remove(qla2x00_dfs_root);
171 qla2x00_dfs_root = NULL;
172 }
173
174 return 0;
175}