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