Blob Blame History Raw
From: Harald Freudenberger <freude@linux.ibm.com>
Date: Wed, 12 Jun 2019 15:05:34 +0200
Subject: s390/zcrypt: new sysfs attributes serialnr and mkvps
Git-commit: 7c4e91c0959bf42a86ba4887425fc944d0d28595
Patch-mainline: v5.4-rc1
References: jsc#SLE-9582 jsc#IBM-505 LTC#181532

This patch extends the sysfs interface with two new attributes for the
CEX4, CEX5 and CEX6 crypto cards/queues in coprocessor ('CCA') mode:
  /sys/devices/ap/cardxx/serialnr
  /sys/devices/ap/cardxx/xx.yyyy/mkvps

The serialnr attribute is card based and shows the 8 character ASCII
serial number string which should unique identify the card.

The mkvps is queue based and displays 3 lines of information about the
new, current and old master key register:
  AES NEW: <new_aes_mk_state> <new_aes_mk_mkvp>
  AES CUR: <cur_aes_mk_state> <cur_aes_mk_mkvp>
  AES OLD: <old_aes_mk_state> <old_aes_mk_mkvp>
with
  <new_aes_mk_state>: 'empty' or 'partial' or 'full'
  <cur_aes_mk_state>: 'valid' or 'invalid'
  <old_aes_mk_state>: 'valid' or 'invalid'
  <new_aes_mk_mkvp>, <cur_aes_mk_mkvp>, <old_aes_mk_mkvp>
    8 byte hex string with leading 0x
MKVP means Master Key Verification Pattern and is a folded hash over
the key value. Only the states 'full' and 'valid' result in displaying
a useful mkvp, otherwise a mkvp of all bytes zero is shown. If for any
reason the FQ fails and the (cached) information is not available, the
state '-' will be shown with the mkvp value also '-'. The values shown
here are the very same as the cca panel tools displays. As of now only
the AES master keys states and verification patterns are shown. A CCA
APQN also has similar master key registers for DES, RSA and ECC. So
the content of this attribute may get extended.

Reading the sysfs attribute automatically triggers an FQ CPRB to be
sent to the queue as long as the queue is (soft-) online. For the
serialnr attribute the queue with the default domain id is addressed
(if available and valid). This is reasonable as it is assumed that
this sysfs interface is not performance critical and on the other side
a master key change should be visiable as soon as possible. When a
queue is (soft-) offline however, the cached values are displayed. If
no cached values are available, the serial number string will be empty
and the mkvp lines will show state '-' and mkvp value '-'.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/s390/crypto/zcrypt_ccamisc.c |   33 ++++++----
 drivers/s390/crypto/zcrypt_ccamisc.h |   16 +++++
 drivers/s390/crypto/zcrypt_cex4.c    |  106 ++++++++++++++++++++++++++++++++++-
 3 files changed, 141 insertions(+), 14 deletions(-)

--- a/drivers/s390/crypto/zcrypt_ccamisc.c
+++ b/drivers/s390/crypto/zcrypt_ccamisc.c
@@ -33,17 +33,6 @@
 /* Size of vardata block used for some of the cca requests/replies */
 #define VARDATASIZE 4096
 
-/* struct to hold cached info for each CCA card/domain */
-struct cca_info {
-	char new_mk_state;  /* '1' Empty, '2' Partially full, '3' Full */
-	char cur_mk_state;  /* '1' Invalid, '2' Valid */
-	char old_mk_state;  /* '1' Invalid, '2' Valid */
-	u64  new_mkvp;	    /* truncated sha256 hash of new master key */
-	u64  cur_mkvp;	    /* truncated sha256 hash of current master key */
-	u64  old_mkvp;	    /* truncated sha256 hash of old master key */
-	char serial[9];
-};
-
 struct cca_info_list_entry {
 	struct list_head list;
 	u16 cardnr;
@@ -164,9 +153,9 @@ static inline void prep_xcrb(struct ica_
 	pxcrb->user_defined = (cardnr == 0xFFFF ? AUTOSELECT : cardnr);
 	pxcrb->request_control_blk_length =
 		preqcblk->cprb_len + preqcblk->req_parml;
-	pxcrb->request_control_blk_addr = (void *) preqcblk;
+	pxcrb->request_control_blk_addr = (void __user *) preqcblk;
 	pxcrb->reply_control_blk_length = preqcblk->rpl_msgbl;
-	pxcrb->reply_control_blk_addr = (void *) prepcblk;
+	pxcrb->reply_control_blk_addr = (void __user *) prepcblk;
 }
 
 /*
@@ -821,6 +810,24 @@ static int fetch_cca_info(u16 cardnr, u1
 }
 
 /*
+ * Fetch cca information about a CCA queue.
+ */
+int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify)
+{
+	int rc;
+
+	rc = cca_info_cache_fetch(card, dom, ci);
+	if (rc || verify) {
+		rc = fetch_cca_info(card, dom, ci);
+		if (rc == 0)
+			cca_info_cache_update(card, dom, ci);
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(cca_get_info);
+
+/*
  * Search for a matching crypto card based on the Master Key
  * Verification Pattern provided inside a secure key.
  * Returns < 0 on failure, 0 if CURRENT MKVP matches and
--- a/drivers/s390/crypto/zcrypt_ccamisc.h
+++ b/drivers/s390/crypto/zcrypt_ccamisc.h
@@ -90,6 +90,22 @@ int cca_query_crypto_facility(u16 cardnr
  */
 int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify);
 
+/* struct to hold info for each CCA queue */
+struct cca_info {
+	char new_mk_state;  /* '1' empty, '2' partially full, '3' full */
+	char cur_mk_state;  /* '1' invalid, '2' valid */
+	char old_mk_state;  /* '1' invalid, '2' valid */
+	u64  new_mkvp;	    /* truncated sha256 hash of new master key */
+	u64  cur_mkvp;	    /* truncated sha256 hash of current master key */
+	u64  old_mkvp;	    /* truncated sha256 hash of old master key */
+	char serial[9];     /* serial number string (8 ascii numbers + 0x00) */
+};
+
+/*
+ * Fetch cca information about an CCA queue.
+ */
+int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify);
+
 void zcrypt_ccamisc_exit(void);
 
 #endif /* _ZCRYPT_CCAMISC_H_ */
--- a/drivers/s390/crypto/zcrypt_cex4.c
+++ b/drivers/s390/crypto/zcrypt_cex4.c
@@ -18,6 +18,7 @@
 #include "zcrypt_msgtype50.h"
 #include "zcrypt_error.h"
 #include "zcrypt_cex4.h"
+#include "zcrypt_ccamisc.h"
 
 #define CEX4A_MIN_MOD_SIZE	  1	/*    8 bits	*/
 #define CEX4A_MAX_MOD_SIZE_2K	256	/* 2048 bits	*/
@@ -65,6 +66,85 @@ static struct ap_device_id zcrypt_cex4_q
 
 MODULE_DEVICE_TABLE(ap, zcrypt_cex4_queue_ids);
 
