linux/drivers/scsi/bfa/bfad_debugfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2005-2014 Brocade Communications Systems, Inc.
   4 * Copyright (c) 2014- QLogic Corporation.
   5 * All rights reserved
   6 * www.qlogic.com
   7 *
   8 * Linux driver for QLogic BR-series Fibre Channel Host Bus Adapter.
   9 */
  10
  11#include <linux/debugfs.h>
  12#include <linux/export.h>
  13
  14#include "bfad_drv.h"
  15#include "bfad_im.h"
  16
  17/*
  18 * BFA debufs interface
  19 *
  20 * To access the interface, debugfs file system should be mounted
  21 * if not already mounted using:
  22 * mount -t debugfs none /sys/kernel/debug
  23 *
  24 * BFA Hierarchy:
  25 *      - bfa/pci_dev:<pci_name>
  26 * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bfa
  27 *
  28 * Debugging service available per pci_dev:
  29 * fwtrc:  To collect current firmware trace.
  30 * drvtrc: To collect current driver trace
  31 * fwsave: To collect last saved fw trace as a result of firmware crash.
  32 * regwr:  To write one word to chip register
  33 * regrd:  To read one or more words from chip register.
  34 */
  35
  36struct bfad_debug_info {
  37        char *debug_buffer;
  38        void *i_private;
  39        int buffer_len;
  40};
  41
  42static int
  43bfad_debugfs_open_drvtrc(struct inode *inode, struct file *file)
  44{
  45        struct bfad_port_s *port = inode->i_private;
  46        struct bfad_s *bfad = port->bfad;
  47        struct bfad_debug_info *debug;
  48
  49        debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
  50        if (!debug)
  51                return -ENOMEM;
  52
  53        debug->debug_buffer = (void *) bfad->trcmod;
  54        debug->buffer_len = sizeof(struct bfa_trc_mod_s);
  55
  56        file->private_data = debug;
  57
  58        return 0;
  59}
  60
  61static int
  62bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file)
  63{
  64        struct bfad_port_s *port = inode->i_private;
  65        struct bfad_s *bfad = port->bfad;
  66        struct bfad_debug_info *fw_debug;
  67        unsigned long flags;
  68        int rc;
  69
  70        fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
  71        if (!fw_debug)
  72                return -ENOMEM;
  73
  74        fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
  75
  76        fw_debug->debug_buffer = vzalloc(fw_debug->buffer_len);
  77        if (!fw_debug->debug_buffer) {
  78                kfree(fw_debug);
  79                printk(KERN_INFO "bfad[%d]: Failed to allocate fwtrc buffer\n",
  80                                bfad->inst_no);
  81                return -ENOMEM;
  82        }
  83
  84        spin_lock_irqsave(&bfad->bfad_lock, flags);
  85        rc = bfa_ioc_debug_fwtrc(&bfad->bfa.ioc,
  86                        fw_debug->debug_buffer,
  87                        &fw_debug->buffer_len);
  88        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
  89        if (rc != BFA_STATUS_OK) {
  90                vfree(fw_debug->debug_buffer);
  91                fw_debug->debug_buffer = NULL;
  92                kfree(fw_debug);
  93                printk(KERN_INFO "bfad[%d]: Failed to collect fwtrc\n",
  94                                bfad->inst_no);
  95                return -ENOMEM;
  96        }
  97
  98        file->private_data = fw_debug;
  99
 100        return 0;
 101}
 102
 103static int
 104bfad_debugfs_open_fwsave(struct inode *inode, struct file *file)
 105{
 106        struct bfad_port_s *port = inode->i_private;
 107        struct bfad_s *bfad = port->bfad;
 108        struct bfad_debug_info *fw_debug;
 109        unsigned long flags;
 110        int rc;
 111
 112        fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
 113        if (!fw_debug)
 114                return -ENOMEM;
 115
 116        fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s);
 117
 118        fw_debug->debug_buffer = vzalloc(fw_debug->buffer_len);
 119        if (!fw_debug->debug_buffer) {
 120                kfree(fw_debug);
 121                printk(KERN_INFO "bfad[%d]: Failed to allocate fwsave buffer\n",
 122                                bfad->inst_no);
 123                return -ENOMEM;
 124        }
 125
 126        spin_lock_irqsave(&bfad->bfad_lock, flags);
 127        rc = bfa_ioc_debug_fwsave(&bfad->bfa.ioc,
 128                        fw_debug->debug_buffer,
 129                        &fw_debug->buffer_len);
 130        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 131        if (rc != BFA_STATUS_OK) {
 132                vfree(fw_debug->debug_buffer);
 133                fw_debug->debug_buffer = NULL;
 134                kfree(fw_debug);
 135                printk(KERN_INFO "bfad[%d]: Failed to collect fwsave\n",
 136                                bfad->inst_no);
 137                return -ENOMEM;
 138        }
 139
 140        file->private_data = fw_debug;
 141
 142        return 0;
 143}
 144
 145static int
 146bfad_debugfs_open_reg(struct inode *inode, struct file *file)
 147{
 148        struct bfad_debug_info *reg_debug;
 149
 150        reg_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL);
 151        if (!reg_debug)
 152                return -ENOMEM;
 153
 154        reg_debug->i_private = inode->i_private;
 155
 156        file->private_data = reg_debug;
 157
 158        return 0;
 159}
 160
 161/* Changes the current file position */
 162static loff_t
 163bfad_debugfs_lseek(struct file *file, loff_t offset, int orig)
 164{
 165        struct bfad_debug_info *debug = file->private_data;
 166        return fixed_size_llseek(file, offset, orig,
 167                                debug->buffer_len);
 168}
 169
 170static ssize_t
 171bfad_debugfs_read(struct file *file, char __user *buf,
 172                        size_t nbytes, loff_t *pos)
 173{
 174        struct bfad_debug_info *debug = file->private_data;
 175
 176        if (!debug || !debug->debug_buffer)
 177                return 0;
 178
 179        return simple_read_from_buffer(buf, nbytes, pos,
 180                                debug->debug_buffer, debug->buffer_len);
 181}
 182
 183#define BFA_REG_CT_ADDRSZ       (0x40000)
 184#define BFA_REG_CB_ADDRSZ       (0x20000)
 185#define BFA_REG_ADDRSZ(__ioc)   \
 186        ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ?  \
 187         BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ))
 188#define BFA_REG_ADDRMSK(__ioc)  (BFA_REG_ADDRSZ(__ioc) - 1)
 189
 190static bfa_status_t
 191bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len)
 192{
 193        u8      area;
 194
 195        /* check [16:15] */
 196        area = (offset >> 15) & 0x7;
 197        if (area == 0) {
 198                /* PCIe core register */
 199                if ((offset + (len<<2)) > 0x8000)    /* 8k dwords or 32KB */
 200                        return BFA_STATUS_EINVAL;
 201        } else if (area == 0x1) {
 202                /* CB 32 KB memory page */
 203                if ((offset + (len<<2)) > 0x10000)    /* 8k dwords or 32KB */
 204                        return BFA_STATUS_EINVAL;
 205        } else {
 206                /* CB register space 64KB */
 207                if ((offset + (len<<2)) > BFA_REG_ADDRMSK(&bfa->ioc))
 208                        return BFA_STATUS_EINVAL;
 209        }
 210        return BFA_STATUS_OK;
 211}
 212
 213static ssize_t
 214bfad_debugfs_read_regrd(struct file *file, char __user *buf,
 215                size_t nbytes, loff_t *pos)
 216{
 217        struct bfad_debug_info *regrd_debug = file->private_data;
 218        struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
 219        struct bfad_s *bfad = port->bfad;
 220        ssize_t rc;
 221
 222        if (!bfad->regdata)
 223                return 0;
 224
 225        rc = simple_read_from_buffer(buf, nbytes, pos,
 226                        bfad->regdata, bfad->reglen);
 227
 228        if ((*pos + nbytes) >= bfad->reglen) {
 229                kfree(bfad->regdata);
 230                bfad->regdata = NULL;
 231                bfad->reglen = 0;
 232        }
 233
 234        return rc;
 235}
 236
 237static ssize_t
 238bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
 239                size_t nbytes, loff_t *ppos)
 240{
 241        struct bfad_debug_info *regrd_debug = file->private_data;
 242        struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private;
 243        struct bfad_s *bfad = port->bfad;
 244        struct bfa_s *bfa = &bfad->bfa;
 245        struct bfa_ioc_s *ioc = &bfa->ioc;
 246        int addr, rc, i;
 247        u32 len;
 248        u32 *regbuf;
 249        void __iomem *rb, *reg_addr;
 250        unsigned long flags;
 251        void *kern_buf;
 252
 253        kern_buf = memdup_user(buf, nbytes);
 254        if (IS_ERR(kern_buf))
 255                return PTR_ERR(kern_buf);
 256
 257        rc = sscanf(kern_buf, "%x:%x", &addr, &len);
 258        if (rc < 2 || len > (UINT_MAX >> 2)) {
 259                printk(KERN_INFO
 260                        "bfad[%d]: %s failed to read user buf\n",
 261                        bfad->inst_no, __func__);
 262                kfree(kern_buf);
 263                return -EINVAL;
 264        }
 265
 266        kfree(kern_buf);
 267        kfree(bfad->regdata);
 268        bfad->regdata = NULL;
 269        bfad->reglen = 0;
 270
 271        bfad->regdata = kzalloc(len << 2, GFP_KERNEL);
 272        if (!bfad->regdata) {
 273                printk(KERN_INFO "bfad[%d]: Failed to allocate regrd buffer\n",
 274                                bfad->inst_no);
 275                return -ENOMEM;
 276        }
 277
 278        bfad->reglen = len << 2;
 279        rb = bfa_ioc_bar0(ioc);
 280        addr &= BFA_REG_ADDRMSK(ioc);
 281
 282        /* offset and len sanity check */
 283        rc = bfad_reg_offset_check(bfa, addr, len);
 284        if (rc) {
 285                printk(KERN_INFO "bfad[%d]: Failed reg offset check\n",
 286                                bfad->inst_no);
 287                kfree(bfad->regdata);
 288                bfad->regdata = NULL;
 289                bfad->reglen = 0;
 290                return -EINVAL;
 291        }
 292
 293        reg_addr = rb + addr;
 294        regbuf =  (u32 *)bfad->regdata;
 295        spin_lock_irqsave(&bfad->bfad_lock, flags);
 296        for (i = 0; i < len; i++) {
 297                *regbuf = readl(reg_addr);
 298                regbuf++;
 299                reg_addr += sizeof(u32);
 300        }
 301        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 302
 303        return nbytes;
 304}
 305
 306static ssize_t
 307bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
 308                size_t nbytes, loff_t *ppos)
 309{
 310        struct bfad_debug_info *debug = file->private_data;
 311        struct bfad_port_s *port = (struct bfad_port_s *)debug->i_private;
 312        struct bfad_s *bfad = port->bfad;
 313        struct bfa_s *bfa = &bfad->bfa;
 314        struct bfa_ioc_s *ioc = &bfa->ioc;
 315        int addr, val, rc;
 316        void __iomem *reg_addr;
 317        unsigned long flags;
 318        void *kern_buf;
 319
 320        kern_buf = memdup_user(buf, nbytes);
 321        if (IS_ERR(kern_buf))
 322                return PTR_ERR(kern_buf);
 323
 324        rc = sscanf(kern_buf, "%x:%x", &addr, &val);
 325        if (rc < 2) {
 326                printk(KERN_INFO
 327                        "bfad[%d]: %s failed to read user buf\n",
 328                        bfad->inst_no, __func__);
 329                kfree(kern_buf);
 330                return -EINVAL;
 331        }
 332        kfree(kern_buf);
 333
 334        addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */
 335
 336        /* offset and len sanity check */
 337        rc = bfad_reg_offset_check(bfa, addr, 1);
 338        if (rc) {
 339                printk(KERN_INFO
 340                        "bfad[%d]: Failed reg offset check\n",
 341                        bfad->inst_no);
 342                return -EINVAL;
 343        }
 344
 345        reg_addr = (bfa_ioc_bar0(ioc)) + addr;
 346        spin_lock_irqsave(&bfad->bfad_lock, flags);
 347        writel(val, reg_addr);
 348        spin_unlock_irqrestore(&bfad->bfad_lock, flags);
 349
 350        return nbytes;
 351}
 352
 353static int
 354bfad_debugfs_release(struct inode *inode, struct file *file)
 355{
 356        struct bfad_debug_info *debug = file->private_data;
 357
 358        if (!debug)
 359                return 0;
 360
 361        file->private_data = NULL;
 362        kfree(debug);
 363        return 0;
 364}
 365
 366static int
 367bfad_debugfs_release_fwtrc(struct inode *inode, struct file *file)
 368{
 369        struct bfad_debug_info *fw_debug = file->private_data;
 370
 371        if (!fw_debug)
 372                return 0;
 373
 374        if (fw_debug->debug_buffer)
 375                vfree(fw_debug->debug_buffer);
 376
 377        file->private_data = NULL;
 378        kfree(fw_debug);
 379        return 0;
 380}
 381
 382static const struct file_operations bfad_debugfs_op_drvtrc = {
 383        .owner          =       THIS_MODULE,
 384        .open           =       bfad_debugfs_open_drvtrc,
 385        .llseek         =       bfad_debugfs_lseek,
 386        .read           =       bfad_debugfs_read,
 387        .release        =       bfad_debugfs_release,
 388};
 389
 390static const struct file_operations bfad_debugfs_op_fwtrc = {
 391        .owner          =       THIS_MODULE,
 392        .open           =       bfad_debugfs_open_fwtrc,
 393        .llseek         =       bfad_debugfs_lseek,
 394        .read           =       bfad_debugfs_read,
 395        .release        =       bfad_debugfs_release_fwtrc,
 396};
 397
 398static const struct file_operations bfad_debugfs_op_fwsave = {
 399        .owner          =       THIS_MODULE,
 400        .open           =       bfad_debugfs_open_fwsave,
 401        .llseek         =       bfad_debugfs_lseek,
 402        .read           =       bfad_debugfs_read,
 403        .release        =       bfad_debugfs_release_fwtrc,
 404};
 405
 406static const struct file_operations bfad_debugfs_op_regrd = {
 407        .owner          =       THIS_MODULE,
 408        .open           =       bfad_debugfs_open_reg,
 409        .llseek         =       bfad_debugfs_lseek,
 410        .read           =       bfad_debugfs_read_regrd,
 411        .write          =       bfad_debugfs_write_regrd,
 412        .release        =       bfad_debugfs_release,
 413};
 414
 415static const struct file_operations bfad_debugfs_op_regwr = {
 416        .owner          =       THIS_MODULE,
 417        .open           =       bfad_debugfs_open_reg,
 418        .llseek         =       bfad_debugfs_lseek,
 419        .write          =       bfad_debugfs_write_regwr,
 420        .release        =       bfad_debugfs_release,
 421};
 422
 423struct bfad_debugfs_entry {
 424        const char *name;
 425        umode_t mode;
 426        const struct file_operations *fops;
 427};
 428
 429static const struct bfad_debugfs_entry bfad_debugfs_files[] = {
 430        { "drvtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_drvtrc, },
 431        { "fwtrc",  S_IFREG|S_IRUGO, &bfad_debugfs_op_fwtrc,  },
 432        { "fwsave", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwsave, },
 433        { "regrd",  S_IFREG|S_IRUGO|S_IWUSR, &bfad_debugfs_op_regrd,  },
 434        { "regwr",  S_IFREG|S_IWUSR, &bfad_debugfs_op_regwr,  },
 435};
 436
 437static struct dentry *bfa_debugfs_root;
 438static atomic_t bfa_debugfs_port_count;
 439
 440inline void
 441bfad_debugfs_init(struct bfad_port_s *port)
 442{
 443        struct bfad_s *bfad = port->bfad;
 444        const struct bfad_debugfs_entry *file;
 445        char name[64];
 446        int i;
 447
 448        if (!bfa_debugfs_enable)
 449                return;
 450
 451        /* Setup the BFA debugfs root directory*/
 452        if (!bfa_debugfs_root) {
 453                bfa_debugfs_root = debugfs_create_dir("bfa", NULL);
 454                atomic_set(&bfa_debugfs_port_count, 0);
 455        }
 456
 457        /* Setup the pci_dev debugfs directory for the port */
 458        snprintf(name, sizeof(name), "pci_dev:%s", bfad->pci_name);
 459        if (!port->port_debugfs_root) {
 460                port->port_debugfs_root =
 461                        debugfs_create_dir(name, bfa_debugfs_root);
 462
 463                atomic_inc(&bfa_debugfs_port_count);
 464
 465                for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
 466                        file = &bfad_debugfs_files[i];
 467                        bfad->bfad_dentry_files[i] =
 468                                        debugfs_create_file(file->name,
 469                                                        file->mode,
 470                                                        port->port_debugfs_root,
 471                                                        port,
 472                                                        file->fops);
 473                }
 474        }
 475
 476        return;
 477}
 478
 479inline void
 480bfad_debugfs_exit(struct bfad_port_s *port)
 481{
 482        struct bfad_s *bfad = port->bfad;
 483        int i;
 484
 485        for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
 486                if (bfad->bfad_dentry_files[i]) {
 487                        debugfs_remove(bfad->bfad_dentry_files[i]);
 488                        bfad->bfad_dentry_files[i] = NULL;
 489                }
 490        }
 491
 492        /* Remove the pci_dev debugfs directory for the port */
 493        if (port->port_debugfs_root) {
 494                debugfs_remove(port->port_debugfs_root);
 495                port->port_debugfs_root = NULL;
 496                atomic_dec(&bfa_debugfs_port_count);
 497        }
 498
 499        /* Remove the BFA debugfs root directory */
 500        if (atomic_read(&bfa_debugfs_port_count) == 0) {
 501                debugfs_remove(bfa_debugfs_root);
 502                bfa_debugfs_root = NULL;
 503        }
 504}
 505