static long zcrypt_rng(char *buffer) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; unsigned int weight, pref_weight; unsigned int func_code; struct ap_message ap_msg; unsigned int domain; int qid = 0, rc = -ENODEV; trace_s390_zcrypt_req(buffer, TP_HWRNGCPRB); rc = get_rng_fc(&ap_msg, &func_code, &domain); if (rc) goto out; pref_zc = NULL; 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)) continue; /* get weight index of the card device */ weight = zc->speed_rating[func_code]; if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) 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)) continue; pref_zc = zc; pref_zq = zq; pref_weight = weight; } } pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); if (!pref_zq) return -ENODEV; qid = pref_zq->queue->qid; rc = pref_zq->ops->rng(pref_zq, buffer, &ap_msg); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); out: trace_s390_zcrypt_rep(buffer, func_code, rc, AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; }
static void zcrypt_device_status_mask(struct zcrypt_device_matrix *matrix) { struct zcrypt_card *zc; struct zcrypt_queue *zq; struct zcrypt_device_status *stat; memset(matrix, 0, sizeof(*matrix)); spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { for_each_zcrypt_queue(zq, zc) { stat = matrix->device; stat += AP_QID_CARD(zq->queue->qid) * MAX_ZDEV_DOMAINS; stat += AP_QID_QUEUE(zq->queue->qid); stat->hwtype = zc->card->ap_dev.device_type; stat->functions = zc->card->functions >> 26; stat->qid = zq->queue->qid; stat->online = zq->online ? 0x01 : 0x00; } }
static void zcrypt_device_status_mask(struct zcrypt_device_status *devstatus) { struct zcrypt_card *zc; struct zcrypt_queue *zq; struct zcrypt_device_status *stat; int card, queue; memset(devstatus, 0, MAX_ZDEV_ENTRIES * sizeof(struct zcrypt_device_status)); spin_lock(&zcrypt_list_lock); for_each_zcrypt_card(zc) { for_each_zcrypt_queue(zq, zc) { card = AP_QID_CARD(zq->queue->qid); if (card >= MAX_ZDEV_CARDIDS) continue; queue = AP_QID_QUEUE(zq->queue->qid); stat = &devstatus[card * AP_DOMAINS + queue]; stat->hwtype = zc->card->ap_dev.device_type; stat->functions = zc->card->functions >> 26; stat->qid = zq->queue->qid; stat->online = zq->online ? 0x01 : 0x00; } }
static long zcrypt_send_ep11_cprb(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, pref_weight; unsigned int func_code; struct ap_message ap_msg; int qid = 0, rc = -ENODEV; trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB); target_num = (unsigned short) xcrb->targets_num; /* empty list indicates autoselect (all available targets) */ targets = NULL; if (target_num != 0) { struct ep11_target_dev __user *uptr; targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL); if (!targets) { rc = -ENOMEM; goto out; } uptr = (struct ep11_target_dev __force __user *) xcrb->targets; if (copy_from_user(targets, uptr, target_num * sizeof(*targets))) { rc = -EFAULT; goto out; } } rc = get_ep11cprb_fc(xcrb, &ap_msg, &func_code); if (rc) goto out_free; pref_zc = NULL; 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)) continue; /* Check for user selected EP11 card */ if (targets && !is_desired_ep11_card(zc->card->id, target_num, targets)) 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)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online || !zq->ops->send_ep11_cprb || (targets && !is_desired_ep11_queue(zq->queue->qid, target_num, targets))) continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; pref_weight = weight; } } pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); if (!pref_zq) { rc = -ENODEV; goto out_free; } qid = pref_zq->queue->qid; rc = pref_zq->ops->send_ep11_cprb(pref_zq, xcrb, &ap_msg); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); out_free: kfree(targets); out: trace_s390_zcrypt_rep(xcrb, func_code, rc, AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; }
static long zcrypt_send_cprb(struct ica_xcRB *xcRB) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; struct ap_message ap_msg; unsigned int weight, pref_weight; unsigned int func_code; unsigned short *domain; int qid = 0, rc = -ENODEV; trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB); rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain); if (rc) goto out; pref_zc = NULL; 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)) continue; /* Check for user selected CCA card */ if (xcRB->user_defined != AUTOSELECT && xcRB->user_defined != 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)) continue; for_each_zcrypt_queue(zq, zc) { /* 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)))) continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; pref_weight = weight; } } pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); if (!pref_zq) { rc = -ENODEV; goto out; } /* in case of auto select, provide the correct domain */ qid = pref_zq->queue->qid; if (*domain == (unsigned short) AUTOSELECT) *domain = AP_QID_QUEUE(qid); rc = pref_zq->ops->send_cprb(pref_zq, xcRB, &ap_msg); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); out: trace_s390_zcrypt_rep(xcRB, func_code, rc, AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; }
static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) { struct zcrypt_card *zc, *pref_zc; struct zcrypt_queue *zq, *pref_zq; unsigned int weight, pref_weight; unsigned int func_code; int qid = 0, rc = -ENODEV; trace_s390_zcrypt_req(crt, TP_ICARSACRT); if (crt->outputdatalength < crt->inputdatalength) { rc = -EINVAL; goto out; } /* * As long as outputdatalength is big enough, we can set the * outputdatalength equal to the inputdatalength, since that is the * number of bytes we will copy in any case */ crt->outputdatalength = crt->inputdatalength; rc = get_rsa_crt_fc(crt, &func_code); if (rc) goto out; pref_zc = NULL; 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)) continue; /* Check for size limits */ if (zc->min_mod_size > crt->inputdatalength || zc->max_mod_size < crt->inputdatalength) continue; /* get weight index of the card device */ weight = zc->speed_rating[func_code]; if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online || !zq->ops->rsa_modexpo_crt) continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; pref_weight = weight; } } pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); if (!pref_zq) { rc = -ENODEV; goto out; } qid = pref_zq->queue->qid; rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); out: trace_s390_zcrypt_rep(crt, func_code, rc, AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; }