summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/base/transport_class.c8
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c40
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c7
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h7
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c57
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c1
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h11
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c5
-rw-r--r--drivers/scsi/lpfc/lpfc_logmsg.h3
-rw-r--r--drivers/scsi/lpfc/lpfc_sli4.h4
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/scsi_transport_fc.c42
-rw-r--r--include/linux/transport_class.h1
-rw-r--r--include/scsi/scsi_transport_fc.h12
14 files changed, 197 insertions, 3 deletions
diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c
index 09ee2a1e35bb..69c6ac2e8263 100644
--- a/drivers/base/transport_class.c
+++ b/drivers/base/transport_class.c
@@ -169,6 +169,12 @@ static int transport_add_class_device(struct attribute_container *cont,
goto err_del;
}
+ if (tcont->encryption) {
+ error = sysfs_create_group(&classdev->kobj, tcont->encryption);
+ if (error)
+ goto err_del;
+ }
+
return 0;
err_del:
@@ -244,6 +250,8 @@ static int transport_remove_classdev(struct attribute_container *cont,
if (tclass->remove != anon_transport_dummy_function) {
if (tcont->statistics)
sysfs_remove_group(&classdev->kobj, tcont->statistics);
+ if (tcont->encryption)
+ sysfs_remove_group(&classdev->kobj, tcont->encryption);
attribute_container_class_device_del(classdev);
}
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 33582d48ec09..4af5c069635a 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -6979,6 +6979,42 @@ lpfc_reset_stats(struct Scsi_Host *shost)
return;
}
+/**
+ * lpfc_get_enc_info - Return encryption information about the session for
+ * a given remote port.
+ * @rport: ptr to fc_rport from scsi transport fc
+ *
+ * Given an rport object, iterate through the fc_nodes list to find node
+ * corresponding with rport. Pass the encryption information from the node to
+ * rport's encryption attribute for reporting to upper layers. Information is
+ * passed through nlp_enc_info struct which contains encryption status.
+ *
+ * Returns:
+ * - Address of rport's fc_encryption_info struct
+ * - NULL when not found
+ **/
+static struct fc_encryption_info *
+lpfc_get_enc_info(struct fc_rport *rport)
+{
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;
+ struct fc_encryption_info *ef = NULL;
+ struct lpfc_nodelist *ndlp, *next_ndlp;
+ unsigned long iflags;
+
+ spin_lock_irqsave(&vport->fc_nodes_list_lock, iflags);
+ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) {
+ if (ndlp->rport && ndlp->rport == rport) {
+ ef = &rport->enc_info;
+ ef->status = ndlp->nlp_enc_info.status;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&vport->fc_nodes_list_lock, iflags);
+ return ef;
+}
+
+
/*
* The LPFC driver treats linkdown handling as target loss events so there
* are no sysfs handlers for link_down_tmo.
@@ -7196,6 +7232,8 @@ struct fc_function_template lpfc_transport_functions = {
.get_fc_host_stats = lpfc_get_stats,
.reset_fc_host_stats = lpfc_reset_stats,
+ .get_fc_rport_enc_info = lpfc_get_enc_info,
+
.dd_fcrport_size = sizeof(struct lpfc_rport_data),
.show_rport_maxframe_size = 1,
.show_rport_supported_classes = 1,
@@ -7265,6 +7303,8 @@ struct fc_function_template lpfc_vport_transport_functions = {
.get_fc_host_stats = lpfc_get_stats,
.reset_fc_host_stats = lpfc_reset_stats,
+ .get_fc_rport_enc_info = lpfc_get_enc_info,
+
.dd_fcrport_size = sizeof(struct lpfc_rport_data),
.show_rport_maxframe_size = 1,
.show_rport_supported_classes = 1,
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 92b5b2dbe847..646f88c776f5 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -872,6 +872,13 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size)
ndlp->nlp_rpi);
len += scnprintf(buf+len, size-len, "flag:x%08lx ",
ndlp->nlp_flag);
+ if (ndlp->nlp_enc_info.status) {
+ len += scnprintf(buf + len,
+ size - len, "ENCRYPTED");
+ len += scnprintf(buf + len, size - len,
+ ndlp->nlp_enc_info.level
+ ? "(CNSA2.0) " : "(CNSA1.0) ");
+ }
if (!ndlp->nlp_type)
len += scnprintf(buf+len, size-len, "UNKNOWN_TYPE ");
if (ndlp->nlp_type & NLP_FC_NODE)
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 51cb8571c049..de0adeecf668 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -77,6 +77,11 @@ struct lpfc_node_rrqs {
unsigned long xri_bitmap[XRI_BITMAP_ULONGS];
};
+struct lpfc_enc_info {
+ u8 status; /* encryption status for session */
+ u8 level; /* CNSA encryption level */
+};
+
enum lpfc_fc4_xpt_flags {
NLP_XPT_REGD = 0x1,
SCSI_XPT_REGD = 0x2,
@@ -138,6 +143,8 @@ struct lpfc_nodelist {
uint8_t vmid_support; /* destination VMID support */
#define NLP_NVME_NSLER 0x1 /* NVME NSLER device */
+ struct lpfc_enc_info nlp_enc_info; /* Encryption information struct */
+
struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */
struct lpfc_hba *phba;
struct fc_rport *rport; /* scsi_transport_fc port structure */
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 02b6d31b9ad9..32da3c23c7f4 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -2014,6 +2014,58 @@ lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
lpfc_nlp_put(ndlp);
return;
}
+
+/**
+ * lpfc_check_encryption - Reports an ndlp's encryption information
+ * @phba: pointer to lpfc hba data structure.
+ * @ndlp: pointer to a node-list data structure.
+ * @cmdiocb: pointer to lpfc command iocbq data structure.
+ * @rspiocb: pointer to lpfc response iocbq data structure.
+ *
+ * This routine is called in the completion callback function for issuing
+ * or receiving a Port Login (PLOGI) command. In a PLOGI completion, if FEDIF
+ * is supported, encryption information will be provided in completion status
+ * data. If @phba supports FEDIF, a log message containing encryption
+ * information will be logged. Encryption status is also saved for encryption
+ * reporting with upper layer through the rport encryption attribute.
+ **/
+static void
+lpfc_check_encryption(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp,
+ struct lpfc_iocbq *cmdiocb, struct lpfc_iocbq *rspiocb)
+{
+ struct lpfc_vport *vport = cmdiocb->vport;
+ u32 did = ndlp->nlp_DID;
+ struct lpfc_enc_info *nlp_enc_info = &ndlp->nlp_enc_info;
+ char enc_status[FC_RPORT_ENCRYPTION_STATUS_MAX_LEN] = {0};
+ char enc_level[8] = "N/A";
+ u8 encryption;
+
+ if (phba->sli4_hba.encryption_support &&
+ ((did & Fabric_DID_MASK) != Fabric_DID_MASK)) {
+ encryption = bf_get(lpfc_wcqe_c_enc,
+ &rspiocb->wcqe_cmpl);
+ nlp_enc_info->status = encryption;
+
+ strscpy(enc_status, encryption ? "Encrypted" : "Unencrypted",
+ sizeof(enc_status));
+
+ if (encryption) {
+ nlp_enc_info->level = bf_get(lpfc_wcqe_c_enc_lvl,
+ &rspiocb->wcqe_cmpl);
+ strscpy(enc_level, nlp_enc_info->level ? "CNSA2.0" :
+ "CNSA1.0",
+ sizeof(enc_level));
+ }
+
+ lpfc_printf_vlog(vport, KERN_INFO, LOG_ENCRYPTION,
+ "0924 DID:x%06x %s Session "
+ "Established, Encryption Level:%s "
+ "rpi:x%x\n",
+ ndlp->nlp_DID, enc_status, enc_level,
+ ndlp->nlp_rpi);
+ }
+}
+
/**
* lpfc_cmpl_els_plogi - Completion callback function for plogi
* @phba: pointer to lpfc hba data structure.
@@ -2153,6 +2205,8 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto out;
ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp);
+ lpfc_check_encryption(phba, ndlp, cmdiocb, rspiocb);
+
sp = (struct serv_parm *)((u8 *)prsp->virt +
sizeof(u32));
@@ -5407,6 +5461,9 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
goto out;
}
+ if (!ulp_status && test_bit(NLP_RCV_PLOGI, &ndlp->nlp_flag))
+ lpfc_check_encryption(phba, ndlp, cmdiocb, rspiocb);
+
lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP,
"ELS rsp cmpl: status:x%x/x%x did:x%x",
ulp_status, ulp_word4, did);
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index bb803f32bc1b..1aeebdc08073 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -5340,6 +5340,7 @@ out:
clear_bit(NLP_NPR_ADISC, &ndlp->nlp_flag);
if (acc_plogi)
clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag);
+ memset(&ndlp->nlp_enc_info, 0, sizeof(ndlp->nlp_enc_info));
return 1;
}
clear_bit(NLP_LOGO_ACC, &ndlp->nlp_flag);
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index a7f7ed86d2b0..c000474c3066 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -437,6 +437,12 @@ struct lpfc_wcqe_complete {
#define lpfc_wcqe_c_cmf_bw_MASK 0x0FFFFFFF
#define lpfc_wcqe_c_cmf_bw_WORD total_data_placed
uint32_t parameter;
+#define lpfc_wcqe_c_enc_SHIFT 31
+#define lpfc_wcqe_c_enc_MASK 0x00000001
+#define lpfc_wcqe_c_enc_WORD parameter
+#define lpfc_wcqe_c_enc_lvl_SHIFT 30
+#define lpfc_wcqe_c_enc_lvl_MASK 0x00000001
+#define lpfc_wcqe_c_enc_lvl_WORD parameter
#define lpfc_wcqe_c_bg_edir_SHIFT 5
#define lpfc_wcqe_c_bg_edir_MASK 0x00000001
#define lpfc_wcqe_c_bg_edir_WORD parameter
@@ -2942,7 +2948,10 @@ struct lpfc_mbx_read_config {
#define lpfc_mbx_rd_conf_topology_SHIFT 24
#define lpfc_mbx_rd_conf_topology_MASK 0x000000FF
#define lpfc_mbx_rd_conf_topology_WORD word2
- uint32_t rsvd_3;
+ uint32_t word3;
+#define lpfc_mbx_rd_conf_fedif_SHIFT 6
+#define lpfc_mbx_rd_conf_fedif_MASK 0x00000001
+#define lpfc_mbx_rd_conf_fedif_WORD word3
uint32_t word4;
#define lpfc_mbx_rd_conf_e_d_tov_SHIFT 0
#define lpfc_mbx_rd_conf_e_d_tov_MASK 0x0000FFFF
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index b1460b16dd91..a116a16c4a6f 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -9999,6 +9999,11 @@ lpfc_sli4_read_config(struct lpfc_hba *phba)
(phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0;
phba->max_vports = phba->max_vpi;
+ if (bf_get(lpfc_mbx_rd_conf_fedif, rd_config))
+ phba->sli4_hba.encryption_support = true;
+ else
+ phba->sli4_hba.encryption_support = false;
+
/* Next decide on FPIN or Signal E2E CGN support
* For congestion alarms and warnings valid combination are:
* 1. FPIN alarms / FPIN warnings
diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h
index 59bd2bafc73f..e00d101d548c 100644
--- a/drivers/scsi/lpfc/lpfc_logmsg.h
+++ b/drivers/scsi/lpfc/lpfc_logmsg.h
@@ -1,7 +1,7 @@
/*******************************************************************
* This file is part of the Emulex Linux Device Driver for *
* Fibre Channel Host Bus Adapters. *
- * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term *
+ * Copyright (C) 2017-2025 Broadcom. All Rights Reserved. The term *
* “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. *
* Copyright (C) 2004-2009 Emulex. All rights reserved. *
* EMULEX and SLI are trademarks of Emulex. *
@@ -47,6 +47,7 @@
#define LOG_RSVD1 0x01000000 /* Reserved */
#define LOG_RSVD2 0x02000000 /* Reserved */
#define LOG_CGN_MGMT 0x04000000 /* Congestion Mgmt events */
+#define LOG_ENCRYPTION 0x40000000 /* EDIF Encryption events. */
#define LOG_TRACE_EVENT 0x80000000 /* Dmp the DBG log on this err */
#define LOG_ALL_MSG 0x7fffffff /* LOG all messages */
diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h
index fd6dab157887..ee58383492b2 100644
--- a/drivers/scsi/lpfc/lpfc_sli4.h
+++ b/drivers/scsi/lpfc/lpfc_sli4.h
@@ -888,6 +888,10 @@ struct lpfc_sli4_hba {
#define LPFC_FP_EQ_MAX_INTR_SEC 10000
uint32_t intr_enable;
+
+ /* Indicates whether SLI Port supports FEDIF */
+ bool encryption_support;
+
struct lpfc_bmbx bmbx;
struct lpfc_max_cfg_param max_cfg_param;
uint16_t extents_in_use; /* must allocate resource extents. */
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index f3dada5bf7c1..c4ca8bf5843a 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -20,7 +20,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "14.4.0.12"
+#define LPFC_DRIVER_VERSION "14.4.0.13"
#define LPFC_DRIVER_NAME "lpfc"
/* Used for SLI 2/3 */
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 987befb02408..b95c46a346fb 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -1328,6 +1328,46 @@ store_fc_rport_fast_io_fail_tmo(struct device *dev,
static FC_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR,
show_fc_rport_fast_io_fail_tmo, store_fc_rport_fast_io_fail_tmo);
+#define fc_rport_encryption(name) \
+static ssize_t fc_rport_encinfo_##name(struct device *cd, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct fc_rport *rport = transport_class_to_rport(cd); \
+ struct Scsi_Host *shost = rport_to_shost(rport); \
+ struct fc_internal *i = to_fc_internal(shost->transportt); \
+ struct fc_encryption_info *info; \
+ ssize_t ret = -ENOENT; \
+ u32 data; \
+ \
+ if (i->f->get_fc_rport_enc_info) { \
+ info = (i->f->get_fc_rport_enc_info)(rport); \
+ if (info) { \
+ data = info->name; \
+ if (!strcmp(#name, "status")) { \
+ ret = scnprintf(buf, \
+ FC_RPORT_ENCRYPTION_STATUS_MAX_LEN, \
+ "%s\n", \
+ data ? "Encrypted" : "Unencrypted"); \
+ } \
+ } \
+ } \
+ return ret; \
+} \
+static FC_DEVICE_ATTR(rport, encryption_##name, 0444, fc_rport_encinfo_##name, NULL) \
+
+fc_rport_encryption(status);
+
+static struct attribute *fc_rport_encryption_attrs[] = {
+ &device_attr_rport_encryption_status.attr,
+ NULL
+};
+
+static struct attribute_group fc_rport_encryption_group = {
+ .name = "encryption",
+ .attrs = fc_rport_encryption_attrs,
+};
+
#define fc_rport_fpin_statistic(name) \
static ssize_t fc_rport_fpinstat_##name(struct device *cd, \
struct device_attribute *attr, \
@@ -2633,6 +2673,8 @@ fc_attach_transport(struct fc_function_template *ft)
i->rport_attr_cont.ac.attrs = &i->rport_attrs[0];
i->rport_attr_cont.ac.class = &fc_rport_class.class;
i->rport_attr_cont.ac.match = fc_rport_match;
+ if (ft->get_fc_rport_enc_info)
+ i->rport_attr_cont.encryption = &fc_rport_encryption_group;
i->rport_attr_cont.statistics = &fc_rport_statistics_group;
transport_container_register(&i->rport_attr_cont);
diff --git a/include/linux/transport_class.h b/include/linux/transport_class.h
index 2efc271a96fa..a009d66db15a 100644
--- a/include/linux/transport_class.h
+++ b/include/linux/transport_class.h
@@ -56,6 +56,7 @@ struct anon_transport_class cls = { \
struct transport_container {
struct attribute_container ac;
const struct attribute_group *statistics;
+ const struct attribute_group *encryption;
};
#define attribute_container_to_transport_container(x) \
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index b908aacfef48..9f30625aa0d3 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -317,6 +317,15 @@ struct fc_fpin_stats {
u64 cn_device_specific;
};
+#define FC_RPORT_ENCRYPTION_STATUS_MAX_LEN 14
+/*
+ * Encryption Information
+ */
+struct fc_encryption_info {
+ /* Encryption Status */
+ u8 status;
+};
+
/* Macro for use in defining Remote Port attributes */
#define FC_RPORT_ATTR(_name,_mode,_show,_store) \
struct device_attribute dev_attr_rport_##_name = \
@@ -364,6 +373,7 @@ struct fc_rport { /* aka fc_starget_attrs */
u64 port_name;
u32 port_id;
u32 roles;
+ struct fc_encryption_info enc_info;
enum fc_port_state port_state; /* Will only be ONLINE or UNKNOWN */
u32 scsi_target_id;
u32 fast_io_fail_tmo;
@@ -691,6 +701,8 @@ struct fc_function_template {
struct fc_host_statistics * (*get_fc_host_stats)(struct Scsi_Host *);
void (*reset_fc_host_stats)(struct Scsi_Host *);
+ struct fc_encryption_info * (*get_fc_rport_enc_info)(struct fc_rport *);
+
int (*issue_fc_host_lip)(struct Scsi_Host *);
void (*dev_loss_tmo_callbk)(struct fc_rport *);