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