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