Blob Blame History Raw
From: Harald Freudenberger <freude@linux.ibm.com>
Date: Tue, 11 Jun 2019 14:10:47 +0200
Subject: s390/zcrypt: add base code for cca crypto card info support
Git-commit: 94bbd34e51bc7809357e24e4011b169d321a8272
Patch-mainline: v5.4-rc1
References: jsc#SLE-9582 jsc#IBM-505 LTC#181532

This patch widens the information held for cca crypto apqns.
Currently the current and old master key verification pattern
is used by the existing code. Now the new master key registers
mkvp, the 8 byte serial number and state info about each master
key register is part of the cca info cache.

In a next step this information will be used to provide some
additional attributes in sysfs for each CCA crypto adapter.

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 |  131 ++++++++++++++++++++---------------
 1 file changed, 75 insertions(+), 56 deletions(-)

--- a/drivers/s390/crypto/zcrypt_ccamisc.c
+++ b/drivers/s390/crypto/zcrypt_ccamisc.c
@@ -33,17 +33,27 @@
 /* Size of vardata block used for some of the cca requests/replies */
 #define VARDATASIZE 4096
 
-/* struct to hold cached mkvp info for each CCA card/domain */
-struct mkvp_info {
+/* 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;
 	u16 domain;
-	u64 mkvp[2];
+	struct cca_info info;
 };
 
-/* a list with mkvp_info entries */
-static LIST_HEAD(mkvp_list);
-static DEFINE_SPINLOCK(mkvp_list_lock);
+/* a list with cca_info_list_entry entries */
+static LIST_HEAD(cca_info_list);
+static DEFINE_SPINLOCK(cca_info_list_lock);
 
 /*
  * Simple check if the token is a valid CCA secure AES key
@@ -697,35 +707,35 @@ out:
 }
 EXPORT_SYMBOL(cca_query_crypto_facility);
 
-static int mkvp_cache_fetch(u16 cardnr, u16 domain, u64 mkvp[2])
+static int cca_info_cache_fetch(u16 cardnr, u16 domain, struct cca_info *ci)
 {
 	int rc = -ENOENT;
-	struct mkvp_info *ptr;
+	struct cca_info_list_entry *ptr;
 
-	spin_lock_bh(&mkvp_list_lock);
-	list_for_each_entry(ptr, &mkvp_list, list) {
-		if (ptr->cardnr == cardnr &&
-		    ptr->domain == domain) {
-			memcpy(mkvp, ptr->mkvp, 2 * sizeof(u64));
+	spin_lock_bh(&cca_info_list_lock);
+	list_for_each_entry(ptr, &cca_info_list, list) {
+		if (ptr->cardnr == cardnr && ptr->domain == domain) {
+			memcpy(ci, &ptr->info, sizeof(*ci));
 			rc = 0;
 			break;
 		}
 	}
-	spin_unlock_bh(&mkvp_list_lock);
+	spin_unlock_bh(&cca_info_list_lock);
 
 	return rc;
 }
 
-static void mkvp_cache_update(u16 cardnr, u16 domain, u64 mkvp[2])
+static void cca_info_cache_update(u16 cardnr, u16 domain,
+				  const struct cca_info *ci)
 {
 	int found = 0;
-	struct mkvp_info *ptr;
+	struct cca_info_list_entry *ptr;
 
-	spin_lock_bh(&mkvp_list_lock);
-	list_for_each_entry(ptr, &mkvp_list, list) {
+	spin_lock_bh(&cca_info_list_lock);
+	list_for_each_entry(ptr, &cca_info_list, list) {
 		if (ptr->cardnr == cardnr &&
 		    ptr->domain == domain) {
-			memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64));
+			memcpy(&ptr->info, ci, sizeof(*ci));
 			found = 1;
 			break;
 		}
@@ -733,23 +743,23 @@ static void mkvp_cache_update(u16 cardnr
 	if (!found) {
 		ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC);
 		if (!ptr) {
-			spin_unlock_bh(&mkvp_list_lock);
+			spin_unlock_bh(&cca_info_list_lock);
 			return;
 		}
 		ptr->cardnr = cardnr;
 		ptr->domain = domain;
-		memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64));
-		list_add(&ptr->list, &mkvp_list);
+		memcpy(&ptr->info, ci, sizeof(*ci));
+		list_add(&ptr->list, &cca_info_list);
 	}
-	spin_unlock_bh(&mkvp_list_lock);
+	spin_unlock_bh(&cca_info_list_lock);
 }
 
-static void mkvp_cache_scrub(u16 cardnr, u16 domain)
+static void cca_info_cache_scrub(u16 cardnr, u16 domain)
 {
-	struct mkvp_info *ptr;
+	struct cca_info_list_entry *ptr;
 
-	spin_lock_bh(&mkvp_list_lock);
-	list_for_each_entry(ptr, &mkvp_list, list) {
+	spin_lock_bh(&cca_info_list_lock);
+	list_for_each_entry(ptr, &cca_info_list, list) {
 		if (ptr->cardnr == cardnr &&
 		    ptr->domain == domain) {
 			list_del(&ptr->list);
@@ -757,26 +767,25 @@ static void mkvp_cache_scrub(u16 cardnr,
 			break;
 		}
 	}
-	spin_unlock_bh(&mkvp_list_lock);
+	spin_unlock_bh(&cca_info_list_lock);
 }
 
 static void __exit mkvp_cache_free(void)
 {
-	struct mkvp_info *ptr, *pnext;
+	struct cca_info_list_entry *ptr, *pnext;
 
-	spin_lock_bh(&mkvp_list_lock);
-	list_for_each_entry_safe(ptr, pnext, &mkvp_list, list) {
+	spin_lock_bh(&cca_info_list_lock);
+	list_for_each_entry_safe(ptr, pnext, &cca_info_list, list) {
 		list_del(&ptr->list);
 		kfree(ptr);
 	}
-	spin_unlock_bh(&mkvp_list_lock);
+	spin_unlock_bh(&cca_info_list_lock);
 }
 
 /*
- * Fetch the current and old mkvp values via
- * query_crypto_facility from adapter.
+ * Fetch cca_info values via query_crypto_facility from adapter.
  */
-static int fetch_mkvp(u16 cardnr, u16 domain, u64 mkvp[2])
+static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci)
 {
 	int rc, found = 0;
 	size_t rlen, vlen;
@@ -791,13 +800,19 @@ static int fetch_mkvp(u16 cardnr, u16 do
 
 	rc = cca_query_crypto_facility(cardnr, domain, "STATICSA",
 				       rarray, &rlen, varray, &vlen);
-	if (rc == 0 && rlen > 8*8 && vlen > 184+8) {
-		if (rarray[8*8] == '2') {
-			/* current master key state is valid */
-			mkvp[0] = *((u64 *)(varray + 184));
-			mkvp[1] = *((u64 *)(varray + 172));
-			found = 1;
-		}
+	if (rc == 0 && rlen >= 10*8 && vlen >= 204) {
+		memset(ci, 0, sizeof(*ci));
+		memcpy(ci->serial, rarray, 8);
+		ci->new_mk_state = (char) rarray[7*8];
+		ci->cur_mk_state = (char) rarray[8*8];
+		ci->old_mk_state = (char) rarray[9*8];
+		if (ci->old_mk_state == '2')
+			memcpy(&ci->old_mkvp, varray + 172, 8);
+		if (ci->cur_mk_state == '2')
+			memcpy(&ci->cur_mkvp, varray + 184, 8);
+		if (ci->new_mk_state == '3')
+			memcpy(&ci->new_mkvp, varray + 196, 8);
+		found = 1;
 	}
 
 	free_page((unsigned long) pg);
@@ -816,7 +831,7 @@ int cca_findcard(const u8 *seckey, u16 *
 	const struct secaeskeytoken *t = (const struct secaeskeytoken *) seckey;
 	struct zcrypt_device_status_ext *device_status;
 	u16 card, dom;
-	u64 mkvp[2];
+	struct cca_info ci;
 	int i, rc, oi = -1;
 
 	/* some simple checks of the given secure key token */
@@ -839,23 +854,24 @@ int cca_findcard(const u8 *seckey, u16 *
 		dom = AP_QID_QUEUE(device_status[i].qid);
 		if (device_status[i].online &&
 		    device_status[i].functions & 0x04) {
-			/* an enabled CCA Coprocessor card */
-			/* try cached mkvp */
-			if (mkvp_cache_fetch(card, dom, mkvp) == 0 &&
-			    t->mkvp == mkvp[0]) {
+			/* enabled CCA card, check current mkvp from cache */
+			if (cca_info_cache_fetch(card, dom, &ci) == 0 &&
+			    ci.cur_mk_state == '2' &&
+			    ci.cur_mkvp == t->mkvp) {
 				if (!verify)
 					break;
-				/* verify: fetch mkvp from adapter */
-				if (fetch_mkvp(card, dom, mkvp) == 0) {
-					mkvp_cache_update(card, dom, mkvp);
-					if (t->mkvp == mkvp[0])
+				/* verify: refresh card info */
+				if (fetch_cca_info(card, dom, &ci) == 0) {
+					cca_info_cache_update(card, dom, &ci);
+					if (ci.cur_mk_state == '2' &&
+					    ci.cur_mkvp == t->mkvp)
 						break;
 				}
 			}
 		} else {
 			/* Card is offline and/or not a CCA card. */
 			/* del mkvp entry from cache if it exists */
-			mkvp_cache_scrub(card, dom);
+			cca_info_cache_scrub(card, dom);
 		}
 	}
 	if (i >= MAX_ZDEV_ENTRIES_EXT) {
@@ -867,11 +883,14 @@ int cca_findcard(const u8 *seckey, u16 *
 			card = AP_QID_CARD(device_status[i].qid);
 			dom = AP_QID_QUEUE(device_status[i].qid);
 			/* fresh fetch mkvp from adapter */
-			if (fetch_mkvp(card, dom, mkvp) == 0) {
-				mkvp_cache_update(card, dom, mkvp);
-				if (t->mkvp == mkvp[0])
+			if (fetch_cca_info(card, dom, &ci) == 0) {
+				cca_info_cache_update(card, dom, &ci);
+				if (ci.cur_mk_state == '2' &&
+				    ci.cur_mkvp == t->mkvp)
 					break;
-				if (t->mkvp == mkvp[1] && oi < 0)
+				if (ci.old_mk_state == '2' &&
+				    ci.old_mkvp == t->mkvp &&
+				    oi < 0)
 					oi = i;
 			}
 		}