1 /* 2 * QLogic Fibre Channel HBA Driver 3 * Copyright (c) 2003-2013 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 12 static struct dentry *qla2x00_dfs_root; 13 static atomic_t qla2x00_dfs_root_count; 14 15 static int 16 qla2x00_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 52 static int 53 qla2x00_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); 73 out: 74 return single_open(file, qla2x00_dfs_fce_show, vha); 75 } 76 77 static int 78 qla2x00_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); 101 out: 102 return single_release(inode, file); 103 } 104 105 static 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 112 int 113 qla2x00_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 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 ql_log(ql_log_warn, vha, 0x00f7, 129 "Unable to create debugfs root directory.\n"); 130 goto out; 131 } 132 133 create_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 ql_log(ql_log_warn, vha, 0x00f8, 141 "Unable to create debugfs ha directory.\n"); 142 goto out; 143 } 144 145 atomic_inc(&qla2x00_dfs_root_count); 146 147 create_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 ql_log(ql_log_warn, vha, 0x00f9, 152 "Unable to create debugfs fce node.\n"); 153 goto out; 154 } 155 out: 156 return 0; 157 } 158 159 int 160 qla2x00_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