]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/scsi/lpfc/lpfc_debugfs.c
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[linux-2.6-omap-h63xx.git] / drivers / scsi / lpfc / lpfc_debugfs.c
1 /*******************************************************************
2  * This file is part of the Emulex Linux Device Driver for         *
3  * Fibre Channel Host Bus Adapters.                                *
4  * Copyright (C) 2007 Emulex.  All rights reserved.                *
5  * EMULEX and SLI are trademarks of Emulex.                        *
6  * www.emulex.com                                                  *
7  *                                                                 *
8  * This program is free software; you can redistribute it and/or   *
9  * modify it under the terms of version 2 of the GNU General       *
10  * Public License as published by the Free Software Foundation.    *
11  * This program is distributed in the hope that it will be useful. *
12  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND          *
13  * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,  *
14  * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE      *
15  * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
16  * TO BE LEGALLY INVALID.  See the GNU General Public License for  *
17  * more details, a copy of which can be found in the file COPYING  *
18  * included with this package.                                     *
19  *******************************************************************/
20
21 #include <linux/blkdev.h>
22 #include <linux/delay.h>
23 #include <linux/dma-mapping.h>
24 #include <linux/idr.h>
25 #include <linux/interrupt.h>
26 #include <linux/kthread.h>
27 #include <linux/pci.h>
28 #include <linux/spinlock.h>
29 #include <linux/ctype.h>
30 #include <linux/version.h>
31
32 #include <scsi/scsi.h>
33 #include <scsi/scsi_device.h>
34 #include <scsi/scsi_host.h>
35 #include <scsi/scsi_transport_fc.h>
36
37 #include "lpfc_hw.h"
38 #include "lpfc_sli.h"
39 #include "lpfc_disc.h"
40 #include "lpfc_scsi.h"
41 #include "lpfc.h"
42 #include "lpfc_logmsg.h"
43 #include "lpfc_crtn.h"
44 #include "lpfc_vport.h"
45 #include "lpfc_version.h"
46 #include "lpfc_vport.h"
47 #include "lpfc_debugfs.h"
48
49 #ifdef CONFIG_LPFC_DEBUG_FS
50 /* debugfs interface
51  *
52  * To access this interface the user should:
53  * # mkdir /debug
54  * # mount -t debugfs none /debug
55  *
56  * The lpfc debugfs directory hierachy is:
57  * lpfc/lpfcX/vportY
58  * where X is the lpfc hba unique_id
59  * where Y is the vport VPI on that hba
60  *
61  * Debugging services available per vport:
62  * discovery_trace
63  * This is an ACSII readable file that contains a trace of the last
64  * lpfc_debugfs_max_disc_trc events that happened on a specific vport.
65  * See lpfc_debugfs.h for different categories of
66  * discovery events. To enable the discovery trace, the following
67  * module parameters must be set:
68  * lpfc_debugfs_enable=1         Turns on lpfc debugfs filesystem support
69  * lpfc_debugfs_max_disc_trc=X   Where X is the event trace depth for
70  *                               EACH vport. X MUST also be a power of 2.
71  * lpfc_debugfs_mask_disc_trc=Y  Where Y is an event mask as defined in
72  *                               lpfc_debugfs.h .
73  */
74 static int lpfc_debugfs_enable = 0;
75 module_param(lpfc_debugfs_enable, int, 0);
76 MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services");
77
78 static int lpfc_debugfs_max_disc_trc = 0;  /* This MUST be a power of 2 */
79 module_param(lpfc_debugfs_max_disc_trc, int, 0);
80 MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc,
81         "Set debugfs discovery trace depth");
82
83 static int lpfc_debugfs_mask_disc_trc = 0;
84 module_param(lpfc_debugfs_mask_disc_trc, int, 0);
85 MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc,
86         "Set debugfs discovery trace mask");
87
88 #include <linux/debugfs.h>
89
90 /* size of discovery_trace output line */
91 #define LPFC_DISC_TRC_ENTRY_SIZE 80
92
93 /* nodelist output buffer size */
94 #define LPFC_NODELIST_SIZE 8192
95 #define LPFC_NODELIST_ENTRY_SIZE 120
96
97 struct lpfc_debug {
98         char *buffer;
99         int  len;
100 };
101
102 atomic_t lpfc_debugfs_disc_trc_cnt = ATOMIC_INIT(0);
103 unsigned long lpfc_debugfs_start_time = 0L;
104
105 static int
106 lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size)
107 {
108         int i, index, len, enable;
109         uint32_t ms;
110         struct lpfc_disc_trc *dtp;
111         char buffer[80];
112
113
114         enable = lpfc_debugfs_enable;
115         lpfc_debugfs_enable = 0;
116
117         len = 0;
118         index = (atomic_read(&vport->disc_trc_cnt) + 1) &
119                 (lpfc_debugfs_max_disc_trc - 1);
120         for (i = index; i < lpfc_debugfs_max_disc_trc; i++) {
121                 dtp = vport->disc_trc + i;
122                 if (!dtp->fmt)
123                         continue;
124                 ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
125                 snprintf(buffer, 80, "%010d:%010d ms:%s\n",
126                         dtp->seq_cnt, ms, dtp->fmt);
127                 len +=  snprintf(buf+len, size-len, buffer,
128                         dtp->data1, dtp->data2, dtp->data3);
129         }
130         for (i = 0; i < index; i++) {
131                 dtp = vport->disc_trc + i;
132                 if (!dtp->fmt)
133                         continue;
134                 ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time);
135                 snprintf(buffer, 80, "%010d:%010d ms:%s\n",
136                         dtp->seq_cnt, ms, dtp->fmt);
137                 len +=  snprintf(buf+len, size-len, buffer,
138                         dtp->data1, dtp->data2, dtp->data3);
139         }
140
141         lpfc_debugfs_enable = enable;
142         return len;
143 }
144
145 static int
146 lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
147 {
148         int len = 0;
149         int cnt;
150         struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
151         struct lpfc_nodelist *ndlp;
152         unsigned char *statep, *name;
153
154         cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE);
155
156         spin_lock_irq(shost->host_lock);
157         list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) {
158                 if (!cnt) {
159                         len +=  snprintf(buf+len, size-len,
160                                 "Missing Nodelist Entries\n");
161                         break;
162                 }
163                 cnt--;
164                 switch (ndlp->nlp_state) {
165                 case NLP_STE_UNUSED_NODE:
166                         statep = "UNUSED";
167                         break;
168                 case NLP_STE_PLOGI_ISSUE:
169                         statep = "PLOGI ";
170                         break;
171                 case NLP_STE_ADISC_ISSUE:
172                         statep = "ADISC ";
173                         break;
174                 case NLP_STE_REG_LOGIN_ISSUE:
175                         statep = "REGLOG";
176                         break;
177                 case NLP_STE_PRLI_ISSUE:
178                         statep = "PRLI  ";
179                         break;
180                 case NLP_STE_UNMAPPED_NODE:
181                         statep = "UNMAP ";
182                         break;
183                 case NLP_STE_MAPPED_NODE:
184                         statep = "MAPPED";
185                         break;
186                 case NLP_STE_NPR_NODE:
187                         statep = "NPR   ";
188                         break;
189                 default:
190                         statep = "UNKNOWN";
191                 }
192                 len +=  snprintf(buf+len, size-len, "%s DID:x%06x ",
193                         statep, ndlp->nlp_DID);
194                 name = (unsigned char *)&ndlp->nlp_portname;
195                 len +=  snprintf(buf+len, size-len,
196                         "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ",
197                         *name, *(name+1), *(name+2), *(name+3),
198                         *(name+4), *(name+5), *(name+6), *(name+7));
199                 name = (unsigned char *)&ndlp->nlp_nodename;
200                 len +=  snprintf(buf+len, size-len,
201                         "WWNN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ",
202                         *name, *(name+1), *(name+2), *(name+3),
203                         *(name+4), *(name+5), *(name+6), *(name+7));
204                 len +=  snprintf(buf+len, size-len, "RPI:%03d flag:x%08x ",
205                         ndlp->nlp_rpi, ndlp->nlp_flag);
206                 if (!ndlp->nlp_type)
207                         len +=  snprintf(buf+len, size-len, "UNKNOWN_TYPE");
208                 if (ndlp->nlp_type & NLP_FC_NODE)
209                         len +=  snprintf(buf+len, size-len, "FC_NODE ");
210                 if (ndlp->nlp_type & NLP_FABRIC)
211                         len +=  snprintf(buf+len, size-len, "FABRIC ");
212                 if (ndlp->nlp_type & NLP_FCP_TARGET)
213                         len +=  snprintf(buf+len, size-len, "FCP_TGT sid:%d ",
214                                 ndlp->nlp_sid);
215                 if (ndlp->nlp_type & NLP_FCP_INITIATOR)
216                         len +=  snprintf(buf+len, size-len, "FCP_INITIATOR");
217                 len +=  snprintf(buf+len, size-len, "\n");
218         }
219         spin_unlock_irq(shost->host_lock);
220         return len;
221 }
222 #endif
223
224
225 inline void
226 lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt,
227         uint32_t data1, uint32_t data2, uint32_t data3)
228 {
229 #ifdef CONFIG_LPFC_DEBUG_FS
230         struct lpfc_disc_trc *dtp;
231         int index;
232
233         if (!(lpfc_debugfs_mask_disc_trc & mask))
234                 return;
235
236         if (!lpfc_debugfs_enable || !lpfc_debugfs_max_disc_trc ||
237                 !vport || !vport->disc_trc)
238                 return;
239
240         index = atomic_inc_return(&vport->disc_trc_cnt) &
241                 (lpfc_debugfs_max_disc_trc - 1);
242         dtp = vport->disc_trc + index;
243         dtp->fmt = fmt;
244         dtp->data1 = data1;
245         dtp->data2 = data2;
246         dtp->data3 = data3;
247         dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_disc_trc_cnt);
248         dtp->jif = jiffies;
249 #endif
250         return;
251 }
252
253 #ifdef CONFIG_LPFC_DEBUG_FS
254 static int
255 lpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file)
256 {
257         struct lpfc_vport *vport = inode->i_private;
258         struct lpfc_debug *debug;
259         int size;
260         int rc = -ENOMEM;
261
262         if (!lpfc_debugfs_max_disc_trc) {
263                  rc = -ENOSPC;
264                 goto out;
265         }
266
267         debug = kmalloc(sizeof(*debug), GFP_KERNEL);
268         if (!debug)
269                 goto out;
270
271         /* Round to page boundry */
272         size =  (lpfc_debugfs_max_disc_trc * LPFC_DISC_TRC_ENTRY_SIZE);
273         size = PAGE_ALIGN(size);
274
275         debug->buffer = kmalloc(size, GFP_KERNEL);
276         if (!debug->buffer) {
277                 kfree(debug);
278                 goto out;
279         }
280
281         debug->len = lpfc_debugfs_disc_trc_data(vport, debug->buffer, size);
282         file->private_data = debug;
283
284         rc = 0;
285 out:
286         return rc;
287 }
288
289 static int
290 lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file)
291 {
292         struct lpfc_vport *vport = inode->i_private;
293         struct lpfc_debug *debug;
294         int rc = -ENOMEM;
295
296         debug = kmalloc(sizeof(*debug), GFP_KERNEL);
297         if (!debug)
298                 goto out;
299
300         /* Round to page boundry */
301         debug->buffer = kmalloc(LPFC_NODELIST_SIZE, GFP_KERNEL);
302         if (!debug->buffer) {
303                 kfree(debug);
304                 goto out;
305         }
306
307         debug->len = lpfc_debugfs_nodelist_data(vport, debug->buffer,
308                 LPFC_NODELIST_SIZE);
309         file->private_data = debug;
310
311         rc = 0;
312 out:
313         return rc;
314 }
315
316 static loff_t
317 lpfc_debugfs_lseek(struct file *file, loff_t off, int whence)
318 {
319         struct lpfc_debug *debug;
320         loff_t pos = -1;
321
322         debug = file->private_data;
323
324         switch (whence) {
325         case 0:
326                 pos = off;
327                 break;
328         case 1:
329                 pos = file->f_pos + off;
330                 break;
331         case 2:
332                 pos = debug->len - off;
333         }
334         return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos);
335 }
336
337 static ssize_t
338 lpfc_debugfs_read(struct file *file, char __user *buf,
339                   size_t nbytes, loff_t *ppos)
340 {
341         struct lpfc_debug *debug = file->private_data;
342         return simple_read_from_buffer(buf, nbytes, ppos, debug->buffer,
343                                        debug->len);
344 }
345
346 static int
347 lpfc_debugfs_release(struct inode *inode, struct file *file)
348 {
349         struct lpfc_debug *debug = file->private_data;
350
351         kfree(debug->buffer);
352         kfree(debug);
353
354         return 0;
355 }
356
357 #undef lpfc_debugfs_op_disc_trc
358 static struct file_operations lpfc_debugfs_op_disc_trc = {
359         .owner =        THIS_MODULE,
360         .open =         lpfc_debugfs_disc_trc_open,
361         .llseek =       lpfc_debugfs_lseek,
362         .read =         lpfc_debugfs_read,
363         .release =      lpfc_debugfs_release,
364 };
365
366 #undef lpfc_debugfs_op_nodelist
367 static struct file_operations lpfc_debugfs_op_nodelist = {
368         .owner =        THIS_MODULE,
369         .open =         lpfc_debugfs_nodelist_open,
370         .llseek =       lpfc_debugfs_lseek,
371         .read =         lpfc_debugfs_read,
372         .release =      lpfc_debugfs_release,
373 };
374
375 static struct dentry *lpfc_debugfs_root = NULL;
376 static atomic_t lpfc_debugfs_hba_count;
377 #endif
378
379 inline void
380 lpfc_debugfs_initialize(struct lpfc_vport *vport)
381 {
382 #ifdef CONFIG_LPFC_DEBUG_FS
383         struct lpfc_hba   *phba = vport->phba;
384         char name[64];
385         uint32_t num, i;
386
387         if (!lpfc_debugfs_enable)
388                 return;
389
390         if (lpfc_debugfs_max_disc_trc) {
391                 num = lpfc_debugfs_max_disc_trc - 1;
392                 if (num & lpfc_debugfs_max_disc_trc) {
393                         /* Change to be a power of 2 */
394                         num = lpfc_debugfs_max_disc_trc;
395                         i = 0;
396                         while (num > 1) {
397                                 num = num >> 1;
398                                 i++;
399                         }
400                         lpfc_debugfs_max_disc_trc = (1 << i);
401                         printk(KERN_ERR
402                                 "lpfc_debugfs_max_disc_trc changed to %d\n",
403                                 lpfc_debugfs_max_disc_trc);
404                 }
405         }
406
407         if (!lpfc_debugfs_root) {
408                 lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL);
409                 atomic_set(&lpfc_debugfs_hba_count, 0);
410                 if (!lpfc_debugfs_root)
411                         goto debug_failed;
412         }
413
414         snprintf(name, sizeof(name), "lpfc%d", phba->brd_no);
415         if (!phba->hba_debugfs_root) {
416                 phba->hba_debugfs_root =
417                         debugfs_create_dir(name, lpfc_debugfs_root);
418                 if (!phba->hba_debugfs_root)
419                         goto debug_failed;
420                 atomic_inc(&lpfc_debugfs_hba_count);
421                 atomic_set(&phba->debugfs_vport_count, 0);
422         }
423
424         snprintf(name, sizeof(name), "vport%d", vport->vpi);
425         if (!vport->vport_debugfs_root) {
426                 vport->vport_debugfs_root =
427                         debugfs_create_dir(name, phba->hba_debugfs_root);
428                 if (!vport->vport_debugfs_root)
429                         goto debug_failed;
430                 atomic_inc(&phba->debugfs_vport_count);
431         }
432
433         if (!lpfc_debugfs_start_time)
434                 lpfc_debugfs_start_time = jiffies;
435
436         vport->disc_trc = kmalloc(
437                 (sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc),
438                 GFP_KERNEL);
439
440         if (!vport->disc_trc)
441                 goto debug_failed;
442         memset(vport->disc_trc, 0,
443                 (sizeof(struct lpfc_disc_trc) * lpfc_debugfs_max_disc_trc));
444
445         snprintf(name, sizeof(name), "discovery_trace");
446         vport->debug_disc_trc =
447                 debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
448                                  vport->vport_debugfs_root,
449                                  vport, &lpfc_debugfs_op_disc_trc);
450         if (!vport->debug_disc_trc) {
451                 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
452                                 "%d:0409 Cannot create debugfs",
453                                 phba->brd_no);
454                 goto debug_failed;
455         }
456         snprintf(name, sizeof(name), "nodelist");
457         vport->debug_nodelist =
458                 debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR,
459                                  vport->vport_debugfs_root,
460                                  vport, &lpfc_debugfs_op_nodelist);
461         if (!vport->debug_nodelist) {
462                 lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
463                                 "%d:0409 Cannot create debugfs",
464                                 phba->brd_no);
465                 goto debug_failed;
466         }
467 debug_failed:
468         return;
469 #endif
470 }
471
472
473 inline void
474 lpfc_debugfs_terminate(struct lpfc_vport *vport)
475 {
476 #ifdef CONFIG_LPFC_DEBUG_FS
477         struct lpfc_hba   *phba = vport->phba;
478
479         if (vport->disc_trc) {
480                 kfree(vport->disc_trc);
481                 vport->disc_trc = NULL;
482         }
483         if (vport->debug_disc_trc) {
484                 debugfs_remove(vport->debug_disc_trc); /* discovery_trace */
485                 vport->debug_disc_trc = NULL;
486         }
487         if (vport->debug_nodelist) {
488                 debugfs_remove(vport->debug_nodelist); /* nodelist */
489                 vport->debug_nodelist = NULL;
490         }
491         if (vport->vport_debugfs_root) {
492                 debugfs_remove(vport->vport_debugfs_root); /* vportX */
493                 vport->vport_debugfs_root = NULL;
494                 atomic_dec(&phba->debugfs_vport_count);
495         }
496         if (atomic_read(&phba->debugfs_vport_count) == 0) {
497                 debugfs_remove(vport->phba->hba_debugfs_root); /* lpfcX */
498                 vport->phba->hba_debugfs_root = NULL;
499                 atomic_dec(&lpfc_debugfs_hba_count);
500                 if (atomic_read(&lpfc_debugfs_hba_count) == 0) {
501                         debugfs_remove(lpfc_debugfs_root); /* lpfc */
502                         lpfc_debugfs_root = NULL;
503                 }
504         }
505 #endif
506 }
507
508