scsi: zfcp: report FC Endpoint Security in sysfs
authorJens Remus <jremus@linux.ibm.com>
Thu, 12 Mar 2020 17:45:01 +0000 (18:45 +0100)
committerMartin K. Petersen <martin.petersen@oracle.com>
Tue, 17 Mar 2020 17:12:38 +0000 (13:12 -0400)
Add an interface to read Fibre Channel Endpoint Security information of FCP
channels and their connections to FC remote ports. It comes in the form of
new sysfs attributes that are attached to the CCW device representing the
FCP device and its zfcp port objects.

The read-only sysfs attribute "fc_security" of a CCW device representing a
FCP device shows the FC Endpoint Security capabilities of the device.
Possible values are: "unknown", "unsupported", "none", or a comma-
separated list of one or more mnemonics and/or one hexadecimal value
representing the supported FC Endpoint Security:

  Authentication: Authentication supported
  Encryption    : Encryption supported

The read-only sysfs attribute "fc_security" of a zfcp port object shows the
FC Endpoint Security used on the connection between its parent FCP device
and the FC remote port. Possible values are: "unknown", "unsupported",
"none", or a mnemonic or hexadecimal value representing the FC Endpoint
Security used:

  Authentication: Connection has been authenticated
  Encryption    : Connection is encrypted

Both sysfs attributes may return hexadecimal values instead of mnemonics,
if the mnemonic lookup table does not contain an entry for the FC Endpoint
Security reported by the FCP device.

Link: https://lore.kernel.org/r/20200312174505.51294-7-maier@linux.ibm.com
Reviewed-by: Fedor Loshakov <loshakov@linux.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/s390/scsi/zfcp_def.h
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_fsf.h
drivers/s390/scsi/zfcp_sysfs.c

index 8cc0eef..861ddc1 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Global definitions for the zfcp device driver.
  *
- * Copyright IBM Corp. 2002, 2018
+ * Copyright IBM Corp. 2002, 2020
  */
 
 #ifndef ZFCP_DEF_H
@@ -158,6 +158,7 @@ struct zfcp_adapter {
        u32                     adapter_features;  /* FCP channel features */
        u32                     connection_features; /* host connection features */
         u32                    hardware_version;  /* of FCP channel */
+       u32                     fc_security_algorithms; /* of FCP channel */
        u16                     timer_ticks;       /* time int for a tick */
        struct Scsi_Host        *scsi_host;        /* Pointer to mid-layer */
        struct list_head        port_list;         /* remote port list */
@@ -218,6 +219,7 @@ struct zfcp_port {
         atomic_t               erp_counter;
        u32                    maxframe_size;
        u32                    supported_classes;
+       u32                    connection_info;
        struct work_struct     gid_pn_work;
        struct work_struct     test_link_work;
        struct work_struct     rport_work;
index c855678..ee82fb5 100644 (file)
@@ -4,7 +4,7 @@
  *
  * External function declarations.
  *
- * Copyright IBM Corp. 2002, 2018
+ * Copyright IBM Corp. 2002, 2020
  */
 
 #ifndef ZFCP_EXT_H
@@ -135,6 +135,13 @@ extern struct zfcp_fsf_req *zfcp_fsf_fcp_task_mgmt(struct scsi_device *sdev,
                                                   u8 tm_flags);
 extern struct zfcp_fsf_req *zfcp_fsf_abort_fcp_cmnd(struct scsi_cmnd *);
 extern void zfcp_fsf_reqid_check(struct zfcp_qdio *, int);
+enum zfcp_fsf_print_fmt {
+       ZFCP_FSF_PRINT_FMT_LIST,
+       ZFCP_FSF_PRINT_FMT_SINGLEITEM,
+};
+extern ssize_t zfcp_fsf_scnprint_fc_security(char *buf, size_t size,
+                                            u32 fc_security,
+                                            enum zfcp_fsf_print_fmt fmt);
 
 /* zfcp_qdio.c */
 extern int zfcp_qdio_setup(struct zfcp_adapter *);
index c3aa054..068cb94 100644 (file)
@@ -664,6 +664,76 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req)
        }
 }
 
