diff options
author | Ralph Wuerthner <rwuerthn@de.ibm.com> | 2006-09-20 09:58:36 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2006-09-20 09:58:36 -0400 |
commit | 5432114baf0300286a6ca1b0aea549492a379432 (patch) | |
tree | 6a9cf64c86e4ee4d439f91e9bd4485688d28ddd7 /drivers | |
parent | fe3a1be59c851aba2330387596c6134bc5ec8397 (diff) |
[S390] zcrypt secure key cryptography extension.
Allow the user space to send extended cprb messages directly to the
PCIXCC / CEX2C cards. This allows the CCA library to construct special
crypto requests that use "secure" keys that are stored on the card.
Signed-off-by: Ralph Wuerthner <rwuerthn@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/s390/crypto/zcrypt_api.c | 112 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_api.h | 3 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_cca_key.h | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_cex2a.c | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_cex2a.h | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_error.h | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_mono.c | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_pcica.c | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_pcica.h | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_pcicc.c | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_pcicc.h | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_pcixcc.c | 263 | ||||
-rw-r--r-- | drivers/s390/crypto/zcrypt_pcixcc.h | 2 |
13 files changed, 373 insertions, 25 deletions
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index b3fe003b3d2d..1edc10a7a6f2 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_api.c | 2 | * linux/drivers/s390/crypto/zcrypt_api.c |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
@@ -392,6 +392,41 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) | |||
392 | return -ENODEV; | 392 | return -ENODEV; |
393 | } | 393 | } |
394 | 394 | ||
395 | static long zcrypt_send_cprb(struct ica_xcRB *xcRB) | ||
396 | { | ||
397 | struct zcrypt_device *zdev; | ||
398 | int rc; | ||
399 | |||
400 | spin_lock_bh(&zcrypt_device_lock); | ||
401 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
402 | if (!zdev->online || !zdev->ops->send_cprb || | ||
403 | (xcRB->user_defined != AUTOSELECT && | ||
404 | AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined) | ||
405 | ) | ||
406 | continue; | ||
407 | zcrypt_device_get(zdev); | ||
408 | get_device(&zdev->ap_dev->device); | ||
409 | zdev->request_count++; | ||
410 | __zcrypt_decrease_preference(zdev); | ||
411 | spin_unlock_bh(&zcrypt_device_lock); | ||
412 | if (try_module_get(zdev->ap_dev->drv->driver.owner)) { | ||
413 | rc = zdev->ops->send_cprb(zdev, xcRB); | ||
414 | module_put(zdev->ap_dev->drv->driver.owner); | ||
415 | } | ||
416 | else | ||
417 | rc = -EAGAIN; | ||
418 | spin_lock_bh(&zcrypt_device_lock); | ||
419 | zdev->request_count--; | ||
420 | __zcrypt_increase_preference(zdev); | ||
421 | put_device(&zdev->ap_dev->device); | ||
422 | zcrypt_device_put(zdev); | ||
423 | spin_unlock_bh(&zcrypt_device_lock); | ||
424 | return rc; | ||
425 | } | ||
426 | spin_unlock_bh(&zcrypt_device_lock); | ||
427 | return -ENODEV; | ||
428 | } | ||
429 | |||
395 | static void zcrypt_status_mask(char status[AP_DEVICES]) | 430 | static void zcrypt_status_mask(char status[AP_DEVICES]) |
396 | { | 431 | { |
397 | struct zcrypt_device *zdev; | 432 | struct zcrypt_device *zdev; |
@@ -535,6 +570,18 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, | |||
535 | return rc; | 570 | return rc; |
536 | return put_user(crt.outputdatalength, &ucrt->outputdatalength); | 571 | return put_user(crt.outputdatalength, &ucrt->outputdatalength); |
537 | } | 572 | } |
573 | case ZSECSENDCPRB: { | ||
574 | struct ica_xcRB __user *uxcRB = (void __user *) arg; | ||
575 | struct ica_xcRB xcRB; | ||
576 | if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB))) | ||
577 | return -EFAULT; | ||
578 | do { | ||
579 | rc = zcrypt_send_cprb(&xcRB); | ||
580 | } while (rc == -EAGAIN); | ||
581 | if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB))) | ||
582 | return -EFAULT; | ||
583 | return rc; | ||
584 | } | ||
538 | case Z90STAT_STATUS_MASK: { | 585 | case Z90STAT_STATUS_MASK: { |
539 | char status[AP_DEVICES]; | 586 | char status[AP_DEVICES]; |
540 | zcrypt_status_mask(status); | 587 | zcrypt_status_mask(status); |
@@ -683,6 +730,67 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd, | |||
683 | return rc; | 730 | return rc; |
684 | } | 731 | } |
685 | 732 | ||
733 | struct compat_ica_xcRB { | ||
734 | unsigned short agent_ID; | ||
735 | unsigned int user_defined; | ||
736 | unsigned short request_ID; | ||
737 | unsigned int request_control_blk_length; | ||
738 | unsigned char padding1[16 - sizeof (compat_uptr_t)]; | ||
739 | compat_uptr_t request_control_blk_addr; | ||
740 | unsigned int request_data_length; | ||
741 | char padding2[16 - sizeof (compat_uptr_t)]; | ||
742 | compat_uptr_t request_data_address; | ||
743 | unsigned int reply_control_blk_length; | ||
744 | char padding3[16 - sizeof (compat_uptr_t)]; | ||
745 | compat_uptr_t reply_control_blk_addr; | ||
746 | unsigned int reply_data_length; | ||
747 | char padding4[16 - sizeof (compat_uptr_t)]; | ||
748 | compat_uptr_t reply_data_addr; | ||
749 | unsigned short priority_window; | ||
750 | unsigned int status; | ||
751 | } __attribute__((packed)); | ||
752 | |||
753 | static long trans_xcRB32(struct file *filp, unsigned int cmd, | ||
754 | unsigned long arg) | ||
755 | { | ||
756 | struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg); | ||
757 | struct compat_ica_xcRB xcRB32; | ||
758 | struct ica_xcRB xcRB64; | ||
759 | long rc; | ||
760 | |||
761 | if (copy_from_user(&xcRB32, uxcRB32, sizeof(xcRB32))) | ||
762 | return -EFAULT; | ||
763 | xcRB64.agent_ID = xcRB32.agent_ID; | ||
764 | xcRB64.user_defined = xcRB32.user_defined; | ||
765 | xcRB64.request_ID = xcRB32.request_ID; | ||
766 | xcRB64.request_control_blk_length = | ||
767 | xcRB32.request_control_blk_length; | ||
768 | xcRB64.request_control_blk_addr = | ||
769 | compat_ptr(xcRB32.request_control_blk_addr); | ||
770 | xcRB64.request_data_length = | ||
771 | xcRB32.request_data_length; | ||
772 | xcRB64.request_data_address = | ||
773 | compat_ptr(xcRB32.request_data_address); | ||
774 | xcRB64.reply_control_blk_length = | ||
775 | xcRB32.reply_control_blk_length; | ||
776 | xcRB64.reply_control_blk_addr = | ||
777 | compat_ptr(xcRB32.reply_control_blk_addr); | ||
778 | xcRB64.reply_data_length = xcRB32.reply_data_length; | ||
779 | xcRB64.reply_data_addr = | ||
780 | compat_ptr(xcRB32.reply_data_addr); | ||
781 | xcRB64.priority_window = xcRB32.priority_window; | ||
782 | xcRB64.status = xcRB32.status; | ||
783 | do { | ||
784 | rc = zcrypt_send_cprb(&xcRB64); | ||
785 | } while (rc == -EAGAIN); | ||
786 | xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length; | ||
787 | xcRB32.reply_data_length = xcRB64.reply_data_length; | ||
788 | xcRB32.status = xcRB64.status; | ||
789 | if (copy_to_user(uxcRB32, &xcRB32, sizeof(xcRB32))) | ||
790 | return -EFAULT; | ||
791 | return rc; | ||
792 | } | ||
793 | |||
686 | long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, | 794 | long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, |
687 | unsigned long arg) | 795 | unsigned long arg) |
688 | { | 796 | { |
@@ -690,6 +798,8 @@ long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, | |||
690 | return trans_modexpo32(filp, cmd, arg); | 798 | return trans_modexpo32(filp, cmd, arg); |
691 | if (cmd == ICARSACRT) | 799 | if (cmd == ICARSACRT) |
692 | return trans_modexpo_crt32(filp, cmd, arg); | 800 | return trans_modexpo_crt32(filp, cmd, arg); |
801 | if (cmd == ZSECSENDCPRB) | ||
802 | return trans_xcRB32(filp, cmd, arg); | ||
693 | return zcrypt_unlocked_ioctl(filp, cmd, arg); | 803 | return zcrypt_unlocked_ioctl(filp, cmd, arg); |
694 | } | 804 | } |
695 | #endif | 805 | #endif |
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 1f0e61f2e9b4..de4877ee618f 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_api.h | 2 | * linux/drivers/s390/crypto/zcrypt_api.h |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
@@ -106,6 +106,7 @@ struct zcrypt_ops { | |||
106 | long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *); | 106 | long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *); |
107 | long (*rsa_modexpo_crt)(struct zcrypt_device *, | 107 | long (*rsa_modexpo_crt)(struct zcrypt_device *, |
108 | struct ica_rsa_modexpo_crt *); | 108 | struct ica_rsa_modexpo_crt *); |
109 | long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *); | ||
109 | }; | 110 | }; |
110 | 111 | ||
111 | struct zcrypt_device { | 112 | struct zcrypt_device { |
diff --git a/drivers/s390/crypto/zcrypt_cca_key.h b/drivers/s390/crypto/zcrypt_cca_key.h index c80f40d44197..8dbcf0eef3e5 100644 --- a/drivers/s390/crypto/zcrypt_cca_key.h +++ b/drivers/s390/crypto/zcrypt_cca_key.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_cca_key.h | 2 | * linux/drivers/s390/crypto/zcrypt_cca_key.h |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 350248e5cd93..a62b00083d0c 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_cex2a.c | 2 | * linux/drivers/s390/crypto/zcrypt_cex2a.c |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
diff --git a/drivers/s390/crypto/zcrypt_cex2a.h b/drivers/s390/crypto/zcrypt_cex2a.h index 61a78c32dce4..8f69d1dacab8 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.h +++ b/drivers/s390/crypto/zcrypt_cex2a.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_cex2a.h | 2 | * linux/drivers/s390/crypto/zcrypt_cex2a.h |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index b22bd055a03b..2cb616ba8bec 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_error.h | 2 | * linux/drivers/s390/crypto/zcrypt_error.h |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c index f48b61a6126c..2a9349ad68b7 100644 --- a/drivers/s390/crypto/zcrypt_mono.c +++ b/drivers/s390/crypto/zcrypt_mono.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_mono.c | 2 | * linux/drivers/s390/crypto/zcrypt_mono.c |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c index 0ff56e86caae..b6a4ecdc8025 100644 --- a/drivers/s390/crypto/zcrypt_pcica.c +++ b/drivers/s390/crypto/zcrypt_pcica.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_pcica.c | 2 | * linux/drivers/s390/crypto/zcrypt_pcica.c |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
diff --git a/drivers/s390/crypto/zcrypt_pcica.h b/drivers/s390/crypto/zcrypt_pcica.h index a08a4f8c33c9..3be11187f6df 100644 --- a/drivers/s390/crypto/zcrypt_pcica.h +++ b/drivers/s390/crypto/zcrypt_pcica.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_pcica.h | 2 | * linux/drivers/s390/crypto/zcrypt_pcica.h |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c index 900362983fec..f295a403b29a 100644 --- a/drivers/s390/crypto/zcrypt_pcicc.c +++ b/drivers/s390/crypto/zcrypt_pcicc.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_pcicc.c | 2 | * linux/drivers/s390/crypto/zcrypt_pcicc.c |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
diff --git a/drivers/s390/crypto/zcrypt_pcicc.h b/drivers/s390/crypto/zcrypt_pcicc.h index 027bafc7312a..6d4454846c8f 100644 --- a/drivers/s390/crypto/zcrypt_pcicc.h +++ b/drivers/s390/crypto/zcrypt_pcicc.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_pcicc.h | 2 | * linux/drivers/s390/crypto/zcrypt_pcicc.h |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 6064cf58be43..2da8b9381407 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_pcixcc.c | 2 | * linux/drivers/s390/crypto/zcrypt_pcixcc.c |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |
@@ -60,6 +60,15 @@ | |||
60 | 60 | ||
61 | #define PCIXCC_CLEANUP_TIME (15*HZ) | 61 | #define PCIXCC_CLEANUP_TIME (15*HZ) |
62 | 62 | ||
63 | #define CEIL4(x) ((((x)+3)/4)*4) | ||
64 | |||
65 | struct response_type { | ||
66 | struct completion work; | ||
67 | int type; | ||
68 | }; | ||
69 | #define PCIXCC_RESPONSE_TYPE_ICA 0 | ||
70 | #define PCIXCC_RESPONSE_TYPE_XCRB 1 | ||
71 | |||
63 | static struct ap_device_id zcrypt_pcixcc_ids[] = { | 72 | static struct ap_device_id zcrypt_pcixcc_ids[] = { |
64 | { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) }, | 73 | { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) }, |
65 | { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) }, | 74 | { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) }, |
@@ -244,6 +253,108 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, | |||
244 | } | 253 | } |
245 | 254 | ||
246 | /** | 255 | /** |
256 | * Convert a XCRB message to a type6 CPRB message. | ||
257 | * | ||
258 | * @zdev: crypto device pointer | ||
259 | * @ap_msg: pointer to AP message | ||
260 | * @xcRB: pointer to user input data | ||
261 | * | ||
262 | * Returns 0 on success or -EFAULT. | ||
263 | */ | ||
264 | struct type86_fmt2_msg { | ||
265 | struct type86_hdr hdr; | ||
266 | struct type86_fmt2_ext fmt2; | ||
267 | } __attribute__((packed)); | ||
268 | |||
269 | static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, | ||
270 | struct ap_message *ap_msg, | ||
271 | struct ica_xcRB *xcRB) | ||
272 | { | ||
273 | static struct type6_hdr static_type6_hdrX = { | ||
274 | .type = 0x06, | ||
275 | .offset1 = 0x00000058, | ||
276 | }; | ||
277 | struct { | ||
278 | struct type6_hdr hdr; | ||
279 | struct ica_CPRBX cprbx; | ||
280 | } __attribute__((packed)) *msg = ap_msg->message; | ||
281 | |||
282 | int rcblen = CEIL4(xcRB->request_control_blk_length); | ||
283 | int replylen; | ||
284 | char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen; | ||
285 | char *function_code; | ||
286 | |||
287 | /* length checks */ | ||
288 | ap_msg->length = sizeof(struct type6_hdr) + | ||
289 | CEIL4(xcRB->request_control_blk_length) + | ||
290 | xcRB->request_data_length; | ||
291 | if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) { | ||
292 | PRINTK("Combined message is too large (%ld/%d/%d).\n", | ||
293 | sizeof(struct type6_hdr), | ||
294 | xcRB->request_control_blk_length, | ||
295 | xcRB->request_data_length); | ||
296 | return -EFAULT; | ||
297 | } | ||
298 | if (CEIL4(xcRB->reply_control_blk_length) > | ||
299 | PCIXCC_MAX_XCRB_REPLY_SIZE) { | ||
300 | PDEBUG("Reply CPRB length is too large (%d).\n", | ||
301 | xcRB->request_control_blk_length); | ||
302 | return -EFAULT; | ||
303 | } | ||
304 | if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE) { | ||
305 | PDEBUG("Reply data block length is too large (%d).\n", | ||
306 | xcRB->reply_data_length); | ||
307 | return -EFAULT; | ||
308 | } | ||
309 | replylen = CEIL4(xcRB->reply_control_blk_length) + | ||
310 | CEIL4(xcRB->reply_data_length) + | ||
311 | sizeof(struct type86_fmt2_msg); | ||
312 | if (replylen > PCIXCC_MAX_XCRB_RESPONSE_SIZE) { | ||
313 | PDEBUG("Reply CPRB + data block > PCIXCC_MAX_XCRB_RESPONSE_SIZE" | ||
314 | " (%d/%d/%d).\n", | ||
315 | sizeof(struct type86_fmt2_msg), | ||
316 | xcRB->reply_control_blk_length, | ||
317 | xcRB->reply_data_length); | ||
318 | xcRB->reply_control_blk_length = PCIXCC_MAX_XCRB_RESPONSE_SIZE - | ||
319 | (sizeof(struct type86_fmt2_msg) + | ||
320 | CEIL4(xcRB->reply_data_length)); | ||
321 | PDEBUG("Capping Reply CPRB length at %d\n", | ||
322 | xcRB->reply_control_blk_length); | ||
323 | } | ||
324 | |||
325 | /* prepare type6 header */ | ||
326 | msg->hdr = static_type6_hdrX; | ||
327 | memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID)); | ||
328 | msg->hdr.ToCardLen1 = xcRB->request_control_blk_length; | ||
329 | if (xcRB->request_data_length) { | ||
330 | msg->hdr.offset2 = msg->hdr.offset1 + rcblen; | ||
331 | msg->hdr.ToCardLen2 = xcRB->request_data_length; | ||
332 | } | ||
333 | msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length; | ||
334 | msg->hdr.FromCardLen2 = xcRB->reply_data_length; | ||
335 | |||
336 | /* prepare CPRB */ | ||
337 | if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr, | ||
338 | xcRB->request_control_blk_length)) | ||
339 | return -EFAULT; | ||
340 | if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) > | ||
341 | xcRB->request_control_blk_length) { | ||
342 | PDEBUG("cprb_len too large (%d/%d)\n", msg->cprbx.cprb_len, | ||
343 | xcRB->request_control_blk_length); | ||
344 | return -EFAULT; | ||
345 | } | ||
346 | function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len; | ||
347 | memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code)); | ||
348 | |||
349 | /* copy data block */ | ||
350 | if (xcRB->request_data_length && | ||
351 | copy_from_user(req_data, xcRB->request_data_address, | ||
352 | xcRB->request_data_length)) | ||
353 | return -EFAULT; | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /** | ||
247 | * Copy results from a type 86 ICA reply message back to user space. | 358 | * Copy results from a type 86 ICA reply message back to user space. |
248 | * | 359 | * |
249 | * @zdev: crypto device pointer | 360 | * @zdev: crypto device pointer |
@@ -363,6 +474,37 @@ static int convert_type86_ica(struct zcrypt_device *zdev, | |||
363 | return 0; | 474 | return 0; |
364 | } | 475 | } |
365 | 476 | ||
477 | /** | ||
478 | * Copy results from a type 86 XCRB reply message back to user space. | ||
479 | * | ||
480 | * @zdev: crypto device pointer | ||
481 | * @reply: reply AP message. | ||
482 | * @xcRB: pointer to XCRB | ||
483 | * | ||
484 | * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. | ||
485 | */ | ||
486 | static int convert_type86_xcrb(struct zcrypt_device *zdev, | ||
487 | struct ap_message *reply, | ||
488 | struct ica_xcRB *xcRB) | ||
489 | { | ||
490 | struct type86_fmt2_msg *msg = reply->message; | ||
491 | char *data = reply->message; | ||
492 | |||
493 | /* Copy CPRB to user */ | ||
494 | if (copy_to_user(xcRB->reply_control_blk_addr, | ||
495 | data + msg->fmt2.offset1, msg->fmt2.count1)) | ||
496 | return -EFAULT; | ||
497 | xcRB->reply_control_blk_length = msg->fmt2.count1; | ||
498 | |||
499 | /* Copy data buffer to user */ | ||
500 | if (msg->fmt2.count2) | ||
501 | if (copy_to_user(xcRB->reply_data_addr, | ||
502 | data + msg->fmt2.offset2, msg->fmt2.count2)) | ||
503 | return -EFAULT; | ||
504 | xcRB->reply_data_length = msg->fmt2.count2; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
366 | static int convert_response_ica(struct zcrypt_device *zdev, | 508 | static int convert_response_ica(struct zcrypt_device *zdev, |
367 | struct ap_message *reply, | 509 | struct ap_message *reply, |
368 | char __user *outputdata, | 510 | char __user *outputdata, |
@@ -391,6 +533,36 @@ static int convert_response_ica(struct zcrypt_device *zdev, | |||
391 | } | 533 | } |
392 | } | 534 | } |
393 | 535 | ||
536 | static int convert_response_xcrb(struct zcrypt_device *zdev, | ||
537 | struct ap_message *reply, | ||
538 | struct ica_xcRB *xcRB) | ||
539 | { | ||
540 | struct type86x_reply *msg = reply->message; | ||
541 | |||
542 | /* Response type byte is the second byte in the response. */ | ||
543 | switch (((unsigned char *) reply->message)[1]) { | ||
544 | case TYPE82_RSP_CODE: | ||
545 | case TYPE88_RSP_CODE: | ||
546 | xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ | ||
547 | return convert_error(zdev, reply); | ||
548 | case TYPE86_RSP_CODE: | ||
549 | if (msg->hdr.reply_code) { | ||
550 | memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32)); | ||
551 | return convert_error(zdev, reply); | ||
552 | } | ||
553 | if (msg->cprbx.cprb_ver_id == 0x02) | ||
554 | return convert_type86_xcrb(zdev, reply, xcRB); | ||
555 | /* no break, incorrect cprb version is an unknown response */ | ||
556 | default: /* Unknown response type, this should NEVER EVER happen */ | ||
557 | PRINTK("Unrecognized Message Header: %08x%08x\n", | ||
558 | *(unsigned int *) reply->message, | ||
559 | *(unsigned int *) (reply->message+4)); | ||
560 | xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ | ||
561 | zdev->online = 0; | ||
562 | return -EAGAIN; /* repeat the request on a different device. */ | ||
563 | } | ||
564 | } | ||
565 | |||
394 | /** | 566 | /** |
395 | * This function is called from the AP bus code after a crypto request | 567 | * This function is called from the AP bus code after a crypto request |
396 | * "msg" has finished with the reply message "reply". | 568 | * "msg" has finished with the reply message "reply". |
@@ -407,6 +579,8 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev, | |||
407 | .type = TYPE82_RSP_CODE, | 579 | .type = TYPE82_RSP_CODE, |
408 | .reply_code = REP82_ERROR_MACHINE_FAILURE, | 580 | .reply_code = REP82_ERROR_MACHINE_FAILURE, |
409 | }; | 581 | }; |
582 | struct response_type *resp_type = | ||
583 | (struct response_type *) msg->private; | ||
410 | struct type86x_reply *t86r = reply->message; | 584 | struct type86x_reply *t86r = reply->message; |
411 | int length; | 585 | int length; |
412 | 586 | ||
@@ -415,12 +589,27 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev, | |||
415 | memcpy(msg->message, &error_reply, sizeof(error_reply)); | 589 | memcpy(msg->message, &error_reply, sizeof(error_reply)); |
416 | else if (t86r->hdr.type == TYPE86_RSP_CODE && | 590 | else if (t86r->hdr.type == TYPE86_RSP_CODE && |
417 | t86r->cprbx.cprb_ver_id == 0x02) { | 591 | t86r->cprbx.cprb_ver_id == 0x02) { |
418 | length = sizeof(struct type86x_reply) + t86r->length - 2; | 592 | switch (resp_type->type) { |
419 | length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length); | 593 | case PCIXCC_RESPONSE_TYPE_ICA: |
420 | memcpy(msg->message, reply->message, length); | 594 | length = sizeof(struct type86x_reply) |
595 | + t86r->length - 2; | ||
596 | length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length); | ||
597 | memcpy(msg->message, reply->message, length); | ||
598 | break; | ||
599 | case PCIXCC_RESPONSE_TYPE_XCRB: | ||
600 | length = t86r->fmt2.offset2 + t86r->fmt2.count2; | ||
601 | length = min(PCIXCC_MAX_XCRB_RESPONSE_SIZE, length); | ||
602 | memcpy(msg->message, reply->message, length); | ||
603 | break; | ||
604 | default: | ||
605 | PRINTK("Invalid internal response type: %i\n", | ||
606 | resp_type->type); | ||
607 | memcpy(msg->message, &error_reply, | ||
608 | sizeof error_reply); | ||
609 | } | ||
421 | } else | 610 | } else |
422 | memcpy(msg->message, reply->message, sizeof error_reply); | 611 | memcpy(msg->message, reply->message, sizeof error_reply); |
423 | complete((struct completion *) msg->private); | 612 | complete(&(resp_type->work)); |
424 | } | 613 | } |
425 | 614 | ||
426 | static atomic_t zcrypt_step = ATOMIC_INIT(0); | 615 | static atomic_t zcrypt_step = ATOMIC_INIT(0); |
@@ -436,7 +625,9 @@ static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev, | |||
436 | struct ica_rsa_modexpo *mex) | 625 | struct ica_rsa_modexpo *mex) |
437 | { | 626 | { |
438 | struct ap_message ap_msg; | 627 | struct ap_message ap_msg; |
439 | struct completion work; | 628 | struct response_type resp_type = { |
629 | .type = PCIXCC_RESPONSE_TYPE_ICA, | ||
630 | }; | ||
440 | int rc; | 631 | int rc; |
441 | 632 | ||
442 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); | 633 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); |
@@ -444,14 +635,14 @@ static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev, | |||
444 | return -ENOMEM; | 635 | return -ENOMEM; |
445 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | 636 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + |
446 | atomic_inc_return(&zcrypt_step); | 637 | atomic_inc_return(&zcrypt_step); |
447 | ap_msg.private = &work; | 638 | ap_msg.private = &resp_type; |
448 | rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex); | 639 | rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex); |
449 | if (rc) | 640 | if (rc) |
450 | goto out_free; | 641 | goto out_free; |
451 | init_completion(&work); | 642 | init_completion(&resp_type.work); |
452 | ap_queue_message(zdev->ap_dev, &ap_msg); | 643 | ap_queue_message(zdev->ap_dev, &ap_msg); |
453 | rc = wait_for_completion_interruptible_timeout( | 644 | rc = wait_for_completion_interruptible_timeout( |
454 | &work, PCIXCC_CLEANUP_TIME); | 645 | &resp_type.work, PCIXCC_CLEANUP_TIME); |
455 | if (rc > 0) | 646 | if (rc > 0) |
456 | rc = convert_response_ica(zdev, &ap_msg, mex->outputdata, | 647 | rc = convert_response_ica(zdev, &ap_msg, mex->outputdata, |
457 | mex->outputdatalength); | 648 | mex->outputdatalength); |
@@ -478,7 +669,9 @@ static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev, | |||
478 | struct ica_rsa_modexpo_crt *crt) | 669 | struct ica_rsa_modexpo_crt *crt) |
479 | { | 670 | { |
480 | struct ap_message ap_msg; | 671 | struct ap_message ap_msg; |
481 | struct completion work; | 672 | struct response_type resp_type = { |
673 | .type = PCIXCC_RESPONSE_TYPE_ICA, | ||
674 | }; | ||
482 | int rc; | 675 | int rc; |
483 | 676 | ||
484 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); | 677 | ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL); |
@@ -486,14 +679,14 @@ static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev, | |||
486 | return -ENOMEM; | 679 | return -ENOMEM; |
487 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | 680 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + |
488 | atomic_inc_return(&zcrypt_step); | 681 | atomic_inc_return(&zcrypt_step); |
489 | ap_msg.private = &work; | 682 | ap_msg.private = &resp_type; |
490 | rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt); | 683 | rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt); |
491 | if (rc) | 684 | if (rc) |
492 | goto out_free; | 685 | goto out_free; |
493 | init_completion(&work); | 686 | init_completion(&resp_type.work); |
494 | ap_queue_message(zdev->ap_dev, &ap_msg); | 687 | ap_queue_message(zdev->ap_dev, &ap_msg); |
495 | rc = wait_for_completion_interruptible_timeout( | 688 | rc = wait_for_completion_interruptible_timeout( |
496 | &work, PCIXCC_CLEANUP_TIME); | 689 | &resp_type.work, PCIXCC_CLEANUP_TIME); |
497 | if (rc > 0) | 690 | if (rc > 0) |
498 | rc = convert_response_ica(zdev, &ap_msg, crt->outputdata, | 691 | rc = convert_response_ica(zdev, &ap_msg, crt->outputdata, |
499 | crt->outputdatalength); | 692 | crt->outputdatalength); |
@@ -510,11 +703,55 @@ out_free: | |||
510 | } | 703 | } |
511 | 704 | ||
512 | /** | 705 | /** |
706 | * The request distributor calls this function if it picked the PCIXCC/CEX2C | ||
707 | * device to handle a send_cprb request. | ||
708 | * @zdev: pointer to zcrypt_device structure that identifies the | ||
709 | * PCIXCC/CEX2C device to the request distributor | ||
710 | * @xcRB: pointer to the send_cprb request buffer | ||
711 | */ | ||
712 | long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB) | ||
713 | { | ||
714 | struct ap_message ap_msg; | ||
715 | struct response_type resp_type = { | ||
716 | .type = PCIXCC_RESPONSE_TYPE_XCRB, | ||
717 | }; | ||
718 | int rc; | ||
719 | |||
720 | ap_msg.message = (void *) kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL); | ||
721 | if (!ap_msg.message) | ||
722 | return -ENOMEM; | ||
723 | ap_msg.psmid = (((unsigned long long) current->pid) << 32) + | ||
724 | atomic_inc_return(&zcrypt_step); | ||
725 | ap_msg.private = &resp_type; | ||
726 | rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB); | ||
727 | if (rc) | ||
728 | goto out_free; | ||
729 | init_completion(&resp_type.work); | ||
730 | ap_queue_message(zdev->ap_dev, &ap_msg); | ||
731 | rc = wait_for_completion_interruptible_timeout( | ||
732 | &resp_type.work, PCIXCC_CLEANUP_TIME); | ||
733 | if (rc > 0) | ||
734 | rc = convert_response_xcrb(zdev, &ap_msg, xcRB); | ||
735 | else { | ||
736 | /* Signal pending or message timed out. */ | ||
737 | ap_cancel_message(zdev->ap_dev, &ap_msg); | ||
738 | if (rc == 0) | ||
739 | /* Message timed out. */ | ||
740 | rc = -ETIME; | ||
741 | } | ||
742 | out_free: | ||
743 | memset(ap_msg.message, 0x0, ap_msg.length); | ||
744 | kfree(ap_msg.message); | ||
745 | return rc; | ||
746 | } | ||
747 | |||
748 | /** | ||
513 | * The crypto operations for a PCIXCC/CEX2C card. | 749 | * The crypto operations for a PCIXCC/CEX2C card. |
514 | */ | 750 | */ |
515 | static struct zcrypt_ops zcrypt_pcixcc_ops = { | 751 | static struct zcrypt_ops zcrypt_pcixcc_ops = { |
516 | .rsa_modexpo = zcrypt_pcixcc_modexpo, | 752 | .rsa_modexpo = zcrypt_pcixcc_modexpo, |
517 | .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt, | 753 | .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt, |
754 | .send_cprb = zcrypt_pcixcc_send_cprb, | ||
518 | }; | 755 | }; |
519 | 756 | ||
520 | /** | 757 | /** |
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h index d4c44c4d7ad0..a78ff307fd19 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.h +++ b/drivers/s390/crypto/zcrypt_pcixcc.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/crypto/zcrypt_pcixcc.h | 2 | * linux/drivers/s390/crypto/zcrypt_pcixcc.h |
3 | * | 3 | * |
4 | * zcrypt 2.0.0 | 4 | * zcrypt 2.1.0 |
5 | * | 5 | * |
6 | * Copyright (C) 2001, 2006 IBM Corporation | 6 | * Copyright (C) 2001, 2006 IBM Corporation |
7 | * Author(s): Robert Burroughs | 7 | * Author(s): Robert Burroughs |