+/*
+ * CCA card addditional device attributes
+ */
+static ssize_t serialnr_show(struct device *dev,
+			     struct device_attribute *attr,
+			     char *buf)
+{
+	struct cca_info ci;
+	struct ap_card *ac = to_ap_card(dev);
+	struct zcrypt_card *zc = ac->private;
+
+	memset(&ci, 0, sizeof(ci));
+
+	if (ap_domain_index >= 0)
+		cca_get_info(ac->id, ap_domain_index, &ci, zc->online);
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", ci.serial);
+}
+static DEVICE_ATTR_RO(serialnr);
+
+static struct attribute *cca_card_attrs[] = {
+	&dev_attr_serialnr.attr,
+	NULL,
+};
+
+static const struct attribute_group cca_card_attr_group = {
+	.attrs = cca_card_attrs,
+};
+
+/*
+ * CCA queue addditional device attributes
+ */
+static ssize_t mkvps_show(struct device *dev,
+			  struct device_attribute *attr,
+			  char *buf)
+{
+	int n = 0;
+	struct cca_info ci;
+	struct zcrypt_queue *zq = to_ap_queue(dev)->private;
+	static const char * const cao_state[] = { "invalid", "valid" };
+	static const char * const new_state[] = { "empty", "partial", "full" };
+
+	memset(&ci, 0, sizeof(ci));
+
+	cca_get_info(AP_QID_CARD(zq->queue->qid),
+		     AP_QID_QUEUE(zq->queue->qid),
+		     &ci, zq->online);
+
+	if (ci.new_mk_state >= '1' && ci.new_mk_state <= '3')
+		n = snprintf(buf, PAGE_SIZE, "AES NEW: %s 0x%016llx\n",
+			     new_state[ci.new_mk_state - '1'], ci.new_mkvp);
+	else
+		n = snprintf(buf, PAGE_SIZE, "AES NEW: - -\n");
+
+	if (ci.cur_mk_state >= '1' && ci.cur_mk_state <= '2')
+		n += snprintf(buf + n, PAGE_SIZE - n, "AES CUR: %s 0x%016llx\n",
+			      cao_state[ci.cur_mk_state - '1'], ci.cur_mkvp);
+	else
+		n += snprintf(buf + n, PAGE_SIZE - n, "AES CUR: - -\n");
+
+	if (ci.old_mk_state >= '1' && ci.old_mk_state <= '2')
+		n += snprintf(buf + n, PAGE_SIZE - n, "AES OLD: %s 0x%016llx\n",
+			      cao_state[ci.old_mk_state - '1'], ci.old_mkvp);
+	else
+		n += snprintf(buf + n, PAGE_SIZE - n, "AES OLD: - -\n");
+
+	return n;
+}
+static DEVICE_ATTR_RO(mkvps);
+
+static struct attribute *cca_queue_attrs[] = {
+	&dev_attr_mkvps.attr,
+	NULL,
+};
+
+static const struct attribute_group cca_queue_attr_group = {
+	.attrs = cca_queue_attrs,
+};
+
 /**
  * Probe function for CEX4/CEX5/CEX6 card device. It always
  * accepts the AP device since the bus_match already checked
@@ -194,8 +274,17 @@ static int zcrypt_cex4_card_probe(struct
 	if (rc) {
 		ac->private = NULL;
 		zcrypt_card_free(zc);
+		goto out;
 	}
 
+	if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) {
+		rc = sysfs_create_group(&ap_dev->device.kobj,
+					&cca_card_attr_group);
+		if (rc)
+			zcrypt_card_unregister(zc);
+	}
+
+out:
 	return rc;
 }
 
@@ -205,8 +294,11 @@ static int zcrypt_cex4_card_probe(struct
  */
 static void zcrypt_cex4_card_remove(struct ap_device *ap_dev)
 {
-	struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private;
+	struct ap_card *ac = to_ap_card(&ap_dev->device);
+	struct zcrypt_card *zc = ac->private;
 
+	if (ap_test_bit(&ac->functions, AP_FUNC_COPRO))
+		sysfs_remove_group(&ap_dev->device.kobj, &cca_card_attr_group);
 	if (zc)
 		zcrypt_card_unregister(zc);
 }
@@ -251,6 +343,7 @@ static int zcrypt_cex4_queue_probe(struc
 	} else {
 		return -ENODEV;
 	}
+
 	zq->queue = aq;
 	zq->online = 1;
 	atomic_set(&zq->load, 0);
@@ -261,8 +354,17 @@ static int zcrypt_cex4_queue_probe(struc
 	if (rc) {
 		aq->private = NULL;
 		zcrypt_queue_free(zq);
+		goto out;
+	}
+
+	if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) {
+		rc = sysfs_create_group(&ap_dev->device.kobj,
+					&cca_queue_attr_group);
+		if (rc)
+			zcrypt_queue_unregister(zq);
 	}
 
+out:
 	return rc;
 }
 
@@ -275,6 +377,8 @@ static void zcrypt_cex4_queue_remove(str
 	struct ap_queue *aq = to_ap_queue(&ap_dev->device);
 	struct zcrypt_queue *zq = aq->private;
 
+	if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO))
+		sysfs_remove_group(&ap_dev->device.kobj, &cca_queue_attr_group);
 	if (zq)
 		zcrypt_queue_unregister(zq);
 }