diff options
| -rw-r--r-- | drivers/base/transport_class.c | 8 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_attr.c | 40 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_debugfs.c | 7 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_disc.h | 7 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 57 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 1 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hw4.h | 11 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_init.c | 5 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_logmsg.h | 3 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_sli4.h | 4 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_version.h | 2 | ||||
| -rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 42 | ||||
| -rw-r--r-- | include/linux/transport_class.h | 1 | ||||
| -rw-r--r-- | include/scsi/scsi_transport_fc.h | 12 |
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 *); |
