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