linux/drivers/scsi/qla2xxx/qla_dfs.c
<<
>>
Prefs
   1/*
   2 * QLogic Fibre Channel HBA Driver
   3 * Copyright (c)  2003-2014 QLogic Corporation
   4 *
   5 * See LICENSE.qla2xxx for copyright and licensing details.
   6 */
   7#include "qla_def.h"
   8
   9#include <linux/debugfs.h>
  10#include <linux/seq_file.h>
  11
  12static struct dentry *qla2x00_dfs_root;
  13static atomic_t qla2x00_dfs_root_count;
  14
  15static int
  16qla2x00_dfs_tgt_sess_show(struct seq_file *s, void *unused)
  17{
  18        scsi_qla_host_t *vha = s->private;
  19        struct qla_hw_data *ha = vha->hw;
  20        unsigned long flags;
  21        struct fc_port *sess = NULL;
  22        struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
  23
  24        seq_printf(s, "%s\n", vha->host_str);
  25        if (tgt) {
  26                seq_puts(s, "Port ID   Port Name                Handle\n");
  27
  28                spin_lock_irqsave(&ha->tgt.sess_lock, flags);
  29                list_for_each_entry(sess, &vha->vp_fcports, list)
  30                        seq_printf(s, "%02x:%02x:%02x  %8phC  %d\n",
  31                            sess->d_id.b.domain, sess->d_id.b.area,
  32                            sess->d_id.b.al_pa, sess->port_name,
  33                            sess->loop_id);
  34                spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
  35        }
  36
  37        return 0;
  38}
  39
  40static int
  41qla2x00_dfs_tgt_sess_open(struct inode *inode, struct file *file)
  42{
  43        scsi_qla_host_t *vha = inode->i_private;
  44        return single_open(file, qla2x00_dfs_tgt_sess_show, vha);
  45}
  46
  47static const struct file_operations dfs_tgt_sess_ops = {
  48        .open           = qla2x00_dfs_tgt_sess_open,
  49        .read           = seq_read,
  50        .llseek         = seq_lseek,
  51        .release        = single_release,
  52};
  53
  54static int
  55qla2x00_dfs_tgt_port_database_show(struct seq_file *s, void *unused)
  56{
  57        scsi_qla_host_t *vha = s->private;
  58        struct qla_hw_data *ha = vha->hw;
  59        struct gid_list_info *gid_list;
  60        dma_addr_t gid_list_dma;
  61        fc_port_t fc_port;
  62        char *id_iter;
  63        int rc, i;
  64        uint16_t entries, loop_id;
  65        struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
  66
  67        seq_printf(s, "%s\n", vha->host_str);
  68        if (tgt) {
  69                gid_list = dma_alloc_coherent(&ha->pdev->dev,
  70                    qla2x00_gid_list_size(ha),
  71                    &gid_list_dma, GFP_KERNEL);
  72                if (!gid_list) {
  73                        ql_dbg(ql_dbg_user, vha, 0x7018,
  74                            "DMA allocation failed for %u\n",
  75                             qla2x00_gid_list_size(ha));
  76                        return 0;
  77                }
  78
  79                rc = qla24xx_gidlist_wait(vha, gid_list, gid_list_dma,
  80                    &entries);
  81                if (rc != QLA_SUCCESS)
  82                        goto out_free_id_list;
  83
  84                id_iter = (char *)gid_list;
  85
  86                seq_puts(s, "Port Name  Port ID         Loop ID\n");
  87
  88                for (i = 0; i < entries; i++) {
  89                        struct gid_list_info *gid =
  90                            (struct gid_list_info *)id_iter;
  91                        loop_id = le16_to_cpu(gid->loop_id);
  92                        memset(&fc_port, 0, sizeof(fc_port_t));
  93
  94                        fc_port.loop_id = loop_id;
  95
  96                        rc = qla24xx_gpdb_wait(vha, &fc_port, 0);
  97                        seq_printf(s, "%8phC  %02x%02x%02x  %d\n",
  98                                fc_port.port_name, fc_port.d_id.b.domain,
  99                                fc_port.d_id.b.area, fc_port.d_id.b.al_pa,
 100                                fc_port.loop_id);
 101                        id_iter += ha->gid_list_info_size;
 102                }
 103out_free_id_list:
 104                dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha),
 105                    gid_list, gid_list_dma);
 106        }
 107
 108        return 0;
 109}
 110
 111static int
 112qla2x00_dfs_tgt_port_database_open(struct inode *inode, struct file *file)
 113{
 114        scsi_qla_host_t *vha = inode->i_private;
 115
 116        return single_open(file, qla2x00_dfs_tgt_port_database_show, vha);
 117}
 118
 119static const struct file_operations dfs_tgt_port_database_ops = {
 120        .open           = qla2x00_dfs_tgt_port_database_open,
 121        .read           = seq_read,
 122        .llseek         = seq_lseek,
 123        .release        = single_release,
 124};
 125
 126static int
 127qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
 128{
 129        struct scsi_qla_host *vha = s->private;
 130        uint16_t mb[MAX_IOCB_MB_REG];
 131        int rc;
 132
 133        rc = qla24xx_res_count_wait(vha, mb, SIZEOF_IOCB_MB_REG);
 134        if (rc != QLA_SUCCESS) {
 135                seq_printf(s, "Mailbox Command failed %d, mb %#x", rc, mb[0]);
 136        } else {
 137                seq_puts(s, "FW Resource count\n\n");
 138                seq_printf(s, "Original TGT exchg count[%d]\n", mb[1]);
 139                seq_printf(s, "current TGT exchg count[%d]\n", mb[2]);
 140                seq_printf(s, "original Initiator Exchange count[%d]\n", mb[3]);
 141                seq_printf(s, "Current Initiator Exchange count[%d]\n", mb[6]);
 142                seq_printf(s, "Original IOCB count[%d]\n", mb[7]);
 143                seq_printf(s, "Current IOCB count[%d]\n", mb[10]);
 144                seq_printf(s, "MAX VP count[%d]\n", mb[11]);
 145                seq_printf(s, "MAX FCF count[%d]\n", mb[12]);
 146                seq_printf(s, "Current free pageable XCB buffer cnt[%d]\n",
 147                    mb[20]);
 148                seq_printf(s, "Original Initiator fast XCB buffer cnt[%d]\n",
 149                    mb[21]);
 150                seq_printf(s, "Current free Initiator fast XCB buffer cnt[%d]\n",
 151                    mb[22]);
 152                seq_printf(s, "Original Target fast XCB buffer cnt[%d]\n",
 153                    mb[23]);
 154
 155        }
 156
 157        return 0;
 158}
 159
 160static int
 161qla_dfs_fw_resource_cnt_open(struct inode *inode, struct file *file)
 162{
 163        struct scsi_qla_host *vha = inode->i_private;
 164        return single_open(file, qla_dfs_fw_resource_cnt_show, vha);
 165}
 166
 167static const struct file_operations dfs_fw_resource_cnt_ops = {
 168        .open           = qla_dfs_fw_resource_cnt_open,
 169        .read           = seq_read,
 170        .llseek         = seq_lseek,
 171        .release        = single_release,
 172};
 173
 174static int
 175qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
 176{
 177        struct scsi_qla_host *vha = s->private;
 178        struct qla_qpair *qpair = vha->hw->base_qpair;
 179        uint64_t qla_core_sbt_cmd, core_qla_que_buf, qla_core_ret_ctio,
 180                core_qla_snd_status, qla_core_ret_sta_ctio, core_qla_free_cmd,
 181                num_q_full_sent, num_alloc_iocb_failed, num_term_xchg_sent;
 182        u16 i;
 183
 184        qla_core_sbt_cmd = qpair->tgt_counters.qla_core_sbt_cmd;
 185        core_qla_que_buf = qpair->tgt_counters.core_qla_que_buf;
 186        qla_core_ret_ctio = qpair->tgt_counters.qla_core_ret_ctio;
 187        core_qla_snd_status = qpair->tgt_counters.core_qla_snd_status;
 188        qla_core_ret_sta_ctio = qpair->tgt_counters.qla_core_ret_sta_ctio;
 189        core_qla_free_cmd = qpair->tgt_counters.core_qla_free_cmd;
 190        num_q_full_sent = qpair->tgt_counters.num_q_full_sent;
 191        num_alloc_iocb_failed = qpair->tgt_counters.num_alloc_iocb_failed;
 192        num_term_xchg_sent = qpair->tgt_counters.num_term_xchg_sent;
 193
 194        for (i = 0; i < vha->hw->max_qpairs; i++) {
 195                qpair = vha->hw->queue_pair_map[i];
 196                qla_core_sbt_cmd += qpair->tgt_counters.qla_core_sbt_cmd;
 197                core_qla_que_buf += qpair->tgt_counters.core_qla_que_buf;
 198                qla_core_ret_ctio += qpair->tgt_counters.qla_core_ret_ctio;
 199                core_qla_snd_status += qpair->tgt_counters.core_qla_snd_status;
 200                qla_core_ret_sta_ctio +=
 201                    qpair->tgt_counters.qla_core_ret_sta_ctio;
 202                core_qla_free_cmd += qpair->tgt_counters.core_qla_free_cmd;
 203                num_q_full_sent += qpair->tgt_counters.num_q_full_sent;
 204                num_alloc_iocb_failed +=
 205                    qpair->tgt_counters.num_alloc_iocb_failed;
 206                num_term_xchg_sent += qpair->tgt_counters.num_term_xchg_sent;
 207        }
 208
 209        seq_puts(s, "Target Counters\n");
 210        seq_printf(s, "qla_core_sbt_cmd = %lld\n",
 211                qla_core_sbt_cmd);
 212        seq_printf(s, "qla_core_ret_sta_ctio = %lld\n",
 213                qla_core_ret_sta_ctio);
 214        seq_printf(s, "qla_core_ret_ctio = %lld\n",
 215                qla_core_ret_ctio);
 216        seq_printf(s, "core_qla_que_buf = %lld\n",
 217                core_qla_que_buf);
 218        seq_printf(s, "core_qla_snd_status = %lld\n",
 219                core_qla_snd_status);
 220        seq_printf(s, "core_qla_free_cmd = %lld\n",
 221                core_qla_free_cmd);
 222        seq_printf(s, "num alloc iocb failed = %lld\n",
 223                num_alloc_iocb_failed);
 224        seq_printf(s, "num term exchange sent = %lld\n",
 225                num_term_xchg_sent);
 226        seq_printf(s, "num Q full sent = %lld\n",
 227                num_q_full_sent);
 228
 229        /* DIF stats */
 230        seq_printf(s, "DIF Inp Bytes = %lld\n",
 231                vha->qla_stats.qla_dif_stats.dif_input_bytes);
 232        seq_printf(s, "DIF Outp Bytes = %lld\n",
 233                vha->qla_stats.qla_dif_stats.dif_output_bytes);
 234        seq_printf(s, "DIF Inp Req = %lld\n",
 235                vha->qla_stats.qla_dif_stats.dif_input_requests);
 236        seq_printf(s, "DIF Outp Req = %lld\n",
 237                vha->qla_stats.qla_dif_stats.dif_output_requests);
 238        seq_printf(s, "DIF Guard err = %d\n",
 239                vha->qla_stats.qla_dif_stats.dif_guard_err);
 240        seq_printf(s, "DIF Ref tag err = %d\n",
 241                vha->qla_stats.qla_dif_stats.dif_ref_tag_err);
 242        seq_printf(s, "DIF App tag err = %d\n",
 243                vha->qla_stats.qla_dif_stats.dif_app_tag_err);
 244        return 0;
 245}
 246
 247static int
 248qla_dfs_tgt_counters_open(struct inode *inode, struct file *file)
 249{
 250        struct scsi_qla_host *vha = inode->i_private;
 251        return single_open(file, qla_dfs_tgt_counters_show, vha);
 252}
 253
 254static const struct file_operations dfs_tgt_counters_ops = {
 255        .open           = qla_dfs_tgt_counters_open,
 256        .read           = seq_read,
 257        .llseek         = seq_lseek,
 258        .release        = single_release,
 259};
 260
 261static int
 262qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
 263{
 264        scsi_qla_host_t *vha = s->private;
 265        uint32_t cnt;
 266        uint32_t *fce;
 267        uint64_t fce_start;
 268        struct qla_hw_data *ha = vha->hw;
 269
 270        mutex_lock(&ha->fce_mutex);
 271
 272        seq_puts(s, "FCE Trace Buffer\n");
 273        seq_printf(s, "In Pointer = %llx\n\n", (unsigned long long)ha->fce_wr);
 274        seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma);
 275        seq_puts(s, "FCE Enable Registers\n");
 276        seq_printf(s, "%08x %08x %08x %08x %08x %08x\n",
 277            ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4],
 278            ha->fce_mb[5], ha->fce_mb[6]);
 279
 280        fce = (uint32_t *) ha->fce;
 281        fce_start = (unsigned long long) ha->fce_dma;
 282        for (cnt = 0; cnt < fce_calc_size(ha->fce_bufs) / 4; cnt++) {
 283                if (cnt % 8 == 0)
 284                        seq_printf(s, "\n%llx: ",
 285                            (unsigned long long)((cnt * 4) + fce_start));
 286                else
 287                        seq_putc(s, ' ');
 288                seq_printf(s, "%08x", *fce++);
 289        }
 290
 291        seq_puts(s, "\nEnd\n");
 292
 293        mutex_unlock(&ha->fce_mutex);
 294
 295        return 0;
 296}
 297
 298static int
 299qla2x00_dfs_fce_open(struct inode *inode, struct file *file)
 300{
 301        scsi_qla_host_t *vha = inode->i_private;
 302        struct qla_hw_data *ha = vha->hw;
 303        int rval;
 304
 305        if (!ha->flags.fce_enabled)
 306                goto out;
 307
 308        mutex_lock(&ha->fce_mutex);
 309
 310        /* Pause tracing to flush FCE buffers. */
 311        rval = qla2x00_disable_fce_trace(vha, &ha->fce_wr, &ha->fce_rd);
 312        if (rval)
 313                ql_dbg(ql_dbg_user, vha, 0x705c,
 314                    "DebugFS: Unable to disable FCE (%d).\n", rval);
 315
 316        ha->flags.fce_enabled = 0;
 317
 318        mutex_unlock(&ha->fce_mutex);
 319out:
 320        return single_open(file, qla2x00_dfs_fce_show, vha);
 321}
 322
 323static int
 324qla2x00_dfs_fce_release(struct inode *inode, struct file *file)
 325{
 326        scsi_qla_host_t *vha = inode->i_private;
 327        struct qla_hw_data *ha = vha->hw;
 328        int rval;
 329
 330        if (ha->flags.fce_enabled)
 331                goto out;
 332
 333        mutex_lock(&ha->fce_mutex);
 334
 335        /* Re-enable FCE tracing. */
 336        ha->flags.fce_enabled = 1;
 337        memset(ha->fce, 0, fce_calc_size(ha->fce_bufs));
 338        rval = qla2x00_enable_fce_trace(vha, ha->fce_dma, ha->fce_bufs,
 339            ha->fce_mb, &ha->fce_bufs);
 340        if (rval) {
 341                ql_dbg(ql_dbg_user, vha, 0x700d,
 342                    "DebugFS: Unable to reinitialize FCE (%d).\n", rval);
 343                ha->flags.fce_enabled = 0;
 344        }
 345
 346        mutex_unlock(&ha->fce_mutex);
 347out:
 348        return single_release(inode, file);
 349}
 350
 351static const struct file_operations dfs_fce_ops = {
 352        .open           = qla2x00_dfs_fce_open,
 353        .read           = seq_read,
 354        .llseek         = seq_lseek,
 355        .release        = qla2x00_dfs_fce_release,
 356};
 357
 358static int
 359qla_dfs_naqp_show(struct seq_file *s, void *unused)
 360{
 361        struct scsi_qla_host *vha = s->private;
 362        struct qla_hw_data *ha = vha->hw;
 363
 364        seq_printf(s, "%d\n", ha->tgt.num_act_qpairs);
 365        return 0;
 366}
 367
 368static int
 369qla_dfs_naqp_open(struct inode *inode, struct file *file)
 370{
 371        struct scsi_qla_host *vha = inode->i_private;
 372
 373        return single_open(file, qla_dfs_naqp_show, vha);
 374}
 375
 376static ssize_t
 377qla_dfs_naqp_write(struct file *file, const char __user *buffer,
 378    size_t count, loff_t *pos)
 379{
 380        struct seq_file *s = file->private_data;
 381        struct scsi_qla_host *vha = s->private;
 382        struct qla_hw_data *ha = vha->hw;
 383        char *buf;
 384        int rc = 0;
 385        unsigned long num_act_qp;
 386
 387        if (!(IS_QLA27XX(ha) || IS_QLA83XX(ha))) {
 388                pr_err("host%ld: this adapter does not support Multi Q.",
 389                    vha->host_no);
 390                return -EINVAL;
 391        }
 392
 393        if (!vha->flags.qpairs_available) {
 394                pr_err("host%ld: Driver is not setup with Multi Q.",
 395                    vha->host_no);
 396                return -EINVAL;
 397        }
 398        buf = memdup_user_nul(buffer, count);
 399        if (IS_ERR(buf)) {
 400                pr_err("host%ld: fail to copy user buffer.",
 401                    vha->host_no);
 402                return PTR_ERR(buf);
 403        }
 404
 405        num_act_qp = simple_strtoul(buf, NULL, 0);
 406
 407        if (num_act_qp >= vha->hw->max_qpairs) {
 408                pr_err("User set invalid number of qpairs %lu. Max = %d",
 409                    num_act_qp, vha->hw->max_qpairs);
 410                rc = -EINVAL;
 411                goto out_free;
 412        }
 413
 414        if (num_act_qp != ha->tgt.num_act_qpairs) {
 415                ha->tgt.num_act_qpairs = num_act_qp;
 416                qlt_clr_qp_table(vha);
 417        }
 418        rc = count;
 419out_free:
 420        kfree(buf);
 421        return rc;
 422}
 423
 424static const struct file_operations dfs_naqp_ops = {
 425        .open           = qla_dfs_naqp_open,
 426        .read           = seq_read,
 427        .llseek         = seq_lseek,
 428        .release        = single_release,
 429        .write          = qla_dfs_naqp_write,
 430};
 431
 432
 433int
 434qla2x00_dfs_setup(scsi_qla_host_t *vha)
 435{
 436        struct qla_hw_data *ha = vha->hw;
 437
 438        if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
 439            !IS_QLA27XX(ha))
 440                goto out;
 441        if (!ha->fce)
 442                goto out;
 443
 444        if (qla2x00_dfs_root)
 445                goto create_dir;
 446
 447        atomic_set(&qla2x00_dfs_root_count, 0);
 448        qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL);
 449        if (!qla2x00_dfs_root) {
 450                ql_log(ql_log_warn, vha, 0x00f7,
 451                    "Unable to create debugfs root directory.\n");
 452                goto out;
 453        }
 454
 455create_dir:
 456        if (ha->dfs_dir)
 457                goto create_nodes;
 458
 459        mutex_init(&ha->fce_mutex);
 460        ha->dfs_dir = debugfs_create_dir(vha->host_str, qla2x00_dfs_root);
 461        if (!ha->dfs_dir) {
 462                ql_log(ql_log_warn, vha, 0x00f8,
 463                    "Unable to create debugfs ha directory.\n");
 464                goto out;
 465        }
 466
 467        atomic_inc(&qla2x00_dfs_root_count);
 468
 469create_nodes:
 470        ha->dfs_fw_resource_cnt = debugfs_create_file("fw_resource_count",
 471            S_IRUSR, ha->dfs_dir, vha, &dfs_fw_resource_cnt_ops);
 472        if (!ha->dfs_fw_resource_cnt) {
 473                ql_log(ql_log_warn, vha, 0x00fd,
 474                    "Unable to create debugFS fw_resource_count node.\n");
 475                goto out;
 476        }
 477
 478        ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR,
 479            ha->dfs_dir, vha, &dfs_tgt_counters_ops);
 480        if (!ha->dfs_tgt_counters) {
 481                ql_log(ql_log_warn, vha, 0xd301,
 482                    "Unable to create debugFS tgt_counters node.\n");
 483                goto out;
 484        }
 485
 486        ha->tgt.dfs_tgt_port_database = debugfs_create_file("tgt_port_database",
 487            S_IRUSR,  ha->dfs_dir, vha, &dfs_tgt_port_database_ops);
 488        if (!ha->tgt.dfs_tgt_port_database) {
 489                ql_log(ql_log_warn, vha, 0xd03f,
 490                    "Unable to create debugFS tgt_port_database node.\n");
 491                goto out;
 492        }
 493
 494        ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
 495            &dfs_fce_ops);
 496        if (!ha->dfs_fce) {
 497                ql_log(ql_log_warn, vha, 0x00f9,
 498                    "Unable to create debugfs fce node.\n");
 499                goto out;
 500        }
 501
 502        ha->tgt.dfs_tgt_sess = debugfs_create_file("tgt_sess",
 503                S_IRUSR, ha->dfs_dir, vha, &dfs_tgt_sess_ops);
 504        if (!ha->tgt.dfs_tgt_sess) {
 505                ql_log(ql_log_warn, vha, 0xd040,
 506                    "Unable to create debugFS tgt_sess node.\n");
 507                goto out;
 508        }
 509
 510        if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) {
 511                ha->tgt.dfs_naqp = debugfs_create_file("naqp",
 512                    0400, ha->dfs_dir, vha, &dfs_naqp_ops);
 513                if (!ha->tgt.dfs_naqp) {
 514                        ql_log(ql_log_warn, vha, 0xd011,
 515                            "Unable to create debugFS naqp node.\n");
 516                        goto out;
 517                }
 518        }
 519out:
 520        return 0;
 521}
 522
 523int
 524qla2x00_dfs_remove(scsi_qla_host_t *vha)
 525{
 526        struct qla_hw_data *ha = vha->hw;
 527
 528        if (ha->tgt.dfs_naqp) {
 529                debugfs_remove(ha->tgt.dfs_naqp);
 530                ha->tgt.dfs_naqp = NULL;
 531        }
 532
 533        if (ha->tgt.dfs_tgt_sess) {
 534                debugfs_remove(ha->tgt.dfs_tgt_sess);
 535                ha->tgt.dfs_tgt_sess = NULL;
 536        }
 537
 538        if (ha->tgt.dfs_tgt_port_database) {
 539                debugfs_remove(ha->tgt.dfs_tgt_port_database);
 540                ha->tgt.dfs_tgt_port_database = NULL;
 541        }
 542
 543        if (ha->dfs_fw_resource_cnt) {
 544                debugfs_remove(ha->dfs_fw_resource_cnt);
 545                ha->dfs_fw_resource_cnt = NULL;
 546        }
 547
 548        if (ha->dfs_tgt_counters) {
 549                debugfs_remove(ha->dfs_tgt_counters);
 550                ha->dfs_tgt_counters = NULL;
 551        }
 552
 553        if (ha->dfs_fce) {
 554                debugfs_remove(ha->dfs_fce);
 555                ha->dfs_fce = NULL;
 556        }
 557
 558        if (ha->dfs_dir) {
 559                debugfs_remove(ha->dfs_dir);
 560                ha->dfs_dir = NULL;
 561                atomic_dec(&qla2x00_dfs_root_count);
 562        }
 563
 564        if (atomic_read(&qla2x00_dfs_root_count) == 0 &&
 565            qla2x00_dfs_root) {
 566                debugfs_remove(qla2x00_dfs_root);
 567                qla2x00_dfs_root = NULL;
 568        }
 569
 570        return 0;
 571}
 572