+/*
+ * Mapping of FC Endpoint Security flag masks to mnemonics
+ */
+static const struct {
+       u32     mask;
+       char    *name;
+} zfcp_fsf_fc_security_mnemonics[] = {
+       { FSF_FC_SECURITY_AUTH,         "Authentication" },
+       { FSF_FC_SECURITY_ENC_FCSP2 |
+         FSF_FC_SECURITY_ENC_ERAS,     "Encryption" },
+};
+
+/**
+ * zfcp_fsf_scnprint_fc_security() - translate FC Endpoint Security flags into
+ *                                   mnemonics and place in a buffer
+ * @buf        : the buffer to place the translated FC Endpoint Security flag(s)
+ *               into
+ * @size       : the size of the buffer, including the trailing null space
+ * @fc_security: one or more FC Endpoint Security flags, or zero
+ * @fmt        : specifies whether a list or a single item is to be put into the
+ *               buffer
+ *
+ * The Fibre Channel (FC) Endpoint Security flags are translated into mnemonics.
+ * If the FC Endpoint Security flags are zero "none" is placed into the buffer.
+ *
+ * With ZFCP_FSF_PRINT_FMT_LIST the mnemonics are placed as a list separated by
+ * a comma followed by a space into the buffer. If one or more FC Endpoint
+ * Security flags cannot be translated into a mnemonic, as they are undefined
+ * in zfcp_fsf_fc_security_mnemonics, their bitwise ORed value in hexadecimal
+ * representation is placed into the buffer.
+ *
+ * With ZFCP_FSF_PRINT_FMT_SINGLEITEM only one single mnemonic is placed into
+ * the buffer. If the FC Endpoint Security flag cannot be translated, as it is
+ * undefined in zfcp_fsf_fc_security_mnemonics, its value in hexadecimal
+ * representation is placed into the buffer. If more than one FC Endpoint
+ * Security flag was specified, their value in hexadecimal representation is
+ * placed into the buffer.
+ *
+ * Return: The number of characters written into buf not including the trailing
+ *         '\0'. If size is == 0 the function returns 0.
+ */
+ssize_t zfcp_fsf_scnprint_fc_security(char *buf, size_t size, u32 fc_security,
+                                     enum zfcp_fsf_print_fmt fmt)
+{
+       const char *prefix = "";
+       ssize_t len = 0;
+       int i;
+
+       if (fc_security == 0)
+               return scnprintf(buf, size, "none");
+       if (fmt == ZFCP_FSF_PRINT_FMT_SINGLEITEM && hweight32(fc_security) != 1)
+               return scnprintf(buf, size, "0x%08x", fc_security);
+
+       for (i = 0; i < ARRAY_SIZE(zfcp_fsf_fc_security_mnemonics); i++) {
+               if (!(fc_security & zfcp_fsf_fc_security_mnemonics[i].mask))
+                       continue;
+
+               len += scnprintf(buf + len, size - len, "%s%s", prefix,
+                                zfcp_fsf_fc_security_mnemonics[i].name);
+               prefix = ", ";
+               fc_security &= ~zfcp_fsf_fc_security_mnemonics[i].mask;
+       }
+
+       if (fc_security != 0)
+               len += scnprintf(buf + len, size - len, "%s0x%08x",
+                                prefix, fc_security);
+
+       return len;
+}
+
 static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
 {
        struct zfcp_adapter *adapter = req->adapter;
@@ -681,6 +751,11 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req)
               FC_FC4_LIST_SIZE);
        memcpy(fc_host_active_fc4s(shost), bottom->active_fc4_types,
               FC_FC4_LIST_SIZE);
+       if (adapter->adapter_features & FSF_FEATURE_FC_SECURITY)
+               adapter->fc_security_algorithms =
+                       bottom->fc_security_algorithms;
+       else
+               adapter->fc_security_algorithms = 0;
 }
 
 static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req)
@@ -1533,6 +1608,10 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
                break;
        case FSF_GOOD:
                port->handle = header->port_handle;
