From patchwork Thu Jun 27 20:13:23 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frank Heimes X-Patchwork-Id: 1123599 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=canonical.com Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45ZWM21jHZz9s4V; Fri, 28 Jun 2019 06:14:06 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1hgamP-0002nk-SQ; Thu, 27 Jun 2019 20:14:01 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:128) (Exim 4.86_2) (envelope-from ) id 1hgamN-0002mZ-KG for kernel-team@lists.ubuntu.com; Thu, 27 Jun 2019 20:13:59 +0000 Received: from 2.general.fheimes.uk.vpn ([10.172.194.67] helo=localhost.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1hgamN-0003fI-7a for kernel-team@lists.ubuntu.com; Thu, 27 Jun 2019 20:13:59 +0000 From: frank.heimes@canonical.com To: kernel-team@lists.ubuntu.com Subject: [SRU][B][D][Patch 2/2] s390/zcrypt: Fix wrong dispatching for control domain CPRBs (backport) Date: Thu, 27 Jun 2019 22:13:23 +0200 Message-Id: <1561666403-11046-3-git-send-email-frank.heimes@canonical.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1561666403-11046-1-git-send-email-frank.heimes@canonical.com> References: <1561666403-11046-1-git-send-email-frank.heimes@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Harald Freudenberger BugLink: https://bugs.launchpad.net/bugs/1832624 The zcrypt device driver does not handle CPRBs which address a control domain correctly. This fix introduces a workaround: The domain field of the request CPRB is checked if there is a valid domain value in there. If this is true and the value is a control only domain (a domain which is enabled in the crypto config ADM mask but disabled in the AQM mask) the CPRB is forwarded to the default usage domain. If there is no default domain, the request is rejected with an ENODEV. This fix is important for maintaining crypto adapters. For example one LPAR can use a crypto adapter domain ('Control and Usage') but another LPAR needs to be able to maintain this adapter domain ('Control'). Scenarios like this did not work properly and the patch enables this. OriginalAuthor: Harald Freudenberger Signed-off-by: Harald Freudenberger Signed-off-by: Heiko Carstens (backported from commit 7379e652797c0b9b5f6caea1576f2dff9ce6a708) Signed-off-by: Frank Heimes --- arch/s390/include/asm/ap.h | 4 ++-- drivers/s390/crypto/ap_bus.c | 28 +++++++++++++++++++++++----- drivers/s390/crypto/ap_bus.h | 3 +++ drivers/s390/crypto/zcrypt_api.c | 17 ++++++++++++++--- 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/arch/s390/include/asm/ap.h b/arch/s390/include/asm/ap.h index 887494aa164f..949335bdd422 100644 --- a/arch/s390/include/asm/ap.h +++ b/arch/s390/include/asm/ap.h @@ -160,8 +160,8 @@ struct ap_config_info { unsigned char Nd; /* max # of Domains - 1 */ unsigned char _reserved3[10]; unsigned int apm[8]; /* AP ID mask */ - unsigned int aqm[8]; /* AP queue mask */ - unsigned int adm[8]; /* AP domain mask */ + unsigned int aqm[8]; /* AP (usage) queue mask */ + unsigned int adm[8]; /* AP (control) domain mask */ unsigned char _reserved4[16]; } __aligned(8); diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 1bf1ef355da0..f029aef21978 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -255,19 +255,37 @@ static inline int ap_test_config_card_id(unsigned int id) } /* - * ap_test_config_domain(): Test, whether an AP usage domain is configured. + * ap_test_config_usage_domain(): Test, whether an AP usage domain + * is configured. * @domain AP usage domain ID * * Returns 0 if the usage domain is not configured * 1 if the usage domain is configured or * if the configuration information is not available */ -static inline int ap_test_config_domain(unsigned int domain) +int ap_test_config_usage_domain(unsigned int domain) { if (!ap_configuration) /* QCI not supported */ return domain < 16; return ap_test_config(ap_configuration->aqm, domain); } +EXPORT_SYMBOL(ap_test_config_usage_domain); + +/* + * ap_test_config_ctrl_domain(): Test, whether an AP control domain + * is configured. + * @domain AP control domain ID + * + * Returns 1 if the control domain is configured + * 0 in all other cases + */ +int ap_test_config_ctrl_domain(unsigned int domain) +{ + if (!ap_configuration) /* QCI not supported */ + return 0; + return ap_test_config(ap_configuration->adm, domain); +} +EXPORT_SYMBOL(ap_test_config_ctrl_domain); /** * ap_query_queue(): Check if an AP queue is available. @@ -1247,7 +1265,7 @@ static int ap_select_domain(void) best_domain = -1; max_count = 0; for (i = 0; i < AP_DOMAINS; i++) { - if (!ap_test_config_domain(i) || + if (!ap_test_config_usage_domain(i) || !test_bit_inv(i, ap_perms.aqm)) continue; count = 0; @@ -1386,7 +1404,7 @@ static void ap_scan_bus(struct work_struct *unused) (void *)(long) qid, __match_queue_device_with_qid); aq = dev ? to_ap_queue(dev) : NULL; - if (!ap_test_config_domain(dom)) { + if (!ap_test_config_usage_domain(dom)) { if (dev) { /* Queue device exists but has been * removed from configuration. @@ -1489,7 +1507,7 @@ static void ap_reset_all(void) int i, j; for (i = 0; i < AP_DOMAINS; i++) { - if (!ap_test_config_domain(i)) + if (!ap_test_config_usage_domain(i)) continue; for (j = 0; j < AP_DEVICES; j++) { if (!ap_test_config_card_id(j)) diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 7e85d238767b..1959c8f5beda 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -248,6 +248,9 @@ void ap_wait(enum ap_wait wait); void ap_request_timeout(struct timer_list *t); void ap_bus_force_rescan(void); +int ap_test_config_usage_domain(unsigned int domain); +int ap_test_config_ctrl_domain(unsigned int domain); + void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *ap_msg); struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type); void ap_queue_remove(struct ap_queue *aq); diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index e6854127b434..e862369a5436 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -368,7 +368,7 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB) struct ap_message ap_msg; unsigned int weight, pref_weight; unsigned int func_code; - unsigned short *domain; + unsigned short *domain, tdom; int qid = 0, rc = -ENODEV; trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB); @@ -378,6 +378,17 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB) if (rc) goto out; + /* + * If a valid target domain is set and this domain is NOT a usage + * domain but a control only domain, use the default domain as target. + */ + tdom = *domain; + if (tdom >= 0 && tdom < AP_DOMAINS && + !ap_test_config_usage_domain(tdom) && + ap_test_config_ctrl_domain(tdom) && + ap_domain_index >= 0) + tdom = ap_domain_index; + pref_zc = NULL; pref_zq = NULL; spin_lock(&zcrypt_list_lock); @@ -397,8 +408,8 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB) /* check if device is online and eligible */ if (!zq->online || !zq->ops->send_cprb || - ((*domain != (unsigned short) AUTOSELECT) && - (*domain != AP_QID_QUEUE(zq->queue->qid)))) + (tdom != (unsigned short) AUTOSELECT && + tdom != AP_QID_QUEUE(zq->queue->qid))) continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight))