diff options
author | Ingo Tuchscherer <ingo.tuchscherer@de.ibm.com> | 2013-11-20 04:47:13 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-12-18 11:37:15 -0500 |
commit | 91f3e3eaba4413e76ce8e12e3ef10525a889142f (patch) | |
tree | e4cef25c9b51388a462776c6a8e642571fa2f19b /drivers/s390/crypto/zcrypt_api.c | |
parent | 9efe4f2992025c3a4027c60bf36ae9d710ca3781 (diff) |
s390/zcrypt: add support for EP11 coprocessor cards
This feature extends the generic cryptographic device driver (zcrypt)
with a new capability to service EP11 requests for the Crypto Express4S
card in EP11 (Enterprise PKCS#11 mode) coprocessor mode.
Signed-off-by: Ingo Tuchscherer <ingo.tuchscherer@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/crypto/zcrypt_api.c')
-rw-r--r-- | drivers/s390/crypto/zcrypt_api.c | 109 |
1 files changed, 106 insertions, 3 deletions
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 31cfaa556072..4b824b15194f 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c | |||
@@ -44,6 +44,8 @@ | |||
44 | #include "zcrypt_debug.h" | 44 | #include "zcrypt_debug.h" |
45 | #include "zcrypt_api.h" | 45 | #include "zcrypt_api.h" |
46 | 46 | ||
47 | #include "zcrypt_msgtype6.h" | ||
48 | |||
47 | /* | 49 | /* |
48 | * Module description. | 50 | * Module description. |
49 | */ | 51 | */ |
@@ -554,9 +556,9 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) | |||
554 | spin_lock_bh(&zcrypt_device_lock); | 556 | spin_lock_bh(&zcrypt_device_lock); |
555 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | 557 | list_for_each_entry(zdev, &zcrypt_device_list, list) { |
556 | if (!zdev->online || !zdev->ops->send_cprb || | 558 | if (!zdev->online || !zdev->ops->send_cprb || |
557 | (xcRB->user_defined != AUTOSELECT && | 559 | (zdev->ops->variant == MSGTYPE06_VARIANT_EP11) || |
558 | AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined) | 560 | (xcRB->user_defined != AUTOSELECT && |
559 | ) | 561 | AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)) |
560 | continue; | 562 | continue; |
561 | zcrypt_device_get(zdev); | 563 | zcrypt_device_get(zdev); |
562 | get_device(&zdev->ap_dev->device); | 564 | get_device(&zdev->ap_dev->device); |
@@ -581,6 +583,90 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) | |||
581 | return -ENODEV; | 583 | return -ENODEV; |
582 | } | 584 | } |
583 | 585 | ||
586 | struct ep11_target_dev_list { | ||
587 | unsigned short targets_num; | ||
588 | struct ep11_target_dev *targets; | ||
589 | }; | ||
590 | |||
591 | static bool is_desired_ep11dev(unsigned int dev_qid, | ||
592 | struct ep11_target_dev_list dev_list) | ||
593 | { | ||
594 | int n; | ||
595 | |||
596 | for (n = 0; n < dev_list.targets_num; n++, dev_list.targets++) { | ||
597 | if ((AP_QID_DEVICE(dev_qid) == dev_list.targets->ap_id) && | ||
598 | (AP_QID_QUEUE(dev_qid) == dev_list.targets->dom_id)) { | ||
599 | return true; | ||
600 | } | ||
601 | } | ||
602 | return false; | ||
603 | } | ||
604 | |||
605 | static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) | ||
606 | { | ||
607 | struct zcrypt_device *zdev; | ||
608 | bool autoselect = false; | ||
609 | int rc; | ||
610 | struct ep11_target_dev_list ep11_dev_list = { | ||
611 | .targets_num = 0x00, | ||
612 | .targets = NULL, | ||
613 | }; | ||
614 | |||
615 | ep11_dev_list.targets_num = (unsigned short) xcrb->targets_num; | ||
616 | |||
617 | /* empty list indicates autoselect (all available targets) */ | ||
618 | if (ep11_dev_list.targets_num == 0) | ||
619 | autoselect = true; | ||
620 | else { | ||
621 | ep11_dev_list.targets = kcalloc((unsigned short) | ||
622 | xcrb->targets_num, | ||
623 | sizeof(struct ep11_target_dev), | ||
624 | GFP_KERNEL); | ||
625 | if (!ep11_dev_list.targets) | ||
626 | return -ENOMEM; | ||
627 | |||
628 | if (copy_from_user(ep11_dev_list.targets, | ||
629 | (struct ep11_target_dev *)xcrb->targets, | ||
630 | xcrb->targets_num * | ||
631 | sizeof(struct ep11_target_dev))) | ||
632 | return -EFAULT; | ||
633 | } | ||
634 | |||
635 | spin_lock_bh(&zcrypt_device_lock); | ||
636 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
637 | /* check if device is eligible */ | ||
638 | if (!zdev->online || | ||
639 | zdev->ops->variant != MSGTYPE06_VARIANT_EP11) | ||
640 | continue; | ||
641 | |||
642 | /* check if device is selected as valid target */ | ||
643 | if (!is_desired_ep11dev(zdev->ap_dev->qid, ep11_dev_list) && | ||
644 | !autoselect) | ||
645 | continue; | ||
646 | |||
647 | zcrypt_device_get(zdev); | ||
648 | get_device(&zdev->ap_dev->device); | ||
649 | zdev->request_count++; | ||
650 | __zcrypt_decrease_preference(zdev); | ||
651 | if (try_module_get(zdev->ap_dev->drv->driver.owner)) { | ||
652 | spin_unlock_bh(&zcrypt_device_lock); | ||
653 | rc = zdev->ops->send_ep11_cprb(zdev, xcrb); | ||
654 | spin_lock_bh(&zcrypt_device_lock); | ||
655 | module_put(zdev->ap_dev->drv->driver.owner); | ||
656 | } else { | ||
657 | rc = -EAGAIN; | ||
658 | } | ||
659 | zdev->request_count--; | ||
660 | __zcrypt_increase_preference(zdev); | ||
661 | put_device(&zdev->ap_dev->device); | ||
662 | zcrypt_device_put(zdev); | ||
663 | spin_unlock_bh(&zcrypt_device_lock); | ||
664 | return rc; | ||
665 | } | ||
666 | spin_unlock_bh(&zcrypt_device_lock); | ||
667 | return -ENODEV; | ||
668 | } | ||
669 | |||
584 | static long zcrypt_rng(char *buffer) | 670 | static long zcrypt_rng(char *buffer) |
585 | { | 671 | { |
586 | struct zcrypt_device *zdev; | 672 | struct zcrypt_device *zdev; |
@@ -784,6 +870,23 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, | |||
784 | return -EFAULT; | 870 | return -EFAULT; |
785 | return rc; | 871 | return rc; |
786 | } | 872 | } |
873 | case ZSENDEP11CPRB: { | ||
874 | struct ep11_urb __user *uxcrb = (void __user *)arg; | ||
875 | struct ep11_urb xcrb; | ||
876 | if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb))) | ||
877 | return -EFAULT; | ||
878 | do { | ||
879 | rc = zcrypt_send_ep11_cprb(&xcrb); | ||
880 | } while (rc == -EAGAIN); | ||
881 | /* on failure: retry once again after a requested rescan */ | ||
882 | if ((rc == -ENODEV) && (zcrypt_process_rescan())) | ||
883 | do { | ||
884 | rc = zcrypt_send_ep11_cprb(&xcrb); | ||
885 | } while (rc == -EAGAIN); | ||
886 | if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb))) | ||
887 | return -EFAULT; | ||
888 | return rc; | ||
889 | } | ||
787 | case Z90STAT_STATUS_MASK: { | 890 | case Z90STAT_STATUS_MASK: { |
788 | char status[AP_DEVICES]; | 891 | char status[AP_DEVICES]; |
789 | zcrypt_status_mask(status); | 892 | zcrypt_status_mask(status); |