snic_debugfs.c (13511B)
1/* 2 * Copyright 2014 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 22#include "snic.h" 23 24/* 25 * snic_debugfs_init - Initialize debugfs for snic debug logging 26 * 27 * Description: 28 * When Debugfs is configured this routine sets up fnic debugfs 29 * filesystem. If not already created. this routine will crate the 30 * fnic directory and statistics directory for trace buffer and 31 * stats logging 32 */ 33void snic_debugfs_init(void) 34{ 35 snic_glob->trc_root = debugfs_create_dir("snic", NULL); 36 37 snic_glob->stats_root = debugfs_create_dir("statistics", 38 snic_glob->trc_root); 39} 40 41/* 42 * snic_debugfs_term - Tear down debugfs intrastructure 43 * 44 * Description: 45 * When Debufs is configured this routine removes debugfs file system 46 * elements that are specific to snic 47 */ 48void 49snic_debugfs_term(void) 50{ 51 debugfs_remove(snic_glob->stats_root); 52 snic_glob->stats_root = NULL; 53 54 debugfs_remove(snic_glob->trc_root); 55 snic_glob->trc_root = NULL; 56} 57 58/* 59 * snic_reset_stats_open - Open the reset_stats file 60 */ 61static int 62snic_reset_stats_open(struct inode *inode, struct file *filp) 63{ 64 SNIC_BUG_ON(!inode->i_private); 65 filp->private_data = inode->i_private; 66 67 return 0; 68} 69 70/* 71 * snic_reset_stats_read - Read a reset_stats debugfs file 72 * @filp: The file pointer to read from. 73 * @ubuf: The buffer tocopy the data to. 74 * @cnt: The number of bytes to read. 75 * @ppos: The position in the file to start reading frm. 76 * 77 * Description: 78 * This routine reads value of variable reset_stats 79 * and stores into local @buf. It will start reading file @ppos and 80 * copy up to @cnt of data to @ubuf from @buf. 81 * 82 * Returns: 83 * This function returns the amount of data that was read. 84 */ 85static ssize_t 86snic_reset_stats_read(struct file *filp, 87 char __user *ubuf, 88 size_t cnt, 89 loff_t *ppos) 90{ 91 struct snic *snic = (struct snic *) filp->private_data; 92 char buf[64]; 93 int len; 94 95 len = sprintf(buf, "%u\n", snic->reset_stats); 96 97 return simple_read_from_buffer(ubuf, cnt, ppos, buf, len); 98} 99 100/* 101 * snic_reset_stats_write - Write to reset_stats debugfs file 102 * @filp: The file pointer to write from 103 * @ubuf: The buffer to copy the data from. 104 * @cnt: The number of bytes to write. 105 * @ppos: The position in the file to start writing to. 106 * 107 * Description: 108 * This routine writes data from user buffer @ubuf to buffer @buf and 109 * resets cumulative stats of snic. 110 * 111 * Returns: 112 * This function returns the amount of data that was written. 113 */ 114static ssize_t 115snic_reset_stats_write(struct file *filp, 116 const char __user *ubuf, 117 size_t cnt, 118 loff_t *ppos) 119{ 120 struct snic *snic = (struct snic *) filp->private_data; 121 struct snic_stats *stats = &snic->s_stats; 122 u64 *io_stats_p = (u64 *) &stats->io; 123 u64 *fw_stats_p = (u64 *) &stats->fw; 124 char buf[64]; 125 unsigned long val; 126 int ret; 127 128 if (cnt >= sizeof(buf)) 129 return -EINVAL; 130 131 if (copy_from_user(&buf, ubuf, cnt)) 132 return -EFAULT; 133 134 buf[cnt] = '\0'; 135 136 ret = kstrtoul(buf, 10, &val); 137 if (ret < 0) 138 return ret; 139 140 snic->reset_stats = val; 141 142 if (snic->reset_stats) { 143 /* Skip variable is used to avoid descrepancies to Num IOs 144 * and IO Completions stats. Skip incrementing No IO Compls 145 * for pending active IOs after reset_stats 146 */ 147 atomic64_set(&snic->io_cmpl_skip, 148 atomic64_read(&stats->io.active)); 149 memset(&stats->abts, 0, sizeof(struct snic_abort_stats)); 150 memset(&stats->reset, 0, sizeof(struct snic_reset_stats)); 151 memset(&stats->misc, 0, sizeof(struct snic_misc_stats)); 152 memset(io_stats_p+1, 153 0, 154 sizeof(struct snic_io_stats) - sizeof(u64)); 155 memset(fw_stats_p+1, 156 0, 157 sizeof(struct snic_fw_stats) - sizeof(u64)); 158 } 159 160 (*ppos)++; 161 162 SNIC_HOST_INFO(snic->shost, "Reset Op: Driver statistics.\n"); 163 164 return cnt; 165} 166 167static int 168snic_reset_stats_release(struct inode *inode, struct file *filp) 169{ 170 filp->private_data = NULL; 171 172 return 0; 173} 174 175/* 176 * snic_stats_show - Formats and prints per host specific driver stats. 177 */ 178static int 179snic_stats_show(struct seq_file *sfp, void *data) 180{ 181 struct snic *snic = (struct snic *) sfp->private; 182 struct snic_stats *stats = &snic->s_stats; 183 struct timespec64 last_isr_tms, last_ack_tms; 184 u64 maxio_tm; 185 int i; 186 187 /* Dump IO Stats */ 188 seq_printf(sfp, 189 "------------------------------------------\n" 190 "\t\t IO Statistics\n" 191 "------------------------------------------\n"); 192 193 maxio_tm = (u64) atomic64_read(&stats->io.max_time); 194 seq_printf(sfp, 195 "Active IOs : %lld\n" 196 "Max Active IOs : %lld\n" 197 "Total IOs : %lld\n" 198 "IOs Completed : %lld\n" 199 "IOs Failed : %lld\n" 200 "IOs Not Found : %lld\n" 201 "Memory Alloc Failures : %lld\n" 202 "REQs Null : %lld\n" 203 "SCSI Cmd Pointers Null : %lld\n" 204 "Max SGL for any IO : %lld\n" 205 "Max IO Size : %lld Sectors\n" 206 "Max Queuing Time : %lld\n" 207 "Max Completion Time : %lld\n" 208 "Max IO Process Time(FW) : %lld (%u msec)\n", 209 (u64) atomic64_read(&stats->io.active), 210 (u64) atomic64_read(&stats->io.max_active), 211 (u64) atomic64_read(&stats->io.num_ios), 212 (u64) atomic64_read(&stats->io.compl), 213 (u64) atomic64_read(&stats->io.fail), 214 (u64) atomic64_read(&stats->io.io_not_found), 215 (u64) atomic64_read(&stats->io.alloc_fail), 216 (u64) atomic64_read(&stats->io.req_null), 217 (u64) atomic64_read(&stats->io.sc_null), 218 (u64) atomic64_read(&stats->io.max_sgl), 219 (u64) atomic64_read(&stats->io.max_io_sz), 220 (u64) atomic64_read(&stats->io.max_qtime), 221 (u64) atomic64_read(&stats->io.max_cmpl_time), 222 maxio_tm, 223 jiffies_to_msecs(maxio_tm)); 224 225 seq_puts(sfp, "\nSGL Counters\n"); 226 227 for (i = 0; i < SNIC_MAX_SG_DESC_CNT; i++) { 228 seq_printf(sfp, 229 "%10lld ", 230 (u64) atomic64_read(&stats->io.sgl_cnt[i])); 231 232 if ((i + 1) % 8 == 0) 233 seq_puts(sfp, "\n"); 234 } 235 236 /* Dump Abort Stats */ 237 seq_printf(sfp, 238 "\n-------------------------------------------\n" 239 "\t\t Abort Statistics\n" 240 "---------------------------------------------\n"); 241 242 seq_printf(sfp, 243 "Aborts : %lld\n" 244 "Aborts Fail : %lld\n" 245 "Aborts Driver Timeout : %lld\n" 246 "Abort FW Timeout : %lld\n" 247 "Abort IO NOT Found : %lld\n" 248 "Abort Queuing Failed : %lld\n", 249 (u64) atomic64_read(&stats->abts.num), 250 (u64) atomic64_read(&stats->abts.fail), 251 (u64) atomic64_read(&stats->abts.drv_tmo), 252 (u64) atomic64_read(&stats->abts.fw_tmo), 253 (u64) atomic64_read(&stats->abts.io_not_found), 254 (u64) atomic64_read(&stats->abts.q_fail)); 255 256 /* Dump Reset Stats */ 257 seq_printf(sfp, 258 "\n-------------------------------------------\n" 259 "\t\t Reset Statistics\n" 260 "---------------------------------------------\n"); 261 262 seq_printf(sfp, 263 "HBA Resets : %lld\n" 264 "HBA Reset Cmpls : %lld\n" 265 "HBA Reset Fail : %lld\n", 266 (u64) atomic64_read(&stats->reset.hba_resets), 267 (u64) atomic64_read(&stats->reset.hba_reset_cmpl), 268 (u64) atomic64_read(&stats->reset.hba_reset_fail)); 269 270 /* Dump Firmware Stats */ 271 seq_printf(sfp, 272 "\n-------------------------------------------\n" 273 "\t\t Firmware Statistics\n" 274 "---------------------------------------------\n"); 275 276 seq_printf(sfp, 277 "Active FW Requests : %lld\n" 278 "Max FW Requests : %lld\n" 279 "FW Out Of Resource Errs : %lld\n" 280 "FW IO Errors : %lld\n" 281 "FW SCSI Errors : %lld\n", 282 (u64) atomic64_read(&stats->fw.actv_reqs), 283 (u64) atomic64_read(&stats->fw.max_actv_reqs), 284 (u64) atomic64_read(&stats->fw.out_of_res), 285 (u64) atomic64_read(&stats->fw.io_errs), 286 (u64) atomic64_read(&stats->fw.scsi_errs)); 287 288 289 /* Dump Miscellenous Stats */ 290 seq_printf(sfp, 291 "\n---------------------------------------------\n" 292 "\t\t Other Statistics\n" 293 "\n---------------------------------------------\n"); 294 295 jiffies_to_timespec64(stats->misc.last_isr_time, &last_isr_tms); 296 jiffies_to_timespec64(stats->misc.last_ack_time, &last_ack_tms); 297 298 seq_printf(sfp, 299 "Last ISR Time : %llu (%8llu.%09lu)\n" 300 "Last Ack Time : %llu (%8llu.%09lu)\n" 301 "Ack ISRs : %llu\n" 302 "IO Cmpl ISRs : %llu\n" 303 "Err Notify ISRs : %llu\n" 304 "Max CQ Entries : %lld\n" 305 "Data Count Mismatch : %lld\n" 306 "IOs w/ Timeout Status : %lld\n" 307 "IOs w/ Aborted Status : %lld\n" 308 "IOs w/ SGL Invalid Stat : %lld\n" 309 "WQ Desc Alloc Fail : %lld\n" 310 "Queue Full : %lld\n" 311 "Queue Ramp Up : %lld\n" 312 "Queue Ramp Down : %lld\n" 313 "Queue Last Queue Depth : %lld\n" 314 "Target Not Ready : %lld\n", 315 (u64) stats->misc.last_isr_time, 316 last_isr_tms.tv_sec, last_isr_tms.tv_nsec, 317 (u64)stats->misc.last_ack_time, 318 last_ack_tms.tv_sec, last_ack_tms.tv_nsec, 319 (u64) atomic64_read(&stats->misc.ack_isr_cnt), 320 (u64) atomic64_read(&stats->misc.cmpl_isr_cnt), 321 (u64) atomic64_read(&stats->misc.errnotify_isr_cnt), 322 (u64) atomic64_read(&stats->misc.max_cq_ents), 323 (u64) atomic64_read(&stats->misc.data_cnt_mismat), 324 (u64) atomic64_read(&stats->misc.io_tmo), 325 (u64) atomic64_read(&stats->misc.io_aborted), 326 (u64) atomic64_read(&stats->misc.sgl_inval), 327 (u64) atomic64_read(&stats->misc.wq_alloc_fail), 328 (u64) atomic64_read(&stats->misc.qfull), 329 (u64) atomic64_read(&stats->misc.qsz_rampup), 330 (u64) atomic64_read(&stats->misc.qsz_rampdown), 331 (u64) atomic64_read(&stats->misc.last_qsz), 332 (u64) atomic64_read(&stats->misc.tgt_not_rdy)); 333 334 return 0; 335} 336 337DEFINE_SHOW_ATTRIBUTE(snic_stats); 338 339static const struct file_operations snic_reset_stats_fops = { 340 .owner = THIS_MODULE, 341 .open = snic_reset_stats_open, 342 .read = snic_reset_stats_read, 343 .write = snic_reset_stats_write, 344 .release = snic_reset_stats_release, 345}; 346 347/* 348 * snic_stats_init - Initialize stats struct and create stats file 349 * per snic 350 * 351 * Description: 352 * When debugfs is cofigured this routine sets up the stats file per snic 353 * It will create file stats and reset_stats under statistics/host# directory 354 * to log per snic stats 355 */ 356void snic_stats_debugfs_init(struct snic *snic) 357{ 358 char name[16]; 359 360 snprintf(name, sizeof(name), "host%d", snic->shost->host_no); 361 362 snic->stats_host = debugfs_create_dir(name, snic_glob->stats_root); 363 364 snic->stats_file = debugfs_create_file("stats", S_IFREG|S_IRUGO, 365 snic->stats_host, snic, 366 &snic_stats_fops); 367 368 snic->reset_stats_file = debugfs_create_file("reset_stats", 369 S_IFREG|S_IRUGO|S_IWUSR, 370 snic->stats_host, snic, 371 &snic_reset_stats_fops); 372} 373 374/* 375 * snic_stats_debugfs_remove - Tear down debugfs infrastructure of stats 376 * 377 * Description: 378 * When Debufs is configured this routine removes debugfs file system 379 * elements that are specific to to snic stats 380 */ 381void 382snic_stats_debugfs_remove(struct snic *snic) 383{ 384 debugfs_remove(snic->stats_file); 385 snic->stats_file = NULL; 386 387 debugfs_remove(snic->reset_stats_file); 388 snic->reset_stats_file = NULL; 389 390 debugfs_remove(snic->stats_host); 391 snic->stats_host = NULL; 392} 393 394/* Trace Facility related API */ 395static void * 396snic_trc_seq_start(struct seq_file *sfp, loff_t *pos) 397{ 398 return &snic_glob->trc; 399} 400 401static void * 402snic_trc_seq_next(struct seq_file *sfp, void *data, loff_t *pos) 403{ 404 return NULL; 405} 406 407static void 408snic_trc_seq_stop(struct seq_file *sfp, void *data) 409{ 410} 411 412#define SNIC_TRC_PBLEN 256 413static int 414snic_trc_seq_show(struct seq_file *sfp, void *data) 415{ 416 char buf[SNIC_TRC_PBLEN]; 417 418 if (snic_get_trc_data(buf, SNIC_TRC_PBLEN) > 0) 419 seq_printf(sfp, "%s\n", buf); 420 421 return 0; 422} 423 424static const struct seq_operations snic_trc_sops = { 425 .start = snic_trc_seq_start, 426 .next = snic_trc_seq_next, 427 .stop = snic_trc_seq_stop, 428 .show = snic_trc_seq_show, 429}; 430 431DEFINE_SEQ_ATTRIBUTE(snic_trc); 432 433#define TRC_ENABLE_FILE "tracing_enable" 434#define TRC_FILE "trace" 435/* 436 * snic_trc_debugfs_init : creates trace/tracing_enable files for trace 437 * under debugfs 438 */ 439void snic_trc_debugfs_init(void) 440{ 441 debugfs_create_bool(TRC_ENABLE_FILE, S_IFREG | S_IRUGO | S_IWUSR, 442 snic_glob->trc_root, &snic_glob->trc.enable); 443 444 debugfs_create_file(TRC_FILE, S_IFREG | S_IRUGO | S_IWUSR, 445 snic_glob->trc_root, NULL, &snic_trc_fops); 446} 447 448/* 449 * snic_trc_debugfs_term : cleans up the files created for trace under debugfs 450 */ 451void 452snic_trc_debugfs_term(void) 453{ 454 debugfs_remove(debugfs_lookup(TRC_FILE, snic_glob->trc_root)); 455 debugfs_remove(debugfs_lookup(TRC_ENABLE_FILE, snic_glob->trc_root)); 456}