+               if (adapter->adapter_features & FSF_FEATURE_FC_SECURITY)
+                       port->connection_info = bottom->connection_info;
+               else
+                       port->connection_info = 0;
                atomic_or(ZFCP_STATUS_COMMON_OPEN |
                                ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
                atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_BOXED,
index 2b1e4da..66de170 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Interface to the FSF support functions.
  *
- * Copyright IBM Corp. 2002, 2018
+ * Copyright IBM Corp. 2002, 2020
  */
 
 #ifndef FSF_H
 #define FSF_FEATURE_MEASUREMENT_DATA           0x00000200
 #define FSF_FEATURE_REQUEST_SFP_DATA           0x00000200
 #define FSF_FEATURE_REPORT_SFP_DATA            0x00000800
+#define FSF_FEATURE_FC_SECURITY                        0x00001000
 #define FSF_FEATURE_DIF_PROT_TYPE1             0x00010000
 #define FSF_FEATURE_DIX_PROT_TCPIP             0x00020000
 
 /* option */
 #define FSF_OPEN_LUN_SUPPRESS_BOXING           0x00000001
 
+/* FC security algorithms */
+#define FSF_FC_SECURITY_AUTH                   0x00000001
+#define FSF_FC_SECURITY_ENC_FCSP2              0x00000002
+#define FSF_FC_SECURITY_ENC_ERAS               0x00000004
+
 struct fsf_queue_designator {
        u8  cssid;
        u8  chpid;
@@ -338,7 +344,8 @@ struct fsf_qtcb_bottom_support {
        u8  res3[3];
        u8  timeout;
         u32 lun_access_info;
-        u8  res4[180];
+       u32 connection_info;
+       u8  res4[176];
        u32 els1_length;
        u32 els2_length;
        u32 req_buf_length;
@@ -426,7 +433,8 @@ struct fsf_qtcb_bottom_port {
                        u16 port_tx_type        :4;
                };
        } sfp_flags;
-       u8 res3[240];
+       u32 fc_security_algorithms;
+       u8 res3[236];
 } __attribute__ ((packed));
 
 union fsf_qtcb_bottom {
index 494b9fe..45d5316 100644 (file)
@@ -4,7 +4,7 @@
  *
  * sysfs attributes.
  *
- * Copyright IBM Corp. 2008, 2010
+ * Copyright IBM Corp. 2008, 2020
  */
 
 #define KMSG_COMPONENT "zfcp"
@@ -370,6 +370,42 @@ static ZFCP_DEV_ATTR(adapter, diag_max_age, 0644,
                     zfcp_sysfs_adapter_diag_max_age_show,
                     zfcp_sysfs_adapter_diag_max_age_store);
 
+static ssize_t zfcp_sysfs_adapter_fc_security_show(
+       struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct ccw_device *cdev = to_ccwdev(dev);
+       struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(cdev);
+       unsigned int status;
+       int i;
+
+       if (!adapter)
+               return -ENODEV;
+
+       /*
+        * Adapter status COMMON_OPEN implies xconf data and xport data
+        * was done. Adapter FC Endpoint Security capability remains
+        * unchanged in case of COMMON_ERP_FAILED (e.g. due to local link
+        * down).
+        */
+       status = atomic_read(&adapter->status);
+       if (0 == (status & ZFCP_STATUS_COMMON_OPEN))
+               i = sprintf(buf, "unknown\n");
+       else if (!(adapter->adapter_features & FSF_FEATURE_FC_SECURITY))
+               i = sprintf(buf, "unsupported\n");
+       else {
+               i = zfcp_fsf_scnprint_fc_security(
+                       buf, PAGE_SIZE - 1, adapter->fc_security_algorithms,
+                       ZFCP_FSF_PRINT_FMT_LIST);
+               i += scnprintf(buf + i, PAGE_SIZE - i, "\n");
+       }
+
+       zfcp_ccw_adapter_put(adapter);
+       return i;
+}
+static ZFCP_DEV_ATTR(adapter, fc_security, S_IRUGO,
+                    zfcp_sysfs_adapter_fc_security_show,
+                    NULL);
+
 static struct attribute *zfcp_adapter_attrs[] = {
        &dev_attr_adapter_failed.attr,
        &dev_attr_adapter_in_recovery.attr,
@@ -383,6 +419,7 @@ static struct attribute *zfcp_adapter_attrs[] = {
        &dev_attr_adapter_status.attr,
        &dev_attr_adapter_hardware_version.attr,
        &dev_attr_adapter_diag_max_age.attr,
+       &dev_attr_adapter_fc_security.attr,
        NULL
 };
 
@@ -426,6 +463,36 @@ static ssize_t zfcp_sysfs_unit_remove_store(struct device *dev,
 }
 static DEVICE_ATTR(unit_remove, S_IWUSR, NULL, zfcp_sysfs_unit_remove_store);
 
+static ssize_t zfcp_sysfs_port_fc_security_show(struct device *dev,
+                                               struct device_attribute *attr,
+                                               char *buf)
+{
+       struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
+       struct zfcp_adapter *adapter = port->adapter;
+       unsigned int status = atomic_read(&port->status);
+       int i;
+
+       if (0 == (status & ZFCP_STATUS_COMMON_OPEN) ||
+           0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) ||
+           0 == (status & ZFCP_STATUS_PORT_PHYS_OPEN) ||
+           0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED) ||
+           0 != (status & ZFCP_STATUS_COMMON_ACCESS_BOXED))
+               i = sprintf(buf, "unknown\n");
+       else if (!(adapter->adapter_features & FSF_FEATURE_FC_SECURITY))
+               i = sprintf(buf, "unsupported\n");
+       else {
+               i = zfcp_fsf_scnprint_fc_security(
+                       buf, PAGE_SIZE - 1, port->connection_info,
+                       ZFCP_FSF_PRINT_FMT_SINGLEITEM);
+               i += scnprintf(buf + i, PAGE_SIZE - i, "\n");
+       }
+
+       return i;
+}
+static ZFCP_DEV_ATTR(port, fc_security, S_IRUGO,
+                    zfcp_sysfs_port_fc_security_show,
+                    NULL);
+
 static struct attribute *zfcp_port_attrs[] = {
        &dev_attr_unit_add.attr,
        &dev_attr_unit_remove.attr,
@@ -433,6 +500,7 @@ static struct attribute *zfcp_port_attrs[] = {
        &dev_attr_port_in_recovery.attr,
        &dev_attr_port_status.attr,
        &dev_attr_port_access_denied.attr,
+       &dev_attr_port_fc_security.attr,
        NULL
 };
 static struct attribute_group zfcp_port_attr_group = {