Merge tag 'spdx-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[linux-2.6-microblaze.git] / drivers / scsi / qla2xxx / qla_dfs.c
index 1db2ede..f89ad32 100644 (file)
 static struct dentry *qla2x00_dfs_root;
 static atomic_t qla2x00_dfs_root_count;
 
+#define QLA_DFS_RPORT_DEVLOSS_TMO      1
+
+static int
+qla_dfs_rport_get(struct fc_port *fp, int attr_id, u64 *val)
+{
+       switch (attr_id) {
+       case QLA_DFS_RPORT_DEVLOSS_TMO:
+               /* Only supported for FC-NVMe devices that are registered. */
+               if (!(fp->nvme_flag & NVME_FLAG_REGISTERED))
+                       return -EIO;
+               *val = fp->nvme_remote_port->dev_loss_tmo;
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static int
+qla_dfs_rport_set(struct fc_port *fp, int attr_id, u64 val)
+{
+       switch (attr_id) {
+       case QLA_DFS_RPORT_DEVLOSS_TMO:
+               /* Only supported for FC-NVMe devices that are registered. */
+               if (!(fp->nvme_flag & NVME_FLAG_REGISTERED))
+                       return -EIO;
+#if (IS_ENABLED(CONFIG_NVME_FC))
+               return nvme_fc_set_remoteport_devloss(fp->nvme_remote_port,
+                                                     val);
+#else /* CONFIG_NVME_FC */
+               return -EINVAL;
+#endif /* CONFIG_NVME_FC */
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+#define DEFINE_QLA_DFS_RPORT_RW_ATTR(_attr_id, _attr)          \
+static int qla_dfs_rport_##_attr##_get(void *data, u64 *val)   \
+{                                                              \
+       struct fc_port *fp = data;                              \
+       return qla_dfs_rport_get(fp, _attr_id, val);            \
+}                                                              \
+static int qla_dfs_rport_##_attr##_set(void *data, u64 val)    \
+{                                                              \
+       struct fc_port *fp = data;                              \
+       return qla_dfs_rport_set(fp, _attr_id, val);            \
+}                                                              \
+DEFINE_DEBUGFS_ATTRIBUTE(qla_dfs_rport_##_attr##_fops,         \
+               qla_dfs_rport_##_attr##_get,                    \
+               qla_dfs_rport_##_attr##_set, "%llu\n")
+
+/*
+ * Wrapper for getting fc_port fields.
+ *
+ * _attr    : Attribute name.
+ * _get_val : Accessor macro to retrieve the value.
+ */
+#define DEFINE_QLA_DFS_RPORT_FIELD_GET(_attr, _get_val)                        \
+static int qla_dfs_rport_field_##_attr##_get(void *data, u64 *val)     \
+{                                                                      \
+       struct fc_port *fp = data;                                      \
+       *val = _get_val;                                                \
+       return 0;                                                       \
+}                                                                      \
+DEFINE_DEBUGFS_ATTRIBUTE(qla_dfs_rport_field_##_attr##_fops,           \
+               qla_dfs_rport_field_##_attr##_get,                      \
+               NULL, "%llu\n")
+
+#define DEFINE_QLA_DFS_RPORT_ACCESS(_attr, _get_val) \
+       DEFINE_QLA_DFS_RPORT_FIELD_GET(_attr, _get_val)
+
+#define DEFINE_QLA_DFS_RPORT_FIELD(_attr) \
+       DEFINE_QLA_DFS_RPORT_FIELD_GET(_attr, fp->_attr)
+
+DEFINE_QLA_DFS_RPORT_RW_ATTR(QLA_DFS_RPORT_DEVLOSS_TMO, dev_loss_tmo);
+
+DEFINE_QLA_DFS_RPORT_FIELD(disc_state);
+DEFINE_QLA_DFS_RPORT_FIELD(scan_state);
+DEFINE_QLA_DFS_RPORT_FIELD(fw_login_state);
+DEFINE_QLA_DFS_RPORT_FIELD(login_pause);
+DEFINE_QLA_DFS_RPORT_FIELD(flags);
+DEFINE_QLA_DFS_RPORT_FIELD(nvme_flag);
+DEFINE_QLA_DFS_RPORT_FIELD(last_rscn_gen);
+DEFINE_QLA_DFS_RPORT_FIELD(rscn_gen);
+DEFINE_QLA_DFS_RPORT_FIELD(login_gen);
+DEFINE_QLA_DFS_RPORT_FIELD(loop_id);
+DEFINE_QLA_DFS_RPORT_FIELD_GET(port_id, fp->d_id.b24);
+DEFINE_QLA_DFS_RPORT_FIELD_GET(sess_kref, kref_read(&fp->sess_kref));
+
+void
+qla2x00_dfs_create_rport(scsi_qla_host_t *vha, struct fc_port *fp)
+{
+       char wwn[32];
+
+#define QLA_CREATE_RPORT_FIELD_ATTR(_attr)                     \
+       debugfs_create_file(#_attr, 0400, fp->dfs_rport_dir,    \
+               fp, &qla_dfs_rport_field_##_attr##_fops)
+
+       if (!vha->dfs_rport_root || fp->dfs_rport_dir)
+               return;
+
+       sprintf(wwn, "pn-%016llx", wwn_to_u64(fp->port_name));
+       fp->dfs_rport_dir = debugfs_create_dir(wwn, vha->dfs_rport_root);
+       if (!fp->dfs_rport_dir)
+               return;
+       if (NVME_TARGET(vha->hw, fp))
+               debugfs_create_file("dev_loss_tmo", 0600, fp->dfs_rport_dir,
+                                   fp, &qla_dfs_rport_dev_loss_tmo_fops);
+
+       QLA_CREATE_RPORT_FIELD_ATTR(disc_state);
+       QLA_CREATE_RPORT_FIELD_ATTR(scan_state);
+       QLA_CREATE_RPORT_FIELD_ATTR(fw_login_state);
+       QLA_CREATE_RPORT_FIELD_ATTR(login_pause);
+       QLA_CREATE_RPORT_FIELD_ATTR(flags);
+       QLA_CREATE_RPORT_FIELD_ATTR(nvme_flag);
+       QLA_CREATE_RPORT_FIELD_ATTR(last_rscn_gen);
+       QLA_CREATE_RPORT_FIELD_ATTR(rscn_gen);
+       QLA_CREATE_RPORT_FIELD_ATTR(login_gen);
+       QLA_CREATE_RPORT_FIELD_ATTR(loop_id);
+       QLA_CREATE_RPORT_FIELD_ATTR(port_id);
+       QLA_CREATE_RPORT_FIELD_ATTR(sess_kref);
+}
+
+void
+qla2x00_dfs_remove_rport(scsi_qla_host_t *vha, struct fc_port *fp)
+{
+       if (!vha->dfs_rport_root || !fp->dfs_rport_dir)
+               return;
+       debugfs_remove_recursive(fp->dfs_rport_dir);
+       fp->dfs_rport_dir = NULL;
+}
+
 static int
 qla2x00_dfs_tgt_sess_show(struct seq_file *s, void *unused)
 {
@@ -56,51 +190,51 @@ qla2x00_dfs_tgt_port_database_show(struct seq_file *s, void *unused)
 {
        scsi_qla_host_t *vha = s->private;
        struct qla_hw_data *ha = vha->hw;
-       struct gid_list_info *gid_list, *gid;
+       struct gid_list_info *gid_list;
        dma_addr_t gid_list_dma;
        fc_port_t fc_port;
+       char *id_iter;
        int rc, i;
        uint16_t entries, loop_id;
-       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
 
        seq_printf(s, "%s\n", vha->host_str);
-       if (tgt) {
-               gid_list = dma_alloc_coherent(&ha->pdev->dev,
-                   qla2x00_gid_list_size(ha),
-                   &gid_list_dma, GFP_KERNEL);
-               if (!gid_list) {
-                       ql_dbg(ql_dbg_user, vha, 0x7018,
-                           "DMA allocation failed for %u\n",
-                            qla2x00_gid_list_size(ha));
-                       return 0;
-               }
+       gid_list = dma_alloc_coherent(&ha->pdev->dev,
+                                     qla2x00_gid_list_size(ha),
+                                     &gid_list_dma, GFP_KERNEL);
+       if (!gid_list) {
+               ql_dbg(ql_dbg_user, vha, 0x7018,
+                      "DMA allocation failed for %u\n",
+                      qla2x00_gid_list_size(ha));
+               return 0;
+       }
 
-               rc = qla24xx_gidlist_wait(vha, gid_list, gid_list_dma,
-                   &entries);
-               if (rc != QLA_SUCCESS)
-                       goto out_free_id_list;
+       rc = qla24xx_gidlist_wait(vha, gid_list, gid_list_dma,
+                                 &entries);
+       if (rc != QLA_SUCCESS)
+               goto out_free_id_list;
 
-               gid = gid_list;
+       id_iter = (char *)gid_list;
 
-               seq_puts(s, "Port Name  Port ID         Loop ID\n");
+       seq_puts(s, "Port Name  Port ID         Loop ID\n");
 
-               for (i = 0; i < entries; i++) {
-                       loop_id = le16_to_cpu(gid->loop_id);
-                       memset(&fc_port, 0, sizeof(fc_port_t));
+       for (i = 0; i < entries; i++) {
+               struct gid_list_info *gid =
+                       (struct gid_list_info *)id_iter;
+               loop_id = le16_to_cpu(gid->loop_id);
+               memset(&fc_port, 0, sizeof(fc_port_t));
 
-                       fc_port.loop_id = loop_id;
+               fc_port.loop_id = loop_id;
 
-                       rc = qla24xx_gpdb_wait(vha, &fc_port, 0);
-                       seq_printf(s, "%8phC  %02x%02x%02x  %d\n",
-                               fc_port.port_name, fc_port.d_id.b.domain,
-                               fc_port.d_id.b.area, fc_port.d_id.b.al_pa,
-                               fc_port.loop_id);
-                       gid = (void *)gid + ha->gid_list_info_size;
-               }
-out_free_id_list:
-               dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha),
-                   gid_list, gid_list_dma);
+               rc = qla24xx_gpdb_wait(vha, &fc_port, 0);
+               seq_printf(s, "%8phC  %02x%02x%02x  %d\n",
+                          fc_port.port_name, fc_port.d_id.b.domain,
+                          fc_port.d_id.b.area, fc_port.d_id.b.al_pa,
+                          fc_port.loop_id);
+               id_iter += ha->gid_list_info_size;
        }
+out_free_id_list:
+       dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha),
+                         gid_list, gid_list_dma);
 
        return 0;
 }
@@ -126,6 +260,8 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
        struct scsi_qla_host *vha = s->private;
        uint16_t mb[MAX_IOCB_MB_REG];
        int rc;
+       struct qla_hw_data *ha = vha->hw;
+       u16 iocbs_used, i;
 
        rc = qla24xx_res_count_wait(vha, mb, SIZEOF_IOCB_MB_REG);
        if (rc != QLA_SUCCESS) {
@@ -150,6 +286,18 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
                    mb[23]);
        }
 
+       if (ql2xenforce_iocb_limit) {
+               /* lock is not require. It's an estimate. */
+               iocbs_used = ha->base_qpair->fwres.iocbs_used;
+               for (i = 0; i < ha->max_qpairs; i++) {
+                       if (ha->queue_pair_map[i])
+                               iocbs_used += ha->queue_pair_map[i]->fwres.iocbs_used;
+               }
+
+               seq_printf(s, "Driver: estimate iocb used [%d] high water limit [%d]\n",
+                          iocbs_used, ha->base_qpair->fwres.iocbs_limit);
+       }
+
        return 0;
 }
 
@@ -472,9 +620,21 @@ create_nodes:
        ha->tgt.dfs_tgt_sess = debugfs_create_file("tgt_sess",
                S_IRUSR, ha->dfs_dir, vha, &dfs_tgt_sess_ops);
 
-       if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha))
+       if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha)) {
                ha->tgt.dfs_naqp = debugfs_create_file("naqp",
                    0400, ha->dfs_dir, vha, &dfs_naqp_ops);
+               if (!ha->tgt.dfs_naqp) {
+                       ql_log(ql_log_warn, vha, 0xd011,
+                              "Unable to create debugFS naqp node.\n");
+                       goto out;
+               }
+       }
+       vha->dfs_rport_root = debugfs_create_dir("rports", ha->dfs_dir);
+       if (!vha->dfs_rport_root) {
+               ql_log(ql_log_warn, vha, 0xd012,
+                      "Unable to create debugFS rports node.\n");
+               goto out;
+       }
 out:
        return 0;
 }
@@ -514,6 +674,11 @@ qla2x00_dfs_remove(scsi_qla_host_t *vha)
                ha->dfs_fce = NULL;
        }
 
+       if (vha->dfs_rport_root) {
+               debugfs_remove_recursive(vha->dfs_rport_root);
+               vha->dfs_rport_root = NULL;
+       }
+
        if (ha->dfs_dir) {
                debugfs_remove(ha->dfs_dir);
                ha->dfs_dir = NULL;