1/* 2 * QLogic Fibre Channel HBA Driver 3 * Copyright (c) 2003-2014 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_puts(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_puts(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_putc(s, ' '); 42 seq_printf(s, "%08x", *fce++); 43 } 44 45 seq_puts(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 ql_dbg(ql_dbg_user, vha, 0x705c, 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 ql_dbg(ql_dbg_user, vha, 0x700d, 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) && !IS_QLA83XX(ha) && 118 !IS_QLA27XX(ha)) 119 goto out; 120 if (!ha->fce) 121 goto out; 122 123 if (qla2x00_dfs_root) 124 goto create_dir; 125 126 atomic_set(&qla2x00_dfs_root_count, 0); 127 qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL); 128 if (!qla2x00_dfs_root) { 129 ql_log(ql_log_warn, vha, 0x00f7, 130 "Unable to create debugfs root directory.\n"); 131 goto out; 132 } 133 134create_dir: 135 if (ha->dfs_dir) 136 goto create_nodes; 137 138 mutex_init(&ha->fce_mutex); 139 ha->dfs_dir = debugfs_create_dir(vha->host_str, qla2x00_dfs_root); 140 if (!ha->dfs_dir) { 141 ql_log(ql_log_warn, vha, 0x00f8, 142 "Unable to create debugfs ha directory.\n"); 143 goto out; 144 } 145 146 atomic_inc(&qla2x00_dfs_root_count); 147 148create_nodes: 149 ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha, 150 &dfs_fce_ops); 151 if (!ha->dfs_fce) { 152 ql_log(ql_log_warn, vha, 0x00f9, 153 "Unable to create debugfs fce node.\n"); 154 goto out; 155 } 156out: 157 return 0; 158} 159 160int 161qla2x00_dfs_remove(scsi_qla_host_t *vha) 162{ 163 struct qla_hw_data *ha = vha->hw; 164 if (ha->dfs_fce) { 165 debugfs_remove(ha->dfs_fce); 166 ha->dfs_fce = NULL; 167 } 168 169 if (ha->dfs_dir) { 170 debugfs_remove(ha->dfs_dir); 171 ha->dfs_dir = NULL; 172 atomic_dec(&qla2x00_dfs_root_count); 173 } 174 175 if (atomic_read(&qla2x00_dfs_root_count) == 0 && 176 qla2x00_dfs_root) { 177 debugfs_remove(qla2x00_dfs_root); 178 qla2x00_dfs_root = NULL; 179 } 180 181 return 0; 182} 183