linux/drivers/scsi/qla2xxx/qla_dfs.c
<<
>>
Prefs
   1/*
   2 * QLogic Fibre Channel HBA Driver
   3 * Copyright (c)  2003-2010 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 *vha = s->private;
  19        uint32_t cnt;
  20        uint32_t *fce;
  21        uint64_t fce_start;
  22        struct qla_hw_data *ha = vha->hw;
  23
  24        mutex_lock(&ha->fce_mutex);
  25
  26        seq_printf(s, "FCE Trace Buffer\n");
  27        seq_printf(s, "In Pointer = %llx\n\n", (unsigned long long)ha->fce_wr);
  28        seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma);
  29        seq_printf(s, "FCE Enable Registers\n");
  30        seq_printf(s, "%08x %08x %08x %08x %08x %08x\n",
  31            ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4],
  32            ha->fce_mb[5], ha->fce_mb[6]);
  33
  34        fce = (uint32_t *) ha->fce;
  35        fce_start = (unsigned long long) ha->fce_dma;
  36        for (cnt = 0; cnt < fce_calc_size(ha->fce_bufs) / 4; cnt++) {
  37                if (cnt % 8 == 0)
  38                        seq_printf(s, "\n%llx: ",
  39                            (unsigned long long)((cnt * 4) + fce_start));
  40                else
  41                        seq_printf(s, " ");
  42                seq_printf(s, "%08x", *fce++);
  43        }
  44
  45        seq_printf(s, "\nEnd\n");
  46
  47        mutex_unlock(&ha->fce_mutex);
  48
  49        return 0;
  50}
  51
  52static int
  53qla2x00_dfs_fce_open(struct inode *inode, struct file *file)
  54{
  55        scsi_qla_host_t *vha = inode->i_private;
  56        struct qla_hw_data *ha = vha->hw;
  57        int rval;
  58
  59        if (!ha->flags.fce_enabled)
  60                goto out;
  61
  62        mutex_lock(&ha->fce_mutex);
  63
  64        /* Pause tracing to flush FCE buffers. */
  65        rval = qla2x00_disable_fce_trace(vha, &ha->fce_wr, &ha->fce_rd);
  66        if (rval)
  67                qla_printk(KERN_WARNING, ha,
  68                    "DebugFS: Unable to disable FCE (%d).\n", rval);
  69
  70        ha->flags.fce_enabled = 0;
  71
  72        mutex_unlock(&ha->fce_mutex);
  73out:
  74        return single_open(file, qla2x00_dfs_fce_show, vha);
  75}
  76
  77static int
  78qla2x00_dfs_fce_release(struct inode *inode, struct file *file)
  79{
  80        scsi_qla_host_t *vha = inode->i_private;
  81        struct qla_hw_data *ha = vha->hw;
  82        int rval;
  83
  84        if (ha->flags.fce_enabled)
  85                goto out;
  86
  87        mutex_lock(&ha->fce_mutex);
  88
  89        /* Re-enable FCE tracing. */
  90        ha->flags.fce_enabled = 1;
  91        memset(ha->fce, 0, fce_calc_size(ha->fce_bufs));
  92        rval = qla2x00_enable_fce_trace(vha, ha->fce_dma, ha->fce_bufs,
  93            ha->fce_mb, &ha->fce_bufs);
  94        if (rval) {
  95                qla_printk(KERN_WARNING, ha,
  96                    "DebugFS: Unable to reinitialize FCE (%d).\n", rval);
  97                ha->flags.fce_enabled = 0;
  98        }
  99
 100        mutex_unlock(&ha->fce_mutex);
 101out:
 102        return single_release(inode, file);
 103}
 104
 105static const struct file_operations dfs_fce_ops = {
 106        .open           = qla2x00_dfs_fce_open,
 107        .read           = seq_read,
 108        .llseek         = seq_lseek,
 109        .release        = qla2x00_dfs_fce_release,
 110};
 111
 112int
 113qla2x00_dfs_setup(scsi_qla_host_t *vha)
 114{
 115        struct qla_hw_data *ha = vha->hw;
 116
 117        if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
 118                goto out;
 119        if (!ha->fce)
 120                goto out;
 121
 122        if (qla2x00_dfs_root)
 123                goto create_dir;
 124
 125        atomic_set(&qla2x00_dfs_root_count, 0);
 126        qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL);
 127        if (!qla2x00_dfs_root) {
 128                qla_printk(KERN_NOTICE, ha,
 129                    "DebugFS: Unable to create root directory.\n");
 130                goto out;
 131        }
 132
 133create_dir:
 134        if (ha->dfs_dir)
 135                goto create_nodes;
 136
 137        mutex_init(&ha->fce_mutex);
 138        ha->dfs_dir = debugfs_create_dir(vha->host_str, qla2x00_dfs_root);
 139        if (!ha->dfs_dir) {
 140                qla_printk(KERN_NOTICE, ha,
 141                    "DebugFS: Unable to create ha directory.\n");
 142                goto out;
 143        }
 144
 145        atomic_inc(&qla2x00_dfs_root_count);
 146
 147create_nodes:
 148        ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
 149            &dfs_fce_ops);
 150        if (!ha->dfs_fce) {
 151                qla_printk(KERN_NOTICE, ha,
 152                    "DebugFS: Unable to fce node.\n");
 153                goto out;
 154        }
 155out:
 156        return 0;
 157}
 158
 159int
 160qla2x00_dfs_remove(scsi_qla_host_t *vha)
 161{
 162        struct qla_hw_data *ha = vha->hw;
 163        if (ha->dfs_fce) {
 164                debugfs_remove(ha->dfs_fce);
 165                ha->dfs_fce = NULL;
 166        }
 167
 168        if (ha->dfs_dir) {
 169                debugfs_remove(ha->dfs_dir);
 170                ha->dfs_dir = NULL;
 171                atomic_dec(&qla2x00_dfs_root_count);
 172        }
 173
 174        if (atomic_read(&qla2x00_dfs_root_count) == 0 &&
 175            qla2x00_dfs_root) {
 176                debugfs_remove(qla2x00_dfs_root);
 177                qla2x00_dfs_root = NULL;
 178        }
 179
 180        return 0;
 181}
 182