]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] s390: crypto device driver part 1
authorAndrew Morton <akpm@osdl.org>
Mon, 12 Apr 2004 06:43:48 +0000 (23:43 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 12 Apr 2004 06:43:48 +0000 (23:43 -0700)
From: Martin Schwidefsky <schwidefsky@de.ibm.com>

The crypto device driver for PCICA & PCICC cards, part 1.

arch/s390/defconfig
drivers/s390/Kconfig
drivers/s390/Makefile
drivers/s390/crypto/Makefile [new file with mode: 0644]
drivers/s390/crypto/z90common.h [new file with mode: 0644]
drivers/s390/crypto/z90crypt.h [new file with mode: 0644]
drivers/s390/crypto/z90hardware.c [new file with mode: 0644]

index e73820a498a59bd632152289ed99e2118c35001b..574c1b2a9d068fcd34077dac1d0760da646008cf 100644 (file)
@@ -195,6 +195,11 @@ CONFIG_S390_TAPE_BLOCK=y
 #
 CONFIG_S390_TAPE_34XX=m
 
+#
+# Cryptographic devices
+#
+CONFIG_Z90CRYPT=m
+
 #
 # Networking support
 #
index 3b60f573fad086290132553f67defdfc4dd9c0f2..4ae29d32d7743d2184b0d4c822b4de753454bf05 100644 (file)
@@ -164,3 +164,16 @@ config S390_TAPE_34XX
          It is safe to say "Y" here.
 
 endmenu
+
+menu "Cryptographic devices"
+
+config Z90CRYPT
+       tristate "Support for PCI-attached cryptographic adapters"
+        default "m"
+        help
+         Select this option if you want to use a PCI-attached cryptographic
+         adapter like the PCI Cryptographic Accelerator (PCICA) or the PCI
+         Cryptographic Coprocessor (PCICC).  This option is also available
+         as a module called z90crypt.ko.
+
+endmenu
index b50465ef93a46a14807d119d02160eef36def428..c99a2fe92fb04acc3ca8fcff49785af8d898f460 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 obj-y += s390mach.o sysinfo.o
-obj-y += cio/ block/ char/ net/ scsi/
+obj-y += cio/ block/ char/ crypto/ net/ scsi/
 
 drivers-y += drivers/s390/built-in.o
+
diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile
new file mode 100644 (file)
index 0000000..ea15f86
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# S/390 miscellaneous devices
+#
+
+z90crypt-objs := z90main.o z90hardware.o
+obj-$(CONFIG_Z90CRYPT) += z90crypt.o
diff --git a/drivers/s390/crypto/z90common.h b/drivers/s390/crypto/z90common.h
new file mode 100644 (file)
index 0000000..624ef6a
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ *  linux/drivers/s390/misc/z90common.h
+ *
+ *  z90crypt 1.3.1
+ *
+ *  Copyright (C)  2001, 2004 IBM Corporation
+ *  Author(s): Robert Burroughs (burrough@us.ibm.com)
+ *            Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _Z90COMMON_
+#define _Z90COMMON_
+
+#define VERSION_Z90COMMON_H "$Revision: 1.8 $"
+
+
+#define RESPBUFFSIZE 256
+#define PCI_FUNC_KEY_DECRYPT 0x5044
+#define PCI_FUNC_KEY_ENCRYPT 0x504B
+
+enum devstat {
+       DEV_GONE,
+       DEV_ONLINE,
+       DEV_QUEUE_FULL,
+       DEV_EMPTY,
+       DEV_NO_WORK,
+       DEV_BAD_MESSAGE,
+       DEV_TSQ_EXCEPTION,
+       DEV_RSQ_EXCEPTION,
+       DEV_SEN_EXCEPTION,
+       DEV_REC_EXCEPTION
+};
+
+enum hdstat {
+       HD_NOT_THERE,
+       HD_BUSY,
+       HD_DECONFIGURED,
+       HD_CHECKSTOPPED,
+       HD_ONLINE,
+       HD_TSQ_EXCEPTION
+};
+
+#define Z90C_AMBIGUOUS_DOMAIN  2
+#define Z90C_INCORRECT_DOMAIN  3
+#define ENOTINIT               4
+
+#define SEN_BUSY        7
+#define SEN_USER_ERROR  8
+#define SEN_QUEUE_FULL 11
+#define SEN_NOT_AVAIL  16
+#define SEN_PAD_ERROR  17
+#define SEN_RETRY      18
+#define SEN_RELEASED   24
+
+#define REC_EMPTY       4
+#define REC_BUSY        6
+#define REC_OPERAND_INV         8
+#define REC_OPERAND_SIZE 9
+#define REC_EVEN_MOD   10
+#define REC_NO_WORK    11
+#define REC_HARDWAR_ERR 12
+#define REC_NO_RESPONSE 13
+#define REC_RETRY_DEV  14
+#define REC_USER_GONE  15
+#define REC_BAD_MESSAGE 16
+#define REC_INVALID_PAD 17
+#define REC_RELEASED   28
+
+#define WRONG_DEVICE_TYPE 20
+
+#define REC_FATAL_ERROR 32
+#define SEN_FATAL_ERROR 33
+#define TSQ_FATAL_ERROR 34
+#define RSQ_FATAL_ERROR 35
+
+#define PCICA  0
+#define PCICC  1
+#define PCIXCC 2
+#define NILDEV -1
+#define ANYDEV -1
+
+enum hdevice_type {
+       PCICC_HW  = 3,
+       PCICA_HW  = 4,
+       PCIXCC_HW = 5,
+       OTHER_HW  = 6,
+       OTHER2_HW = 7
+};
+
+#ifndef DEV_NAME
+#define DEV_NAME       "z90crypt"
+#endif
+#define PRINTK(fmt, args...) \
+       printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+#define PRINTKN(fmt, args...) \
+       printk(KERN_DEBUG DEV_NAME ": " fmt, ## args)
+#define PRINTKW(fmt, args...) \
+       printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+#define PRINTKC(fmt, args...) \
+       printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+
+#ifdef Z90CRYPT_DEBUG
+#define PDEBUG(fmt, args...) \
+       printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+#else
+#define PDEBUG(fmt, args...) do {} while (0)
+#endif
+
+#define UMIN(a,b) ((a) < (b) ? (a) : (b))
+#define IS_EVEN(x) ((x) == (2 * ((x) / 2)))
+
+
+#endif
diff --git a/drivers/s390/crypto/z90crypt.h b/drivers/s390/crypto/z90crypt.h
new file mode 100644 (file)
index 0000000..4ec1eaa
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ *  linux/drivers/s390/misc/z90crypt.h
+ *
+ *  z90crypt 1.3.1
+ *
+ *  Copyright (C)  2001, 2004 IBM Corporation
+ *  Author(s): Robert Burroughs (burrough@us.ibm.com)
+ *            Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _LINUX_Z90CRYPT_H_
+#define _LINUX_Z90CRYPT_H_
+
+#include <linux/ioctl.h>
+
+#define VERSION_Z90CRYPT_H "$Revision: 1.2 $"
+
+#define z90crypt_VERSION 1
+#define z90crypt_RELEASE 3     // 2 = PCIXCC, 3 = rewrite for coding standards
+#define z90crypt_VARIANT 1
+
+/**
+ * struct ica_rsa_modexpo
+ *
+ * Requirements:
+ * - outputdatalength is at least as large as inputdatalength.
+ * - All key parts are right justified in their fields, padded on
+ *   the left with zeroes.
+ * - length(b_key) = inputdatalength
+ * - length(n_modulus) = inputdatalength
+ */
+struct ica_rsa_modexpo {
+       char *          inputdata;
+       unsigned int    inputdatalength;
+       char *          outputdata;
+       unsigned int    outputdatalength;
+       char *          b_key;
+       char *          n_modulus;
+};
+
+/**
+ * struct ica_rsa_modexpo_crt
+ *
+ * Requirements:
+ * - inputdatalength is even.
+ * - outputdatalength is at least as large as inputdatalength.
+ * - All key parts are right justified in their fields, padded on
+ *   the left with zeroes.
+ * - length(bp_key)    = inputdatalength/2 + 8
+ * - length(bq_key)    = inputdatalength/2
+ * - length(np_key)    = inputdatalength/2 + 8
+ * - length(nq_key)    = inputdatalength/2
+ * - length(u_mult_inv) = inputdatalength/2 + 8
+ */
+struct ica_rsa_modexpo_crt {
+       char *          inputdata;
+       unsigned int    inputdatalength;
+       char *          outputdata;
+       unsigned int    outputdatalength;
+       char *          bp_key;
+       char *          bq_key;
+       char *          np_prime;
+       char *          nq_prime;
+       char *          u_mult_inv;
+};
+
+#define Z90_IOCTL_MAGIC 'z'  // NOTE:  Need to allocate from linux folks
+
+/**
+ * Interface notes:
+ *
+ * The ioctl()s which are implemented (along with relevant details)
+ * are:
+ *
+ *   ICARSAMODEXPO
+ *     Perform an RSA operation using a Modulus-Exponent pair
+ *     This takes an ica_rsa_modexpo struct as its arg.
+ *
+ *     NOTE: please refer to the comments preceding this structure
+ *          for the implementation details for the contents of the
+ *          block
+ *
+ *   ICARSACRT
+ *     Perform an RSA operation using a Chinese-Remainder Theorem key
+ *     This takes an ica_rsa_modexpo_crt struct as its arg.
+ *
+ *     NOTE: please refer to the comments preceding this structure
+ *          for the implementation details for the contents of the
+ *          block
+ *
+ *   Z90STAT_TOTALCOUNT
+ *     Return an integer count of all device types together.
+ *
+ *   Z90STAT_PCICACOUNT
+ *     Return an integer count of all PCICAs.
+ *
+ *   Z90STAT_PCICCCOUNT
+ *     Return an integer count of all PCICCs.
+ *
+ *   Z90STAT_PCIXCCCOUNT
+ *     Return an integer count of all PCIXCCs.
+ *
+ *   Z90STAT_REQUESTQ_COUNT
+ *     Return an integer count of the number of entries waiting to be
+ *     sent to a device.
+ *
+ *   Z90STAT_PENDINGQ_COUNT
+ *     Return an integer count of the number of entries sent to a
+ *     device awaiting the reply.
+ *
+ *   Z90STAT_TOTALOPEN_COUNT
+ *     Return an integer count of the number of open file handles.
+ *
+ *   Z90STAT_DOMAIN_INDEX
+ *     Return the integer value of the Cryptographic Domain.
+ *
+ *   Z90STAT_STATUS_MASK
+ *     Return an 64 element array of unsigned chars for the status of
+ *     all devices.
+ *      0x01: PCICA
+ *      0x02: PCICC
+ *      0x03: PCIXCC
+ *      0x0d: device is disabled via the proc filesystem
+ *
+ *   Z90STAT_QDEPTH_MASK
+ *     Return an 64 element array of unsigned chars for the queue
+ *     depth of all devices.
+ *
+ *   Z90STAT_PERDEV_REQCNT
+ *     Return an 64 element array of unsigned integers for the number
+ *     of successfully completed requests per device since the device
+ *     was detected and made available.
+ *
+ *   ICAZ90STATUS (deprecated)
+ *     Return some device driver status in a ica_z90_status struct
+ *     This takes an ica_z90_status struct as its arg.
+ *
+ *     NOTE: this ioctl() is deprecated, and has been replaced with
+ *          single ioctl()s for each type of status being requested
+ *
+ *   Z90QUIESCE (not recommended)
+ *     Quiesce the driver.  This is intended to stop all new
+ *     requests from being processed.  Its use is not recommended,
+ *     except in circumstances where there is no other way to stop
+ *     callers from accessing the driver.  Its original use was to
+ *     allow the driver to be "drained" of work in preparation for
+ *     a system shutdown.
+ *
+ *     NOTE: once issued, this ban on new work cannot be undone
+ *          except by unloading and reloading the driver.
+ */
+
+/**
+ * Supported ioctl calls
+ */
+#define ICARSAMODEXPO  _IOC(_IOC_READ|_IOC_WRITE, Z90_IOCTL_MAGIC, 0x05, 0)
+#define ICARSACRT      _IOC(_IOC_READ|_IOC_WRITE, Z90_IOCTL_MAGIC, 0x06, 0)
+
+/* DEPRECATED status call (bound for removal SOON) */
+#define ICAZ90STATUS   _IOR(Z90_IOCTL_MAGIC, 0x10, struct ica_z90_status)
+
+/* unrelated to ICA callers */
+#define Z90QUIESCE     _IO(Z90_IOCTL_MAGIC, 0x11)
+
+/* New status calls */
+#define Z90STAT_TOTALCOUNT     _IOR(Z90_IOCTL_MAGIC, 0x40, int)
+#define Z90STAT_PCICACOUNT     _IOR(Z90_IOCTL_MAGIC, 0x41, int)
+#define Z90STAT_PCICCCOUNT     _IOR(Z90_IOCTL_MAGIC, 0x42, int)
+#define Z90STAT_PCIXCCCOUNT    _IOR(Z90_IOCTL_MAGIC, 0x43, int)
+#define Z90STAT_REQUESTQ_COUNT _IOR(Z90_IOCTL_MAGIC, 0x44, int)
+#define Z90STAT_PENDINGQ_COUNT _IOR(Z90_IOCTL_MAGIC, 0x45, int)
+#define Z90STAT_TOTALOPEN_COUNT _IOR(Z90_IOCTL_MAGIC, 0x46, int)
+#define Z90STAT_DOMAIN_INDEX   _IOR(Z90_IOCTL_MAGIC, 0x47, int)
+#define Z90STAT_STATUS_MASK    _IOR(Z90_IOCTL_MAGIC, 0x48, char[64])
+#define Z90STAT_QDEPTH_MASK    _IOR(Z90_IOCTL_MAGIC, 0x49, char[64])
+#define Z90STAT_PERDEV_REQCNT  _IOR(Z90_IOCTL_MAGIC, 0x4a, int[64])
+
+/**
+ * local errno definitions
+ */
+#define ENOBUFF          129   // filp->private_data->...>work_elem_p->buffer is NULL
+#define EWORKPEND 130  // user issues ioctl while another pending
+#define ERELEASED 131  // user released while ioctl pending
+#define EQUIESCE  132  // z90crypt quiescing (no more work allowed)
+#define ETIMEOUT  133  // request timed out
+#define EUNKNOWN  134  // some unrecognized error occured
+#define EGETBUFF  135  // Error getting buffer
+
+/**
+ * DEPRECATED STRUCTURES
+ */
+
+/**
+ * This structure is DEPRECATED and the corresponding ioctl() has been
+ * replaced with individual ioctl()s for each piece of data!
+ * This structure will NOT survive past version 1.3.1, so switch to the
+ * new ioctl()s.
+ */
+#define MASK_LENGTH 64 // mask length
+struct ica_z90_status {
+       int totalcount;
+       int leedslitecount; // PCICA
+       int leeds2count;    // PCICC
+       // int PCIXCCCount; is not in struct for backward compatibility
+       int requestqWaitCount;
+       int pendingqWaitCount;
+       int totalOpenCount;
+       int cryptoDomain;
+       // status: 0=not there. 1=PCICA. 2=PCICC. 3=PCIXCC
+       unsigned char status[MASK_LENGTH];
+       // qdepth: # work elements waiting for each device
+       unsigned char qdepth[MASK_LENGTH];
+};
+
+#endif /* _LINUX_Z90CRYPT_H_ */
diff --git a/drivers/s390/crypto/z90hardware.c b/drivers/s390/crypto/z90hardware.c
new file mode 100644 (file)
index 0000000..8c8db43
--- /dev/null
@@ -0,0 +1,2184 @@
+/*
+ *  linux/drivers/s390/misc/z90hardware.c
+ *
+ *  z90crypt 1.3.1
+ *
+ *  Copyright (C)  2001, 2004 IBM Corporation
+ *  Author(s): Robert Burroughs (burrough@us.ibm.com)
+ *            Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/uaccess.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include "z90crypt.h"
+#include "z90common.h"
+
+#define VERSION_Z90HARDWARE_C "$Revision: 1.19 $"
+
+char z90chardware_version[] __initdata =
+       "z90hardware.o (" VERSION_Z90HARDWARE_C "/"
+                         VERSION_Z90COMMON_H "/" VERSION_Z90CRYPT_H ")";
+
+struct cca_token_hdr {
+       unsigned char  token_identifier;
+       unsigned char  version;
+       unsigned short token_length;
+       unsigned char  reserved[4];
+};
+
+#define CCA_TKN_HDR_ID_EXT 0x1E
+
+struct cca_private_ext_ME_sec {
+       unsigned char  section_identifier;
+       unsigned char  version;
+       unsigned short section_length;
+       unsigned char  private_key_hash[20];
+       unsigned char  reserved1[4];
+       unsigned char  key_format;
+       unsigned char  reserved2;
+       unsigned char  key_name_hash[20];
+       unsigned char  key_use_flags[4];
+       unsigned char  reserved3[6];
+       unsigned char  reserved4[24];
+       unsigned char  confounder[24];
+       unsigned char  exponent[128];
+       unsigned char  modulus[128];
+};
+
+#define CCA_PVT_USAGE_ALL 0x80
+
+struct cca_public_sec {
+       unsigned char  section_identifier;
+       unsigned char  version;
+       unsigned short section_length;
+       unsigned char  reserved[2];
+       unsigned short exponent_len;
+       unsigned short modulus_bit_len;
+       unsigned short modulus_byte_len;
+       unsigned char  exponent[3];
+};
+
+struct cca_private_ext_ME {
+       struct cca_token_hdr          pvtMEHdr;
+       struct cca_private_ext_ME_sec pvtMESec;
+       struct cca_public_sec         pubMESec;
+};
+
+struct cca_public_key {
+       struct cca_token_hdr  pubHdr;
+       struct cca_public_sec pubSec;
+};
+
+struct cca_pvt_ext_CRT_sec {
+       unsigned char  section_identifier;
+       unsigned char  version;
+       unsigned short section_length;
+       unsigned char  private_key_hash[20];
+       unsigned char  reserved1[4];
+       unsigned char  key_format;
+       unsigned char  reserved2;
+       unsigned char  key_name_hash[20];
+       unsigned char  key_use_flags[4];
+       unsigned short p_len;
+       unsigned short q_len;
+       unsigned short dp_len;
+       unsigned short dq_len;
+       unsigned short u_len;
+       unsigned short mod_len;
+       unsigned char  reserved3[4];
+       unsigned short pad_len;
+       unsigned char  reserved4[52];
+       unsigned char  confounder[8];
+};
+
+#define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08
+#define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40
+
+struct cca_private_ext_CRT {
+       struct cca_token_hdr       pvtCrtHdr;
+       struct cca_pvt_ext_CRT_sec pvtCrtSec;
+       struct cca_public_sec      pubCrtSec;
+};
+
+struct ap_status_word {
+       unsigned char q_stat_flags;
+       unsigned char response_code;
+       unsigned char reserved[2];
+};
+
+#define AP_Q_STATUS_EMPTY              0x80
+#define AP_Q_STATUS_REPLIES_WAITING    0x40
+#define AP_Q_STATUS_ARRAY_FULL         0x20
+
+#define AP_RESPONSE_NORMAL             0x00
+#define AP_RESPONSE_Q_NOT_AVAIL                0x01
+#define AP_RESPONSE_RESET_IN_PROGRESS  0x02
+#define AP_RESPONSE_DECONFIGURED       0x03
+#define AP_RESPONSE_CHECKSTOPPED       0x04
+#define AP_RESPONSE_BUSY               0x05
+#define AP_RESPONSE_Q_FULL             0x10
+#define AP_RESPONSE_NO_PENDING_REPLY   0x10
+#define AP_RESPONSE_INDEX_TOO_BIG      0x11
+#define AP_RESPONSE_NO_FIRST_PART      0x13
+#define AP_RESPONSE_MESSAGE_TOO_BIG    0x15
+
+#define AP_MAX_CDX_BITL                4
+#define AP_RQID_RESERVED_BITL  4
+#define SKIP_BITL              (AP_MAX_CDX_BITL + AP_RQID_RESERVED_BITL)
+
+struct type4_hdr {
+       unsigned char  reserved1;
+       unsigned char  msg_type_code;
+       unsigned short msg_len;
+       unsigned char  request_code;
+       unsigned char  msg_fmt;
+       unsigned short reserved2;
+};
+
+#define TYPE4_TYPE_CODE 0x04
+#define TYPE4_REQU_CODE 0x40
+
+#define TYPE4_SME_LEN 0x0188
+#define TYPE4_LME_LEN 0x0308
+#define TYPE4_SCR_LEN 0x01E0
+#define TYPE4_LCR_LEN 0x03A0
+
+#define TYPE4_SME_FMT 0x00
+#define TYPE4_LME_FMT 0x10
+#define TYPE4_SCR_FMT 0x40
+#define TYPE4_LCR_FMT 0x50
+
+struct type4_sme {
+       struct type4_hdr header;
+       unsigned char    message[128];
+       unsigned char    exponent[128];
+       unsigned char    modulus[128];
+};
+
+struct type4_lme {
+       struct type4_hdr header;
+       unsigned char    message[256];
+       unsigned char    exponent[256];
+       unsigned char    modulus[256];
+};
+
+struct type4_scr {
+       struct type4_hdr header;
+       unsigned char    message[128];
+       unsigned char    dp[72];
+       unsigned char    dq[64];
+       unsigned char    p[72];
+       unsigned char    q[64];
+       unsigned char    u[72];
+};
+
+struct type4_lcr {
+       struct type4_hdr header;
+       unsigned char    message[256];
+       unsigned char    dp[136];
+       unsigned char    dq[128];
+       unsigned char    p[136];
+       unsigned char    q[128];
+       unsigned char    u[136];
+};
+
+union type4_msg {
+       struct type4_sme sme;
+       struct type4_lme lme;
+       struct type4_scr scr;
+       struct type4_lcr lcr;
+};
+
+struct type84_hdr {
+       unsigned char  reserved1;
+       unsigned char  code;
+       unsigned short len;
+       unsigned char  reserved2[4];
+};
+
+#define TYPE84_RSP_CODE 0x84
+
+struct type6_hdr {
+       unsigned char reserved1;
+       unsigned char type;
+       unsigned char reserved2[2];
+       unsigned char right[4];
+       unsigned char reserved3[2];
+       unsigned char reserved4[2];
+       unsigned char pfs[4];
+       unsigned int  offset1;
+       unsigned int  offset2;
+       unsigned int  offset3;
+       unsigned int  offset4;
+       unsigned char agent_id[16];
+       unsigned char rqid[2];
+       unsigned char reserved5[2];
+       unsigned char function_code[2];
+       unsigned char reserved6[2];
+       unsigned int  ToCardLen1;
+       unsigned int  ToCardLen2;
+       unsigned int  ToCardLen3;
+       unsigned int  ToCardLen4;
+       unsigned int  FromCardLen1;
+       unsigned int  FromCardLen2;
+       unsigned int  FromCardLen3;
+       unsigned int  FromCardLen4;
+};
+
+struct CPRB {
+       unsigned char cprb_len[2];
+       unsigned char cprb_ver_id;
+       unsigned char pad_000;
+       unsigned char srpi_rtcode[4];
+       unsigned char srpi_verb;
+       unsigned char flags;
+       unsigned char func_id[2];
+       unsigned char checkpoint_flag;
+       unsigned char resv2;
+       unsigned char req_parml[2];
+       unsigned char req_parmp[4];
+       unsigned char req_datal[4];
+       unsigned char req_datap[4];
+       unsigned char rpl_parml[2];
+       unsigned char pad_001[2];
+       unsigned char rpl_parmp[4];
+       unsigned char rpl_datal[4];
+       unsigned char rpl_datap[4];
+       unsigned char ccp_rscode[2];
+       unsigned char ccp_rtcode[2];
+       unsigned char repd_parml[2];
+       unsigned char mac_data_len[2];
+       unsigned char repd_datal[4];
+       unsigned char req_pc[2];
+       unsigned char res_origin[8];
+       unsigned char mac_value[8];
+       unsigned char logon_id[8];
+       unsigned char usage_domain[2];
+       unsigned char resv3[18];
+       unsigned char svr_namel[2];
+       unsigned char svr_name[8];
+};
+
+struct CPRBX {
+       unsigned short cprb_len;
+       unsigned char  cprb_ver_id;
+       unsigned char  pad_000[3];
+       unsigned char  func_id[2];
+       unsigned char  cprb_flags[4];
+       unsigned int   req_parml;
+       unsigned int   req_datal;
+       unsigned int   rpl_msgbl;
+       unsigned int   rpld_parml;
+       unsigned int   rpl_datal;
+       unsigned int   rpld_datal;
+       unsigned int   req_extbl;
+       unsigned char  pad_001[4];
+       unsigned int   rpld_extbl;
+       unsigned char  req_parmb[16];
+       unsigned char  req_datab[16];
+       unsigned char  rpl_parmb[16];
+       unsigned char  rpl_datab[16];
+       unsigned char  req_extb[16];
+       unsigned char  rpl_extb[16];
+       unsigned short ccp_rtcode;
+       unsigned short ccp_rscode;
+       unsigned int   mac_data_len;
+       unsigned char  logon_id[8];
+       unsigned char  mac_value[8];
+       unsigned char  mac_content_flgs;
+       unsigned char  pad_002;
+       unsigned short domain;
+       unsigned char  pad_003[12];
+       unsigned char  pad_004[36];
+};
+
+struct type6_msg {
+       struct type6_hdr header;
+       struct CPRB      CPRB;
+};
+
+union request_msg {
+       union  type4_msg t4msg;
+       struct type6_msg t6msg;
+};
+
+struct request_msg_ext {
+       int               q_nr;
+       unsigned char     *psmid;
+       union request_msg reqMsg;
+};
+
+struct type82_hdr {
+       unsigned char reserved1;
+       unsigned char type;
+       unsigned char reserved2[2];
+       unsigned char reply_code;
+       unsigned char reserved3[3];
+};
+
+#define TYPE82_RSP_CODE 0x82
+
+#define REPLY_ERROR_MACHINE_FAILURE  0x10
+#define REPLY_ERROR_PREEMPT_FAILURE  0x12
+#define REPLY_ERROR_CHECKPT_FAILURE  0x14
+#define REPLY_ERROR_MESSAGE_TYPE     0x20
+#define REPLY_ERROR_INVALID_COMM_CD  0x21
+#define REPLY_ERROR_INVALID_MSG_LEN  0x23
+#define REPLY_ERROR_RESERVD_FIELD    0x24
+#define REPLY_ERROR_FORMAT_FIELD     0x29
+#define REPLY_ERROR_INVALID_COMMAND  0x30
+#define REPLY_ERROR_MALFORMED_MSG    0x40
+#define REPLY_ERROR_RESERVED_FIELD   0x50
+#define REPLY_ERROR_WORD_ALIGNMENT   0x60
+#define REPLY_ERROR_MESSAGE_LENGTH   0x80
+#define REPLY_ERROR_OPERAND_INVALID  0x82
+#define REPLY_ERROR_OPERAND_SIZE     0x84
+#define REPLY_ERROR_EVEN_MOD_IN_OPND 0x85
+#define REPLY_ERROR_TRANSPORT_FAIL   0x90
+#define REPLY_ERROR_PACKET_TRUNCATED 0xA0
+#define REPLY_ERROR_ZERO_BUFFER_LEN  0xB0
+
+struct type86_hdr {
+       unsigned char reserved1;
+       unsigned char type;
+       unsigned char format;
+       unsigned char reserved2;
+       unsigned char reply_code;
+       unsigned char reserved3[3];
+};
+
+#define TYPE86_RSP_CODE 0x86
+#define TYPE86_FMT2    0x02
+
+struct type86_fmt2_msg {
+       struct type86_hdr hdr;
+       unsigned char     reserved[4];
+       unsigned char     apfs[4];
+       unsigned int      count1;
+       unsigned int      offset1;
+       unsigned int      count2;
+       unsigned int      offset2;
+       unsigned int      count3;
+       unsigned int      offset3;
+       unsigned int      ount4;
+       unsigned int      offset4;
+};
+
+static struct type6_hdr static_type6_hdr = {
+       0x00,
+       0x06,
+       {0x00,0x00},
+       {0x00,0x00,0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00,0x00,0x00},
+       0x00000058,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       {0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50,
+        0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01},
+       {0x00,0x00},
+       {0x00,0x00},
+       {0x50,0x44},
+       {0x00,0x00},
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000
+};
+
+static struct type6_hdr static_type6_hdrX = {
+       0x00,
+       0x06,
+       {0x00,0x00},
+       {0x00,0x00,0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00,0x00,0x00},
+       0x00000058,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       {0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00},
+       {0x50,0x44},
+       {0x00,0x00},
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000
+};
+
+static struct CPRB static_cprb = {
+       {0x70,0x00},
+       0x41,
+       0x00,
+       {0x00,0x00,0x00,0x00},
+       0x00,
+       0x00,
+       {0x54,0x32},
+       0x01,
+       0x00,
+       {0x00,0x00},
+       {0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00,0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       {0x00,0x00},
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x00,0x00},
+       {0x08,0x00},
+       {0x49,0x43,0x53,0x46,0x20,0x20,0x20,0x20}
+};
+
+struct function_and_rules_block {
+       unsigned char function_code[2];
+       unsigned char ulen[2];
+       unsigned char only_rule[8];
+};
+
+static struct function_and_rules_block static_pkd_function_and_rules = {
+       {0x50,0x44},
+       {0x0A,0x00},
+       {'P','K','C','S','-','1','.','2'}
+};
+
+static struct function_and_rules_block static_pke_function_and_rules = {
+       {0x50,0x4B},
+       {0x0A,0x00},
+       {'P','K','C','S','-','1','.','2'}
+};
+
+struct T6_keyBlock_hdr {
+       unsigned char blen[2];
+       unsigned char ulen[2];
+       unsigned char flags[2];
+};
+
+static struct T6_keyBlock_hdr static_T6_keyBlock_hdr = {
+       {0x89,0x01},
+       {0x87,0x01},
+       {0x00}
+};
+
+static struct CPRBX static_cprbx = {
+       0x00DC,
+       0x02,
+       {0x00,0x00,0x00},
+       {0x54,0x32},
+       {0x00,0x00,0x00,0x00},
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       {0x00,0x00,0x00,0x00},
+       0x00000000,
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       0x0000,
+       0x0000,
+       0x00000000,
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       0x00,
+       0x00,
+       0x0000,
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+       {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+};
+
+static struct function_and_rules_block static_pkd_function_and_rulesX = {
+       {0x50,0x44},
+       {0x00,0x0A},
+       {'P','K','C','S','-','1','.','2'}
+};
+
+static struct function_and_rules_block static_pke_function_and_rulesX = {
+       {0x50,0x4B},
+       {0x00,0x0A},
+       {'Z','E','R','O','-','P','A','D'}
+};
+
+struct T6_keyBlock_hdrX {
+       unsigned short blen;
+       unsigned short ulen;
+       unsigned char flags[2];
+};
+
+static unsigned char static_pad[256] = {
+0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
+0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
+0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
+0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
+0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
+0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
+0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
+0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
+0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
+0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
+0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
+0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
+0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
+0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
+0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
+0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
+};
+
+static struct cca_private_ext_ME static_pvt_me_key = {
+       {
+               0x1E,
+               0x00,
+               0x0183,
+               {0x00,0x00,0x00,0x00}
+       },
+
+       {
+               0x02,
+               0x00,
+               0x016C,
+               {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00},
+               {0x00,0x00,0x00,0x00},
+               0x00,
+               0x00,
+               {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00},
+               {0x80,0x00,0x00,0x00},
+               {0x00,0x00,0x00,0x00,0x00,0x00},
+               {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+               {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+               {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+               {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+       },
+
+       {
+               0x04,
+               0x00,
+               0x000F,
+               {0x00,0x00},
+               0x0003,
+               0x0000,
+               0x0000,
+               {0x01,0x00,0x01}
+       }
+};
+
+static struct cca_public_key static_public_key = {
+       {
+               0x1E,
+               0x00,
+               0x0000,
+               {0x00,0x00,0x00,0x00}
+       },
+
+       {
+               0x04,
+               0x00,
+               0x0000,
+               {0x00,0x00},
+               0x0000,
+               0x0000,
+               0x0000,
+               {0x01,0x00,0x01}
+       }
+};
+
+#define FIXED_TYPE6_ME_LEN 0x0000025F
+
+#define FIXED_TYPE6_ME_EN_LEN 0x000000F0
+
+#define FIXED_TYPE6_ME_LENX 0x000002CB
+
+#define FIXED_TYPE6_ME_EN_LENX 0x0000015C
+
+static struct cca_public_sec static_cca_pub_sec = {
+       0x04,
+       0x00,
+       0x000f,
+       {0x00,0x00},
+       0x0003,
+       0x0000,
+       0x0000,
+       {0x01,0x00,0x01}
+};
+
+#define FIXED_TYPE6_CR_LEN 0x00000177
+
+#define FIXED_TYPE6_CR_LENX 0x000001E3
+
+#ifndef MAX_RESPONSE_SIZE
+#define MAX_RESPONSE_SIZE 0x00000710
+
+#define MAX_RESPONSEX_SIZE 0x0000077C
+#endif
+
+#define RESPONSE_CPRB_SIZE  0x000006B8
+#define RESPONSE_CPRBX_SIZE 0x00000724
+
+#define CALLER_HEADER 12
+
+static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
+
+static inline int
+testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
+{
+       int ccode;
+
+       asm volatile
+#ifdef __s390x__
+       ("      llgfr   0,%4            \n"
+        "      slgr    1,1             \n"
+        "      lgr     2,1             \n"
+        "0:    .long   0xb2af0000      \n"
+        "1:    ipm     %0              \n"
+        "      srl     %0,28           \n"
+        "      iihh    %0,0            \n"
+        "      iihl    %0,0            \n"
+        "      lgr     %1,1            \n"
+        "      lgr     %3,2            \n"
+        "      srl     %3,24           \n"
+        "      sll     2,24            \n"
+        "      srl     2,24            \n"
+        "      lgr     %2,2            \n"
+        "2:                            \n"
+        ".section .fixup,\"ax\"        \n"
+        "3:                            \n"
+        "      lhi     %0,%h5          \n"
+        "      jg      2b              \n"
+        ".previous                     \n"
+        ".section __ex_table,\"a\"     \n"
+        "      .align  8               \n"
+        "      .quad   0b,3b           \n"
+        "      .quad   1b,3b           \n"
+        ".previous"
+        :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type)
+        :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION)
+        :"cc","0","1","2","memory");
+#else
+       ("      lr      0,%4            \n"
+        "      slr     1,1             \n"
+        "      lr      2,1             \n"
+        "0:    .long   0xb2af0000      \n"
+        "1:    ipm     %0              \n"
+        "      srl     %0,28           \n"
+        "      lr      %1,1            \n"
+        "      lr      %3,2            \n"
+        "      srl     %3,24           \n"
+        "      sll     2,24            \n"
+        "      srl     2,24            \n"
+        "      lr      %2,2            \n"
+        "2:                            \n"
+        ".section .fixup,\"ax\"        \n"
+        "3:                            \n"
+        "      lhi     %0,%h5          \n"
+        "      bras    1,4f            \n"
+        "      .long   2b              \n"
+        "4:                            \n"
+        "      l       1,0(1)          \n"
+        "      br      1               \n"
+        ".previous                     \n"
+        ".section __ex_table,\"a\"     \n"
+        "      .align  4               \n"
+        "      .long   0b,3b           \n"
+        "      .long   1b,3b           \n"
+        ".previous"
+        :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type)
+        :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION)
+        :"cc","0","1","2","memory");
+#endif
+       return ccode;
+}
+
+static inline int
+resetq(int q_nr, struct ap_status_word *stat_p)
+{
+       int ccode;
+
+       asm volatile
+#ifdef __s390x__
+       ("      llgfr   0,%2            \n"
+        "      lghi    1,1             \n"
+        "      sll     1,24            \n"
+        "      or      0,1             \n"
+        "      slgr    1,1             \n"
+        "      lgr     2,1             \n"
+        "0:    .long   0xb2af0000      \n"
+        "1:    ipm     %0              \n"
+        "      srl     %0,28           \n"
+        "      iihh    %0,0            \n"
+        "      iihl    %0,0            \n"
+        "      lgr     %1,1            \n"
+        "2:                            \n"
+        ".section .fixup,\"ax\"        \n"
+        "3:                            \n"
+        "      lhi     %0,%h3          \n"
+        "      jg      2b              \n"
+        ".previous                     \n"
+        ".section __ex_table,\"a\"     \n"
+        "      .align  8               \n"
+        "      .quad   0b,3b           \n"
+        "      .quad   1b,3b           \n"
+        ".previous"
+        :"=d" (ccode),"=d" (*stat_p)
+        :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION)
+        :"cc","0","1","2","memory");
+#else
+       ("      lr      0,%2            \n"
+        "      lhi     1,1             \n"
+        "      sll     1,24            \n"
+        "      or      0,1             \n"
+        "      slr     1,1             \n"
+        "      lr      2,1             \n"
+        "0:    .long   0xb2af0000      \n"
+        "1:    ipm     %0              \n"
+        "      srl     %0,28           \n"
+        "      lr      %1,1            \n"
+        "2:                            \n"
+        ".section .fixup,\"ax\"        \n"
+        "3:                            \n"
+        "      lhi     %0,%h3          \n"
+        "      bras    1,4f            \n"
+        "      .long   2b              \n"
+        "4:                            \n"
+        "      l       1,0(1)          \n"
+        "      br      1               \n"
+        ".previous                     \n"
+        ".section __ex_table,\"a\"     \n"
+        "      .align  4               \n"
+        "      .long   0b,3b           \n"
+        "      .long   1b,3b           \n"
+        ".previous"
+        :"=d" (ccode),"=d" (*stat_p)
+        :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION)
+        :"cc","0","1","2","memory");
+#endif
+       return ccode;
+}
+
+static inline int
+sen(int msg_len, unsigned char *msg_ext, struct ap_status_word *stat)
+{
+       int ccode;
+
+       asm volatile
+#ifdef __s390x__
+       ("      lgr     6,%3            \n"
+        "      llgfr   7,%2            \n"
+        "      llgt    0,0(6)          \n"
+        "      lghi    1,64            \n"
+        "      sll     1,24            \n"
+        "      or      0,1             \n"
+        "      la      6,4(6)          \n"
+        "      llgt    2,0(6)          \n"
+        "      llgt    3,4(6)          \n"
+        "      la      6,8(6)          \n"
+        "      slr     1,1             \n"
+        "0:    .long   0xb2ad0026      \n"
+        "1:    brc     2,0b            \n"
+        "      ipm     %0              \n"
+        "      srl     %0,28           \n"
+        "      iihh    %0,0            \n"
+        "      iihl    %0,0            \n"
+        "      lgr     %1,1            \n"
+        "2:                            \n"
+        ".section .fixup,\"ax\"        \n"
+        "3:                            \n"
+        "      lhi     %0,%h4          \n"
+        "      jg      2b              \n"
+        ".previous                     \n"
+        ".section __ex_table,\"a\"     \n"
+        "      .align  8               \n"
+        "      .quad   0b,3b           \n"
+        "      .quad   1b,3b           \n"
+        ".previous"
+        :"=d" (ccode),"=d" (*stat)
+        :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION)
+        :"cc","0","1","2","3","6","7","memory");
+#else
+       ("      lr      6,%3            \n"
+        "      lr      7,%2            \n"
+        "      l       0,0(6)          \n"
+        "      lhi     1,64            \n"
+        "      sll     1,24            \n"
+        "      or      0,1             \n"
+        "      la      6,4(6)          \n"
+        "      l       2,0(6)          \n"
+        "      l       3,4(6)          \n"
+        "      la      6,8(6)          \n"
+        "      slr     1,1             \n"
+        "0:    .long   0xb2ad0026      \n"
+        "1:    brc     2,0b            \n"
+        "      ipm     %0              \n"
+        "      srl     %0,28           \n"
+        "      lr      %1,1            \n"
+        "2:                            \n"
+        ".section .fixup,\"ax\"        \n"
+        "3:                            \n"
+        "      lhi     %0,%h4          \n"
+        "      bras    1,4f            \n"
+        "      .long   2b              \n"
+        "4:                            \n"
+        "      l       1,0(1)          \n"
+        "      br      1               \n"
+        ".previous                     \n"
+        ".section __ex_table,\"a\"     \n"
+        "      .align  4               \n"
+        "      .long   0b,3b           \n"
+        "      .long   1b,3b           \n"
+        ".previous"
+        :"=d" (ccode),"=d" (*stat)
+        :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION)
+        :"cc","0","1","2","3","6","7","memory");
+#endif
+       return ccode;
+}
+
+static inline int
+rec(int q_nr, int buff_l, unsigned char *rsp, unsigned char *id,
+    struct ap_status_word *st)
+{
+       int ccode;
+
+       asm volatile
+#ifdef __s390x__
+       ("      llgfr   0,%2            \n"
+        "      lgr     3,%4            \n"
+        "      lgr     6,%3            \n"
+        "      llgfr   7,%5            \n"
+        "      lghi    1,128           \n"
+        "      sll     1,24            \n"
+        "      or      0,1             \n"
+        "      slgr    1,1             \n"
+        "      lgr     2,1             \n"
+        "      lgr     4,1             \n"
+        "      lgr     5,1             \n"
+        "0:    .long   0xb2ae0046      \n"
+        "1:    brc     2,0b            \n"
+        "      brc     4,0b            \n"
+        "      ipm     %0              \n"
+        "      srl     %0,28           \n"
+        "      iihh    %0,0            \n"
+        "      iihl    %0,0            \n"
+        "      lgr     %1,1            \n"
+        "      st      4,0(3)          \n"
+        "      st      5,4(3)          \n"
+        "2:                            \n"
+        ".section .fixup,\"ax\"        \n"
+        "3:                            \n"
+        "      lhi   %0,%h6            \n"
+        "      jg    2b                \n"
+        ".previous                     \n"
+        ".section __ex_table,\"a\"     \n"
+        "   .align     8               \n"
+        "   .quad      0b,3b           \n"
+        "   .quad      1b,3b           \n"
+        ".previous"
+        :"=d"(ccode),"=d"(*st)
+        :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION)
+        :"cc","0","1","2","3","4","5","6","7","memory");
+#else
+       ("      lr      0,%2            \n"
+        "      lr      3,%4            \n"
+        "      lr      6,%3            \n"
+        "      lr      7,%5            \n"
+        "      lhi     1,128           \n"
+        "      sll     1,24            \n"
+        "      or      0,1             \n"
+        "      slr     1,1             \n"
+        "      lr      2,1             \n"
+        "      lr      4,1             \n"
+        "      lr      5,1             \n"
+        "0:    .long   0xb2ae0046      \n"
+        "1:    brc     2,0b            \n"
+        "      brc     4,0b            \n"
+        "      ipm     %0              \n"
+        "      srl     %0,28           \n"
+        "      lr      %1,1            \n"
+        "      st      4,0(3)          \n"
+        "      st      5,4(3)          \n"
+        "2:                            \n"
+        ".section .fixup,\"ax\"        \n"
+        "3:                            \n"
+        "      lhi   %0,%h6            \n"
+        "      bras  1,4f              \n"
+        "      .long 2b                \n"
+        "4:                            \n"
+        "      l     1,0(1)            \n"
+        "      br    1                 \n"
+        ".previous                     \n"
+        ".section __ex_table,\"a\"     \n"
+        "   .align     4               \n"
+        "   .long      0b,3b           \n"
+        "   .long      1b,3b           \n"
+        ".previous"
+        :"=d"(ccode),"=d"(*st)
+        :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION)
+        :"cc","0","1","2","3","4","5","6","7","memory");
+#endif
+       return ccode;
+}
+
+static inline void
+itoLe2(int *i_p, unsigned char *lechars)
+{
+       *lechars       = *((unsigned char *) i_p + sizeof(int) - 1);
+       *(lechars + 1) = *((unsigned char *) i_p + sizeof(int) - 2);
+}
+
+static inline void
+le2toI(unsigned char *lechars, int *i_p)
+{
+       unsigned char *ic_p;
+       *i_p = 0;
+       ic_p = (unsigned char *) i_p;
+       *(ic_p + 2) = *(lechars + 1);
+       *(ic_p + 3) = *(lechars);
+}
+
+static inline int
+is_empty(unsigned char *ptr, int len)
+{
+       return !memcmp(ptr, (unsigned char *) &static_pvt_me_key+60, len);
+}
+
+enum hdstat
+query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type)
+{
+       int q_nr, i, t_depth, t_dev_type;
+       enum devstat ccode;
+       struct ap_status_word stat_word;
+       enum hdstat stat;
+       int break_out;
+
+       q_nr = (deviceNr << SKIP_BITL) + cdx;
+       stat = HD_BUSY;
+       ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word);
+       PDEBUG("ccode %d response_code %02X\n", ccode, stat_word.response_code);
+       break_out = 0;
+       for (i = 0; i < resetNr; i++) {
+               if (ccode > 3) {
+                       PRINTKC("Exception testing device %d\n", i);
+                       return HD_TSQ_EXCEPTION;
+               }
+               switch (ccode) {
+               case 0:
+                       PDEBUG("t_dev_type %d\n", t_dev_type);
+                       break_out = 1;
+                       stat = HD_ONLINE;
+                       *q_depth = t_depth + 1;
+                       switch (t_dev_type) {
+                       case OTHER_HW:
+                       case OTHER2_HW:
+                               stat = HD_NOT_THERE;
+                               *dev_type = NILDEV;
+                               break;
+                       case PCICA_HW:
+                               *dev_type = PCICA;
+                               break;
+                       case PCICC_HW:
+                               *dev_type = PCICC;
+                               break;
+                       case PCIXCC_HW:
+                               *dev_type = PCIXCC;
+                               break;
+                       default:
+                               *dev_type = NILDEV;
+                               break;
+                       }
+                       PDEBUG("available device %d: Q depth = %d, dev "
+                              "type = %d, stat = %02X%02X%02X%02X\n",
+                              deviceNr, *q_depth, *dev_type,
+                              stat_word.q_stat_flags,
+                              stat_word.response_code,
+                              stat_word.reserved[0],
+                              stat_word.reserved[1]);
+                       break;
+               case 3:
+                       switch (stat_word.response_code) {
+                       case AP_RESPONSE_NORMAL:
+                               stat = HD_ONLINE;
+                               break_out = 1;
+                               *q_depth = t_depth + 1;
+                               *dev_type = t_dev_type;
+                               PDEBUG("cc3, available device "
+                                      "%d: Q depth = %d, dev "
+                                      "type = %d, stat = "
+                                      "%02X%02X%02X%02X\n",
+                                      deviceNr, *q_depth,
+                                      *dev_type,
+                                      stat_word.q_stat_flags,
+                                      stat_word.response_code,
+                                      stat_word.reserved[0],
+                                      stat_word.reserved[1]);
+                               break;
+                       case AP_RESPONSE_Q_NOT_AVAIL:
+                               stat = HD_NOT_THERE;
+                               break_out = 1;
+                               break;
+                       case AP_RESPONSE_RESET_IN_PROGRESS:
+                               PDEBUG("device %d in reset\n",
+                                      deviceNr);
+                               break;
+                       case AP_RESPONSE_DECONFIGURED:
+                               stat = HD_DECONFIGURED;
+                               break_out = 1;
+                               break;
+                       case AP_RESPONSE_CHECKSTOPPED:
+                               stat = HD_CHECKSTOPPED;
+                               break_out = 1;
+                               break;
+                       case AP_RESPONSE_BUSY:
+                               PDEBUG("device %d busy\n",
+                                      deviceNr);
+                               break;
+                       default:
+                               break;
+                       }
+                       break;
+               default:
+                       stat = HD_NOT_THERE;
+                       break_out = 1;
+               }
+               if (break_out)
+                       break;
+
+               udelay(5);
+
+               ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word);
+       }
+       return stat;
+}
+
+enum devstat
+reset_device(int deviceNr, int cdx, int resetNr)
+{
+       int q_nr, ccode = 0, dummy_qdepth, dummy_devType, i;
+       struct ap_status_word stat_word;
+       enum devstat stat;
+       int break_out;
+
+       q_nr = (deviceNr << SKIP_BITL) + cdx;
+       stat = DEV_GONE;
+       ccode = resetq(q_nr, &stat_word);
+       if (ccode > 3)
+               return DEV_RSQ_EXCEPTION;
+
+       break_out = 0;
+       for (i = 0; i < resetNr; i++) {
+               switch (ccode) {
+               case 0:
+                       stat = DEV_ONLINE;
+                       if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
+                               break_out = 1;
+                       break;
+               case 3:
+                       switch (stat_word.response_code) {
+                       case AP_RESPONSE_NORMAL:
+                               stat = DEV_ONLINE;
+                               if (stat_word.q_stat_flags &
+                                   AP_Q_STATUS_EMPTY)
+                                       break_out = 1;
+                               break;
+                       case AP_RESPONSE_Q_NOT_AVAIL:
+                               stat = DEV_GONE;
+                               break_out = 1;
+                               break;
+                       case AP_RESPONSE_DECONFIGURED:
+                               stat = DEV_GONE;
+                               break_out = 1;
+                               break;
+                       case AP_RESPONSE_CHECKSTOPPED:
+                               stat = DEV_GONE;
+                               break_out = 1;
+                               break;
+                       case AP_RESPONSE_RESET_IN_PROGRESS:
+                       case AP_RESPONSE_BUSY:
+                       default:
+                               break;
+                       }
+                       break;
+               default:
+                       stat = DEV_GONE;
+                       break_out = 1;
+               }
+               if (break_out == 1)
+                       break;
+               udelay(5);
+
+               ccode = testq(q_nr, &dummy_qdepth, &dummy_devType, &stat_word);
+               if (ccode > 3) {
+                       stat = DEV_TSQ_EXCEPTION;
+                       break;
+               }
+       }
+       PDEBUG("Number of testq's needed for reset: %d\n", i);
+
+       if (i >= resetNr) {
+         stat = DEV_GONE;
+       }
+
+       return stat;
+}
+
+#ifdef DEBUG_HYDRA_MSGS
+static inline void
+print_buffer(unsigned char *buffer, int bufflen)
+{
+       int i;
+       for (i = 0; i < bufflen; i += 16) {
+               PRINTK("%04X: %02X%02X%02X%02X %02X%02X%02X%02X "
+                      "%02X%02X%02X%02X %02X%02X%02X%02X\n", i,
+                      buffer[i+0], buffer[i+1], buffer[i+2], buffer[i+3],
+                      buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7],
+                      buffer[i+8], buffer[i+9], buffer[i+10], buffer[i+11],
+                      buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]);
+       }
+}
+#endif
+
+enum devstat
+send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext)
+{
+       struct ap_status_word stat_word;
+       enum devstat stat;
+       int ccode;
+
+       ((struct request_msg_ext *) msg_ext)->q_nr =
+               (dev_nr << SKIP_BITL) + cdx;
+       PDEBUG("msg_len passed to sen: %d\n", msg_len);
+       PDEBUG("q number passed to sen: %02x%02x%02x%02x\n",
+              msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3]);
+       stat = DEV_GONE;
+
+#ifdef DEBUG_HYDRA_MSGS
+       PRINTK("Request header: %02X%02X%02X%02X %02X%02X%02X%02X "
+              "%02X%02X%02X%02X\n",
+              msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3],
+              msg_ext[4], msg_ext[5], msg_ext[6], msg_ext[7],
+              msg_ext[8], msg_ext[9], msg_ext[10], msg_ext[11]);
+       print_buffer(msg_ext+12, msg_len);
+#endif
+
+       ccode = sen(msg_len, msg_ext, &stat_word);
+       if (ccode > 3)
+               return DEV_SEN_EXCEPTION;
+
+       PDEBUG("nq cc: %u, st: %02x%02x%02x%02x\n",
+              ccode, stat_word.q_stat_flags, stat_word.response_code,
+              stat_word.reserved[0], stat_word.reserved[1]);
+       switch (ccode) {
+       case 0:
+               stat = DEV_ONLINE;
+               break;
+       case 1:
+               stat = DEV_GONE;
+               break;
+       case 3:
+               switch (stat_word.response_code) {
+               case AP_RESPONSE_NORMAL:
+                       stat = DEV_ONLINE;
+                       break;
+               case AP_RESPONSE_Q_FULL:
+                       stat = DEV_QUEUE_FULL;
+                       break;
+               default:
+                       stat = DEV_GONE;
+                       break;
+               }
+               break;
+       default:
+               stat = DEV_GONE;
+       }
+
+       return stat;
+}
+
+enum devstat
+receive_from_AP(int dev_nr, int cdx, int resplen,
+               unsigned char *resp, unsigned char *psmid)
+{
+       int ccode;
+       struct ap_status_word stat_word;
+       enum devstat stat;
+
+       memset(resp, 0x00, 8);
+
+       ccode = rec((dev_nr << SKIP_BITL) + cdx, resplen, resp, psmid,
+                   &stat_word);
+       if (ccode > 3)
+               return DEV_REC_EXCEPTION;
+
+       PDEBUG("dq cc: %u, st: %02x%02x%02x%02x\n",
+              ccode, stat_word.q_stat_flags, stat_word.response_code,
+              stat_word.reserved[0], stat_word.reserved[1]);
+
+       stat = DEV_GONE;
+       switch (ccode) {
+       case 0:
+               stat = DEV_ONLINE;
+#ifdef DEBUG_HYDRA_MSGS
+               print_buffer(resp, resplen);
+#endif
+               break;
+       case 3:
+               switch (stat_word.response_code) {
+               case AP_RESPONSE_NORMAL:
+                       stat = DEV_ONLINE;
+                       break;
+               case AP_RESPONSE_NO_PENDING_REPLY:
+                       if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
+                               stat = DEV_EMPTY;
+                       else
+                               stat = DEV_NO_WORK;
+                       break;
+               case AP_RESPONSE_INDEX_TOO_BIG:
+               case AP_RESPONSE_NO_FIRST_PART:
+               case AP_RESPONSE_MESSAGE_TOO_BIG:
+                       stat = DEV_BAD_MESSAGE;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return stat;
+}
+
+static inline int
+pad_msg(unsigned char *buffer, int  totalLength, int msgLength)
+{
+       int pad_len;
+
+       for (pad_len = 0; pad_len < (totalLength - msgLength); pad_len++)
+               if (buffer[pad_len] != 0x00)
+                       break;
+       pad_len -= 3;
+       if (pad_len < 8)
+               return SEN_PAD_ERROR;
+
+       buffer[0] = 0x00;
+       buffer[1] = 0x02;
+
+       memcpy(buffer+2, static_pad, pad_len);
+
+       buffer[pad_len + 2] = 0x00;
+
+       return 0;
+}
+
+static inline int
+is_common_public_key(unsigned char *key, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++)
+               if (key[i])
+                       break;
+       key += i;
+       len -= i;
+       if (((len == 1) && (key[0] == 3)) ||
+           ((len == 3) && (key[0] == 1) && (key[1] == 0) && (key[2] == 1)))
+               return 1;
+
+       return 0;
+}
+
+static int
+ICAMEX_msg_to_type4MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
+                          union type4_msg *z90cMsg_p)
+{
+       int mod_len, msg_size, mod_tgt_len, exp_tgt_len, inp_tgt_len;
+       unsigned char *mod_tgt, *exp_tgt, *inp_tgt;
+       union type4_msg *tmp_type4_msg;
+
+       mod_len = icaMex_p->inputdatalength;
+
+       msg_size = ((mod_len <= 128) ? TYPE4_SME_LEN : TYPE4_LME_LEN) +
+                   CALLER_HEADER;
+
+       memset(z90cMsg_p, 0, msg_size);
+
+       tmp_type4_msg = (union type4_msg *)
+               ((unsigned char *) z90cMsg_p + CALLER_HEADER);
+
+       tmp_type4_msg->sme.header.msg_type_code = TYPE4_TYPE_CODE;
+       tmp_type4_msg->sme.header.request_code = TYPE4_REQU_CODE;
+
+       if (mod_len <= 128) {
+               tmp_type4_msg->sme.header.msg_fmt = TYPE4_SME_FMT;
+               tmp_type4_msg->sme.header.msg_len = TYPE4_SME_LEN;
+               mod_tgt = tmp_type4_msg->sme.modulus;
+               mod_tgt_len = sizeof(tmp_type4_msg->sme.modulus);
+               exp_tgt = tmp_type4_msg->sme.exponent;
+               exp_tgt_len = sizeof(tmp_type4_msg->sme.exponent);
+               inp_tgt = tmp_type4_msg->sme.message;
+               inp_tgt_len = sizeof(tmp_type4_msg->sme.message);
+       } else {
+               tmp_type4_msg->lme.header.msg_fmt = TYPE4_LME_FMT;
+               tmp_type4_msg->lme.header.msg_len = TYPE4_LME_LEN;
+               mod_tgt = tmp_type4_msg->lme.modulus;
+               mod_tgt_len = sizeof(tmp_type4_msg->lme.modulus);
+               exp_tgt = tmp_type4_msg->lme.exponent;
+               exp_tgt_len = sizeof(tmp_type4_msg->lme.exponent);
+               inp_tgt = tmp_type4_msg->lme.message;
+               inp_tgt_len = sizeof(tmp_type4_msg->lme.message);
+       }
+
+       mod_tgt += (mod_tgt_len - mod_len);
+       if (copy_from_user(mod_tgt, icaMex_p->n_modulus, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(mod_tgt, mod_len))
+               return SEN_USER_ERROR;
+       exp_tgt += (exp_tgt_len - mod_len);
+       if (copy_from_user(exp_tgt, icaMex_p->b_key, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(exp_tgt, mod_len))
+               return SEN_USER_ERROR;
+       inp_tgt += (inp_tgt_len - mod_len);
+       if (copy_from_user(inp_tgt, icaMex_p->inputdata, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(inp_tgt, mod_len))
+               return SEN_USER_ERROR;
+
+       *z90cMsg_l_p = msg_size - CALLER_HEADER;
+
+       return 0;
+}
+
+static int
+ICACRT_msg_to_type4CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
+                          int *z90cMsg_l_p, union type4_msg *z90cMsg_p)
+{
+       int mod_len, short_len, long_len, tmp_size, p_tgt_len, q_tgt_len,
+           dp_tgt_len, dq_tgt_len, u_tgt_len, inp_tgt_len;
+       unsigned char *p_tgt, *q_tgt, *dp_tgt, *dq_tgt, *u_tgt, *inp_tgt;
+       union type4_msg *tmp_type4_msg;
+
+       mod_len = icaMsg_p->inputdatalength;
+       short_len = mod_len / 2;
+       long_len = mod_len / 2 + 8;
+
+       tmp_size = ((mod_len <= 128) ? TYPE4_SCR_LEN : TYPE4_LCR_LEN) +
+                   CALLER_HEADER;
+
+       memset(z90cMsg_p, 0, tmp_size);
+
+       tmp_type4_msg = (union type4_msg *)
+               ((unsigned char *) z90cMsg_p + CALLER_HEADER);
+
+       tmp_type4_msg->scr.header.msg_type_code = TYPE4_TYPE_CODE;
+       tmp_type4_msg->scr.header.request_code = TYPE4_REQU_CODE;
+       if (mod_len <= 128) {
+               tmp_type4_msg->scr.header.msg_fmt = TYPE4_SCR_FMT;
+               tmp_type4_msg->scr.header.msg_len = TYPE4_SCR_LEN;
+               p_tgt = tmp_type4_msg->scr.p;
+               p_tgt_len = sizeof(tmp_type4_msg->scr.p);
+               q_tgt = tmp_type4_msg->scr.q;
+               q_tgt_len = sizeof(tmp_type4_msg->scr.q);
+               dp_tgt = tmp_type4_msg->scr.dp;
+               dp_tgt_len = sizeof(tmp_type4_msg->scr.dp);
+               dq_tgt = tmp_type4_msg->scr.dq;
+               dq_tgt_len = sizeof(tmp_type4_msg->scr.dq);
+               u_tgt = tmp_type4_msg->scr.u;
+               u_tgt_len = sizeof(tmp_type4_msg->scr.u);
+               inp_tgt = tmp_type4_msg->scr.message;
+               inp_tgt_len = sizeof(tmp_type4_msg->scr.message);
+       } else {
+               tmp_type4_msg->lcr.header.msg_fmt = TYPE4_LCR_FMT;
+               tmp_type4_msg->lcr.header.msg_len = TYPE4_LCR_LEN;
+               p_tgt = tmp_type4_msg->lcr.p;
+               p_tgt_len = sizeof(tmp_type4_msg->lcr.p);
+               q_tgt = tmp_type4_msg->lcr.q;
+               q_tgt_len = sizeof(tmp_type4_msg->lcr.q);
+               dp_tgt = tmp_type4_msg->lcr.dp;
+               dp_tgt_len = sizeof(tmp_type4_msg->lcr.dp);
+               dq_tgt = tmp_type4_msg->lcr.dq;
+               dq_tgt_len = sizeof(tmp_type4_msg->lcr.dq);
+               u_tgt = tmp_type4_msg->lcr.u;
+               u_tgt_len = sizeof(tmp_type4_msg->lcr.u);
+               inp_tgt = tmp_type4_msg->lcr.message;
+               inp_tgt_len = sizeof(tmp_type4_msg->lcr.message);
+       }
+
+       p_tgt += (p_tgt_len - long_len);
+       if (copy_from_user(p_tgt, icaMsg_p->np_prime, long_len))
+               return SEN_RELEASED;
+       if (is_empty(p_tgt, long_len))
+               return SEN_USER_ERROR;
+       q_tgt += (q_tgt_len - short_len);
+       if (copy_from_user(q_tgt, icaMsg_p->nq_prime, short_len))
+               return SEN_RELEASED;
+       if (is_empty(q_tgt, short_len))
+               return SEN_USER_ERROR;
+       dp_tgt += (dp_tgt_len - long_len);
+       if (copy_from_user(dp_tgt, icaMsg_p->bp_key, long_len))
+               return SEN_RELEASED;
+       if (is_empty(dp_tgt, long_len))
+               return SEN_USER_ERROR;
+       dq_tgt += (dq_tgt_len - short_len);
+       if (copy_from_user(dq_tgt, icaMsg_p->bq_key, short_len))
+               return SEN_RELEASED;
+       if (is_empty(dq_tgt, short_len))
+               return SEN_USER_ERROR;
+       u_tgt += (u_tgt_len - long_len);
+       if (copy_from_user(u_tgt, icaMsg_p->u_mult_inv, long_len))
+               return SEN_RELEASED;
+       if (is_empty(u_tgt, long_len))
+               return SEN_USER_ERROR;
+       inp_tgt += (inp_tgt_len - mod_len);
+       if (copy_from_user(inp_tgt, icaMsg_p->inputdata, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(inp_tgt, mod_len))
+               return SEN_USER_ERROR;
+
+       *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
+       return 0;
+}
+
+static int
+ICAMEX_msg_to_type6MEX_de_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
+                             int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+{
+       int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
+       unsigned char *temp;
+       struct type6_hdr *tp6Hdr_p;
+       struct CPRB *cprb_p;
+       struct cca_private_ext_ME *key_p;
+
+       mod_len = icaMsg_p->inputdatalength;
+       tmp_size = FIXED_TYPE6_ME_LEN + mod_len;
+       total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
+       parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
+       tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
+
+       memset(z90cMsg_p, 0, tmp_size);
+
+       temp = (unsigned char *)z90cMsg_p + CALLER_HEADER;
+       memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr));
+       tp6Hdr_p = (struct type6_hdr *)temp;
+       tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
+       tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
+
+       temp += sizeof(struct type6_hdr);
+       memcpy(temp, &static_cprb, sizeof(struct CPRB));
+       cprb_p = (struct CPRB *) temp;
+       cprb_p->usage_domain[0]= (unsigned char)cdx;
+       itoLe2(&parmBlock_l, cprb_p->req_parml);
+       itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml);
+
+       temp += sizeof(struct CPRB);
+       memcpy(temp, &static_pkd_function_and_rules,
+              sizeof(struct function_and_rules_block));
+
+       temp += sizeof(struct function_and_rules_block);
+       vud_len = 2 + icaMsg_p->inputdatalength;
+       itoLe2(&vud_len, temp);
+
+       temp += 2;
+       if (copy_from_user(temp, icaMsg_p->inputdata, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(temp, mod_len))
+               return SEN_USER_ERROR;
+
+       temp += mod_len;
+       memcpy(temp, &static_T6_keyBlock_hdr, sizeof(struct T6_keyBlock_hdr));
+
+       temp += sizeof(struct T6_keyBlock_hdr);
+       memcpy(temp, &static_pvt_me_key, sizeof(struct cca_private_ext_ME));
+       key_p = (struct cca_private_ext_ME *)temp;
+       temp = key_p->pvtMESec.exponent + sizeof(key_p->pvtMESec.exponent)
+              - mod_len;
+       if (copy_from_user(temp, icaMsg_p->b_key, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(temp, mod_len))
+               return SEN_USER_ERROR;
+
+       if (is_common_public_key(temp, mod_len)) {
+               PRINTK("Common public key used for modex decrypt\n");
+               return SEN_NOT_AVAIL;
+       }
+
+       temp = key_p->pvtMESec.modulus + sizeof(key_p->pvtMESec.modulus)
+              - mod_len;
+       if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len) != 0)
+               return SEN_RELEASED;
+       if (is_empty(temp, mod_len))
+               return SEN_USER_ERROR;
+
+       key_p->pubMESec.modulus_bit_len = 8 * mod_len;
+
+       *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
+       return 0;
+}
+
+static int
+ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
+                             int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+{
+       int mod_len, vud_len, exp_len, key_len;
+       int pad_len, tmp_size, total_CPRB_len, parmBlock_l, i;
+       unsigned char temp_exp[256], *exp_p, *temp;
+       struct type6_hdr *tp6Hdr_p;
+       struct CPRB *cprb_p;
+       struct cca_public_key *key_p;
+       struct T6_keyBlock_hdr *keyb_p;
+
+       mod_len = icaMsg_p->inputdatalength;
+       if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(temp_exp, mod_len))
+               return SEN_USER_ERROR;
+
+       exp_p = temp_exp;
+       for (i = 0; i < mod_len; i++)
+               if (exp_p[i])
+                       break;
+       if (i >= mod_len)
+               return SEN_USER_ERROR;
+
+       exp_len = mod_len - i;
+       exp_p += i;
+
+       PDEBUG("exp_len after computation: %08x\n", exp_len);
+       tmp_size = FIXED_TYPE6_ME_EN_LEN + 2 * mod_len + exp_len;
+       total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
+       parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
+       tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
+
+       vud_len = 2 + mod_len;
+       memset(z90cMsg_p, 0, tmp_size);
+
+       temp = (unsigned char *)z90cMsg_p + CALLER_HEADER;
+       memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr));
+       tp6Hdr_p = (struct type6_hdr *)temp;
+       tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
+       tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
+       memcpy(tp6Hdr_p->function_code, static_PKE_function_code,
+              sizeof(static_PKE_function_code));
+       temp += sizeof(struct type6_hdr);
+       memcpy(temp, &static_cprb, sizeof(struct CPRB));
+       cprb_p = (struct CPRB *) temp;
+       cprb_p->usage_domain[0]= (unsigned char)cdx;
+       itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml);
+       temp += sizeof(struct CPRB);
+       memcpy(temp, &static_pke_function_and_rules,
+                sizeof(struct function_and_rules_block));
+       temp += sizeof(struct function_and_rules_block);
+       temp += 2;
+       if (copy_from_user(temp, icaMsg_p->inputdata, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(temp, mod_len))
+               return SEN_USER_ERROR;
+       if (temp[0] != 0x00 || temp[1] != 0x02)
+               return SEN_NOT_AVAIL;
+       for (i = 2; i < mod_len; i++)
+               if (temp[i] == 0x00)
+                       break;
+       if ((i < 9) || (i > (mod_len - 2)))
+               return SEN_NOT_AVAIL;
+       pad_len = i + 1;
+       vud_len = mod_len - pad_len;
+       memmove(temp, temp+pad_len, vud_len);
+       temp -= 2;
+       vud_len += 2;
+       itoLe2(&vud_len, temp);
+       temp += (vud_len);
+       keyb_p = (struct T6_keyBlock_hdr *)temp;
+       temp += sizeof(struct T6_keyBlock_hdr);
+       memcpy(temp, &static_public_key, sizeof(static_public_key));
+       key_p = (struct cca_public_key *)temp;
+       temp = key_p->pubSec.exponent;
+       memcpy(temp, exp_p, exp_len);
+       temp += exp_len;
+       if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(temp, mod_len))
+               return SEN_USER_ERROR;
+       key_p->pubSec.modulus_bit_len = 8 * mod_len;
+       key_p->pubSec.modulus_byte_len = mod_len;
+       key_p->pubSec.exponent_len = exp_len;
+       key_p->pubSec.section_length = 12 + mod_len + exp_len;
+       key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
+       key_p->pubHdr.token_length = key_len;
+       key_len += 4;
+       itoLe2(&key_len, keyb_p->ulen);
+       key_len += 2;
+       itoLe2(&key_len, keyb_p->blen);
+       parmBlock_l -= pad_len;
+       itoLe2(&parmBlock_l, cprb_p->req_parml);
+       *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
+       return 0;
+}
+
+static int
+ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
+                          int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+{
+       int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len;
+       int long_len, pad_len, keyPartsLen, tmp_l;
+       unsigned char *tgt_p, *temp;
+       struct type6_hdr *tp6Hdr_p;
+       struct CPRB *cprb_p;
+       struct cca_token_hdr *keyHdr_p;
+       struct cca_pvt_ext_CRT_sec *pvtSec_p;
+       struct cca_public_sec *pubSec_p;
+
+       mod_len = icaMsg_p->inputdatalength;
+       short_len = mod_len / 2;
+       long_len = 8 + short_len;
+       keyPartsLen = 3 * long_len + 2 * short_len;
+       pad_len = (8 - (keyPartsLen % 8)) % 8;
+       keyPartsLen += pad_len + mod_len;
+       tmp_size = FIXED_TYPE6_CR_LEN + keyPartsLen + mod_len;
+       total_CPRB_len = tmp_size -  sizeof(struct type6_hdr);
+       parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
+       vud_len = 2 + mod_len;
+       tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
+
+       memset(z90cMsg_p, 0, tmp_size);
+       tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
+       memcpy(tgt_p, &static_type6_hdr, sizeof(struct type6_hdr));
+       tp6Hdr_p = (struct type6_hdr *)tgt_p;
+       tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
+       tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
+       tgt_p += sizeof(struct type6_hdr);
+       cprb_p = (struct CPRB *) tgt_p;
+       memcpy(tgt_p, &static_cprb, sizeof(struct CPRB));
+       cprb_p->usage_domain[0]= *((unsigned char *)(&(cdx))+3);
+       itoLe2(&parmBlock_l, cprb_p->req_parml);
+       memcpy(cprb_p->rpl_parml, cprb_p->req_parml,
+              sizeof(cprb_p->req_parml));
+       tgt_p += sizeof(struct CPRB);
+       memcpy(tgt_p, &static_pkd_function_and_rules,
+              sizeof(struct function_and_rules_block));
+       tgt_p += sizeof(struct function_and_rules_block);
+       itoLe2(&vud_len, tgt_p);
+       tgt_p += 2;
+       if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, mod_len))
+               return SEN_USER_ERROR;
+       tgt_p += mod_len;
+       tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) +
+               sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen;
+       itoLe2(&tmp_l, tgt_p);
+       temp = tgt_p + 2;
+       tmp_l -= 2;
+       itoLe2(&tmp_l, temp);
+       tgt_p += sizeof(struct T6_keyBlock_hdr);
+       keyHdr_p = (struct cca_token_hdr *)tgt_p;
+       keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT;
+       tmp_l -= 4;
+       keyHdr_p->token_length = tmp_l;
+       tgt_p += sizeof(struct cca_token_hdr);
+       pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p;
+       pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
+       pvtSec_p->section_length =
+               sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen;
+       pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
+       pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL;
+       pvtSec_p->p_len = long_len;
+       pvtSec_p->q_len = short_len;
+       pvtSec_p->dp_len = long_len;
+       pvtSec_p->dq_len = short_len;
+       pvtSec_p->u_len = long_len;
+       pvtSec_p->mod_len = mod_len;
+       pvtSec_p->pad_len = pad_len;
+       tgt_p += sizeof(struct cca_pvt_ext_CRT_sec);
+       if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, long_len))
+               return SEN_USER_ERROR;
+       tgt_p += long_len;
+       if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, short_len))
+               return SEN_USER_ERROR;
+       tgt_p += short_len;
+       if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, long_len))
+               return SEN_USER_ERROR;
+       tgt_p += long_len;
+       if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, short_len))
+               return SEN_USER_ERROR;
+       tgt_p += short_len;
+       if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, long_len))
+               return SEN_USER_ERROR;
+       tgt_p += long_len;
+       tgt_p += pad_len;
+       memset(tgt_p, 0xFF, mod_len);
+       tgt_p += mod_len;
+       memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec));
+       pubSec_p = (struct cca_public_sec *) tgt_p;
+       pubSec_p->modulus_bit_len = 8 * mod_len;
+       *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
+       return 0;
+}
+
+static int
+ICAMEX_msg_to_type6MEX_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
+                           int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+{
+       int mod_len, exp_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
+       int key_len, i;
+       unsigned char temp_exp[256], *tgt_p, *temp, *exp_p;
+       struct type6_hdr *tp6Hdr_p;
+       struct CPRBX *cprbx_p;
+       struct cca_public_key *key_p;
+       struct T6_keyBlock_hdrX *keyb_p;
+
+       mod_len = icaMsg_p->inputdatalength;
+       if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(temp_exp, mod_len))
+               return SEN_USER_ERROR;
+       exp_p = temp_exp;
+       for (i = 0; i < mod_len; i++)
+               if (exp_p[i])
+                       break;
+       if (i >= mod_len)
+               return SEN_USER_ERROR;
+       exp_len = mod_len - i;
+       exp_p += i;
+       PDEBUG("exp_len after computation: %08x\n", exp_len);
+       tmp_size = FIXED_TYPE6_ME_EN_LENX + 2 * mod_len + exp_len;
+       total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
+       parmBlock_l = total_CPRB_len - sizeof(struct CPRBX);
+       tmp_size = tmp_size + CALLER_HEADER;
+       vud_len = 2 + mod_len;
+       memset(z90cMsg_p, 0, tmp_size);
+       tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
+       memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr));
+       tp6Hdr_p = (struct type6_hdr *)tgt_p;
+       tp6Hdr_p->ToCardLen1 = total_CPRB_len;
+       tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE;
+       memcpy(tp6Hdr_p->function_code, static_PKE_function_code,
+              sizeof(static_PKE_function_code));
+       tgt_p += sizeof(struct type6_hdr);
+       memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX));
+       cprbx_p = (struct CPRBX *) tgt_p;
+       cprbx_p->domain = (unsigned short)cdx;
+       cprbx_p->rpl_msgbl = RESPONSE_CPRBX_SIZE;
+       tgt_p += sizeof(struct CPRBX);
+       memcpy(tgt_p, &static_pke_function_and_rulesX,
+              sizeof(struct function_and_rules_block));
+       tgt_p += sizeof(struct function_and_rules_block);
+
+       tgt_p += 2;
+       if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
+             return SEN_RELEASED;
+       if (is_empty(tgt_p, mod_len))
+             return SEN_USER_ERROR;
+       tgt_p -= 2;
+       *((short *)tgt_p) = (short) vud_len;
+       tgt_p += vud_len;
+       keyb_p = (struct T6_keyBlock_hdrX *)tgt_p;
+       tgt_p += sizeof(struct T6_keyBlock_hdrX);
+       memcpy(tgt_p, &static_public_key, sizeof(static_public_key));
+       key_p = (struct cca_public_key *)tgt_p;
+       temp = key_p->pubSec.exponent;
+       memcpy(temp, exp_p, exp_len);
+       temp += exp_len;
+       if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
+             return SEN_RELEASED;
+       if (is_empty(temp, mod_len))
+             return SEN_USER_ERROR;
+       key_p->pubSec.modulus_bit_len = 8 * mod_len;
+       key_p->pubSec.modulus_byte_len = mod_len;
+       key_p->pubSec.exponent_len = exp_len;
+       key_p->pubSec.section_length = 12 + mod_len + exp_len;
+       key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
+       key_p->pubHdr.token_length = key_len;
+       key_len += 4;
+       keyb_p->ulen = (unsigned short)key_len;
+       key_len += 2;
+       keyb_p->blen = (unsigned short)key_len;
+       cprbx_p->req_parml = parmBlock_l;
+       *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
+       return 0;
+}
+
+static int
+ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
+                           int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
+{
+       int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len;
+       int long_len, pad_len, keyPartsLen, tmp_l;
+       unsigned char *tgt_p, *temp;
+       struct type6_hdr *tp6Hdr_p;
+       struct CPRBX *cprbx_p;
+       struct cca_token_hdr *keyHdr_p;
+       struct cca_pvt_ext_CRT_sec *pvtSec_p;
+       struct cca_public_sec *pubSec_p;
+
+       mod_len = icaMsg_p->inputdatalength;
+       short_len = mod_len / 2;
+       long_len = 8 + short_len;
+       keyPartsLen = 3 * long_len + 2 * short_len;
+       pad_len = (8 - (keyPartsLen % 8)) % 8;
+       keyPartsLen += pad_len + mod_len;
+       tmp_size = FIXED_TYPE6_CR_LENX + keyPartsLen + mod_len;
+       total_CPRB_len = tmp_size -  sizeof(struct type6_hdr);
+       parmBlock_l = total_CPRB_len - sizeof(struct CPRBX);
+       vud_len = 2 + mod_len;
+       tmp_size = tmp_size + CALLER_HEADER;
+       memset(z90cMsg_p, 0, tmp_size);
+       tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
+       memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr));
+       tp6Hdr_p = (struct type6_hdr *)tgt_p;
+       tp6Hdr_p->ToCardLen1 = total_CPRB_len;
+       tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE;
+       tgt_p += sizeof(struct type6_hdr);
+       cprbx_p = (struct CPRBX *) tgt_p;
+       memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX));
+       cprbx_p->domain = (unsigned short)cdx;
+       cprbx_p->req_parml = parmBlock_l;
+       cprbx_p->rpl_msgbl = parmBlock_l;
+       tgt_p += sizeof(struct CPRBX);
+       memcpy(tgt_p, &static_pkd_function_and_rulesX,
+              sizeof(struct function_and_rules_block));
+       tgt_p += sizeof(struct function_and_rules_block);
+       *((short *)tgt_p) = (short) vud_len;
+       tgt_p += 2;
+       if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, mod_len))
+               return SEN_USER_ERROR;
+       tgt_p += mod_len;
+       tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) +
+               sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen;
+       *((short *)tgt_p) = (short) tmp_l;
+       temp = tgt_p + 2;
+       tmp_l -= 2;
+       *((short *)temp) = (short) tmp_l;
+       tgt_p += sizeof(struct T6_keyBlock_hdr);
+       keyHdr_p = (struct cca_token_hdr *)tgt_p;
+       keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT;
+       tmp_l -= 4;
+       keyHdr_p->token_length = tmp_l;
+       tgt_p += sizeof(struct cca_token_hdr);
+       pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p;
+       pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
+       pvtSec_p->section_length =
+               sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen;
+       pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
+       pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL;
+       pvtSec_p->p_len = long_len;
+       pvtSec_p->q_len = short_len;
+       pvtSec_p->dp_len = long_len;
+       pvtSec_p->dq_len = short_len;
+       pvtSec_p->u_len = long_len;
+       pvtSec_p->mod_len = mod_len;
+       pvtSec_p->pad_len = pad_len;
+       tgt_p += sizeof(struct cca_pvt_ext_CRT_sec);
+       if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, long_len))
+               return SEN_USER_ERROR;
+       tgt_p += long_len;
+       if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, short_len))
+               return SEN_USER_ERROR;
+       tgt_p += short_len;
+       if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, long_len))
+               return SEN_USER_ERROR;
+       tgt_p += long_len;
+       if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, short_len))
+               return SEN_USER_ERROR;
+       tgt_p += short_len;
+       if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len))
+               return SEN_RELEASED;
+       if (is_empty(tgt_p, long_len))
+               return SEN_USER_ERROR;
+       tgt_p += long_len;
+       tgt_p += pad_len;
+       memset(tgt_p, 0xFF, mod_len);
+       tgt_p += mod_len;
+       memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec));
+       pubSec_p = (struct cca_public_sec *) tgt_p;
+       pubSec_p->modulus_bit_len = 8 * mod_len;
+       *z90cMsg_l_p = tmp_size - CALLER_HEADER;
+
+       return 0;
+}
+
+int
+convert_request(unsigned char *buffer, int func, unsigned short function,
+               int cdx, int dev_type, int *msg_l_p, unsigned char *msg_p)
+{
+       if (dev_type == PCICA) {
+               if (func == ICARSACRT)
+                       return ICACRT_msg_to_type4CRT_msg(
+                               (struct ica_rsa_modexpo_crt *) buffer,
+                               msg_l_p, (union type4_msg *) msg_p);
+               else
+                       return ICAMEX_msg_to_type4MEX_msg(
+                               (struct ica_rsa_modexpo *) buffer,
+                               msg_l_p, (union type4_msg *) msg_p);
+       }
+       if (dev_type == PCICC) {
+               if (func == ICARSACRT)
+                       return ICACRT_msg_to_type6CRT_msg(
+                               (struct ica_rsa_modexpo_crt *) buffer,
+                               cdx, msg_l_p, (struct type6_msg *)msg_p);
+               if (function == PCI_FUNC_KEY_ENCRYPT)
+                       return ICAMEX_msg_to_type6MEX_en_msg(
+                               (struct ica_rsa_modexpo *) buffer,
+                               cdx, msg_l_p, (struct type6_msg *) msg_p);
+               else
+                       return ICAMEX_msg_to_type6MEX_de_msg(
+                               (struct ica_rsa_modexpo *) buffer,
+                               cdx, msg_l_p, (struct type6_msg *) msg_p);
+       }
+       if (dev_type == PCIXCC) {
+               if (func == ICARSACRT)
+                       return ICACRT_msg_to_type6CRT_msgX(
+                               (struct ica_rsa_modexpo_crt *) buffer,
+                               cdx, msg_l_p, (struct type6_msg *) msg_p);
+               else
+                       return ICAMEX_msg_to_type6MEX_msgX(
+                               (struct ica_rsa_modexpo *) buffer,
+                               cdx, msg_l_p, (struct type6_msg *) msg_p);
+       }
+
+       return 0;
+}
+
+int
+convert_response(unsigned char *response, unsigned char *buffer,
+                int *respbufflen_p, unsigned char *resp_buff)
+{
+       struct ica_rsa_modexpo *icaMsg_p = (struct ica_rsa_modexpo *) buffer;
+       struct type82_hdr *t82h_p = (struct type82_hdr *) response;
+       struct type84_hdr *t84h_p = (struct type84_hdr *) response;
+       struct type86_hdr *t86h_p = (struct type86_hdr *) response;
+       int rv, reply_code, service_rc, service_rs, src_l;
+       unsigned char *src_p, *tgt_p;
+       struct CPRB *cprb_p;
+       struct CPRBX *cprbx_p;
+
+       src_p = 0;
+       reply_code = 0;
+       service_rc = 0;
+       service_rs = 0;
+       src_l = 0;
+       rv = 0;
+       switch (t82h_p->type) {
+       case TYPE82_RSP_CODE:
+               reply_code = t82h_p->reply_code;
+               rv = 4;
+               src_p = (unsigned char *)t82h_p;
+               PRINTK("Hardware error: Type 82 Message Header: "
+                      "%02x%02x%02x%02x%02x%02x%02x%02x\n",
+                      src_p[0], src_p[1], src_p[2], src_p[3],
+                      src_p[4], src_p[5], src_p[6], src_p[7]);
+               break;
+       case TYPE84_RSP_CODE:
+               src_l = icaMsg_p->outputdatalength;
+               src_p = response + (int)t84h_p->len - src_l;
+               break;
+       case TYPE86_RSP_CODE:
+               reply_code = t86h_p->reply_code;
+               if (t86h_p->format != TYPE86_FMT2) {
+                       rv = 4;
+                       break;
+               }
+               if (reply_code != 0) {
+                       rv = 4;
+                       break;
+               }
+               cprb_p = (struct CPRB *)
+                       (response + sizeof(struct type86_fmt2_msg));
+               cprbx_p = (struct CPRBX *) cprb_p;
+               if (cprb_p->cprb_ver_id != 0x02) {
+                       le2toI(cprb_p->ccp_rtcode, &service_rc);
+                       if (service_rc != 0) {
+                               le2toI(cprb_p->ccp_rscode, &service_rs);
+                               if ((service_rc == 8) && (service_rs == 66))
+                                       PDEBUG("8/66 on PCICC\n");
+                               else
+                                       PRINTK("service rc/rs: %d/%d\n",
+                                              service_rc, service_rs);
+                               rv = 8;
+                       }
+                       src_p = (unsigned char *)cprb_p + sizeof(struct CPRB);
+                       src_p += 4;
+                       le2toI(src_p, &src_l);
+                       src_l -= 2;
+                       src_p += 2;
+               } else {
+                       service_rc = (int)cprbx_p->ccp_rtcode;
+                       if (service_rc != 0) {
+                               service_rs = (int) cprbx_p->ccp_rscode;
+                               if ((service_rc == 8) && (service_rs == 66))
+                                       PDEBUG("8/66 on PCIXCC\n");
+                               else
+                                       PRINTK("service rc/rs: %d/%d\n",
+                                              service_rc, service_rs);
+                               rv = 8;
+                       }
+                       src_p = (unsigned char *)
+                               cprbx_p + sizeof(struct CPRBX);
+                       src_p += 4;
+                       src_l = (int)(*((short *) src_p));
+                       src_l -= 2;
+                       src_p += 2;
+               }
+               break;
+       default:
+               break;
+       }
+
+       if (rv == 8)
+               return 8;
+       if (rv == 4)
+               switch (reply_code) {
+               case REPLY_ERROR_OPERAND_INVALID:
+                       return REC_OPERAND_INV;
+               case REPLY_ERROR_OPERAND_SIZE:
+                       return REC_OPERAND_SIZE;
+               case REPLY_ERROR_EVEN_MOD_IN_OPND:
+                       return REC_EVEN_MOD;
+               case REPLY_ERROR_MESSAGE_TYPE:
+                       return WRONG_DEVICE_TYPE;
+               default:
+                       return 12;
+               }
+
+       if (service_rc != 0)
+               return REC_OPERAND_INV;
+
+       if ((src_l > icaMsg_p->outputdatalength) ||
+           (src_l > RESPBUFFSIZE) ||
+           (src_l <= 0))
+               return REC_OPERAND_SIZE;
+
+       PDEBUG("Length returned = %d\n", src_l);
+       tgt_p = resp_buff + icaMsg_p->outputdatalength - src_l;
+       memcpy(tgt_p, src_p, src_l);
+       if ((t82h_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
+               memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l);
+               rv = pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l);
+               if (rv != 0)
+                       return rv;
+       }
+       *respbufflen_p = icaMsg_p->outputdatalength;
+       if (*respbufflen_p == 0)
+               PRINTK("Zero *respbufflen_p\n");
+
+       return rv;
+}
+