diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/fnic/Makefile | 2 | ||||
-rw-r--r-- | drivers/scsi/fnic/fnic.h | 1 | ||||
-rw-r--r-- | drivers/scsi/fnic/fnic_debugfs.c | 314 | ||||
-rw-r--r-- | drivers/scsi/fnic/fnic_main.c | 14 | ||||
-rw-r--r-- | drivers/scsi/fnic/fnic_scsi.c | 120 | ||||
-rw-r--r-- | drivers/scsi/fnic/fnic_trace.c | 273 | ||||
-rw-r--r-- | drivers/scsi/fnic/fnic_trace.h | 90 |
7 files changed, 803 insertions, 11 deletions
diff --git a/drivers/scsi/fnic/Makefile b/drivers/scsi/fnic/Makefile index 37c3440bc17c..383598fadf04 100644 --- a/drivers/scsi/fnic/Makefile +++ b/drivers/scsi/fnic/Makefile | |||
@@ -7,6 +7,8 @@ fnic-y := \ | |||
7 | fnic_res.o \ | 7 | fnic_res.o \ |
8 | fnic_fcs.o \ | 8 | fnic_fcs.o \ |
9 | fnic_scsi.o \ | 9 | fnic_scsi.o \ |
10 | fnic_trace.o \ | ||
11 | fnic_debugfs.o \ | ||
10 | vnic_cq.o \ | 12 | vnic_cq.o \ |
11 | vnic_dev.o \ | 13 | vnic_dev.o \ |
12 | vnic_intr.o \ | 14 | vnic_intr.o \ |
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 9c95a1ad56b9..98436c363035 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <scsi/libfcoe.h> | 26 | #include <scsi/libfcoe.h> |
27 | #include "fnic_io.h" | 27 | #include "fnic_io.h" |
28 | #include "fnic_res.h" | 28 | #include "fnic_res.h" |
29 | #include "fnic_trace.h" | ||
29 | #include "vnic_dev.h" | 30 | #include "vnic_dev.h" |
30 | #include "vnic_wq.h" | 31 | #include "vnic_wq.h" |
31 | #include "vnic_rq.h" | 32 | #include "vnic_rq.h" |
diff --git a/drivers/scsi/fnic/fnic_debugfs.c b/drivers/scsi/fnic/fnic_debugfs.c new file mode 100644 index 000000000000..adc1f7f471f5 --- /dev/null +++ b/drivers/scsi/fnic/fnic_debugfs.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Cisco Systems, Inc. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you may redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; version 2 of the License. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
9 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
10 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
11 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
12 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
15 | * SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/debugfs.h> | ||
21 | #include "fnic.h" | ||
22 | |||
23 | static struct dentry *fnic_trace_debugfs_root; | ||
24 | static struct dentry *fnic_trace_debugfs_file; | ||
25 | static struct dentry *fnic_trace_enable; | ||
26 | |||
27 | /* | ||
28 | * fnic_trace_ctrl_open - Open the trace_enable file | ||
29 | * @inode: The inode pointer. | ||
30 | * @file: The file pointer to attach the trace enable/disable flag. | ||
31 | * | ||
32 | * Description: | ||
33 | * This routine opens a debugsfs file trace_enable. | ||
34 | * | ||
35 | * Returns: | ||
36 | * This function returns zero if successful. | ||
37 | */ | ||
38 | static int fnic_trace_ctrl_open(struct inode *inode, struct file *filp) | ||
39 | { | ||
40 | filp->private_data = inode->i_private; | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | /* | ||
45 | * fnic_trace_ctrl_read - Read a trace_enable debugfs file | ||
46 | * @filp: The file pointer to read from. | ||
47 | * @ubuf: The buffer to copy the data to. | ||
48 | * @cnt: The number of bytes to read. | ||
49 | * @ppos: The position in the file to start reading from. | ||
50 | * | ||
51 | * Description: | ||
52 | * This routine reads value of variable fnic_tracing_enabled | ||
53 | * and stores into local @buf. It will start reading file at @ppos and | ||
54 | * copy up to @cnt of data to @ubuf from @buf. | ||
55 | * | ||
56 | * Returns: | ||
57 | * This function returns the amount of data that was read. | ||
58 | */ | ||
59 | static ssize_t fnic_trace_ctrl_read(struct file *filp, | ||
60 | char __user *ubuf, | ||
61 | size_t cnt, loff_t *ppos) | ||
62 | { | ||
63 | char buf[64]; | ||
64 | int len; | ||
65 | len = sprintf(buf, "%u\n", fnic_tracing_enabled); | ||
66 | |||
67 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, len); | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * fnic_trace_ctrl_write - Write to trace_enable debugfs file | ||
72 | * @filp: The file pointer to write from. | ||
73 | * @ubuf: The buffer to copy the data from. | ||
74 | * @cnt: The number of bytes to write. | ||
75 | * @ppos: The position in the file to start writing to. | ||
76 | * | ||
77 | * Description: | ||
78 | * This routine writes data from user buffer @ubuf to buffer @buf and | ||
79 | * sets fnic_tracing_enabled value as per user input. | ||
80 | * | ||
81 | * Returns: | ||
82 | * This function returns the amount of data that was written. | ||
83 | */ | ||
84 | static ssize_t fnic_trace_ctrl_write(struct file *filp, | ||
85 | const char __user *ubuf, | ||
86 | size_t cnt, loff_t *ppos) | ||
87 | { | ||
88 | char buf[64]; | ||
89 | unsigned long val; | ||
90 | int ret; | ||
91 | |||
92 | if (cnt >= sizeof(buf)) | ||
93 | return -EINVAL; | ||
94 | |||
95 | if (copy_from_user(&buf, ubuf, cnt)) | ||
96 | return -EFAULT; | ||
97 | |||
98 | buf[cnt] = 0; | ||
99 | |||
100 | ret = kstrtoul(buf, 10, &val); | ||
101 | if (ret < 0) | ||
102 | return ret; | ||
103 | |||
104 | fnic_tracing_enabled = val; | ||
105 | (*ppos)++; | ||
106 | |||
107 | return cnt; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * fnic_trace_debugfs_open - Open the fnic trace log | ||
112 | * @inode: The inode pointer | ||
113 | * @file: The file pointer to attach the log output | ||
114 | * | ||
115 | * Description: | ||
116 | * This routine is the entry point for the debugfs open file operation. | ||
117 | * It allocates the necessary buffer for the log, fills the buffer from | ||
118 | * the in-memory log and then returns a pointer to that log in | ||
119 | * the private_data field in @file. | ||
120 | * | ||
121 | * Returns: | ||
122 | * This function returns zero if successful. On error it will return | ||
123 | * a negative error value. | ||
124 | */ | ||
125 | static int fnic_trace_debugfs_open(struct inode *inode, | ||
126 | struct file *file) | ||
127 | { | ||
128 | fnic_dbgfs_t *fnic_dbg_prt; | ||
129 | fnic_dbg_prt = kzalloc(sizeof(fnic_dbgfs_t), GFP_KERNEL); | ||
130 | if (!fnic_dbg_prt) | ||
131 | return -ENOMEM; | ||
132 | |||
133 | fnic_dbg_prt->buffer = vmalloc((3*(trace_max_pages * PAGE_SIZE))); | ||
134 | if (!fnic_dbg_prt->buffer) { | ||
135 | kfree(fnic_dbg_prt); | ||
136 | return -ENOMEM; | ||
137 | } | ||
138 | memset((void *)fnic_dbg_prt->buffer, 0, | ||
139 | (3*(trace_max_pages * PAGE_SIZE))); | ||
140 | fnic_dbg_prt->buffer_len = fnic_get_trace_data(fnic_dbg_prt); | ||
141 | file->private_data = fnic_dbg_prt; | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | /* | ||
146 | * fnic_trace_debugfs_lseek - Seek through a debugfs file | ||
147 | * @file: The file pointer to seek through. | ||
148 | * @offset: The offset to seek to or the amount to seek by. | ||
149 | * @howto: Indicates how to seek. | ||
150 | * | ||
151 | * Description: | ||
152 | * This routine is the entry point for the debugfs lseek file operation. | ||
153 | * The @howto parameter indicates whether @offset is the offset to directly | ||
154 | * seek to, or if it is a value to seek forward or reverse by. This function | ||
155 | * figures out what the new offset of the debugfs file will be and assigns | ||
156 | * that value to the f_pos field of @file. | ||
157 | * | ||
158 | * Returns: | ||
159 | * This function returns the new offset if successful and returns a negative | ||
160 | * error if unable to process the seek. | ||
161 | */ | ||
162 | static loff_t fnic_trace_debugfs_lseek(struct file *file, | ||
163 | loff_t offset, | ||
164 | int howto) | ||
165 | { | ||
166 | fnic_dbgfs_t *fnic_dbg_prt = file->private_data; | ||
167 | loff_t pos = -1; | ||
168 | |||
169 | switch (howto) { | ||
170 | case 0: | ||
171 | pos = offset; | ||
172 | break; | ||
173 | case 1: | ||
174 | pos = file->f_pos + offset; | ||
175 | break; | ||
176 | case 2: | ||
177 | pos = fnic_dbg_prt->buffer_len - offset; | ||
178 | } | ||
179 | return (pos < 0 || pos > fnic_dbg_prt->buffer_len) ? | ||
180 | -EINVAL : (file->f_pos = pos); | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * fnic_trace_debugfs_read - Read a debugfs file | ||
185 | * @file: The file pointer to read from. | ||
186 | * @ubuf: The buffer to copy the data to. | ||
187 | * @nbytes: The number of bytes to read. | ||
188 | * @pos: The position in the file to start reading from. | ||
189 | * | ||
190 | * Description: | ||
191 | * This routine reads data from the buffer indicated in the private_data | ||
192 | * field of @file. It will start reading at @pos and copy up to @nbytes of | ||
193 | * data to @ubuf. | ||
194 | * | ||
195 | * Returns: | ||
196 | * This function returns the amount of data that was read (this could be | ||
197 | * less than @nbytes if the end of the file was reached). | ||
198 | */ | ||
199 | static ssize_t fnic_trace_debugfs_read(struct file *file, | ||
200 | char __user *ubuf, | ||
201 | size_t nbytes, | ||
202 | loff_t *pos) | ||
203 | { | ||
204 | fnic_dbgfs_t *fnic_dbg_prt = file->private_data; | ||
205 | int rc = 0; | ||
206 | rc = simple_read_from_buffer(ubuf, nbytes, pos, | ||
207 | fnic_dbg_prt->buffer, | ||
208 | fnic_dbg_prt->buffer_len); | ||
209 | return rc; | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | * fnic_trace_debugfs_release - Release the buffer used to store | ||
214 | * debugfs file data | ||
215 | * @inode: The inode pointer | ||
216 | * @file: The file pointer that contains the buffer to release | ||
217 | * | ||
218 | * Description: | ||
219 | * This routine frees the buffer that was allocated when the debugfs | ||
220 | * file was opened. | ||
221 | * | ||
222 | * Returns: | ||
223 | * This function returns zero. | ||
224 | */ | ||
225 | static int fnic_trace_debugfs_release(struct inode *inode, | ||
226 | struct file *file) | ||
227 | { | ||
228 | fnic_dbgfs_t *fnic_dbg_prt = file->private_data; | ||
229 | |||
230 | vfree(fnic_dbg_prt->buffer); | ||
231 | kfree(fnic_dbg_prt); | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static const struct file_operations fnic_trace_ctrl_fops = { | ||
236 | .owner = THIS_MODULE, | ||
237 | .open = fnic_trace_ctrl_open, | ||
238 | .read = fnic_trace_ctrl_read, | ||
239 | .write = fnic_trace_ctrl_write, | ||
240 | }; | ||
241 | |||
242 | static const struct file_operations fnic_trace_debugfs_fops = { | ||
243 | .owner = THIS_MODULE, | ||
244 | .open = fnic_trace_debugfs_open, | ||
245 | .llseek = fnic_trace_debugfs_lseek, | ||
246 | .read = fnic_trace_debugfs_read, | ||
247 | .release = fnic_trace_debugfs_release, | ||
248 | }; | ||
249 | |||
250 | /* | ||
251 | * fnic_trace_debugfs_init - Initialize debugfs for fnic trace logging | ||
252 | * | ||
253 | * Description: | ||
254 | * When Debugfs is configured this routine sets up the fnic debugfs | ||
255 | * file system. If not already created, this routine will create the | ||
256 | * fnic directory. It will create file trace to log fnic trace buffer | ||
257 | * output into debugfs and it will also create file trace_enable to | ||
258 | * control enable/disable of trace logging into trace buffer. | ||
259 | */ | ||
260 | int fnic_trace_debugfs_init(void) | ||
261 | { | ||
262 | int rc = -1; | ||
263 | fnic_trace_debugfs_root = debugfs_create_dir("fnic", NULL); | ||
264 | if (!fnic_trace_debugfs_root) { | ||
265 | printk(KERN_DEBUG "Cannot create debugfs root\n"); | ||
266 | return rc; | ||
267 | } | ||
268 | fnic_trace_enable = debugfs_create_file("tracing_enable", | ||
269 | S_IFREG|S_IRUGO|S_IWUSR, | ||
270 | fnic_trace_debugfs_root, | ||
271 | NULL, &fnic_trace_ctrl_fops); | ||
272 | |||
273 | if (!fnic_trace_enable) { | ||
274 | printk(KERN_DEBUG "Cannot create trace_enable file" | ||
275 | " under debugfs"); | ||
276 | return rc; | ||
277 | } | ||
278 | |||
279 | fnic_trace_debugfs_file = debugfs_create_file("trace", | ||
280 | S_IFREG|S_IRUGO|S_IWUSR, | ||
281 | fnic_trace_debugfs_root, | ||
282 | NULL, | ||
283 | &fnic_trace_debugfs_fops); | ||
284 | |||
285 | if (!fnic_trace_debugfs_file) { | ||
286 | printk(KERN_DEBUG "Cannot create trace file under debugfs"); | ||
287 | return rc; | ||
288 | } | ||
289 | rc = 0; | ||
290 | return rc; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * fnic_trace_debugfs_terminate - Tear down debugfs infrastructure | ||
295 | * | ||
296 | * Description: | ||
297 | * When Debugfs is configured this routine removes debugfs file system | ||
298 | * elements that are specific to fnic trace logging. | ||
299 | */ | ||
300 | void fnic_trace_debugfs_terminate(void) | ||
301 | { | ||
302 | if (fnic_trace_debugfs_file) { | ||
303 | debugfs_remove(fnic_trace_debugfs_file); | ||
304 | fnic_trace_debugfs_file = NULL; | ||
305 | } | ||
306 | if (fnic_trace_enable) { | ||
307 | debugfs_remove(fnic_trace_enable); | ||
308 | fnic_trace_enable = NULL; | ||
309 | } | ||
310 | if (fnic_trace_debugfs_root) { | ||
311 | debugfs_remove(fnic_trace_debugfs_root); | ||
312 | fnic_trace_debugfs_root = NULL; | ||
313 | } | ||
314 | } | ||
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index fcecbb7281aa..d601ac543c52 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c | |||
@@ -68,6 +68,10 @@ unsigned int fnic_log_level; | |||
68 | module_param(fnic_log_level, int, S_IRUGO|S_IWUSR); | 68 | module_param(fnic_log_level, int, S_IRUGO|S_IWUSR); |
69 | MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels"); | 69 | MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels"); |
70 | 70 | ||
71 | unsigned int fnic_trace_max_pages = 16; | ||
72 | module_param(fnic_trace_max_pages, uint, S_IRUGO|S_IWUSR); | ||
73 | MODULE_PARM_DESC(fnic_trace_max_pages, "Total allocated memory pages " | ||
74 | "for fnic trace buffer"); | ||
71 | 75 | ||
72 | static struct libfc_function_template fnic_transport_template = { | 76 | static struct libfc_function_template fnic_transport_template = { |
73 | .frame_send = fnic_send, | 77 | .frame_send = fnic_send, |
@@ -861,6 +865,14 @@ static int __init fnic_init_module(void) | |||
861 | 865 | ||
862 | printk(KERN_INFO PFX "%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION); | 866 | printk(KERN_INFO PFX "%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION); |
863 | 867 | ||
868 | /* Allocate memory for trace buffer */ | ||
869 | err = fnic_trace_buf_init(); | ||
870 | if (err < 0) { | ||
871 | printk(KERN_ERR PFX "Trace buffer initialization Failed " | ||
872 | "Fnic Tracing utility is disabled\n"); | ||
873 | fnic_trace_free(); | ||
874 | } | ||
875 | |||
864 | /* Create a cache for allocation of default size sgls */ | 876 | /* Create a cache for allocation of default size sgls */ |
865 | len = sizeof(struct fnic_dflt_sgl_list); | 877 | len = sizeof(struct fnic_dflt_sgl_list); |
866 | fnic_sgl_cache[FNIC_SGL_CACHE_DFLT] = kmem_cache_create | 878 | fnic_sgl_cache[FNIC_SGL_CACHE_DFLT] = kmem_cache_create |
@@ -931,6 +943,7 @@ err_create_fnic_ioreq_slab: | |||
931 | err_create_fnic_sgl_slab_max: | 943 | err_create_fnic_sgl_slab_max: |
932 | kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); | 944 | kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); |
933 | err_create_fnic_sgl_slab_dflt: | 945 | err_create_fnic_sgl_slab_dflt: |
946 | fnic_trace_free(); | ||
934 | return err; | 947 | return err; |
935 | } | 948 | } |
936 | 949 | ||
@@ -942,6 +955,7 @@ static void __exit fnic_cleanup_module(void) | |||
942 | kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); | 955 | kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); |
943 | kmem_cache_destroy(fnic_io_req_cache); | 956 | kmem_cache_destroy(fnic_io_req_cache); |
944 | fc_release_transport(fnic_fc_transport); | 957 | fc_release_transport(fnic_fc_transport); |
958 | fnic_trace_free(); | ||
945 | } | 959 | } |
946 | 960 | ||
947 | module_init(fnic_init_module); | 961 | module_init(fnic_init_module); |
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 7cb653309125..be99e7549d89 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c | |||
@@ -393,11 +393,12 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ | |||
393 | { | 393 | { |
394 | struct fc_lport *lp = shost_priv(sc->device->host); | 394 | struct fc_lport *lp = shost_priv(sc->device->host); |
395 | struct fc_rport *rport; | 395 | struct fc_rport *rport; |
396 | struct fnic_io_req *io_req; | 396 | struct fnic_io_req *io_req = NULL; |
397 | struct fnic *fnic = lport_priv(lp); | 397 | struct fnic *fnic = lport_priv(lp); |
398 | struct vnic_wq_copy *wq; | 398 | struct vnic_wq_copy *wq; |
399 | int ret; | 399 | int ret; |
400 | int sg_count; | 400 | u64 cmd_trace; |
401 | int sg_count = 0; | ||
401 | unsigned long flags; | 402 | unsigned long flags; |
402 | unsigned long ptr; | 403 | unsigned long ptr; |
403 | 404 | ||
@@ -437,6 +438,9 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ | |||
437 | /* Map the data buffer */ | 438 | /* Map the data buffer */ |
438 | sg_count = scsi_dma_map(sc); | 439 | sg_count = scsi_dma_map(sc); |
439 | if (sg_count < 0) { | 440 | if (sg_count < 0) { |
441 | FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, | ||
442 | sc->request->tag, sc, 0, sc->cmnd[0], | ||
443 | sg_count, CMD_STATE(sc)); | ||
440 | mempool_free(io_req, fnic->io_req_pool); | 444 | mempool_free(io_req, fnic->io_req_pool); |
441 | goto out; | 445 | goto out; |
442 | } | 446 | } |
@@ -486,7 +490,9 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ | |||
486 | * refetch the pointer under the lock. | 490 | * refetch the pointer under the lock. |
487 | */ | 491 | */ |
488 | spinlock_t *io_lock = fnic_io_lock_hash(fnic, sc); | 492 | spinlock_t *io_lock = fnic_io_lock_hash(fnic, sc); |
489 | 493 | FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, | |
494 | sc->request->tag, sc, 0, 0, 0, | ||
495 | (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); | ||
490 | spin_lock_irqsave(io_lock, flags); | 496 | spin_lock_irqsave(io_lock, flags); |
491 | io_req = (struct fnic_io_req *)CMD_SP(sc); | 497 | io_req = (struct fnic_io_req *)CMD_SP(sc); |
492 | CMD_SP(sc) = NULL; | 498 | CMD_SP(sc) = NULL; |
@@ -501,6 +507,15 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_ | |||
501 | CMD_FLAGS(sc) |= FNIC_IO_ISSUED; | 507 | CMD_FLAGS(sc) |= FNIC_IO_ISSUED; |
502 | } | 508 | } |
503 | out: | 509 | out: |
510 | cmd_trace = ((u64)sc->cmnd[0] << 56 | (u64)sc->cmnd[7] << 40 | | ||
511 | (u64)sc->cmnd[8] << 32 | (u64)sc->cmnd[2] << 24 | | ||
512 | (u64)sc->cmnd[3] << 16 | (u64)sc->cmnd[4] << 8 | | ||
513 | sc->cmnd[5]); | ||
514 | |||
515 | FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, | ||
516 | sc->request->tag, sc, io_req, | ||
517 | sg_count, cmd_trace, | ||
518 | (((u64)CMD_FLAGS(sc) >> 32) | CMD_STATE(sc))); | ||
504 | atomic_dec(&fnic->in_flight); | 519 | atomic_dec(&fnic->in_flight); |
505 | /* acquire host lock before returning to SCSI */ | 520 | /* acquire host lock before returning to SCSI */ |
506 | spin_lock(lp->host->host_lock); | 521 | spin_lock(lp->host->host_lock); |
@@ -674,6 +689,7 @@ static inline void fnic_fcpio_ack_handler(struct fnic *fnic, | |||
674 | struct vnic_wq_copy *wq; | 689 | struct vnic_wq_copy *wq; |
675 | u16 request_out = desc->u.ack.request_out; | 690 | u16 request_out = desc->u.ack.request_out; |
676 | unsigned long flags; | 691 | unsigned long flags; |
692 | u64 *ox_id_tag = (u64 *)(void *)desc; | ||
677 | 693 | ||
678 | /* mark the ack state */ | 694 | /* mark the ack state */ |
679 | wq = &fnic->wq_copy[cq_index - fnic->raw_wq_count - fnic->rq_count]; | 695 | wq = &fnic->wq_copy[cq_index - fnic->raw_wq_count - fnic->rq_count]; |
@@ -684,6 +700,9 @@ static inline void fnic_fcpio_ack_handler(struct fnic *fnic, | |||
684 | fnic->fw_ack_recd[0] = 1; | 700 | fnic->fw_ack_recd[0] = 1; |
685 | } | 701 | } |
686 | spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); | 702 | spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); |
703 | FNIC_TRACE(fnic_fcpio_ack_handler, | ||
704 | fnic->lport->host->host_no, 0, 0, ox_id_tag[2], ox_id_tag[3], | ||
705 | ox_id_tag[4], ox_id_tag[5]); | ||
687 | } | 706 | } |
688 | 707 | ||
689 | /* | 708 | /* |
@@ -703,6 +722,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, | |||
703 | struct scsi_cmnd *sc; | 722 | struct scsi_cmnd *sc; |
704 | unsigned long flags; | 723 | unsigned long flags; |
705 | spinlock_t *io_lock; | 724 | spinlock_t *io_lock; |
725 | u64 cmd_trace; | ||
706 | unsigned long start_time; | 726 | unsigned long start_time; |
707 | 727 | ||
708 | /* Decode the cmpl description to get the io_req id */ | 728 | /* Decode the cmpl description to get the io_req id */ |
@@ -724,6 +744,14 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, | |||
724 | "icmnd_cmpl sc is null - " | 744 | "icmnd_cmpl sc is null - " |
725 | "hdr status = %s tag = 0x%x desc = 0x%p\n", | 745 | "hdr status = %s tag = 0x%x desc = 0x%p\n", |
726 | fnic_fcpio_status_to_str(hdr_status), id, desc); | 746 | fnic_fcpio_status_to_str(hdr_status), id, desc); |
747 | FNIC_TRACE(fnic_fcpio_icmnd_cmpl_handler, | ||
748 | fnic->lport->host->host_no, id, | ||
749 | ((u64)icmnd_cmpl->_resvd0[1] << 16 | | ||
750 | (u64)icmnd_cmpl->_resvd0[0]), | ||
751 | ((u64)hdr_status << 16 | | ||
752 | (u64)icmnd_cmpl->scsi_status << 8 | | ||
753 | (u64)icmnd_cmpl->flags), desc, | ||
754 | (u64)icmnd_cmpl->residual, 0); | ||
727 | return; | 755 | return; |
728 | } | 756 | } |
729 | 757 | ||
@@ -864,6 +892,20 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, | |||
864 | 892 | ||
865 | mempool_free(io_req, fnic->io_req_pool); | 893 | mempool_free(io_req, fnic->io_req_pool); |
866 | 894 | ||
895 | cmd_trace = ((u64)hdr_status << 56) | | ||
896 | (u64)icmnd_cmpl->scsi_status << 48 | | ||
897 | (u64)icmnd_cmpl->flags << 40 | (u64)sc->cmnd[0] << 32 | | ||
898 | (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | | ||
899 | (u64)sc->cmnd[4] << 8 | sc->cmnd[5]; | ||
900 | |||
901 | FNIC_TRACE(fnic_fcpio_icmnd_cmpl_handler, | ||
902 | sc->device->host->host_no, id, sc, | ||
903 | ((u64)icmnd_cmpl->_resvd0[1] << 56 | | ||
904 | (u64)icmnd_cmpl->_resvd0[0] << 48 | | ||
905 | jiffies_to_msecs(jiffies - start_time)), | ||
906 | desc, cmd_trace, | ||
907 | (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); | ||
908 | |||
867 | if (sc->sc_data_direction == DMA_FROM_DEVICE) { | 909 | if (sc->sc_data_direction == DMA_FROM_DEVICE) { |
868 | fnic->lport->host_stats.fcp_input_requests++; | 910 | fnic->lport->host_stats.fcp_input_requests++; |
869 | fnic->fcp_input_bytes += xfer_len; | 911 | fnic->fcp_input_bytes += xfer_len; |
@@ -876,7 +918,6 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, | |||
876 | /* Call SCSI completion function to complete the IO */ | 918 | /* Call SCSI completion function to complete the IO */ |
877 | if (sc->scsi_done) | 919 | if (sc->scsi_done) |
878 | sc->scsi_done(sc); | 920 | sc->scsi_done(sc); |
879 | |||
880 | } | 921 | } |
881 | 922 | ||
882 | /* fnic_fcpio_itmf_cmpl_handler | 923 | /* fnic_fcpio_itmf_cmpl_handler |
@@ -974,8 +1015,21 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, | |||
974 | 1015 | ||
975 | fnic_release_ioreq_buf(fnic, io_req, sc); | 1016 | fnic_release_ioreq_buf(fnic, io_req, sc); |
976 | mempool_free(io_req, fnic->io_req_pool); | 1017 | mempool_free(io_req, fnic->io_req_pool); |
977 | if (sc->scsi_done) | 1018 | if (sc->scsi_done) { |
1019 | FNIC_TRACE(fnic_fcpio_itmf_cmpl_handler, | ||
1020 | sc->device->host->host_no, id, | ||
1021 | sc, | ||
1022 | jiffies_to_msecs(jiffies - start_time), | ||
1023 | desc, | ||
1024 | (((u64)hdr_status << 40) | | ||
1025 | (u64)sc->cmnd[0] << 32 | | ||
1026 | (u64)sc->cmnd[2] << 24 | | ||
1027 | (u64)sc->cmnd[3] << 16 | | ||
1028 | (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), | ||
1029 | (((u64)CMD_FLAGS(sc) << 32) | | ||
1030 | CMD_STATE(sc))); | ||
978 | sc->scsi_done(sc); | 1031 | sc->scsi_done(sc); |
1032 | } | ||
979 | } | 1033 | } |
980 | 1034 | ||
981 | } else if (id & FNIC_TAG_DEV_RST) { | 1035 | } else if (id & FNIC_TAG_DEV_RST) { |
@@ -984,6 +1038,11 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, | |||
984 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { | 1038 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { |
985 | spin_unlock_irqrestore(io_lock, flags); | 1039 | spin_unlock_irqrestore(io_lock, flags); |
986 | CMD_FLAGS(sc) |= FNIC_DEV_RST_ABTS_PENDING; | 1040 | CMD_FLAGS(sc) |= FNIC_DEV_RST_ABTS_PENDING; |
1041 | FNIC_TRACE(fnic_fcpio_itmf_cmpl_handler, | ||
1042 | sc->device->host->host_no, id, sc, | ||
1043 | jiffies_to_msecs(jiffies - start_time), | ||
1044 | desc, 0, | ||
1045 | (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); | ||
987 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | 1046 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, |
988 | "Terminate pending " | 1047 | "Terminate pending " |
989 | "dev reset cmpl recd. id %d status %s\n", | 1048 | "dev reset cmpl recd. id %d status %s\n", |
@@ -994,6 +1053,11 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, | |||
994 | if (CMD_FLAGS(sc) & FNIC_DEV_RST_TIMED_OUT) { | 1053 | if (CMD_FLAGS(sc) & FNIC_DEV_RST_TIMED_OUT) { |
995 | /* Need to wait for terminate completion */ | 1054 | /* Need to wait for terminate completion */ |
996 | spin_unlock_irqrestore(io_lock, flags); | 1055 | spin_unlock_irqrestore(io_lock, flags); |
1056 | FNIC_TRACE(fnic_fcpio_itmf_cmpl_handler, | ||
1057 | sc->device->host->host_no, id, sc, | ||
1058 | jiffies_to_msecs(jiffies - start_time), | ||
1059 | desc, 0, | ||
1060 | (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); | ||
997 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | 1061 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, |
998 | "dev reset cmpl recd after time out. " | 1062 | "dev reset cmpl recd after time out. " |
999 | "id %d status %s\n", | 1063 | "id %d status %s\n", |
@@ -1142,8 +1206,18 @@ cleanup_scsi_cmd: | |||
1142 | " DID_TRANSPORT_DISRUPTED\n"); | 1206 | " DID_TRANSPORT_DISRUPTED\n"); |
1143 | 1207 | ||
1144 | /* Complete the command to SCSI */ | 1208 | /* Complete the command to SCSI */ |
1145 | if (sc->scsi_done) | 1209 | if (sc->scsi_done) { |
1210 | FNIC_TRACE(fnic_cleanup_io, | ||
1211 | sc->device->host->host_no, i, sc, | ||
1212 | jiffies_to_msecs(jiffies - start_time), | ||
1213 | 0, ((u64)sc->cmnd[0] << 32 | | ||
1214 | (u64)sc->cmnd[2] << 24 | | ||
1215 | (u64)sc->cmnd[3] << 16 | | ||
1216 | (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), | ||
1217 | (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); | ||
1218 | |||
1146 | sc->scsi_done(sc); | 1219 | sc->scsi_done(sc); |
1220 | } | ||
1147 | } | 1221 | } |
1148 | } | 1222 | } |
1149 | 1223 | ||
@@ -1195,8 +1269,17 @@ wq_copy_cleanup_scsi_cmd: | |||
1195 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "wq_copy_cleanup_handler:" | 1269 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "wq_copy_cleanup_handler:" |
1196 | " DID_NO_CONNECT\n"); | 1270 | " DID_NO_CONNECT\n"); |
1197 | 1271 | ||
1198 | if (sc->scsi_done) | 1272 | if (sc->scsi_done) { |
1273 | FNIC_TRACE(fnic_wq_copy_cleanup_handler, | ||
1274 | sc->device->host->host_no, id, sc, | ||
1275 | jiffies_to_msecs(jiffies - start_time), | ||
1276 | 0, ((u64)sc->cmnd[0] << 32 | | ||
1277 | (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | | ||
1278 | (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), | ||
1279 | (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); | ||
1280 | |||
1199 | sc->scsi_done(sc); | 1281 | sc->scsi_done(sc); |
1282 | } | ||
1200 | } | 1283 | } |
1201 | 1284 | ||
1202 | static inline int fnic_queue_abort_io_req(struct fnic *fnic, int tag, | 1285 | static inline int fnic_queue_abort_io_req(struct fnic *fnic, int tag, |
@@ -1476,7 +1559,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) | |||
1476 | { | 1559 | { |
1477 | struct fc_lport *lp; | 1560 | struct fc_lport *lp; |
1478 | struct fnic *fnic; | 1561 | struct fnic *fnic; |
1479 | struct fnic_io_req *io_req; | 1562 | struct fnic_io_req *io_req = NULL; |
1480 | struct fc_rport *rport; | 1563 | struct fc_rport *rport; |
1481 | spinlock_t *io_lock; | 1564 | spinlock_t *io_lock; |
1482 | unsigned long flags; | 1565 | unsigned long flags; |
@@ -1503,7 +1586,6 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) | |||
1503 | 1586 | ||
1504 | CMD_FLAGS(sc) = FNIC_NO_FLAGS; | 1587 | CMD_FLAGS(sc) = FNIC_NO_FLAGS; |
1505 | 1588 | ||
1506 | |||
1507 | if (lp->state != LPORT_ST_READY || !(lp->link_up)) { | 1589 | if (lp->state != LPORT_ST_READY || !(lp->link_up)) { |
1508 | ret = FAILED; | 1590 | ret = FAILED; |
1509 | goto fnic_abort_cmd_end; | 1591 | goto fnic_abort_cmd_end; |
@@ -1621,6 +1703,14 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) | |||
1621 | mempool_free(io_req, fnic->io_req_pool); | 1703 | mempool_free(io_req, fnic->io_req_pool); |
1622 | 1704 | ||
1623 | fnic_abort_cmd_end: | 1705 | fnic_abort_cmd_end: |
1706 | FNIC_TRACE(fnic_abort_cmd, sc->device->host->host_no, | ||
1707 | sc->request->tag, sc, | ||
1708 | jiffies_to_msecs(jiffies - start_time), | ||
1709 | 0, ((u64)sc->cmnd[0] << 32 | | ||
1710 | (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | | ||
1711 | (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), | ||
1712 | (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); | ||
1713 | |||
1624 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | 1714 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, |
1625 | "Returning from abort cmd type %x %s\n", task_req, | 1715 | "Returning from abort cmd type %x %s\n", task_req, |
1626 | (ret == SUCCESS) ? | 1716 | (ret == SUCCESS) ? |
@@ -1891,7 +1981,7 @@ int fnic_device_reset(struct scsi_cmnd *sc) | |||
1891 | { | 1981 | { |
1892 | struct fc_lport *lp; | 1982 | struct fc_lport *lp; |
1893 | struct fnic *fnic; | 1983 | struct fnic *fnic; |
1894 | struct fnic_io_req *io_req; | 1984 | struct fnic_io_req *io_req = NULL; |
1895 | struct fc_rport *rport; | 1985 | struct fc_rport *rport; |
1896 | int status; | 1986 | int status; |
1897 | int ret = FAILED; | 1987 | int ret = FAILED; |
@@ -1899,7 +1989,7 @@ int fnic_device_reset(struct scsi_cmnd *sc) | |||
1899 | unsigned long flags; | 1989 | unsigned long flags; |
1900 | unsigned long start_time = 0; | 1990 | unsigned long start_time = 0; |
1901 | struct scsi_lun fc_lun; | 1991 | struct scsi_lun fc_lun; |
1902 | int tag; | 1992 | int tag = 0; |
1903 | DECLARE_COMPLETION_ONSTACK(tm_done); | 1993 | DECLARE_COMPLETION_ONSTACK(tm_done); |
1904 | int tag_gen_flag = 0; /*to track tags allocated by fnic driver*/ | 1994 | int tag_gen_flag = 0; /*to track tags allocated by fnic driver*/ |
1905 | 1995 | ||
@@ -2094,6 +2184,14 @@ fnic_device_reset_clean: | |||
2094 | } | 2184 | } |
2095 | 2185 | ||
2096 | fnic_device_reset_end: | 2186 | fnic_device_reset_end: |
2187 | FNIC_TRACE(fnic_device_reset, sc->device->host->host_no, | ||
2188 | sc->request->tag, sc, | ||
2189 | jiffies_to_msecs(jiffies - start_time), | ||
2190 | 0, ((u64)sc->cmnd[0] << 32 | | ||
2191 | (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | | ||
2192 | (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), | ||
2193 | (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); | ||
2194 | |||
2097 | /* free tag if it is allocated */ | 2195 | /* free tag if it is allocated */ |
2098 | if (unlikely(tag_gen_flag)) | 2196 | if (unlikely(tag_gen_flag)) |
2099 | fnic_scsi_host_end_tag(fnic, sc); | 2197 | fnic_scsi_host_end_tag(fnic, sc); |
diff --git a/drivers/scsi/fnic/fnic_trace.c b/drivers/scsi/fnic/fnic_trace.c new file mode 100644 index 000000000000..23a60e3d8527 --- /dev/null +++ b/drivers/scsi/fnic/fnic_trace.c | |||
@@ -0,0 +1,273 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Cisco Systems, Inc. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you may redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; version 2 of the License. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
9 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
10 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
11 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
12 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
15 | * SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/mempool.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/spinlock.h> | ||
22 | #include <linux/kallsyms.h> | ||
23 | #include "fnic_io.h" | ||
24 | #include "fnic.h" | ||
25 | |||
26 | unsigned int trace_max_pages; | ||
27 | static int fnic_max_trace_entries; | ||
28 | |||
29 | static unsigned long fnic_trace_buf_p; | ||
30 | static DEFINE_SPINLOCK(fnic_trace_lock); | ||
31 | |||
32 | static fnic_trace_dbg_t fnic_trace_entries; | ||
33 | int fnic_tracing_enabled = 1; | ||
34 | |||
35 | /* | ||
36 | * fnic_trace_get_buf - Give buffer pointer to user to fill up trace information | ||
37 | * | ||
38 | * Description: | ||
39 | * This routine gets next available trace buffer entry location @wr_idx | ||
40 | * from allocated trace buffer pages and give that memory location | ||
41 | * to user to store the trace information. | ||
42 | * | ||
43 | * Return Value: | ||
44 | * This routine returns pointer to next available trace entry | ||
45 | * @fnic_buf_head for user to fill trace information. | ||
46 | */ | ||
47 | fnic_trace_data_t *fnic_trace_get_buf(void) | ||
48 | { | ||
49 | unsigned long fnic_buf_head; | ||
50 | unsigned long flags; | ||
51 | |||
52 | spin_lock_irqsave(&fnic_trace_lock, flags); | ||
53 | |||
54 | /* | ||
55 | * Get next available memory location for writing trace information | ||
56 | * at @wr_idx and increment @wr_idx | ||
57 | */ | ||
58 | fnic_buf_head = | ||
59 | fnic_trace_entries.page_offset[fnic_trace_entries.wr_idx]; | ||
60 | fnic_trace_entries.wr_idx++; | ||
61 | |||
62 | /* | ||
63 | * Verify if trace buffer is full then change wd_idx to | ||
64 | * start from zero | ||
65 | */ | ||
66 | if (fnic_trace_entries.wr_idx >= fnic_max_trace_entries) | ||
67 | fnic_trace_entries.wr_idx = 0; | ||
68 | |||
69 | /* | ||
70 | * Verify if write index @wr_idx and read index @rd_idx are same then | ||
71 | * increment @rd_idx to move to next entry in trace buffer | ||
72 | */ | ||
73 | if (fnic_trace_entries.wr_idx == fnic_trace_entries.rd_idx) { | ||
74 | fnic_trace_entries.rd_idx++; | ||
75 | if (fnic_trace_entries.rd_idx >= fnic_max_trace_entries) | ||
76 | fnic_trace_entries.rd_idx = 0; | ||
77 | } | ||
78 | spin_unlock_irqrestore(&fnic_trace_lock, flags); | ||
79 | return (fnic_trace_data_t *)fnic_buf_head; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * fnic_get_trace_data - Copy trace buffer to a memory file | ||
84 | * @fnic_dbgfs_t: pointer to debugfs trace buffer | ||
85 | * | ||
86 | * Description: | ||
87 | * This routine gathers the fnic trace debugfs data from the fnic_trace_data_t | ||
88 | * buffer and dumps it to fnic_dbgfs_t. It will start at the rd_idx entry in | ||
89 | * the log and process the log until the end of the buffer. Then it will gather | ||
90 | * from the beginning of the log and process until the current entry @wr_idx. | ||
91 | * | ||
92 | * Return Value: | ||
93 | * This routine returns the amount of bytes that were dumped into fnic_dbgfs_t | ||
94 | */ | ||
95 | int fnic_get_trace_data(fnic_dbgfs_t *fnic_dbgfs_prt) | ||
96 | { | ||
97 | int rd_idx; | ||
98 | int wr_idx; | ||
99 | int len = 0; | ||
100 | unsigned long flags; | ||
101 | char str[KSYM_SYMBOL_LEN]; | ||
102 | struct timespec val; | ||
103 | fnic_trace_data_t *tbp; | ||
104 | |||
105 | spin_lock_irqsave(&fnic_trace_lock, flags); | ||
106 | rd_idx = fnic_trace_entries.rd_idx; | ||
107 | wr_idx = fnic_trace_entries.wr_idx; | ||
108 | if (wr_idx < rd_idx) { | ||
109 | while (1) { | ||
110 | /* Start from read index @rd_idx */ | ||
111 | tbp = (fnic_trace_data_t *) | ||
112 | fnic_trace_entries.page_offset[rd_idx]; | ||
113 | if (!tbp) { | ||
114 | spin_unlock_irqrestore(&fnic_trace_lock, flags); | ||
115 | return 0; | ||
116 | } | ||
117 | /* Convert function pointer to function name */ | ||
118 | if (sizeof(unsigned long) < 8) { | ||
119 | sprint_symbol(str, tbp->fnaddr.low); | ||
120 | jiffies_to_timespec(tbp->timestamp.low, &val); | ||
121 | } else { | ||
122 | sprint_symbol(str, tbp->fnaddr.val); | ||
123 | jiffies_to_timespec(tbp->timestamp.val, &val); | ||
124 | } | ||
125 | /* | ||
126 | * Dump trace buffer entry to memory file | ||
127 | * and increment read index @rd_idx | ||
128 | */ | ||
129 | len += snprintf(fnic_dbgfs_prt->buffer + len, | ||
130 | (trace_max_pages * PAGE_SIZE * 3) - len, | ||
131 | "%16lu.%16lu %-50s %8x %8x %16llx %16llx " | ||
132 | "%16llx %16llx %16llx\n", val.tv_sec, | ||
133 | val.tv_nsec, str, tbp->host_no, tbp->tag, | ||
134 | tbp->data[0], tbp->data[1], tbp->data[2], | ||
135 | tbp->data[3], tbp->data[4]); | ||
136 | rd_idx++; | ||
137 | /* | ||
138 | * If rd_idx is reached to maximum trace entries | ||
139 | * then move rd_idx to zero | ||
140 | */ | ||
141 | if (rd_idx > (fnic_max_trace_entries-1)) | ||
142 | rd_idx = 0; | ||
143 | /* | ||
144 | * Continure dumpping trace buffer entries into | ||
145 | * memory file till rd_idx reaches write index | ||
146 | */ | ||
147 | if (rd_idx == wr_idx) | ||
148 | break; | ||
149 | } | ||
150 | } else if (wr_idx > rd_idx) { | ||
151 | while (1) { | ||
152 | /* Start from read index @rd_idx */ | ||
153 | tbp = (fnic_trace_data_t *) | ||
154 | fnic_trace_entries.page_offset[rd_idx]; | ||
155 | if (!tbp) { | ||
156 | spin_unlock_irqrestore(&fnic_trace_lock, flags); | ||
157 | return 0; | ||
158 | } | ||
159 | /* Convert function pointer to function name */ | ||
160 | if (sizeof(unsigned long) < 8) { | ||
161 | sprint_symbol(str, tbp->fnaddr.low); | ||
162 | jiffies_to_timespec(tbp->timestamp.low, &val); | ||
163 | } else { | ||
164 | sprint_symbol(str, tbp->fnaddr.val); | ||
165 | jiffies_to_timespec(tbp->timestamp.val, &val); | ||
166 | } | ||
167 | /* | ||
168 | * Dump trace buffer entry to memory file | ||
169 | * and increment read index @rd_idx | ||
170 | */ | ||
171 | len += snprintf(fnic_dbgfs_prt->buffer + len, | ||
172 | (trace_max_pages * PAGE_SIZE * 3) - len, | ||
173 | "%16lu.%16lu %-50s %8x %8x %16llx %16llx " | ||
174 | "%16llx %16llx %16llx\n", val.tv_sec, | ||
175 | val.tv_nsec, str, tbp->host_no, tbp->tag, | ||
176 | tbp->data[0], tbp->data[1], tbp->data[2], | ||
177 | tbp->data[3], tbp->data[4]); | ||
178 | rd_idx++; | ||
179 | /* | ||
180 | * Continue dumpping trace buffer entries into | ||
181 | * memory file till rd_idx reaches write index | ||
182 | */ | ||
183 | if (rd_idx == wr_idx) | ||
184 | break; | ||
185 | } | ||
186 | } | ||
187 | spin_unlock_irqrestore(&fnic_trace_lock, flags); | ||
188 | return len; | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * fnic_trace_buf_init - Initialize fnic trace buffer logging facility | ||
193 | * | ||
194 | * Description: | ||
195 | * Initialize trace buffer data structure by allocating required memory and | ||
196 | * setting page_offset information for every trace entry by adding trace entry | ||
197 | * length to previous page_offset value. | ||
198 | */ | ||
199 | int fnic_trace_buf_init(void) | ||
200 | { | ||
201 | unsigned long fnic_buf_head; | ||
202 | int i; | ||
203 | int err = 0; | ||
204 | |||
205 | trace_max_pages = fnic_trace_max_pages; | ||
206 | fnic_max_trace_entries = (trace_max_pages * PAGE_SIZE)/ | ||
207 | FNIC_ENTRY_SIZE_BYTES; | ||
208 | |||
209 | fnic_trace_buf_p = (unsigned long)vmalloc((trace_max_pages * PAGE_SIZE)); | ||
210 | if (!fnic_trace_buf_p) { | ||
211 | printk(KERN_ERR PFX "Failed to allocate memory " | ||
212 | "for fnic_trace_buf_p\n"); | ||
213 | err = -ENOMEM; | ||
214 | goto err_fnic_trace_buf_init; | ||
215 | } | ||
216 | memset((void *)fnic_trace_buf_p, 0, (trace_max_pages * PAGE_SIZE)); | ||
217 | |||
218 | fnic_trace_entries.page_offset = vmalloc(fnic_max_trace_entries * | ||
219 | sizeof(unsigned long)); | ||
220 | if (!fnic_trace_entries.page_offset) { | ||
221 | printk(KERN_ERR PFX "Failed to allocate memory for" | ||
222 | " page_offset\n"); | ||
223 | if (fnic_trace_buf_p) { | ||
224 | vfree((void *)fnic_trace_buf_p); | ||
225 | fnic_trace_buf_p = 0; | ||
226 | } | ||
227 | err = -ENOMEM; | ||
228 | goto err_fnic_trace_buf_init; | ||
229 | } | ||
230 | memset((void *)fnic_trace_entries.page_offset, 0, | ||
231 | (fnic_max_trace_entries * sizeof(unsigned long))); | ||
232 | fnic_trace_entries.wr_idx = fnic_trace_entries.rd_idx = 0; | ||
233 | fnic_buf_head = fnic_trace_buf_p; | ||
234 | |||
235 | /* | ||
236 | * Set page_offset field of fnic_trace_entries struct by | ||
237 | * calculating memory location for every trace entry using | ||
238 | * length of each trace entry | ||
239 | */ | ||
240 | for (i = 0; i < fnic_max_trace_entries; i++) { | ||
241 | fnic_trace_entries.page_offset[i] = fnic_buf_head; | ||
242 | fnic_buf_head += FNIC_ENTRY_SIZE_BYTES; | ||
243 | } | ||
244 | err = fnic_trace_debugfs_init(); | ||
245 | if (err < 0) { | ||
246 | printk(KERN_ERR PFX "Failed to initialize debugfs for tracing\n"); | ||
247 | goto err_fnic_trace_debugfs_init; | ||
248 | } | ||
249 | printk(KERN_INFO PFX "Successfully Initialized Trace Buffer\n"); | ||
250 | return err; | ||
251 | err_fnic_trace_debugfs_init: | ||
252 | fnic_trace_free(); | ||
253 | err_fnic_trace_buf_init: | ||
254 | return err; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * fnic_trace_free - Free memory of fnic trace data structures. | ||
259 | */ | ||
260 | void fnic_trace_free(void) | ||
261 | { | ||
262 | fnic_tracing_enabled = 0; | ||
263 | fnic_trace_debugfs_terminate(); | ||
264 | if (fnic_trace_entries.page_offset) { | ||
265 | vfree((void *)fnic_trace_entries.page_offset); | ||
266 | fnic_trace_entries.page_offset = NULL; | ||
267 | } | ||
268 | if (fnic_trace_buf_p) { | ||
269 | vfree((void *)fnic_trace_buf_p); | ||
270 | fnic_trace_buf_p = 0; | ||
271 | } | ||
272 | printk(KERN_INFO PFX "Successfully Freed Trace Buffer\n"); | ||
273 | } | ||
diff --git a/drivers/scsi/fnic/fnic_trace.h b/drivers/scsi/fnic/fnic_trace.h new file mode 100644 index 000000000000..cef42b4c4d6c --- /dev/null +++ b/drivers/scsi/fnic/fnic_trace.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Cisco Systems, Inc. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you may redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; version 2 of the License. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
9 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
10 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
11 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
12 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
15 | * SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #ifndef __FNIC_TRACE_H__ | ||
19 | #define __FNIC_TRACE_H__ | ||
20 | |||
21 | #define FNIC_ENTRY_SIZE_BYTES 64 | ||
22 | |||
23 | extern ssize_t simple_read_from_buffer(void __user *to, | ||
24 | size_t count, | ||
25 | loff_t *ppos, | ||
26 | const void *from, | ||
27 | size_t available); | ||
28 | |||
29 | extern unsigned int fnic_trace_max_pages; | ||
30 | extern int fnic_tracing_enabled; | ||
31 | extern unsigned int trace_max_pages; | ||
32 | |||
33 | typedef struct fnic_trace_dbg { | ||
34 | int wr_idx; | ||
35 | int rd_idx; | ||
36 | unsigned long *page_offset; | ||
37 | } fnic_trace_dbg_t; | ||
38 | |||
39 | typedef struct fnic_dbgfs { | ||
40 | int buffer_len; | ||
41 | char *buffer; | ||
42 | } fnic_dbgfs_t; | ||
43 | |||
44 | struct fnic_trace_data { | ||
45 | union { | ||
46 | struct { | ||
47 | u32 low; | ||
48 | u32 high; | ||
49 | }; | ||
50 | u64 val; | ||
51 | } timestamp, fnaddr; | ||
52 | u32 host_no; | ||
53 | u32 tag; | ||
54 | u64 data[5]; | ||
55 | } __attribute__((__packed__)); | ||
56 | |||
57 | typedef struct fnic_trace_data fnic_trace_data_t; | ||
58 | |||
59 | #define FNIC_TRACE_ENTRY_SIZE \ | ||
60 | (FNIC_ENTRY_SIZE_BYTES - sizeof(fnic_trace_data_t)) | ||
61 | |||
62 | #define FNIC_TRACE(_fn, _hn, _t, _a, _b, _c, _d, _e) \ | ||
63 | if (unlikely(fnic_tracing_enabled)) { \ | ||
64 | fnic_trace_data_t *trace_buf = fnic_trace_get_buf(); \ | ||
65 | if (trace_buf) { \ | ||
66 | if (sizeof(unsigned long) < 8) { \ | ||
67 | trace_buf->timestamp.low = jiffies; \ | ||
68 | trace_buf->fnaddr.low = (u32)(unsigned long)_fn; \ | ||
69 | } else { \ | ||
70 | trace_buf->timestamp.val = jiffies; \ | ||
71 | trace_buf->fnaddr.val = (u64)(unsigned long)_fn; \ | ||
72 | } \ | ||
73 | trace_buf->host_no = _hn; \ | ||
74 | trace_buf->tag = _t; \ | ||
75 | trace_buf->data[0] = (u64)(unsigned long)_a; \ | ||
76 | trace_buf->data[1] = (u64)(unsigned long)_b; \ | ||
77 | trace_buf->data[2] = (u64)(unsigned long)_c; \ | ||
78 | trace_buf->data[3] = (u64)(unsigned long)_d; \ | ||
79 | trace_buf->data[4] = (u64)(unsigned long)_e; \ | ||
80 | } \ | ||
81 | } | ||
82 | |||
83 | fnic_trace_data_t *fnic_trace_get_buf(void); | ||
84 | int fnic_get_trace_data(fnic_dbgfs_t *); | ||
85 | int fnic_trace_buf_init(void); | ||
86 | void fnic_trace_free(void); | ||
87 | int fnic_trace_debugfs_init(void); | ||
88 | void fnic_trace_debugfs_terminate(void); | ||
89 | |||
90 | #endif | ||