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        struct qla_hw_data *ha = vha->hw;
 131
 132        seq_puts(s, "FW Resource count\n\n");
 133        seq_printf(s, "Original TGT exchg count[%d]\n",
 134            ha->orig_fw_tgt_xcb_count);
 135        seq_printf(s, "current TGT exchg count[%d]\n",
 136            ha->cur_fw_tgt_xcb_count);
 137        seq_printf(s, "original Initiator Exchange count[%d]\n",
 138            ha->orig_fw_xcb_count);
 139        seq_printf(s, "Current Initiator Exchange count[%d]\n",
 140            ha->cur_fw_xcb_count);
 141        seq_printf(s, "Original IOCB count[%d]\n", ha->orig_fw_iocb_count);
 142        seq_printf(s, "Current IOCB count[%d]\n", ha->cur_fw_iocb_count);
 143        seq_printf(s, "MAX VP count[%d]\n", ha->max_npiv_vports);
 144        seq_printf(s, "MAX FCF count[%d]\n", ha->fw_max_fcf_count);
 145
 146        return 0;
 147}
 148
 149static int
 150qla_dfs_fw_resource_cnt_open(struct inode *inode, struct file *file)
 151{
 152        struct scsi_qla_host *vha = inode->i_private;
 153        return single_open(file, qla_dfs_fw_resource_cnt_show, vha);
 154}
 155
 156static const struct file_operations dfs_fw_resource_cnt_ops = {
 157        .open           = qla_dfs_fw_resource_cnt_open,
 158        .read           = seq_read,
 159        .llseek         = seq_lseek,
 160        .release        = single_release,
 161};
 162
 163static int
 164qla_dfs_tgt_counters_show(struct seq_file *s, void *unused)
 165{
 166        struct scsi_qla_host *vha = s->private;
 167        struct qla_qpair *qpair = vha->hw->base_qpair;
 168        uint64_t qla_core_sbt_cmd, core_qla_que_buf, qla_core_ret_ctio,
 169                core_qla_snd_status, qla_core_ret_sta_ctio, core_qla_free_cmd,
 170                num_q_full_sent, num_alloc_iocb_failed, num_term_xchg_sent;
 171        u16 i;
 172
 173        qla_core_sbt_cmd = qpair->tgt_counters.qla_core_sbt_cmd;
 174        core_qla_que_buf = qpair->tgt_counters.core_qla_que_buf;
 175        qla_core_ret_ctio = qpair->tgt_counters.qla_core_ret_ctio;
 176        core_qla_snd_status = qpair->tgt_counters.core_qla_snd_status;
 177        qla_core_ret_sta_ctio = qpair->tgt_counters.qla_core_ret_sta_ctio;
 178        core_qla_free_cmd = qpair->tgt_counters.core_qla_free_cmd;
 179        num_q_full_sent = qpair->tgt_counters.num_q_full_sent;
 180        num_alloc_iocb_failed = qpair->tgt_counters.num_alloc_iocb_failed;
 181        num_term_xchg_sent = qpair->tgt_counters.num_term_xchg_sent;
 182
 183        for (i = 0; i < vha->hw->max_qpairs; i++) {
 184                qpair = vha->hw->queue_pair_map[i];
 185                qla_core_sbt_cmd += qpair->tgt_counters.qla_core_sbt_cmd;
 186                core_qla_que_buf += qpair->tgt_counters.core_qla_que_buf;
 187                qla_core_ret_ctio += qpair->tgt_counters.qla_core_ret_ctio;
 188                core_qla_snd_status += qpair->tgt_counters.core_qla_snd_status;
 189                qla_core_ret_sta_ctio +=
 190                    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 +=
 194                    qpair->tgt_counters.num_alloc_iocb_failed;
 195                num_term_xchg_sent += qpair->tgt_counters.num_term_xchg_sent;
 196        }
 197
 198        seq_puts(s, "Target Counters\n");
 199        seq_printf(s, "qla_core_sbt_cmd = %lld\n",
 200                qla_core_sbt_cmd);
 201        seq_printf(s, "qla_core_ret_sta_ctio = %lld\n",
 202                qla_core_ret_sta_ctio);
 203        seq_printf(s, "qla_core_ret_ctio = %lld\n",
 204                qla_core_ret_ctio);
 205        seq_printf(s, "core_qla_que_buf = %lld\n",
 206                core_qla_que_buf);
 207        seq_printf(s, "core_qla_snd_status = %lld\n",
 208                core_qla_snd_status);
 209        seq_printf(s, "core_qla_free_cmd = %lld\n",
 210                core_qla_free_cmd);
 211        seq_printf(s, "num alloc iocb failed = %lld\n",
 212                num_alloc_iocb_failed);
 213        seq_printf(s, "num term exchange sent = %lld\n",
 214                num_term_xchg_sent);
 215        seq_printf(s, "num Q full sent = %lld\n",
 216                num_q_full_sent);
 217
 218        /* DIF stats */
 219        seq_printf(s, "DIF Inp Bytes = %lld\n",
 220                vha->qla_stats.qla_dif_stats.dif_input_bytes);
 221        seq_printf(s, "DIF Outp Bytes = %lld\n",
 222                vha->qla_stats.qla_dif_stats.dif_output_bytes);
 223        seq_printf(s, "DIF Inp Req = %lld\n",
 224                vha->qla_stats.qla_dif_stats.dif_input_requests);
 225        seq_printf(s, "DIF Outp Req = %lld\n",
 226                vha->qla_stats.qla_dif_stats.dif_output_requests);
 227        seq_printf(s, "DIF Guard err = %d\n",
 228                vha->qla_stats.qla_dif_stats.dif_guard_err);
 229        seq_printf(s, "DIF Ref tag err = %d\n",
 230                vha->qla_stats.qla_dif_stats.dif_ref_tag_err);
 231        seq_printf(s, "DIF App tag err = %d\n",
 232                vha->qla_stats.qla_dif_stats.dif_app_tag_err);
 233        return 0;
 234}
 235
 236static int
 237qla_dfs_tgt_counters_open(struct inode *inode, struct file *file)
 238{
 239        struct scsi_qla_host *vha = inode->i_private;
 240        return single_open(file, qla_dfs_tgt_counters_show, vha);
 241}
 242
 243static const struct file_operations dfs_tgt_counters_ops = {
 244        .open           = qla_dfs_tgt_counters_open,
 245        .read           = seq_read,
 246        .llseek         = seq_lseek,
 247        .release        = single_release,
 248};
 249
 250static int
 251qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
 252{
 253        scsi_qla_host_t *vha = s->private;
 254        uint32_t cnt;
 255        uint32_t *fce;
 256        uint64_t fce_start;
 257        struct qla_hw_data *ha = vha->hw;
 258
 259        mutex_lock(&ha->fce_mutex);
 260
 261        seq_puts(s, "FCE Trace Buffer\n");
 262        seq_printf(s, "In Pointer = %llx\n\n", (unsigned long long)ha->fce_wr);
 263        seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma);
 264        seq_puts(s, "FCE Enable Registers\n");
 265        seq_printf(s, "%08x %08x %08x %08x %08x %08x\n",
 266            ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4],
 267            ha->fce_mb[5], ha->fce_mb[6]);
 268
 269        fce = (uint32_t *) ha->fce;
 270        fce_start = (unsigned long long) ha->fce_dma;
 271        for (cnt = 0; cnt < fce_calc_size(ha->fce_bufs) / 4; cnt++) {
 272                if (cnt % 8 == 0)
 273                        seq_printf(s, "\n%llx: ",
 274                            (unsigned long long)((cnt * 4) + fce_start));
 275                else
 276                        seq_putc(s, ' ');
 277                seq_printf(s, "%08x", *fce++);
 278        }
 279
 280        seq_puts(s, "\nEnd\n");
 281
 282        mutex_unlock(&ha->fce_mutex);
 283
 284        return 0;
 285}
 286
 287static int
 288qla2x00_dfs_fce_open(struct inode *inode, struct file *file)
 289{
 290        scsi_qla_host_t *vha = inode->i_private;
 291        struct qla_hw_data *ha = vha->hw;
 292        int rval;
 293
 294        if (!ha->flags.fce_enabled)
 295                goto out;
 296
 297        mutex_lock(&ha->fce_mutex);
 298
 299        /* Pause tracing to flush FCE buffers. */
 300        rval = qla2x00_disable_fce_trace(vha, &ha->fce_wr, &ha->fce_rd);
 301        if (rval)
 302                ql_dbg(ql_dbg_user, vha, 0x705c,
 303                    "DebugFS: Unable to disable FCE (%d).\n", rval);
 304
 305        ha->flags.fce_enabled = 0;
 306
 307        mutex_unlock(&ha->fce_mutex);
 308out:
 309        return single_open(file, qla2x00_dfs_fce_show, vha);
 310}
 311
 312static int
 313qla2x00_dfs_fce_release(struct inode *inode, struct file *file)
 314{
 315        scsi_qla_host_t *vha = inode->i_private;
 316        struct qla_hw_data *ha = vha->hw;
 317        int rval;
 318
 319        if (ha->flags.fce_enabled)
 320                goto out;
 321
 322        mutex_lock(&ha->fce_mutex);
 323
 324        /* Re-enable FCE tracing. */
 325        ha->flags.fce_enabled = 1;
 326        memset(ha->fce, 0, fce_calc_size(ha->fce_bufs));
 327        rval = qla2x00_enable_fce_trace(vha, ha->fce_dma, ha->fce_bufs,
 328            ha->fce_mb, &ha->fce_bufs);
 329        if (rval) {
 330                ql_dbg(ql_dbg_user, vha, 0x700d,
 331                    "DebugFS: Unable to reinitialize FCE (%d).\n", rval);
 332                ha->flags.fce_enabled = 0;
 333        }
 334
 335        mutex_unlock(&ha->fce_mutex);
 336out:
 337        return single_release(inode, file);
 338}
 339
 340static const struct file_operations dfs_fce_ops = {
 341        .open           = qla2x00_dfs_fce_open,
 342        .read           = seq_read,
 343        .llseek         = seq_lseek,
 344        .release        = qla2x00_dfs_fce_release,
 345};
 346
 347static int
 348qla_dfs_naqp_show(struct seq_file *s, void *unused)
 349{
 350        struct scsi_qla_host *vha = s->private;
 351        struct qla_hw_data *ha = vha->hw;
 352
 353        seq_printf(s, "%d\n", ha->tgt.num_act_qpairs);
 354        return 0;
 355}
 356
 357static int
 358qla_dfs_naqp_open(struct inode *inode, struct file *file)
 359{
 360        struct scsi_qla_host *vha = inode->i_private;
 361
 362        return single_open(file, qla_dfs_naqp_show, vha);
 363}
 364
 365static ssize_t
 366qla_dfs_naqp_write(struct file *file, const char __user *buffer,
 367    size_t count, loff_t *pos)
 368{
 369        struct seq_file *s = file->private_data;
 370        struct scsi_qla_host *vha = s->private;
 371        struct qla_hw_data *ha = vha->hw;
 372        char *buf;
 373        int rc = 0;
 374        unsigned long num_act_qp;
 375
 376        if (!(IS_QLA27XX(ha) || IS_QLA83XX(ha))) {
 377                pr_err("host%ld: this adapter does not support Multi Q.",
 378                    vha->host_no);
 379                return -EINVAL;
 380        }
 381
 382        if (!vha->flags.qpairs_available) {
 383                pr_err("host%ld: Driver is not setup with Multi Q.",
 384                    vha->host_no);
 385                return -EINVAL;
 386        }
 387        buf = memdup_user_nul(buffer, count);
 388        if (IS_ERR(buf)) {
 389                pr_err("host%ld: fail to copy user buffer.",
 390                    vha->host_no);
 391                return PTR_ERR(buf);
 392        }
 393
 394        num_act_qp = simple_strtoul(buf, NULL, 0);
 395
 396        if (num_act_qp >= vha->hw->max_qpairs) {
 397                pr_err("User set invalid number of qpairs %lu. Max = %d",
 398                    num_act_qp, vha->hw->max_qpairs);
 399                rc = -EINVAL;
 400                goto out_free;
 401        }
 402
 403        if (num_act_qp != ha->tgt.num_act_qpairs) {
 404                ha->tgt.num_act_qpairs = num_act_qp;
 405                qlt_clr_qp_table(vha);
 406        }
 407        rc = count;
 408out_free:
 409        kfree(buf);
 410        return rc;
 411}
 412
 413static const struct file_operations dfs_naqp_ops = {
 414        .open           = qla_dfs_naqp_open,
 415        .read           = seq_read,
 416        .llseek         = seq_lseek,
 417        .release        = single_release,
 418        .write          = qla_dfs_naqp_write,
 419};
 420
 421
 422int
 423qla2x00_dfs_setup(scsi_qla_host_t *vha)
 424{
 425        struct qla_hw_data *ha = vha->hw;
 426
 427        if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
 428            !IS_QLA27XX(ha))
 429                goto out;
 430        if (!ha->fce)
 431                goto out;
 432
 433        if (qla2x00_dfs_root)
 434                goto create_dir;
 435
 436        atomic_set(&qla2x00_dfs_root_count, 0);
 437        qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL);
 438        if (!qla2x00_dfs_root) {
 439                ql_log(ql_log_warn, vha, 0x00f7,
 440                    "Unable to create debugfs root directory.\n");
 441                goto out;
 442        }
 443
 444create_dir:
 445        if (ha->dfs_dir)
 446                goto create_nodes;
 447
 448        mutex_init(&ha->fce_mutex);
 449        ha->dfs_dir = debugfs_create_dir(vha->host_str, qla2x00_dfs_root);
 450        if (!ha->dfs_dir) {
 451                ql_log(ql_log_warn, vha, 0x00f8,
 452                    "Unable to create debugfs ha directory.\n");
 453                goto out;
 454        }
 455
 456        atomic_inc(&qla2x00_dfs_root_count);
 457
 458create_nodes:
 459        ha->dfs_fw_resource_cnt = debugfs_create_file("fw_resource_count",
 460            S_IRUSR, ha->dfs_dir, vha, &dfs_fw_resource_cnt_ops);
 461        if (!ha->dfs_fw_resource_cnt) {
 462                ql_log(ql_log_warn, vha, 0x00fd,
 463                    "Unable to create debugFS fw_resource_count node.\n");
 464                goto out;
 465        }
 466
 467        ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR,
 468            ha->dfs_dir, vha, &dfs_tgt_counters_ops);
 469        if (!ha->dfs_tgt_counters) {
 470                ql_log(ql_log_warn, vha, 0xd301,
 471                    "Unable to create debugFS tgt_counters node.\n");
 472                goto out;
 473        }
 474
 475        ha->tgt.dfs_tgt_port_database = debugfs_create_file("tgt_port_database",
 476            S_IRUSR,  ha->dfs_dir, vha, &dfs_tgt_port_database_ops);
 477        if (!ha->tgt.dfs_tgt_port_database) {
 478                ql_log(ql_log_warn, vha, 0xd03f,
 479                    "Unable to create debugFS tgt_port_database node.\n");
 480                goto out;
 481        }
 482
 483        ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha,
 484            &dfs_fce_ops);
 485        if (!ha->dfs_fce) {
 486                ql_log(ql_log_warn, vha, 0x00f9,
 487                    "Unable to create debugfs fce node.\n");
 488                goto out;
 489        }
 490
 491        ha->tgt.dfs_tgt_sess = debugfs_create_file("tgt_sess",
 492                S_IRUSR, ha->dfs_dir, vha, &dfs_tgt_sess_ops);
 493        if (!ha->tgt.dfs_tgt_sess) {
 494                ql_log(ql_log_warn, vha, 0xd040,
 495                    "Unable to create debugFS tgt_sess node.\n");
 496                goto out;
 497        }
 498
 499        if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) {
 500                ha->tgt.dfs_naqp = debugfs_create_file("naqp",
 501                    0400, ha->dfs_dir, vha, &dfs_naqp_ops);
 502                if (!ha->tgt.dfs_naqp) {
 503                        ql_log(ql_log_warn, vha, 0xd011,
 504                            "Unable to create debugFS naqp node.\n");
 505                        goto out;
 506                }
 507        }
 508out:
 509        return 0;
 510}
 511
 512int
 513qla2x00_dfs_remove(scsi_qla_host_t *vha)
 514{
 515        struct qla_hw_data *ha = vha->hw;
 516
 517        if (ha->tgt.dfs_naqp) {
 518                debugfs_remove(ha->tgt.dfs_naqp);
 519                ha->tgt.dfs_naqp = NULL;
 520        }
 521
 522        if (ha->tgt.dfs_tgt_sess) {
 523                debugfs_remove(ha->tgt.dfs_tgt_sess);
 524                ha->tgt.dfs_tgt_sess = NULL;
 525        }
 526
 527        if (ha->tgt.dfs_tgt_port_database) {
 528                debugfs_remove(ha->tgt.dfs_tgt_port_database);
 529                ha->tgt.dfs_tgt_port_database = NULL;
 530        }
 531
 532        if (ha->dfs_fw_resource_cnt) {
 533                debugfs_remove(ha->dfs_fw_resource_cnt);
 534                ha->dfs_fw_resource_cnt = NULL;
 535        }
 536
 537        if (ha->dfs_tgt_counters) {
 538                debugfs_remove(ha->dfs_tgt_counters);
 539                ha->dfs_tgt_counters = NULL;
 540        }
 541
 542        if (ha->dfs_fce) {
 543                debugfs_remove(ha->dfs_fce);
 544                ha->dfs_fce = NULL;
 545        }
 546
 547        if (ha->dfs_dir) {
 548                debugfs_remove(ha->dfs_dir);
 549                ha->dfs_dir = NULL;
 550                atomic_dec(&qla2x00_dfs_root_count);
 551        }
 552
 553        if (atomic_read(&qla2x00_dfs_root_count) == 0 &&
 554            qla2x00_dfs_root) {
 555                debugfs_remove(qla2x00_dfs_root);
 556                qla2x00_dfs_root = NULL;
 557        }
 558
 559        return 0;
 560}
 561