From 52f72feba9dbe4fac848ae0d90bc0b85b17f91bc Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Tue, 15 Sep 2020 17:01:58 +0200 Subject: s390/zcrypt: remove set_fs() invocation in zcrypt device driver This patch reworks the zcrypt device driver so that the set_fs() invocation is not needed any more. Instead there is a new flag bool userspace passed through all the functions which tells if the pointer arguments are userspace or kernelspace. Together with the two new inline functions z_copy_from_user() and z_copy_to_user() which either invoke copy_from_user (userspace is true) or memcpy (userspace is false) the zcrypt dd and the AP bus now has no requirement for the set_fs() functionality any more. Signed-off-by: Harald Freudenberger Reviewed-by: Ingo Franzki Reviewed-by: Christoph Hellwig Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/zcrypt_api.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers/s390/crypto/zcrypt_api.c') diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 4dbbfd88262c..a711728c3857 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -797,7 +797,7 @@ out: return rc; } -static long _zcrypt_send_cprb(struct ap_perms *perms, +static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, struct ica_xcRB *xcRB) { struct zcrypt_card *zc, *pref_zc; @@ -813,7 +813,7 @@ static long _zcrypt_send_cprb(struct ap_perms *perms, xcRB->status = 0; ap_init_message(&ap_msg); - rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain); + rc = get_cprb_fc(userspace, xcRB, &ap_msg, &func_code, &domain); if (rc) goto out; @@ -878,7 +878,7 @@ static long _zcrypt_send_cprb(struct ap_perms *perms, if (*domain == AUTOSEL_DOM) *domain = AP_QID_QUEUE(qid); - rc = pref_zq->ops->send_cprb(pref_zq, xcRB, &ap_msg); + rc = pref_zq->ops->send_cprb(userspace, pref_zq, xcRB, &ap_msg); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, mod, weight); @@ -893,7 +893,7 @@ out: long zcrypt_send_cprb(struct ica_xcRB *xcRB) { - return _zcrypt_send_cprb(&ap_perms, xcRB); + return _zcrypt_send_cprb(false, &ap_perms, xcRB); } EXPORT_SYMBOL(zcrypt_send_cprb); @@ -924,7 +924,7 @@ static bool is_desired_ep11_queue(unsigned int dev_qid, return false; } -static long _zcrypt_send_ep11_cprb(struct ap_perms *perms, +static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, struct ep11_urb *xcrb) { struct zcrypt_card *zc, *pref_zc; @@ -956,7 +956,7 @@ static long _zcrypt_send_ep11_cprb(struct ap_perms *perms, } uptr = (struct ep11_target_dev __force __user *) xcrb->targets; - if (copy_from_user(targets, uptr, + if (z_copy_from_user(userspace, targets, uptr, target_num * sizeof(*targets))) { func_code = 0; rc = -EFAULT; @@ -964,7 +964,7 @@ static long _zcrypt_send_ep11_cprb(struct ap_perms *perms, } } - rc = get_ep11cprb_fc(xcrb, &ap_msg, &func_code); + rc = get_ep11cprb_fc(userspace, xcrb, &ap_msg, &func_code); if (rc) goto out_free; @@ -1015,7 +1015,7 @@ static long _zcrypt_send_ep11_cprb(struct ap_perms *perms, } qid = pref_zq->queue->qid; - rc = pref_zq->ops->send_ep11_cprb(pref_zq, xcrb, &ap_msg); + rc = pref_zq->ops->send_ep11_cprb(userspace, pref_zq, xcrb, &ap_msg); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, mod, weight); @@ -1032,7 +1032,7 @@ out: long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) { - return _zcrypt_send_ep11_cprb(&ap_perms, xcrb); + return _zcrypt_send_ep11_cprb(false, &ap_perms, xcrb); } EXPORT_SYMBOL(zcrypt_send_ep11_cprb); @@ -1353,12 +1353,12 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg) if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB))) return -EFAULT; do { - rc = _zcrypt_send_cprb(perms, &xcRB); + rc = _zcrypt_send_cprb(true, perms, &xcRB); } while (rc == -EAGAIN); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = _zcrypt_send_cprb(perms, &xcRB); + rc = _zcrypt_send_cprb(true, perms, &xcRB); } while (rc == -EAGAIN); if (rc) ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d status=0x%x\n", @@ -1377,12 +1377,12 @@ static int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg) if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb))) return -EFAULT; do { - rc = _zcrypt_send_ep11_cprb(perms, &xcrb); + rc = _zcrypt_send_ep11_cprb(true, perms, &xcrb); } while (rc == -EAGAIN); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = _zcrypt_send_ep11_cprb(perms, &xcrb); + rc = _zcrypt_send_ep11_cprb(true, perms, &xcrb); } while (rc == -EAGAIN); if (rc) ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d\n", rc); @@ -1655,12 +1655,12 @@ static long trans_xcRB32(struct ap_perms *perms, struct file *filp, xcRB64.priority_window = xcRB32.priority_window; xcRB64.status = xcRB32.status; do { - rc = _zcrypt_send_cprb(perms, &xcRB64); + rc = _zcrypt_send_cprb(true, perms, &xcRB64); } while (rc == -EAGAIN); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = _zcrypt_send_cprb(perms, &xcRB64); + rc = _zcrypt_send_cprb(true, perms, &xcRB64); } while (rc == -EAGAIN); xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length; xcRB32.reply_data_length = xcRB64.reply_data_length; -- cgit v1.2.3-59-g8ed1b From 91ffc519c1997520ff3435ee227d86cfaa30d037 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 2 Jul 2020 11:10:11 +0200 Subject: s390/zcrypt: introduce msg tracking in zcrypt functions Introduce a new internal struct zcrypt_track with an retry counter field and a last return code field. Fill and update these fields at certain points during processing of an request/reply. This tracking info is then used to - avoid trying to resend the message forever. Now each message is tried to be send TRACK_AGAIN_MAX (currently 10) times and then the ioctl returns to userspace with errno EAGAIN. - avoid trying to resend the message on the very same card/domain. If possible (more than one APQN with same quality) don't use the very same qid as the previous attempt when again scheduling the request. This is done by adding penalty weight values when the dispatching takes place. There is a penalty TRACK_AGAIN_CARD_WEIGHT_PENALTY for using the same card as previously and another penalty define TRACK_AGAIN_QUEUE_WEIGHT_PENALTY to be considered when the same qid as the previous sent attempt is calculated. Both values make it harder to choose the very same card/domain but not impossible. For example when only one APQN is available a resend can only address the very same APQN. There are some more ideas for the future to extend the use of this tracking information. For example the last response code at NQAP and DQAP could be stored there, giving the possibility to extended tracing and debugging about requests failing to get processed properly. Signed-off-by: Harald Freudenberger Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/zcrypt_api.c | 253 +++++++++++++++++++++++++------------ drivers/s390/crypto/zcrypt_api.h | 14 +- drivers/s390/crypto/zcrypt_cex2a.c | 6 +- drivers/s390/crypto/zcrypt_cex2c.c | 6 +- drivers/s390/crypto/zcrypt_cex4.c | 58 ++++----- 5 files changed, 213 insertions(+), 124 deletions(-) (limited to 'drivers/s390/crypto/zcrypt_api.c') diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index a711728c3857..223e1c233278 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -602,13 +602,13 @@ static inline bool zcrypt_card_compare(struct zcrypt_card *zc, unsigned int pref_weight) { if (!pref_zc) - return false; + return true; weight += atomic_read(&zc->load); pref_weight += atomic_read(&pref_zc->load); if (weight == pref_weight) - return atomic64_read(&zc->card->total_request_count) > + return atomic64_read(&zc->card->total_request_count) < atomic64_read(&pref_zc->card->total_request_count); - return weight > pref_weight; + return weight < pref_weight; } static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq, @@ -617,26 +617,27 @@ static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq, unsigned int pref_weight) { if (!pref_zq) - return false; + return true; weight += atomic_read(&zq->load); pref_weight += atomic_read(&pref_zq->load); if (weight == pref_weight) - return zq->queue->total_request_count > + return zq->queue->total_request_count < pref_zq->queue->total_request_count; - return weight > pref_weight; + return weight < pref_weight; } /* * zcrypt ioctls. */ static long zcrypt_rsa_modexpo(struct ap_perms *perms, + struct zcrypt_track *tr, struct ica_rsa_modexpo *mex) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; - unsigned int weight = 0, pref_weight = 0; + unsigned int wgt = 0, pref_wgt = 0; unsigned int func_code; - int qid = 0, rc = -ENODEV; + int cpen, qpen, qid = 0, rc = -ENODEV; struct module *mod; trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO); @@ -673,8 +674,12 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, if (!zcrypt_check_card(perms, zc->card->id)) continue; /* get weight index of the card device */ - weight = zc->speed_rating[func_code]; - if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) + wgt = zc->speed_rating[func_code]; + /* penalty if this msg was previously sent via this card */ + cpen = (tr && tr->again_counter && tr->last_qid && + AP_QID_CARD(tr->last_qid) == zc->card->id) ? + TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0; + if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ @@ -684,15 +689,19 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, if (!zcrypt_check_queue(perms, AP_QID_QUEUE(zq->queue->qid))) continue; - if (zcrypt_queue_compare(zq, pref_zq, - weight, pref_weight)) + /* penalty if the msg was previously sent at this qid */ + qpen = (tr && tr->again_counter && tr->last_qid && + tr->last_qid == zq->queue->qid) ? + TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0; + if (!zcrypt_queue_compare(zq, pref_zq, + wgt + cpen + qpen, pref_wgt)) continue; pref_zc = zc; pref_zq = zq; - pref_weight = weight; + pref_wgt = wgt + cpen + qpen; } } - pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, weight); + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt); spin_unlock(&zcrypt_list_lock); if (!pref_zq) { @@ -704,23 +713,28 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, rc = pref_zq->ops->rsa_modexpo(pref_zq, mex); spin_lock(&zcrypt_list_lock); - zcrypt_drop_queue(pref_zc, pref_zq, mod, weight); + zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); spin_unlock(&zcrypt_list_lock); out: + if (tr) { + tr->last_rc = rc; + tr->last_qid = qid; + } trace_s390_zcrypt_rep(mex, func_code, rc, AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } static long zcrypt_rsa_crt(struct ap_perms *perms, + struct zcrypt_track *tr, struct ica_rsa_modexpo_crt *crt) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; - unsigned int weight = 0, pref_weight = 0; + unsigned int wgt = 0, pref_wgt = 0; unsigned int func_code; - int qid = 0, rc = -ENODEV; + int cpen, qpen, qid = 0, rc = -ENODEV; struct module *mod; trace_s390_zcrypt_req(crt, TP_ICARSACRT); @@ -757,8 +771,12 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, if (!zcrypt_check_card(perms, zc->card->id)) continue; /* get weight index of the card device */ - weight = zc->speed_rating[func_code]; - if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) + wgt = zc->speed_rating[func_code]; + /* penalty if this msg was previously sent via this card */ + cpen = (tr && tr->again_counter && tr->last_qid && + AP_QID_CARD(tr->last_qid) == zc->card->id) ? + TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0; + if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ @@ -768,15 +786,19 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, if (!zcrypt_check_queue(perms, AP_QID_QUEUE(zq->queue->qid))) continue; - if (zcrypt_queue_compare(zq, pref_zq, - weight, pref_weight)) + /* penalty if the msg was previously sent at this qid */ + qpen = (tr && tr->again_counter && tr->last_qid && + tr->last_qid == zq->queue->qid) ? + TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0; + if (!zcrypt_queue_compare(zq, pref_zq, + wgt + cpen + qpen, pref_wgt)) continue; pref_zc = zc; pref_zq = zq; - pref_weight = weight; + pref_wgt = wgt + cpen + qpen; } } - pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, weight); + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt); spin_unlock(&zcrypt_list_lock); if (!pref_zq) { @@ -788,25 +810,30 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt); spin_lock(&zcrypt_list_lock); - zcrypt_drop_queue(pref_zc, pref_zq, mod, weight); + zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); spin_unlock(&zcrypt_list_lock); out: + if (tr) { + tr->last_rc = rc; + tr->last_qid = qid; + } trace_s390_zcrypt_rep(crt, func_code, rc, AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, + struct zcrypt_track *tr, struct ica_xcRB *xcRB) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; struct ap_message ap_msg; - unsigned int weight = 0, pref_weight = 0; + unsigned int wgt = 0, pref_wgt = 0; unsigned int func_code; unsigned short *domain, tdom; - int qid = 0, rc = -ENODEV; + int cpen, qpen, qid = 0, rc = -ENODEV; struct module *mod; trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB); @@ -843,8 +870,12 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, if (!zcrypt_check_card(perms, zc->card->id)) continue; /* get weight index of the card device */ - weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY]; - if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) + wgt = speed_idx_cca(func_code) * zc->speed_rating[SECKEY]; + /* penalty if this msg was previously sent via this card */ + cpen = (tr && tr->again_counter && tr->last_qid && + AP_QID_CARD(tr->last_qid) == zc->card->id) ? + TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0; + if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ @@ -857,15 +888,19 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, if (!zcrypt_check_queue(perms, AP_QID_QUEUE(zq->queue->qid))) continue; - if (zcrypt_queue_compare(zq, pref_zq, - weight, pref_weight)) + /* penalty if the msg was previously sent at this qid */ + qpen = (tr && tr->again_counter && tr->last_qid && + tr->last_qid == zq->queue->qid) ? + TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0; + if (!zcrypt_queue_compare(zq, pref_zq, + wgt + cpen + qpen, pref_wgt)) continue; pref_zc = zc; pref_zq = zq; - pref_weight = weight; + pref_wgt = wgt + cpen + qpen; } } - pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, weight); + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt); spin_unlock(&zcrypt_list_lock); if (!pref_zq) { @@ -881,11 +916,15 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, rc = pref_zq->ops->send_cprb(userspace, pref_zq, xcRB, &ap_msg); spin_lock(&zcrypt_list_lock); - zcrypt_drop_queue(pref_zc, pref_zq, mod, weight); + zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); spin_unlock(&zcrypt_list_lock); out: ap_release_message(&ap_msg); + if (tr) { + tr->last_rc = rc; + tr->last_qid = qid; + } trace_s390_zcrypt_rep(xcRB, func_code, rc, AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; @@ -893,7 +932,7 @@ out: long zcrypt_send_cprb(struct ica_xcRB *xcRB) { - return _zcrypt_send_cprb(false, &ap_perms, xcRB); + return _zcrypt_send_cprb(false, &ap_perms, NULL, xcRB); } EXPORT_SYMBOL(zcrypt_send_cprb); @@ -925,16 +964,17 @@ static bool is_desired_ep11_queue(unsigned int dev_qid, } static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, + struct zcrypt_track *tr, struct ep11_urb *xcrb) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; struct ep11_target_dev *targets; unsigned short target_num; - unsigned int weight = 0, pref_weight = 0; + unsigned int wgt = 0, pref_wgt = 0; unsigned int func_code; struct ap_message ap_msg; - int qid = 0, rc = -ENODEV; + int cpen, qpen, qid = 0, rc = -ENODEV; struct module *mod; trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB); @@ -983,8 +1023,12 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, if (!zcrypt_check_card(perms, zc->card->id)) continue; /* get weight index of the card device */ - weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY]; - if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) + wgt = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY]; + /* penalty if this msg was previously sent via this card */ + cpen = (tr && tr->again_counter && tr->last_qid && + AP_QID_CARD(tr->last_qid) == zc->card->id) ? + TRACK_AGAIN_CARD_WEIGHT_PENALTY : 0; + if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ @@ -998,15 +1042,19 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, if (!zcrypt_check_queue(perms, AP_QID_QUEUE(zq->queue->qid))) continue; - if (zcrypt_queue_compare(zq, pref_zq, - weight, pref_weight)) + /* penalty if the msg was previously sent at this qid */ + qpen = (tr && tr->again_counter && tr->last_qid && + tr->last_qid == zq->queue->qid) ? + TRACK_AGAIN_QUEUE_WEIGHT_PENALTY : 0; + if (!zcrypt_queue_compare(zq, pref_zq, + wgt + cpen + qpen, pref_wgt)) continue; pref_zc = zc; pref_zq = zq; - pref_weight = weight; + pref_wgt = wgt + cpen + qpen; } } - pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, weight); + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt); spin_unlock(&zcrypt_list_lock); if (!pref_zq) { @@ -1018,13 +1066,17 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, rc = pref_zq->ops->send_ep11_cprb(userspace, pref_zq, xcrb, &ap_msg); spin_lock(&zcrypt_list_lock); - zcrypt_drop_queue(pref_zc, pref_zq, mod, weight); + zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); spin_unlock(&zcrypt_list_lock); out_free: kfree(targets); out: ap_release_message(&ap_msg); + if (tr) { + tr->last_rc = rc; + tr->last_qid = qid; + } trace_s390_zcrypt_rep(xcrb, func_code, rc, AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; @@ -1032,7 +1084,7 @@ out: long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) { - return _zcrypt_send_ep11_cprb(false, &ap_perms, xcrb); + return _zcrypt_send_ep11_cprb(false, &ap_perms, NULL, xcrb); } EXPORT_SYMBOL(zcrypt_send_ep11_cprb); @@ -1040,7 +1092,7 @@ static long zcrypt_rng(char *buffer) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; - unsigned int weight = 0, pref_weight = 0; + unsigned int wgt = 0, pref_wgt = 0; unsigned int func_code; struct ap_message ap_msg; unsigned int domain; @@ -1062,22 +1114,21 @@ static long zcrypt_rng(char *buffer) if (!zc->online || !(zc->card->functions & 0x10000000)) continue; /* get weight index of the card device */ - weight = zc->speed_rating[func_code]; - if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) + wgt = zc->speed_rating[func_code]; + if (!zcrypt_card_compare(zc, pref_zc, wgt, pref_wgt)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online || !zq->ops->rng) continue; - if (zcrypt_queue_compare(zq, pref_zq, - weight, pref_weight)) + if (!zcrypt_queue_compare(zq, pref_zq, wgt, pref_wgt)) continue; pref_zc = zc; pref_zq = zq; - pref_weight = weight; + pref_wgt = wgt; } } - pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, weight); + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, &mod, wgt); spin_unlock(&zcrypt_list_lock); if (!pref_zq) { @@ -1089,7 +1140,7 @@ static long zcrypt_rng(char *buffer) rc = pref_zq->ops->rng(pref_zq, buffer, &ap_msg); spin_lock(&zcrypt_list_lock); - zcrypt_drop_queue(pref_zc, pref_zq, mod, weight); + zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); spin_unlock(&zcrypt_list_lock); out: @@ -1301,19 +1352,25 @@ static int zcrypt_requestq_count(void) static int icarsamodexpo_ioctl(struct ap_perms *perms, unsigned long arg) { int rc; + struct zcrypt_track tr; struct ica_rsa_modexpo mex; struct ica_rsa_modexpo __user *umex = (void __user *) arg; + memset(&tr, 0, sizeof(tr)); if (copy_from_user(&mex, umex, sizeof(mex))) return -EFAULT; do { - rc = zcrypt_rsa_modexpo(perms, &mex); - } while (rc == -EAGAIN); + rc = zcrypt_rsa_modexpo(perms, &tr, &mex); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = zcrypt_rsa_modexpo(perms, &mex); - } while (rc == -EAGAIN); + rc = zcrypt_rsa_modexpo(perms, &tr, &mex); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); if (rc) { ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSAMODEXPO rc=%d\n", rc); return rc; @@ -1324,19 +1381,25 @@ static int icarsamodexpo_ioctl(struct ap_perms *perms, unsigned long arg) static int icarsacrt_ioctl(struct ap_perms *perms, unsigned long arg) { int rc; + struct zcrypt_track tr; struct ica_rsa_modexpo_crt crt; struct ica_rsa_modexpo_crt __user *ucrt = (void __user *) arg; + memset(&tr, 0, sizeof(tr)); if (copy_from_user(&crt, ucrt, sizeof(crt))) return -EFAULT; do { - rc = zcrypt_rsa_crt(perms, &crt); - } while (rc == -EAGAIN); + rc = zcrypt_rsa_crt(perms, &tr, &crt); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = zcrypt_rsa_crt(perms, &crt); - } while (rc == -EAGAIN); + rc = zcrypt_rsa_crt(perms, &tr, &crt); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); if (rc) { ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSACRT rc=%d\n", rc); return rc; @@ -1348,18 +1411,24 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg) { int rc; struct ica_xcRB xcRB; + struct zcrypt_track tr; struct ica_xcRB __user *uxcRB = (void __user *) arg; + memset(&tr, 0, sizeof(tr)); if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB))) return -EFAULT; do { - rc = _zcrypt_send_cprb(true, perms, &xcRB); - } while (rc == -EAGAIN); + rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = _zcrypt_send_cprb(true, perms, &xcRB); - } while (rc == -EAGAIN); + rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); if (rc) ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d status=0x%x\n", rc, xcRB.status); @@ -1372,18 +1441,24 @@ static int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg) { int rc; struct ep11_urb xcrb; + struct zcrypt_track tr; struct ep11_urb __user *uxcrb = (void __user *)arg; + memset(&tr, 0, sizeof(tr)); if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb))) return -EFAULT; do { - rc = _zcrypt_send_ep11_cprb(true, perms, &xcrb); - } while (rc == -EAGAIN); + rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = _zcrypt_send_ep11_cprb(true, perms, &xcrb); - } while (rc == -EAGAIN); + rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); if (rc) ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d\n", rc); if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb))) @@ -1535,8 +1610,10 @@ static long trans_modexpo32(struct ap_perms *perms, struct file *filp, struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg); struct compat_ica_rsa_modexpo mex32; struct ica_rsa_modexpo mex64; + struct zcrypt_track tr; long rc; + memset(&tr, 0, sizeof(tr)); if (copy_from_user(&mex32, umex32, sizeof(mex32))) return -EFAULT; mex64.inputdata = compat_ptr(mex32.inputdata); @@ -1546,13 +1623,17 @@ static long trans_modexpo32(struct ap_perms *perms, struct file *filp, mex64.b_key = compat_ptr(mex32.b_key); mex64.n_modulus = compat_ptr(mex32.n_modulus); do { - rc = zcrypt_rsa_modexpo(perms, &mex64); - } while (rc == -EAGAIN); + rc = zcrypt_rsa_modexpo(perms, &tr, &mex64); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = zcrypt_rsa_modexpo(perms, &mex64); - } while (rc == -EAGAIN); + rc = zcrypt_rsa_modexpo(perms, &tr, &mex64); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); if (rc) return rc; return put_user(mex64.outputdatalength, @@ -1577,8 +1658,10 @@ static long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp, struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg); struct compat_ica_rsa_modexpo_crt crt32; struct ica_rsa_modexpo_crt crt64; + struct zcrypt_track tr; long rc; + memset(&tr, 0, sizeof(tr)); if (copy_from_user(&crt32, ucrt32, sizeof(crt32))) return -EFAULT; crt64.inputdata = compat_ptr(crt32.inputdata); @@ -1591,13 +1674,17 @@ static long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp, crt64.nq_prime = compat_ptr(crt32.nq_prime); crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv); do { - rc = zcrypt_rsa_crt(perms, &crt64); - } while (rc == -EAGAIN); + rc = zcrypt_rsa_crt(perms, &tr, &crt64); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = zcrypt_rsa_crt(perms, &crt64); - } while (rc == -EAGAIN); + rc = zcrypt_rsa_crt(perms, &tr, &crt64); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); if (rc) return rc; return put_user(crt64.outputdatalength, @@ -1629,9 +1716,11 @@ static long trans_xcRB32(struct ap_perms *perms, struct file *filp, { struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg); struct compat_ica_xcRB xcRB32; + struct zcrypt_track tr; struct ica_xcRB xcRB64; long rc; + memset(&tr, 0, sizeof(tr)); if (copy_from_user(&xcRB32, uxcRB32, sizeof(xcRB32))) return -EFAULT; xcRB64.agent_ID = xcRB32.agent_ID; @@ -1655,13 +1744,17 @@ static long trans_xcRB32(struct ap_perms *perms, struct file *filp, xcRB64.priority_window = xcRB32.priority_window; xcRB64.status = xcRB32.status; do { - rc = _zcrypt_send_cprb(true, perms, &xcRB64); - } while (rc == -EAGAIN); + rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB64); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) do { - rc = _zcrypt_send_cprb(true, perms, &xcRB64); - } while (rc == -EAGAIN); + rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB64); + if (rc == -EAGAIN) + tr.again_counter++; + } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length; xcRB32.reply_data_length = xcRB64.reply_data_length; xcRB32.status = xcRB64.status; diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 19ddfc38e029..263ed1735431 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -55,6 +55,18 @@ enum crypto_ops { struct zcrypt_queue; +/* struct to hold tracking information for a userspace request/response */ +struct zcrypt_track { + int again_counter; /* retry attempts counter */ + int last_qid; /* last qid used */ + int last_rc; /* last return code */ +}; + +/* defines related to message tracking */ +#define TRACK_AGAIN_MAX 10 +#define TRACK_AGAIN_CARD_WEIGHT_PENALTY 1000 +#define TRACK_AGAIN_QUEUE_WEIGHT_PENALTY 10000 + struct zcrypt_ops { long (*rsa_modexpo)(struct zcrypt_queue *, struct ica_rsa_modexpo *); long (*rsa_modexpo_crt)(struct zcrypt_queue *, @@ -82,7 +94,7 @@ struct zcrypt_card { int min_mod_size; /* Min number of bits. */ int max_mod_size; /* Max number of bits. */ int max_exp_bit_length; - int speed_rating[NUM_OPS]; /* Speed idx of crypto ops. */ + const int *speed_rating; /* Speed idx of crypto ops. */ atomic_t load; /* Utilization of the crypto device */ int request_count; /* # current requests. */ diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index b447f3e9e4a2..226a5612e855 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -94,8 +94,7 @@ static int zcrypt_cex2a_card_probe(struct ap_device *ap_dev) if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A) { zc->min_mod_size = CEX2A_MIN_MOD_SIZE; zc->max_mod_size = CEX2A_MAX_MOD_SIZE; - memcpy(zc->speed_rating, CEX2A_SPEED_IDX, - sizeof(CEX2A_SPEED_IDX)); + zc->speed_rating = CEX2A_SPEED_IDX; zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; zc->type_string = "CEX2A"; zc->user_space_type = ZCRYPT_CEX2A; @@ -108,8 +107,7 @@ static int zcrypt_cex2a_card_probe(struct ap_device *ap_dev) zc->max_mod_size = CEX3A_MAX_MOD_SIZE; zc->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; } - memcpy(zc->speed_rating, CEX3A_SPEED_IDX, - sizeof(CEX3A_SPEED_IDX)); + zc->speed_rating = CEX3A_SPEED_IDX; zc->type_string = "CEX3A"; zc->user_space_type = ZCRYPT_CEX3A; } else { diff --git a/drivers/s390/crypto/zcrypt_cex2c.c b/drivers/s390/crypto/zcrypt_cex2c.c index 146eb9f24694..7a8cbdbe4408 100644 --- a/drivers/s390/crypto/zcrypt_cex2c.c +++ b/drivers/s390/crypto/zcrypt_cex2c.c @@ -266,8 +266,7 @@ static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev) case AP_DEVICE_TYPE_CEX2C: zc->user_space_type = ZCRYPT_CEX2C; zc->type_string = "CEX2C"; - memcpy(zc->speed_rating, CEX2C_SPEED_IDX, - sizeof(CEX2C_SPEED_IDX)); + zc->speed_rating = CEX2C_SPEED_IDX; zc->min_mod_size = CEX2C_MIN_MOD_SIZE; zc->max_mod_size = CEX2C_MAX_MOD_SIZE; zc->max_exp_bit_length = CEX2C_MAX_MOD_SIZE; @@ -275,8 +274,7 @@ static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev) case AP_DEVICE_TYPE_CEX3C: zc->user_space_type = ZCRYPT_CEX3C; zc->type_string = "CEX3C"; - memcpy(zc->speed_rating, CEX3C_SPEED_IDX, - sizeof(CEX3C_SPEED_IDX)); + zc->speed_rating = CEX3C_SPEED_IDX; zc->min_mod_size = CEX3C_MIN_MOD_SIZE; zc->max_mod_size = CEX3C_MAX_MOD_SIZE; zc->max_exp_bit_length = CEX3C_MAX_MOD_SIZE; diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index d9ebe3a3c210..f5195bca1d85 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -409,31 +409,31 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) * Normalized speed ratings per crypto adapter * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY */ - static const int CEX4A_SPEED_IDX[] = { + static const int CEX4A_SPEED_IDX[NUM_OPS] = { 14, 19, 249, 42, 228, 1458, 0, 0}; - static const int CEX5A_SPEED_IDX[] = { + static const int CEX5A_SPEED_IDX[NUM_OPS] = { 8, 9, 20, 18, 66, 458, 0, 0}; - static const int CEX6A_SPEED_IDX[] = { + static const int CEX6A_SPEED_IDX[NUM_OPS] = { 6, 9, 20, 17, 65, 438, 0, 0}; - static const int CEX7A_SPEED_IDX[] = { + static const int CEX7A_SPEED_IDX[NUM_OPS] = { 6, 8, 17, 15, 54, 362, 0, 0}; - static const int CEX4C_SPEED_IDX[] = { + static const int CEX4C_SPEED_IDX[NUM_OPS] = { 59, 69, 308, 83, 278, 2204, 209, 40}; static const int CEX5C_SPEED_IDX[] = { 24, 31, 50, 37, 90, 479, 27, 10}; - static const int CEX6C_SPEED_IDX[] = { + static const int CEX6C_SPEED_IDX[NUM_OPS] = { 16, 20, 32, 27, 77, 455, 24, 9}; - static const int CEX7C_SPEED_IDX[] = { + static const int CEX7C_SPEED_IDX[NUM_OPS] = { 14, 16, 26, 23, 64, 376, 23, 8}; - static const int CEX4P_SPEED_IDX[] = { + static const int CEX4P_SPEED_IDX[NUM_OPS] = { 0, 0, 0, 0, 0, 0, 0, 50}; - static const int CEX5P_SPEED_IDX[] = { + static const int CEX5P_SPEED_IDX[NUM_OPS] = { 0, 0, 0, 0, 0, 0, 0, 10}; - static const int CEX6P_SPEED_IDX[] = { + static const int CEX6P_SPEED_IDX[NUM_OPS] = { 0, 0, 0, 0, 0, 0, 0, 9}; - static const int CEX7P_SPEED_IDX[] = { + static const int CEX7P_SPEED_IDX[NUM_OPS] = { 0, 0, 0, 0, 0, 0, 0, 8}; struct ap_card *ac = to_ap_card(&ap_dev->device); @@ -449,26 +449,22 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { zc->type_string = "CEX4A"; zc->user_space_type = ZCRYPT_CEX4; - memcpy(zc->speed_rating, CEX4A_SPEED_IDX, - sizeof(CEX4A_SPEED_IDX)); + zc->speed_rating = CEX4A_SPEED_IDX; } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) { zc->type_string = "CEX5A"; zc->user_space_type = ZCRYPT_CEX5; - memcpy(zc->speed_rating, CEX5A_SPEED_IDX, - sizeof(CEX5A_SPEED_IDX)); + zc->speed_rating = CEX5A_SPEED_IDX; } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX6) { zc->type_string = "CEX6A"; zc->user_space_type = ZCRYPT_CEX6; - memcpy(zc->speed_rating, CEX6A_SPEED_IDX, - sizeof(CEX6A_SPEED_IDX)); + zc->speed_rating = CEX6A_SPEED_IDX; } else { zc->type_string = "CEX7A"; /* wrong user space type, just for compatibility * with the ZCRYPT_STATUS_MASK ioctl. */ zc->user_space_type = ZCRYPT_CEX6; - memcpy(zc->speed_rating, CEX7A_SPEED_IDX, - sizeof(CEX7A_SPEED_IDX)); + zc->speed_rating = CEX7A_SPEED_IDX; } zc->min_mod_size = CEX4A_MIN_MOD_SIZE; if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) && @@ -488,32 +484,28 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) * just keep it for cca compatibility */ zc->user_space_type = ZCRYPT_CEX3C; - memcpy(zc->speed_rating, CEX4C_SPEED_IDX, - sizeof(CEX4C_SPEED_IDX)); + zc->speed_rating = CEX4C_SPEED_IDX; } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) { zc->type_string = "CEX5C"; /* wrong user space type, must be CEX5 * just keep it for cca compatibility */ zc->user_space_type = ZCRYPT_CEX3C; - memcpy(zc->speed_rating, CEX5C_SPEED_IDX, - sizeof(CEX5C_SPEED_IDX)); + zc->speed_rating = CEX5C_SPEED_IDX; } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX6) { zc->type_string = "CEX6C"; /* wrong user space type, must be CEX6 * just keep it for cca compatibility */ zc->user_space_type = ZCRYPT_CEX3C; - memcpy(zc->speed_rating, CEX6C_SPEED_IDX, - sizeof(CEX6C_SPEED_IDX)); + zc->speed_rating = CEX6C_SPEED_IDX; } else { zc->type_string = "CEX7C"; /* wrong user space type, must be CEX7 * just keep it for cca compatibility */ zc->user_space_type = ZCRYPT_CEX3C; - memcpy(zc->speed_rating, CEX7C_SPEED_IDX, - sizeof(CEX7C_SPEED_IDX)); + zc->speed_rating = CEX7C_SPEED_IDX; } zc->min_mod_size = CEX4C_MIN_MOD_SIZE; zc->max_mod_size = CEX4C_MAX_MOD_SIZE; @@ -522,26 +514,22 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { zc->type_string = "CEX4P"; zc->user_space_type = ZCRYPT_CEX4; - memcpy(zc->speed_rating, CEX4P_SPEED_IDX, - sizeof(CEX4P_SPEED_IDX)); + zc->speed_rating = CEX4P_SPEED_IDX; } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX5) { zc->type_string = "CEX5P"; zc->user_space_type = ZCRYPT_CEX5; - memcpy(zc->speed_rating, CEX5P_SPEED_IDX, - sizeof(CEX5P_SPEED_IDX)); + zc->speed_rating = CEX5P_SPEED_IDX; } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX6) { zc->type_string = "CEX6P"; zc->user_space_type = ZCRYPT_CEX6; - memcpy(zc->speed_rating, CEX6P_SPEED_IDX, - sizeof(CEX6P_SPEED_IDX)); + zc->speed_rating = CEX6P_SPEED_IDX; } else { zc->type_string = "CEX7P"; /* wrong user space type, just for compatibility * with the ZCRYPT_STATUS_MASK ioctl. */ zc->user_space_type = ZCRYPT_CEX6; - memcpy(zc->speed_rating, CEX7P_SPEED_IDX, - sizeof(CEX7P_SPEED_IDX)); + zc->speed_rating = CEX7P_SPEED_IDX; } zc->min_mod_size = CEX4C_MIN_MOD_SIZE; zc->max_mod_size = CEX4C_MAX_MOD_SIZE; -- cgit v1.2.3-59-g8ed1b From 4f2fcccdb547b09a4532c705078811e672fb9235 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 2 Jul 2020 16:57:00 +0200 Subject: s390/ap: add card/queue deconfig state This patch adds a new config state to the ap card and queue devices. This state reflects the response code 0x03 "AP deconfigured" on TQAP invocation and is tracked with every ap bus scan. Together with this new state now a card/queue device which is 'deconfigured' is not disposed any more. However, for backward compatibility the online state now needs to take this state into account. So a card/queue is offline when the device is not configured. Furthermore a device can't get switched from offline to online state when not configured. The config state is shown in sysfs at /sys/devices/ap/cardxx/config for the card and /sys/devices/ap/cardxx/xx.yyyy/config for each queue within each card. It is a read-only attribute reflecting the negation of the 'AP deconfig' state as it is noted in the AP documents. Signed-off-by: Harald Freudenberger Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/ap_bus.c | 364 +++++++++++++++++++++++++------------ drivers/s390/crypto/ap_bus.h | 2 + drivers/s390/crypto/ap_card.c | 11 ++ drivers/s390/crypto/ap_queue.c | 15 ++ drivers/s390/crypto/zcrypt_api.c | 46 +++-- drivers/s390/crypto/zcrypt_card.c | 12 +- drivers/s390/crypto/zcrypt_queue.c | 11 +- 7 files changed, 319 insertions(+), 142 deletions(-) (limited to 'drivers/s390/crypto/zcrypt_api.c') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 6d61e89c5984..485cbfcbf06e 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -307,7 +307,7 @@ EXPORT_SYMBOL(ap_test_config_ctrl_domain); * false otherwise. */ static bool ap_queue_info(ap_qid_t qid, int *q_type, - unsigned int *q_fac, int *q_depth) + unsigned int *q_fac, int *q_depth, bool *q_decfg) { struct ap_queue_status status; unsigned long info = 0; @@ -322,6 +322,9 @@ static bool ap_queue_info(ap_qid_t qid, int *q_type, switch (status.response_code) { case AP_RESPONSE_NORMAL: case AP_RESPONSE_RESET_IN_PROGRESS: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + case AP_RESPONSE_BUSY: /* * According to the architecture in all these cases the * info should be filled. All bits 0 is not possible as @@ -332,6 +335,7 @@ static bool ap_queue_info(ap_qid_t qid, int *q_type, *q_type = (int)((info >> 24) & 0xff); *q_fac = (unsigned int)(info >> 32); *q_depth = (int)(info & 0xff); + *q_decfg = status.response_code == AP_RESPONSE_DECONFIGURED; switch (*q_type) { /* For CEX2 and CEX3 the available functions * are not reflected by the facilities bits. @@ -1290,154 +1294,278 @@ static int __match_queue_device_with_queue_id(struct device *dev, const void *da /* * Helper function for ap_scan_bus(). - * Does the scan bus job for the given adapter id. + * Remove card device and associated queue devices. + */ +static inline void ap_scan_rm_card_dev_and_queue_devs(struct ap_card *ac) +{ + bus_for_each_dev(&ap_bus_type, NULL, + (void *)(long) ac->id, + __ap_queue_devices_with_id_unregister); + device_unregister(&ac->ap_dev.device); +} + +/* + * Helper function for ap_scan_bus(). + * Does the scan bus job for all the domains within + * a valid adapter given by an ap_card ptr. */ -static void _ap_scan_bus_adapter(int id) +static inline void ap_scan_domains(struct ap_card *ac) { - bool broken; + bool decfg; ap_qid_t qid; unsigned int func; - struct ap_card *ac; struct device *dev; struct ap_queue *aq; + int rc, dom, depth, type; + + /* + * Go through the configuration for the domains and compare them + * to the existing queue devices. Also take care of the config + * and error state for the queue devices. + */ + + for (dom = 0; dom <= ap_max_domain_id; dom++) { + qid = AP_MKQID(ac->id, dom); + dev = bus_find_device(&ap_bus_type, NULL, + (void *)(long) qid, + __match_queue_device_with_qid); + aq = dev ? to_ap_queue(dev) : NULL; + if (!ap_test_config_usage_domain(dom)) { + if (dev) { + AP_DBF_INFO("%s(%d,%d) not in config any more, rm queue device\n", + __func__, ac->id, dom); + device_unregister(dev); + put_device(dev); + } + continue; + } + /* domain is valid, get info from this APQN */ + if (!ap_queue_info(qid, &type, &func, &depth, &decfg)) { + if (aq) { + AP_DBF_INFO( + "%s(%d,%d) ap_queue_info() not successful, rm queue device\n", + __func__, ac->id, dom); + device_unregister(dev); + put_device(dev); + } + continue; + } + /* if no queue device exists, create a new one */ + if (!aq) { + aq = ap_queue_create(qid, ac->ap_dev.device_type); + if (!aq) { + AP_DBF_WARN("%s(%d,%d) ap_queue_create() failed\n", + __func__, ac->id, dom); + continue; + } + aq->card = ac; + aq->config = !decfg; + dev = &aq->ap_dev.device; + dev->bus = &ap_bus_type; + dev->parent = &ac->ap_dev.device; + dev_set_name(dev, "%02x.%04x", ac->id, dom); + /* register queue device */ + rc = device_register(dev); + if (rc) { + AP_DBF_WARN("%s(%d,%d) device_register() failed\n", + __func__, ac->id, dom); + goto put_dev_and_continue; + } + if (decfg) + AP_DBF_INFO("%s(%d,%d) new (decfg) queue device created\n", + __func__, ac->id, dom); + else + AP_DBF_INFO("%s(%d,%d) new queue device created\n", + __func__, ac->id, dom); + goto put_dev_and_continue; + } + /* Check config state on the already existing queue device */ + spin_lock_bh(&aq->lock); + if (decfg && aq->config) { + /* config off this queue device */ + aq->config = false; + if (aq->dev_state > AP_DEV_STATE_UNINITIATED) { + aq->dev_state = AP_DEV_STATE_ERROR; + aq->last_err_rc = AP_RESPONSE_DECONFIGURED; + } + spin_unlock_bh(&aq->lock); + AP_DBF_INFO("%s(%d,%d) queue device config off\n", + __func__, ac->id, dom); + /* 'receive' pending messages with -EAGAIN */ + ap_flush_queue(aq); + goto put_dev_and_continue; + } + if (!decfg && !aq->config) { + /* config on this queue device */ + aq->config = true; + if (aq->dev_state > AP_DEV_STATE_UNINITIATED) { + aq->dev_state = AP_DEV_STATE_OPERATING; + aq->sm_state = AP_SM_STATE_RESET_START; + } + spin_unlock_bh(&aq->lock); + AP_DBF_INFO("%s(%d,%d) queue device config on\n", + __func__, ac->id, dom); + goto put_dev_and_continue; + } + /* handle other error states */ + if (!decfg && aq->dev_state == AP_DEV_STATE_ERROR) { + spin_unlock_bh(&aq->lock); + /* 'receive' pending messages with -EAGAIN */ + ap_flush_queue(aq); + /* re-init (with reset) the queue device */ + ap_queue_init_state(aq); + AP_DBF_INFO("%s(%d,%d) queue device reinit enforced\n", + __func__, ac->id, dom); + goto put_dev_and_continue; + } + spin_unlock_bh(&aq->lock); +put_dev_and_continue: + put_device(dev); + } +} + +/* + * Helper function for ap_scan_bus(). + * Does the scan bus job for the given adapter id. + */ +static inline void ap_scan_adapter(int ap) +{ + bool decfg; + ap_qid_t qid; + unsigned int func; + struct device *dev; + struct ap_card *ac; int rc, dom, depth, type, comp_type; - /* check if there is a card device registered with this id */ + /* Is there currently a card device for this adapter ? */ dev = bus_find_device(&ap_bus_type, NULL, - (void *)(long) id, + (void *)(long) ap, __match_card_device_with_id); ac = dev ? to_ap_card(dev) : NULL; - if (!ap_test_config_card_id(id)) { - if (dev) { - /* Card device has been removed from configuration */ - bus_for_each_dev(&ap_bus_type, NULL, - (void *)(long) id, - __ap_queue_devices_with_id_unregister); - device_unregister(dev); + + /* Adapter not in configuration ? */ + if (!ap_test_config_card_id(ap)) { + if (ac) { + AP_DBF_INFO("%s(%d) ap not in config any more, rm card and queue devices\n", + __func__, ap); + ap_scan_rm_card_dev_and_queue_devs(ac); put_device(dev); } return; } /* - * This card id is enabled in the configuration. If we already have - * a card device with this id, check if type and functions are still - * the very same. Also verify that at least one queue is available. + * Adapter ap is valid in the current configuration. So do some checks: + * If no card device exists, build one. If a card device exists, check + * for type and functions changed. For all this we need to find a valid + * APQN first. */ - if (ac) { - /* find the first valid queue */ - for (dom = 0; dom < AP_DOMAINS; dom++) { - qid = AP_MKQID(id, dom); - if (ap_queue_info(qid, &type, &func, &depth)) + + for (dom = 0; dom <= ap_max_domain_id; dom++) + if (ap_test_config_usage_domain(dom)) { + qid = AP_MKQID(ap, dom); + if (ap_queue_info(qid, &type, &func, &depth, &decfg)) break; } - broken = false; - if (dom >= AP_DOMAINS) { - /* no accessible queue on this card */ - broken = true; - } else if (ac->raw_hwtype != type) { - /* card type has changed */ - AP_DBF_INFO("card=%02x type changed.\n", id); - broken = true; - } else if (ac->functions != func) { - /* card functions have changed */ - AP_DBF_INFO("card=%02x functions changed.\n", id); - broken = true; + if (dom > ap_max_domain_id) { + /* Could not find a valid APQN for this adapter */ + if (ac) { + AP_DBF_INFO( + "%s(%d) no type info (no APQN found), rm card and queue devices\n", + __func__, ap); + ap_scan_rm_card_dev_and_queue_devs(ac); + put_device(dev); + } else { + AP_DBF_DBG("%s(%d) no type info (no APQN found), ignored\n", + __func__, ap); } - if (broken) { - /* unregister card device and associated queues */ - bus_for_each_dev(&ap_bus_type, NULL, - (void *)(long) id, - __ap_queue_devices_with_id_unregister); - device_unregister(dev); + return; + } + if (!type) { + /* No apdater type info available, an unusable adapter */ + if (ac) { + AP_DBF_INFO("%s(%d) no valid type (0) info, rm card and queue devices\n", + __func__, ap); + ap_scan_rm_card_dev_and_queue_devs(ac); put_device(dev); - /* go back if there is no valid queue on this card */ - if (dom >= AP_DOMAINS) - return; - ac = NULL; + } else { + AP_DBF_DBG("%s(%d) no valid type (0) info, ignored\n", + __func__, ap); } + return; } - /* - * Go through all possible queue ids. Check and maybe create or release - * queue devices for this card. If there exists no card device yet, - * create a card device also. - */ - for (dom = 0; dom < AP_DOMAINS; dom++) { - qid = AP_MKQID(id, dom); - dev = bus_find_device(&ap_bus_type, NULL, - (void *)(long) qid, - __match_queue_device_with_qid); - aq = dev ? to_ap_queue(dev) : NULL; - if (!ap_test_config_usage_domain(dom)) { - if (dev) { - /* Queue device exists but has been - * removed from configuration. - */ - device_unregister(dev); - put_device(dev); - } - continue; - } - /* try to fetch infos about this queue */ - broken = !ap_queue_info(qid, &type, &func, &depth); - if (dev) { - if (!broken) { - spin_lock_bh(&aq->lock); - broken = aq->dev_state == AP_DEV_STATE_ERROR; - spin_unlock_bh(&aq->lock); + if (ac) { + /* Check APQN against existing card device for changes */ + if (ac->raw_hwtype != type) { + AP_DBF_INFO("%s(%d) hwtype %d changed, rm card and queue devices\n", + __func__, ap, type); + ap_scan_rm_card_dev_and_queue_devs(ac); + put_device(dev); + ac = NULL; + } else if (ac->functions != func) { + AP_DBF_INFO("%s(%d) functions 0x%08x changed, rm card and queue devices\n", + __func__, ap, type); + ap_scan_rm_card_dev_and_queue_devs(ac); + put_device(dev); + ac = NULL; + } else { + if (decfg && ac->config) { + ac->config = false; + AP_DBF_INFO("%s(%d) card device config off\n", + __func__, ap); + } - if (broken) { - /* Remove broken device */ - AP_DBF_DBG("removing broken queue=%02x.%04x\n", - id, dom); - device_unregister(dev); + if (!decfg && !ac->config) { + ac->config = true; + AP_DBF_INFO("%s(%d) card device config on\n", + __func__, ap); } - put_device(dev); - continue; } - if (broken) - continue; - /* a new queue device is needed, check out comp type */ + } + + if (!ac) { + /* Build a new card device */ comp_type = ap_get_compatible_type(qid, type, func); - if (!comp_type) - continue; - /* maybe a card device needs to be created first */ + if (!comp_type) { + AP_DBF_WARN("%s(%d) type %d, can't get compatibility type\n", + __func__, ap, type); + return; + } + ac = ap_card_create(ap, depth, type, comp_type, func); if (!ac) { - ac = ap_card_create(id, depth, type, comp_type, func); - if (!ac) - continue; - ac->ap_dev.device.bus = &ap_bus_type; - ac->ap_dev.device.parent = ap_root_device; - dev_set_name(&ac->ap_dev.device, "card%02x", id); - /* Register card device with AP bus */ - rc = device_register(&ac->ap_dev.device); - if (rc) { - put_device(&ac->ap_dev.device); - ac = NULL; - break; - } - /* get it and thus adjust reference counter */ - get_device(&ac->ap_dev.device); + AP_DBF_WARN("%s(%d) ap_card_create() failed\n", + __func__, ap); + return; } - /* now create the new queue device */ - aq = ap_queue_create(qid, comp_type); - if (!aq) - continue; - aq->card = ac; - aq->ap_dev.device.bus = &ap_bus_type; - aq->ap_dev.device.parent = &ac->ap_dev.device; - dev_set_name(&aq->ap_dev.device, "%02x.%04x", id, dom); - /* Register queue device */ - rc = device_register(&aq->ap_dev.device); + ac->config = !decfg; + dev = &ac->ap_dev.device; + dev->bus = &ap_bus_type; + dev->parent = ap_root_device; + dev_set_name(dev, "card%02x", ap); + /* Register the new card device with AP bus */ + rc = device_register(dev); if (rc) { - put_device(&aq->ap_dev.device); - continue; + AP_DBF_WARN("%s(%d) device_register() failed\n", + __func__, ap); + put_device(dev); + return; } - } /* end domain loop */ + /* get it and thus adjust reference counter */ + get_device(dev); + if (decfg) + AP_DBF_INFO("%s(%d) new (decfg) card device type=%d func=0x%08x created\n", + __func__, ap, type, func); + else + AP_DBF_INFO("%s(%d) new card device type=%d func=0x%08x created\n", + __func__, ap, type, func); + } + + /* Verify the domains and the queue devices for this card */ + ap_scan_domains(ac); - if (ac) - put_device(&ac->ap_dev.device); + /* release the card device */ + put_device(&ac->ap_dev.device); } /** @@ -1446,7 +1574,7 @@ static void _ap_scan_bus_adapter(int id) */ static void ap_scan_bus(struct work_struct *unused) { - int id; + int ap; ap_fetch_qci_info(ap_qci_info); ap_select_domain(); @@ -1454,8 +1582,8 @@ static void ap_scan_bus(struct work_struct *unused) AP_DBF_DBG("%s running\n", __func__); /* loop over all possible adapters */ - for (id = 0; id < AP_DEVICES; id++) - _ap_scan_bus_adapter(id); + for (ap = 0; ap <= ap_max_adapter_id; ap++) + ap_scan_adapter(ap); /* check if there is at least one queue available with default domain */ if (ap_domain_index >= 0) { diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 0b66e8866a2c..56c8bed7b6a1 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -166,6 +166,7 @@ struct ap_card { unsigned int functions; /* AP device function bitfield. */ int queue_depth; /* AP queue depth.*/ int id; /* AP card number. */ + bool config; /* configured state */ atomic64_t total_request_count; /* # requests ever for this AP device.*/ }; @@ -178,6 +179,7 @@ struct ap_queue { spinlock_t lock; /* Per device lock. */ void *private; /* ap driver private pointer. */ enum ap_dev_state dev_state; /* queue device state */ + bool config; /* configured state */ ap_qid_t qid; /* AP queue id. */ int interrupt; /* indicate if interrupts are enabled */ int queue_count; /* # messages currently on AP queue. */ diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index 6588713319ba..bf1e964b0048 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -139,6 +139,16 @@ static ssize_t modalias_show(struct device *dev, static DEVICE_ATTR_RO(modalias); +static ssize_t config_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + + return scnprintf(buf, PAGE_SIZE, "%d\n", ac->config ? 1 : 0); +} + +static DEVICE_ATTR_RO(config); + static struct attribute *ap_card_dev_attrs[] = { &dev_attr_hwtype.attr, &dev_attr_raw_hwtype.attr, @@ -148,6 +158,7 @@ static struct attribute *ap_card_dev_attrs[] = { &dev_attr_requestq_count.attr, &dev_attr_pendingq_count.attr, &dev_attr_modalias.attr, + &dev_attr_config.attr, NULL }; diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 69ea3d2c20ae..5523338ca65d 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -563,6 +563,20 @@ static ssize_t interrupt_show(struct device *dev, static DEVICE_ATTR_RO(interrupt); +static ssize_t config_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + int rc; + + spin_lock_bh(&aq->lock); + rc = scnprintf(buf, PAGE_SIZE, "%d\n", aq->config ? 1 : 0); + spin_unlock_bh(&aq->lock); + return rc; +} + +static DEVICE_ATTR_RO(config); + #ifdef CONFIG_ZCRYPT_DEBUG static ssize_t states_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -676,6 +690,7 @@ static struct attribute *ap_queue_dev_attrs[] = { &dev_attr_pendingq_count.attr, &dev_attr_reset.attr, &dev_attr_interrupt.attr, + &dev_attr_config.attr, #ifdef CONFIG_ZCRYPT_DEBUG &dev_attr_states.attr, &dev_attr_last_err_rc.attr, diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 223e1c233278..ab18e847cee7 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -663,8 +663,9 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, pref_zq = NULL; spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { - /* Check for online accelarator and CCA cards */ - if (!zc->online || !(zc->card->functions & 0x18000000)) + /* Check for useable accelarator or CCA card */ + if (!zc->online || !zc->card->config || + !(zc->card->functions & 0x18000000)) continue; /* Check for size limits */ if (zc->min_mod_size > mex->inputdatalength || @@ -682,8 +683,9 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) continue; for_each_zcrypt_queue(zq, zc) { - /* check if device is online and eligible */ - if (!zq->online || !zq->ops->rsa_modexpo) + /* check if device is useable and eligible */ + if (!zq->online || !zq->ops->rsa_modexpo || + !zq->queue->config) continue; /* check if device node has admission for this queue */ if (!zcrypt_check_queue(perms, @@ -760,8 +762,9 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, pref_zq = NULL; spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { - /* Check for online accelarator and CCA cards */ - if (!zc->online || !(zc->card->functions & 0x18000000)) + /* Check for useable accelarator or CCA card */ + if (!zc->online || !zc->card->config || + !(zc->card->functions & 0x18000000)) continue; /* Check for size limits */ if (zc->min_mod_size > crt->inputdatalength || @@ -779,8 +782,9 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) continue; for_each_zcrypt_queue(zq, zc) { - /* check if device is online and eligible */ - if (!zq->online || !zq->ops->rsa_modexpo_crt) + /* check if device is useable and eligible */ + if (!zq->online || !zq->ops->rsa_modexpo_crt || + !zq->queue->config) continue; /* check if device node has admission for this queue */ if (!zcrypt_check_queue(perms, @@ -859,8 +863,9 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, pref_zq = NULL; spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { - /* Check for online CCA cards */ - if (!zc->online || !(zc->card->functions & 0x10000000)) + /* Check for useable CCA card */ + if (!zc->online || !zc->card->config || + !(zc->card->functions & 0x10000000)) continue; /* Check for user selected CCA card */ if (xcRB->user_defined != AUTOSELECT && @@ -878,9 +883,10 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) continue; for_each_zcrypt_queue(zq, zc) { - /* check if device is online and eligible */ + /* check for device useable and eligible */ if (!zq->online || !zq->ops->send_cprb || + !zq->queue->config || (tdom != AUTOSEL_DOM && tdom != AP_QID_QUEUE(zq->queue->qid))) continue; @@ -1012,8 +1018,9 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, pref_zq = NULL; spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { - /* Check for online EP11 cards */ - if (!zc->online || !(zc->card->functions & 0x04000000)) + /* Check for useable EP11 card */ + if (!zc->online || !zc->card->config || + !(zc->card->functions & 0x04000000)) continue; /* Check for user selected EP11 card */ if (targets && @@ -1031,9 +1038,10 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, if (!zcrypt_card_compare(zc, pref_zc, wgt + cpen, pref_wgt)) continue; for_each_zcrypt_queue(zq, zc) { - /* check if device is online and eligible */ + /* check if device is useable and eligible */ if (!zq->online || !zq->ops->send_ep11_cprb || + !zq->queue->config || (targets && !is_desired_ep11_queue(zq->queue->qid, target_num, targets))) @@ -1110,16 +1118,18 @@ static long zcrypt_rng(char *buffer) pref_zq = NULL; spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { - /* Check for online CCA cards */ - if (!zc->online || !(zc->card->functions & 0x10000000)) + /* Check for useable CCA card */ + if (!zc->online || !zc->card->config || + !(zc->card->functions & 0x10000000)) continue; /* get weight index of the card device */ wgt = zc->speed_rating[func_code]; if (!zcrypt_card_compare(zc, pref_zc, wgt, pref_wgt)) continue; for_each_zcrypt_queue(zq, zc) { - /* check if device is online and eligible */ - if (!zq->online || !zq->ops->rng) + /* check if device is useable and eligible */ + if (!zq->online || !zq->ops->rng || + !zq->queue->config) continue; if (!zcrypt_queue_compare(zq, pref_zq, wgt, pref_wgt)) continue; diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c index c53cab4b0c9e..e342eb86acd1 100644 --- a/drivers/s390/crypto/zcrypt_card.c +++ b/drivers/s390/crypto/zcrypt_card.c @@ -50,22 +50,28 @@ static ssize_t online_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct zcrypt_card *zc = to_ap_card(dev)->private; + struct ap_card *ac = to_ap_card(dev); + struct zcrypt_card *zc = ac->private; + int online = ac->config && zc->online ? 1 : 0; - return scnprintf(buf, PAGE_SIZE, "%d\n", zc->online); + return scnprintf(buf, PAGE_SIZE, "%d\n", online); } static ssize_t online_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct zcrypt_card *zc = to_ap_card(dev)->private; + struct ap_card *ac = to_ap_card(dev); + struct zcrypt_card *zc = ac->private; struct zcrypt_queue *zq; int online, id; if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) return -EINVAL; + if (online && !ac->config) + return -ENODEV; + zc->online = online; id = zc->card->id; diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c index 8bae6ad159a7..3c207066313c 100644 --- a/drivers/s390/crypto/zcrypt_queue.c +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -40,22 +40,27 @@ static ssize_t online_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct zcrypt_queue *zq = to_ap_queue(dev)->private; + struct ap_queue *aq = to_ap_queue(dev); + struct zcrypt_queue *zq = aq->private; + int online = aq->config && zq->online ? 1 : 0; - return scnprintf(buf, PAGE_SIZE, "%d\n", zq->online); + return scnprintf(buf, PAGE_SIZE, "%d\n", online); } static ssize_t online_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct zcrypt_queue *zq = to_ap_queue(dev)->private; + struct ap_queue *aq = to_ap_queue(dev); + struct zcrypt_queue *zq = aq->private; struct zcrypt_card *zc = zq->zcard; int online; if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) return -EINVAL; + if (online && (!aq->config || !aq->card->config)) + return -ENODEV; if (online && !zc->online) return -EINVAL; zq->online = online; -- cgit v1.2.3-59-g8ed1b From 3730f5300b450bc89306c3ab79c254e6039d9197 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Sat, 26 Sep 2020 22:51:38 +0200 Subject: s390/zcrypt: move ap_msg param one level up the call chain Move the creating and disposal of the struct ap_message one level up the call chain. The ap message was constructed in the calling functions in msgtype50 and msgtype6 but only for the ica rsa messages. For CCA and EP11 CPRBs the ap message struct is created in the zcrypt api functions. This patch moves the construction of the ap message struct into the functions zcrypt_rsa_modexpo and zcrypt_rsa_crt. So now all the 4 zcrypt api functions zcrypt_rsa_modexpo, zcrypt_rsa_crt, zcrypt_send_cprb and zcrypt_send_ep11_cprb appear and act similar. There are no functional changes coming with this patch. However, the availability of the ap_message struct has advantages which will be needed by a follow up patch. Signed-off-by: Harald Freudenberger Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/zcrypt_api.c | 12 +++++- drivers/s390/crypto/zcrypt_api.h | 6 ++- drivers/s390/crypto/zcrypt_msgtype50.c | 74 +++++++++++++++++----------------- drivers/s390/crypto/zcrypt_msgtype6.c | 62 ++++++++++++++-------------- 4 files changed, 82 insertions(+), 72 deletions(-) (limited to 'drivers/s390/crypto/zcrypt_api.c') diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index ab18e847cee7..d642be65a3a0 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -635,6 +635,7 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; + struct ap_message ap_msg; unsigned int wgt = 0, pref_wgt = 0; unsigned int func_code; int cpen, qpen, qid = 0, rc = -ENODEV; @@ -642,6 +643,8 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO); + ap_init_message(&ap_msg); + if (mex->outputdatalength < mex->inputdatalength) { func_code = 0; rc = -EINVAL; @@ -712,13 +715,14 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, } qid = pref_zq->queue->qid; - rc = pref_zq->ops->rsa_modexpo(pref_zq, mex); + rc = pref_zq->ops->rsa_modexpo(pref_zq, mex, &ap_msg); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); spin_unlock(&zcrypt_list_lock); out: + ap_release_message(&ap_msg); if (tr) { tr->last_rc = rc; tr->last_qid = qid; @@ -734,6 +738,7 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; + struct ap_message ap_msg; unsigned int wgt = 0, pref_wgt = 0; unsigned int func_code; int cpen, qpen, qid = 0, rc = -ENODEV; @@ -741,6 +746,8 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, trace_s390_zcrypt_req(crt, TP_ICARSACRT); + ap_init_message(&ap_msg); + if (crt->outputdatalength < crt->inputdatalength) { func_code = 0; rc = -EINVAL; @@ -811,13 +818,14 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, } qid = pref_zq->queue->qid; - rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt); + rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt, &ap_msg); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, mod, wgt); spin_unlock(&zcrypt_list_lock); out: + ap_release_message(&ap_msg); if (tr) { tr->last_rc = rc; tr->last_qid = qid; diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 263ed1735431..03804f03b5d0 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -68,9 +68,11 @@ struct zcrypt_track { #define TRACK_AGAIN_QUEUE_WEIGHT_PENALTY 10000 struct zcrypt_ops { - long (*rsa_modexpo)(struct zcrypt_queue *, struct ica_rsa_modexpo *); + long (*rsa_modexpo)(struct zcrypt_queue *, struct ica_rsa_modexpo *, + struct ap_message *); long (*rsa_modexpo_crt)(struct zcrypt_queue *, - struct ica_rsa_modexpo_crt *); + struct ica_rsa_modexpo_crt *, + struct ap_message *); long (*send_cprb)(bool userspace, struct zcrypt_queue *, struct ica_xcRB *, struct ap_message *); long (*send_ep11_cprb)(bool userspace, struct zcrypt_queue *, struct ep11_urb *, diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index 0f7f404ed858..c543b5959509 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -450,42 +450,41 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0); * @mex: pointer to the modexpo request buffer */ static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq, - struct ica_rsa_modexpo *mex) + struct ica_rsa_modexpo *mex, + struct ap_message *ap_msg) { - struct ap_message ap_msg; struct completion work; int rc; - ap_init_message(&ap_msg); if (zq->zcard->user_space_type == ZCRYPT_CEX2A) - ap_msg.msg = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL); + ap_msg->msg = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL); else - ap_msg.msg = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, GFP_KERNEL); - if (!ap_msg.msg) + ap_msg->msg = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, GFP_KERNEL); + if (!ap_msg->msg) return -ENOMEM; - ap_msg.receive = zcrypt_cex2a_receive; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &work; - rc = ICAMEX_msg_to_type50MEX_msg(zq, &ap_msg, mex); + ap_msg->receive = zcrypt_cex2a_receive; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = &work; + rc = ICAMEX_msg_to_type50MEX_msg(zq, ap_msg, mex); if (rc) - goto out_free; + goto out; init_completion(&work); - rc = ap_queue_message(zq->queue, &ap_msg); + rc = ap_queue_message(zq->queue, ap_msg); if (rc) - goto out_free; + goto out; rc = wait_for_completion_interruptible(&work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_cex2a(zq, &ap_msg, + rc = convert_response_cex2a(zq, ap_msg, mex->outputdata, mex->outputdatalength); } else /* Signal pending. */ - ap_cancel_message(zq->queue, &ap_msg); -out_free: - kfree(ap_msg.msg); + ap_cancel_message(zq->queue, ap_msg); +out: + ap_msg->private = NULL; return rc; } @@ -497,42 +496,41 @@ out_free: * @crt: pointer to the modexpoc_crt request buffer */ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq, - struct ica_rsa_modexpo_crt *crt) + struct ica_rsa_modexpo_crt *crt, + struct ap_message *ap_msg) { - struct ap_message ap_msg; struct completion work; int rc; - ap_init_message(&ap_msg); if (zq->zcard->user_space_type == ZCRYPT_CEX2A) - ap_msg.msg = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL); + ap_msg->msg = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL); else - ap_msg.msg = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, GFP_KERNEL); - if (!ap_msg.msg) + ap_msg->msg = kmalloc(MSGTYPE50_CRB3_MAX_MSG_SIZE, GFP_KERNEL); + if (!ap_msg->msg) return -ENOMEM; - ap_msg.receive = zcrypt_cex2a_receive; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &work; - rc = ICACRT_msg_to_type50CRT_msg(zq, &ap_msg, crt); + ap_msg->receive = zcrypt_cex2a_receive; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = &work; + rc = ICACRT_msg_to_type50CRT_msg(zq, ap_msg, crt); if (rc) - goto out_free; + goto out; init_completion(&work); - rc = ap_queue_message(zq->queue, &ap_msg); + rc = ap_queue_message(zq->queue, ap_msg); if (rc) - goto out_free; + goto out; rc = wait_for_completion_interruptible(&work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_cex2a(zq, &ap_msg, + rc = convert_response_cex2a(zq, ap_msg, crt->outputdata, crt->outputdatalength); } else /* Signal pending. */ - ap_cancel_message(zq->queue, &ap_msg); -out_free: - kfree(ap_msg.msg); + ap_cancel_message(zq->queue, ap_msg); +out: + ap_msg->private = NULL; return rc; } diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 30eaa7a7aede..aab7f0692035 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -1007,41 +1007,42 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0); * @mex: pointer to the modexpo request buffer */ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq, - struct ica_rsa_modexpo *mex) + struct ica_rsa_modexpo *mex, + struct ap_message *ap_msg) { - struct ap_message ap_msg; struct response_type resp_type = { .type = CEXXC_RESPONSE_TYPE_ICA, }; int rc; - ap_init_message(&ap_msg); - ap_msg.msg = (void *) get_zeroed_page(GFP_KERNEL); - if (!ap_msg.msg) + ap_msg->msg = (void *) get_zeroed_page(GFP_KERNEL); + if (!ap_msg->msg) return -ENOMEM; - ap_msg.receive = zcrypt_msgtype6_receive; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &resp_type; - rc = ICAMEX_msg_to_type6MEX_msgX(zq, &ap_msg, mex); + ap_msg->receive = zcrypt_msgtype6_receive; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = &resp_type; + rc = ICAMEX_msg_to_type6MEX_msgX(zq, ap_msg, mex); if (rc) goto out_free; init_completion(&resp_type.work); - rc = ap_queue_message(zq->queue, &ap_msg); + rc = ap_queue_message(zq->queue, ap_msg); if (rc) goto out_free; rc = wait_for_completion_interruptible(&resp_type.work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_ica(zq, &ap_msg, + rc = convert_response_ica(zq, ap_msg, mex->outputdata, mex->outputdatalength); } else /* Signal pending. */ - ap_cancel_message(zq->queue, &ap_msg); + ap_cancel_message(zq->queue, ap_msg); out_free: - free_page((unsigned long) ap_msg.msg); + free_page((unsigned long) ap_msg->msg); + ap_msg->private = NULL; + ap_msg->msg = NULL; return rc; } @@ -1053,42 +1054,43 @@ out_free: * @crt: pointer to the modexpoc_crt request buffer */ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq, - struct ica_rsa_modexpo_crt *crt) + struct ica_rsa_modexpo_crt *crt, + struct ap_message *ap_msg) { - struct ap_message ap_msg; struct response_type resp_type = { .type = CEXXC_RESPONSE_TYPE_ICA, }; int rc; - ap_init_message(&ap_msg); - ap_msg.msg = (void *) get_zeroed_page(GFP_KERNEL); - if (!ap_msg.msg) + ap_msg->msg = (void *) get_zeroed_page(GFP_KERNEL); + if (!ap_msg->msg) return -ENOMEM; - ap_msg.receive = zcrypt_msgtype6_receive; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &resp_type; - rc = ICACRT_msg_to_type6CRT_msgX(zq, &ap_msg, crt); + ap_msg->receive = zcrypt_msgtype6_receive; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = &resp_type; + rc = ICACRT_msg_to_type6CRT_msgX(zq, ap_msg, crt); if (rc) goto out_free; init_completion(&resp_type.work); - rc = ap_queue_message(zq->queue, &ap_msg); + rc = ap_queue_message(zq->queue, ap_msg); if (rc) goto out_free; rc = wait_for_completion_interruptible(&resp_type.work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_ica(zq, &ap_msg, + rc = convert_response_ica(zq, ap_msg, crt->outputdata, crt->outputdatalength); } else { /* Signal pending. */ - ap_cancel_message(zq->queue, &ap_msg); + ap_cancel_message(zq->queue, ap_msg); } out_free: - free_page((unsigned long) ap_msg.msg); + free_page((unsigned long) ap_msg->msg); + ap_msg->private = NULL; + ap_msg->msg = NULL; return rc; } -- cgit v1.2.3-59-g8ed1b From 27c4f6738bdc535e42dfc1295dadc78ab7582939 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Tue, 29 Sep 2020 16:07:22 +0200 Subject: s390/zcrypt: Introduce Failure Injection feature Introduce a way to specify additional debug flags with an crpyto request to be able to trigger certain failures within the zcrypt device drivers and/or ap core code. This failure injection possibility is only enabled with a kernel debug build CONFIG_ZCRYPT_DEBUG) and should never be available on a regular kernel running in production environment. Details: * The ioctl(ICARSAMODEXPO) get's a struct ica_rsa_modexpo. If the leftmost bit of the 32 bit unsigned int inputdatalength field is set, the uppermost 16 bits are separated and used as debug flag value. The process is checked to have the CAP_SYS_ADMIN capability enabled or EPERM is returned. * The ioctl(ICARSACRT) get's a struct ica_rsa_modexpo_crt. If the leftmost bit of the 32 bit unsigned int inputdatalength field is set, the uppermost 16 bits are separated and used als debug flag value. The process is checked to have the CAP_SYS_ADMIN capability enabled or EPERM is returned. * The ioctl(ZSECSENDCPRB) used to send CCA CPRBs get's a struct ica_xcRB. If the leftmost bit of the 32 bit unsigned int status field is set, the uppermost 16 bits of this field are used as debug flag value. The process is checked to have the CAP_SYS_ADMIN capability enabled or EPERM is returned. * The ioctl(ZSENDEP11CPRB) used to send EP11 CPRBs get's a struct ep11_urb. If the leftmost bit of the 64 bit unsigned int req_len field is set, the uppermost 16 bits of this field are used as debug flag value. The process is checked to have the CAP_SYS_ADMIN capability enabled or EPERM is returned. So it is possible to send an additional 16 bit value to the zcrypt API to be used to carry a failure injection command which may trigger special behavior within the zcrypt API and layers below. This 16 bit value is for the rest of the test referred as 'fi command' for Failure Injection. The lower 8 bits of the fi command construct a numerical argument in the range of 1-255 and is the 'fi action' to be performed with the request or the resulting reply: * 0x00 (all requests): No failure injection action but flags may be provided which may affect the processing of the request or reply. * 0x01 (only CCA CPRBs): The CPRB's agent_ID field is set to 'FF'. This results in an reply code 0x90 (Transport-Protocol Failure). * 0x02 (only CCA CPRBs): After the APQN to send to has been chosen, the domain field within the CPRB is overwritten with value 99 to enforce an reply with RY 0x8A. * 0x03 (all requests): At NQAP invocation the invalid qid value 0xFF00 is used causing an response code of 0x01 (AP queue not valid). The upper 8 bits of the fi command may carry bit flags which may influence the processing of an request or response: * 0x01: No retry. If this bit is set, the usual loop in the zcrypt API which retries an CPRB up to 10 times when the lower layers return with EAGAIN is abandoned after the first attempt to send the CPRB. * 0x02: Toggle special. Toggles the special bit on this request. This should result in an reply code RY~0x41 and result in an ioctl failure with errno EINVAL. This failure injection possibilities may get some further extensions in the future. As of now this is a starting point for Continuous Test and Integration to trigger some failures and watch for the reaction of the ap bus and zcrypt device driver code. Signed-off-by: Harald Freudenberger Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/ap_bus.h | 29 ++++++++++- drivers/s390/crypto/ap_queue.c | 10 +++- drivers/s390/crypto/zcrypt_api.c | 91 ++++++++++++++++++++++++++++++++++ drivers/s390/crypto/zcrypt_api.h | 3 ++ drivers/s390/crypto/zcrypt_msgtype50.c | 11 ++++ drivers/s390/crypto/zcrypt_msgtype6.c | 10 ++++ 6 files changed, 151 insertions(+), 3 deletions(-) (limited to 'drivers/s390/crypto/zcrypt_api.c') diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 03fd95b5a0e8..5029b80132aa 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -200,12 +200,37 @@ struct ap_queue { typedef enum ap_sm_wait (ap_func_t)(struct ap_queue *queue); +/* failure injection cmd struct */ +struct ap_fi { + union { + u16 cmd; /* fi flags + action */ + struct { + u8 flags; /* fi flags only */ + u8 action; /* fi action only */ + }; + }; +}; + +/* all currently known fi actions */ +enum ap_fi_actions { + AP_FI_ACTION_CCA_AGENT_FF = 0x01, + AP_FI_ACTION_CCA_DOM_INVAL = 0x02, + AP_FI_ACTION_NQAP_QID_INVAL = 0x03, +}; + +/* all currently known fi flags */ +enum ap_fi_flags { + AP_FI_FLAG_NO_RETRY = 0x01, + AP_FI_FLAG_TOGGLE_SPECIAL = 0x02, +}; + struct ap_message { struct list_head list; /* Request queueing. */ unsigned long long psmid; /* Message id. */ void *msg; /* Pointer to message buffer. */ unsigned int len; /* Message length. */ - u32 flags; /* Flags, see AP_MSG_FLAG_xxx */ + u16 flags; /* Flags, see AP_MSG_FLAG_xxx */ + struct ap_fi fi; /* Failure Injection cmd */ int rc; /* Return code for this message */ void *private; /* ap driver private pointer. */ /* receive is called from tasklet context */ @@ -213,7 +238,7 @@ struct ap_message { struct ap_message *); }; -#define AP_MSG_FLAG_SPECIAL (1 << 16) /* flag msg as 'special' with NQAP */ +#define AP_MSG_FLAG_SPECIAL 1 /* flag msg as 'special' with NQAP */ /** * ap_init_message() - Initialize ap_message. diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index ada37f1c7ac7..13d4fe2c6127 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -214,12 +214,20 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq) { struct ap_queue_status status; struct ap_message *ap_msg; + ap_qid_t qid = aq->qid; if (aq->requestq_count <= 0) return AP_SM_WAIT_NONE; /* Start the next request on the queue. */ ap_msg = list_entry(aq->requestq.next, struct ap_message, list); - status = __ap_send(aq->qid, ap_msg->psmid, +#ifdef CONFIG_ZCRYPT_DEBUG + if (ap_msg->fi.action == AP_FI_ACTION_NQAP_QID_INVAL) { + AP_DBF_WARN("%s fi cmd 0x%04x: forcing invalid qid 0xFF00\n", + __func__, ap_msg->fi.cmd); + qid = 0xFF00; + } +#endif + status = __ap_send(qid, ap_msg->psmid, ap_msg->msg, ap_msg->len, ap_msg->flags & AP_MSG_FLAG_SPECIAL); switch (status.response_code) { diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index d642be65a3a0..08bb0f60c4b0 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #define CREATE_TRACE_POINTS @@ -645,6 +646,11 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms, ap_init_message(&ap_msg); +#ifdef CONFIG_ZCRYPT_DEBUG + if (tr && tr->fi.cmd) + ap_msg.fi.cmd = tr->fi.cmd; +#endif + if (mex->outputdatalength < mex->inputdatalength) { func_code = 0; rc = -EINVAL; @@ -748,6 +754,11 @@ static long zcrypt_rsa_crt(struct ap_perms *perms, ap_init_message(&ap_msg); +#ifdef CONFIG_ZCRYPT_DEBUG + if (tr && tr->fi.cmd) + ap_msg.fi.cmd = tr->fi.cmd; +#endif + if (crt->outputdatalength < crt->inputdatalength) { func_code = 0; rc = -EINVAL; @@ -852,6 +863,17 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, xcRB->status = 0; ap_init_message(&ap_msg); + +#ifdef CONFIG_ZCRYPT_DEBUG + if (tr && tr->fi.cmd) + ap_msg.fi.cmd = tr->fi.cmd; + if (tr && tr->fi.action == AP_FI_ACTION_CCA_AGENT_FF) { + ZCRYPT_DBF_WARN("%s fi cmd 0x%04x: forcing invalid agent_ID 'FF'\n", + __func__, tr->fi.cmd); + xcRB->agent_ID = 0x4646; + } +#endif + rc = get_cprb_fc(userspace, xcRB, &ap_msg, &func_code, &domain); if (rc) goto out; @@ -927,6 +949,14 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms, if (*domain == AUTOSEL_DOM) *domain = AP_QID_QUEUE(qid); +#ifdef CONFIG_ZCRYPT_DEBUG + if (tr && tr->fi.action == AP_FI_ACTION_CCA_DOM_INVAL) { + ZCRYPT_DBF_WARN("%s fi cmd 0x%04x: forcing invalid domain\n", + __func__, tr->fi.cmd); + *domain = 99; + } +#endif + rc = pref_zq->ops->send_cprb(userspace, pref_zq, xcRB, &ap_msg); spin_lock(&zcrypt_list_lock); @@ -995,6 +1025,11 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms, ap_init_message(&ap_msg); +#ifdef CONFIG_ZCRYPT_DEBUG + if (tr && tr->fi.cmd) + ap_msg.fi.cmd = tr->fi.cmd; +#endif + target_num = (unsigned short) xcrb->targets_num; /* empty list indicates autoselect (all available targets) */ @@ -1377,10 +1412,24 @@ static int icarsamodexpo_ioctl(struct ap_perms *perms, unsigned long arg) memset(&tr, 0, sizeof(tr)); if (copy_from_user(&mex, umex, sizeof(mex))) return -EFAULT; + +#ifdef CONFIG_ZCRYPT_DEBUG + if (mex.inputdatalength & (1U << 31)) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + tr.fi.cmd = (u16)(mex.inputdatalength >> 16); + } + mex.inputdatalength &= 0x0000FFFF; +#endif + do { rc = zcrypt_rsa_modexpo(perms, &tr, &mex); if (rc == -EAGAIN) tr.again_counter++; +#ifdef CONFIG_ZCRYPT_DEBUG + if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY)) + break; +#endif } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) @@ -1406,10 +1455,24 @@ static int icarsacrt_ioctl(struct ap_perms *perms, unsigned long arg) memset(&tr, 0, sizeof(tr)); if (copy_from_user(&crt, ucrt, sizeof(crt))) return -EFAULT; + +#ifdef CONFIG_ZCRYPT_DEBUG + if (crt.inputdatalength & (1U << 31)) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + tr.fi.cmd = (u16)(crt.inputdatalength >> 16); + } + crt.inputdatalength &= 0x0000FFFF; +#endif + do { rc = zcrypt_rsa_crt(perms, &tr, &crt); if (rc == -EAGAIN) tr.again_counter++; +#ifdef CONFIG_ZCRYPT_DEBUG + if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY)) + break; +#endif } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) @@ -1435,10 +1498,24 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg) memset(&tr, 0, sizeof(tr)); if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB))) return -EFAULT; + +#ifdef CONFIG_ZCRYPT_DEBUG + if (xcRB.status & (1U << 31)) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + tr.fi.cmd = (u16)(xcRB.status >> 16); + } + xcRB.status &= 0x0000FFFF; +#endif + do { rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB); if (rc == -EAGAIN) tr.again_counter++; +#ifdef CONFIG_ZCRYPT_DEBUG + if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY)) + break; +#endif } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) @@ -1465,10 +1542,24 @@ static int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg) memset(&tr, 0, sizeof(tr)); if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb))) return -EFAULT; + +#ifdef CONFIG_ZCRYPT_DEBUG + if (xcrb.req_len & (1ULL << 63)) { + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + tr.fi.cmd = (u16)(xcrb.req_len >> 48); + } + xcrb.req_len &= 0x0000FFFFFFFFFFFFULL; +#endif + do { rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb); if (rc == -EAGAIN) tr.again_counter++; +#ifdef CONFIG_ZCRYPT_DEBUG + if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY)) + break; +#endif } while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX); /* on failure: retry once again after a requested rescan */ if ((rc == -ENODEV) && (zcrypt_process_rescan())) diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 03804f03b5d0..51c0b8bdef50 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -60,6 +60,9 @@ struct zcrypt_track { int again_counter; /* retry attempts counter */ int last_qid; /* last qid used */ int last_rc; /* last return code */ +#ifdef CONFIG_ZCRYPT_DEBUG + struct ap_fi fi; /* failure injection cmd */ +#endif }; /* defines related to message tracking */ diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index c543b5959509..bf14ee445f89 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -246,6 +246,12 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq, copy_from_user(exp, mex->b_key, mod_len) || copy_from_user(inp, mex->inputdata, mod_len)) return -EFAULT; + +#ifdef CONFIG_ZCRYPT_DEBUG + if (ap_msg->fi.flags & AP_FI_FLAG_TOGGLE_SPECIAL) + ap_msg->flags ^= AP_MSG_FLAG_SPECIAL; +#endif + return 0; } @@ -332,6 +338,11 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq, copy_from_user(inp, crt->inputdata, mod_len)) return -EFAULT; +#ifdef CONFIG_ZCRYPT_DEBUG + if (ap_msg->fi.flags & AP_FI_FLAG_TOGGLE_SPECIAL) + ap_msg->flags ^= AP_MSG_FLAG_SPECIAL; +#endif + return 0; } diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index aab7f0692035..307f90657d1d 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -482,6 +482,11 @@ static int XCRB_msg_to_type6CPRB_msgX(bool userspace, struct ap_message *ap_msg, || memcmp(function_code, "AU", 2) == 0) ap_msg->flags |= AP_MSG_FLAG_SPECIAL; +#ifdef CONFIG_ZCRYPT_DEBUG + if (ap_msg->fi.flags & AP_FI_FLAG_TOGGLE_SPECIAL) + ap_msg->flags ^= AP_MSG_FLAG_SPECIAL; +#endif + /* copy data block */ if (xcRB->request_data_length && z_copy_from_user(userspace, req_data, xcRB->request_data_address, @@ -569,6 +574,11 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap if (msg->cprbx.flags & 0x20) ap_msg->flags |= AP_MSG_FLAG_SPECIAL; +#ifdef CONFIG_ZCRYPT_DEBUG + if (ap_msg->fi.flags & AP_FI_FLAG_TOGGLE_SPECIAL) + ap_msg->flags ^= AP_MSG_FLAG_SPECIAL; +#endif + return 0; } -- cgit v1.2.3-59-g8ed1b