Commit 94bbd34e authored by Harald Freudenberger's avatar Harald Freudenberger Committed by Vasily Gorbik

s390/zcrypt: add base code for cca crypto card info support

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: default avatarHarald Freudenberger <freude@linux.ibm.com>
Reviewed-by: default avatarIngo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: default avatarVasily Gorbik <gor@linux.ibm.com>
parent efc598e6
...@@ -33,17 +33,27 @@ ...@@ -33,17 +33,27 @@
/* Size of vardata block used for some of the cca requests/replies */ /* Size of vardata block used for some of the cca requests/replies */
#define VARDATASIZE 4096 #define VARDATASIZE 4096
/* struct to hold cached mkvp info for each CCA card/domain */ /* struct to hold cached info for each CCA card/domain */
struct mkvp_info { 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; struct list_head list;
u16 cardnr; u16 cardnr;
u16 domain; u16 domain;
u64 mkvp[2]; struct cca_info info;
}; };
/* a list with mkvp_info entries */ /* a list with cca_info_list_entry entries */
static LIST_HEAD(mkvp_list); static LIST_HEAD(cca_info_list);
static DEFINE_SPINLOCK(mkvp_list_lock); static DEFINE_SPINLOCK(cca_info_list_lock);
/* /*
* Simple check if the token is a valid CCA secure AES key * Simple check if the token is a valid CCA secure AES key
...@@ -697,35 +707,35 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain, ...@@ -697,35 +707,35 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain,
} }
EXPORT_SYMBOL(cca_query_crypto_facility); 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; int rc = -ENOENT;
struct mkvp_info *ptr; struct cca_info_list_entry *ptr;
spin_lock_bh(&mkvp_list_lock); spin_lock_bh(&cca_info_list_lock);
list_for_each_entry(ptr, &mkvp_list, list) { list_for_each_entry(ptr, &cca_info_list, list) {
if (ptr->cardnr == cardnr && if (ptr->cardnr == cardnr && ptr->domain == domain) {
ptr->domain == domain) { memcpy(ci, &ptr->info, sizeof(*ci));
memcpy(mkvp, ptr->mkvp, 2 * sizeof(u64));
rc = 0; rc = 0;
break; break;
} }
} }
spin_unlock_bh(&mkvp_list_lock); spin_unlock_bh(&cca_info_list_lock);
return rc; 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; int found = 0;
struct mkvp_info *ptr; struct cca_info_list_entry *ptr;
spin_lock_bh(&mkvp_list_lock); spin_lock_bh(&cca_info_list_lock);
list_for_each_entry(ptr, &mkvp_list, list) { list_for_each_entry(ptr, &cca_info_list, list) {
if (ptr->cardnr == cardnr && if (ptr->cardnr == cardnr &&
ptr->domain == domain) { ptr->domain == domain) {
memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64)); memcpy(&ptr->info, ci, sizeof(*ci));
found = 1; found = 1;
break; break;
} }
...@@ -733,23 +743,23 @@ static void mkvp_cache_update(u16 cardnr, u16 domain, u64 mkvp[2]) ...@@ -733,23 +743,23 @@ static void mkvp_cache_update(u16 cardnr, u16 domain, u64 mkvp[2])
if (!found) { if (!found) {
ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC); ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC);
if (!ptr) { if (!ptr) {
spin_unlock_bh(&mkvp_list_lock); spin_unlock_bh(&cca_info_list_lock);
return; return;
} }
ptr->cardnr = cardnr; ptr->cardnr = cardnr;
ptr->domain = domain; ptr->domain = domain;
memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64)); memcpy(&ptr->info, ci, sizeof(*ci));
list_add(&ptr->list, &mkvp_list); 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); spin_lock_bh(&cca_info_list_lock);
list_for_each_entry(ptr, &mkvp_list, list) { list_for_each_entry(ptr, &cca_info_list, list) {
if (ptr->cardnr == cardnr && if (ptr->cardnr == cardnr &&
ptr->domain == domain) { ptr->domain == domain) {
list_del(&ptr->list); list_del(&ptr->list);
...@@ -757,26 +767,25 @@ static void mkvp_cache_scrub(u16 cardnr, u16 domain) ...@@ -757,26 +767,25 @@ static void mkvp_cache_scrub(u16 cardnr, u16 domain)
break; break;
} }
} }
spin_unlock_bh(&mkvp_list_lock); spin_unlock_bh(&cca_info_list_lock);
} }
static void __exit mkvp_cache_free(void) 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); spin_lock_bh(&cca_info_list_lock);
list_for_each_entry_safe(ptr, pnext, &mkvp_list, list) { list_for_each_entry_safe(ptr, pnext, &cca_info_list, list) {
list_del(&ptr->list); list_del(&ptr->list);
kfree(ptr); kfree(ptr);
} }
spin_unlock_bh(&mkvp_list_lock); spin_unlock_bh(&cca_info_list_lock);
} }
/* /*
* Fetch the current and old mkvp values via * Fetch cca_info values via query_crypto_facility from adapter.
* 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; int rc, found = 0;
size_t rlen, vlen; size_t rlen, vlen;
...@@ -791,14 +800,20 @@ static int fetch_mkvp(u16 cardnr, u16 domain, u64 mkvp[2]) ...@@ -791,14 +800,20 @@ static int fetch_mkvp(u16 cardnr, u16 domain, u64 mkvp[2])
rc = cca_query_crypto_facility(cardnr, domain, "STATICSA", rc = cca_query_crypto_facility(cardnr, domain, "STATICSA",
rarray, &rlen, varray, &vlen); rarray, &rlen, varray, &vlen);
if (rc == 0 && rlen > 8*8 && vlen > 184+8) { if (rc == 0 && rlen >= 10*8 && vlen >= 204) {
if (rarray[8*8] == '2') { memset(ci, 0, sizeof(*ci));
/* current master key state is valid */ memcpy(ci->serial, rarray, 8);
mkvp[0] = *((u64 *)(varray + 184)); ci->new_mk_state = (char) rarray[7*8];
mkvp[1] = *((u64 *)(varray + 172)); 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; found = 1;
} }
}
free_page((unsigned long) pg); free_page((unsigned long) pg);
...@@ -816,7 +831,7 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify) ...@@ -816,7 +831,7 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify)
const struct secaeskeytoken *t = (const struct secaeskeytoken *) seckey; const struct secaeskeytoken *t = (const struct secaeskeytoken *) seckey;
struct zcrypt_device_status_ext *device_status; struct zcrypt_device_status_ext *device_status;
u16 card, dom; u16 card, dom;
u64 mkvp[2]; struct cca_info ci;
int i, rc, oi = -1; int i, rc, oi = -1;
/* some simple checks of the given secure key token */ /* some simple checks of the given secure key token */
...@@ -839,23 +854,24 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify) ...@@ -839,23 +854,24 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify)
dom = AP_QID_QUEUE(device_status[i].qid); dom = AP_QID_QUEUE(device_status[i].qid);
if (device_status[i].online && if (device_status[i].online &&
device_status[i].functions & 0x04) { device_status[i].functions & 0x04) {
/* an enabled CCA Coprocessor card */ /* enabled CCA card, check current mkvp from cache */
/* try cached mkvp */ if (cca_info_cache_fetch(card, dom, &ci) == 0 &&
if (mkvp_cache_fetch(card, dom, mkvp) == 0 && ci.cur_mk_state == '2' &&
t->mkvp == mkvp[0]) { ci.cur_mkvp == t->mkvp) {
if (!verify) if (!verify)
break; break;
/* verify: fetch mkvp from adapter */ /* verify: refresh card info */
if (fetch_mkvp(card, dom, mkvp) == 0) { if (fetch_cca_info(card, dom, &ci) == 0) {
mkvp_cache_update(card, dom, mkvp); cca_info_cache_update(card, dom, &ci);
if (t->mkvp == mkvp[0]) if (ci.cur_mk_state == '2' &&
ci.cur_mkvp == t->mkvp)
break; break;
} }
} }
} else { } else {
/* Card is offline and/or not a CCA card. */ /* Card is offline and/or not a CCA card. */
/* del mkvp entry from cache if it exists */ /* 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) { if (i >= MAX_ZDEV_ENTRIES_EXT) {
...@@ -867,11 +883,14 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify) ...@@ -867,11 +883,14 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify)
card = AP_QID_CARD(device_status[i].qid); card = AP_QID_CARD(device_status[i].qid);
dom = AP_QID_QUEUE(device_status[i].qid); dom = AP_QID_QUEUE(device_status[i].qid);
/* fresh fetch mkvp from adapter */ /* fresh fetch mkvp from adapter */
if (fetch_mkvp(card, dom, mkvp) == 0) { if (fetch_cca_info(card, dom, &ci) == 0) {
mkvp_cache_update(card, dom, mkvp); cca_info_cache_update(card, dom, &ci);
if (t->mkvp == mkvp[0]) if (ci.cur_mk_state == '2' &&
ci.cur_mkvp == t->mkvp)
break; break;
if (t->mkvp == mkvp[1] && oi < 0) if (ci.old_mk_state == '2' &&
ci.old_mkvp == t->mkvp &&
oi < 0)
oi = i; oi = i;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment