Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 1944

kernel-2.6.18-128.1.10.el5.src.rpm

From: Jan Glauber <jglauber@redhat.com>
Subject: [RHEL5.1 PATCH] s390 crypto driver update
Date: Tue, 20 Feb 2007 19:00:24 +0100
Bugzilla: 228049
Message-Id: <1171994425.6031.63.camel@localhost.localdomain>
Changelog: [s390] crypto driver update


BZ 228049

With 2.6.19 the s390 crypto driver was completely rewriten. On top of
the rewrite the secure key feature was added. Beside the secure key
functionality the new driver is much more modular using a bus concept
for the different card types. That will make it easier to maintain the
driver, so thats another reason for switching to the new driver with U1
(although we still have to maintain the old crypto driver for RHEL4).

The new crypto driver is called called zcrypt.

zcrypt features: 
o support for PCICC, PCICA, PCIXCC, CEX2C, CEX2A cards 
o support for clear key and secure key cryptographic functions 
o user space interface compatible to z90crypt 
o a modular design utilizing the Linux device model 
o improved performance by using a poll thread and an advanced load
  balancing algorithm

There are 3 patches attached, that
- remove the old crypto driver
- add rewriten crypto driver
- mangle config options

Tested by IBM.

Jan
-- 
jglauber@redhat.com
jang@de.ibm.com

 drivers/s390/Kconfig              |   13 
 drivers/s390/crypto/Makefile      |    6 
 drivers/s390/crypto/z90common.h   |  166 -
 drivers/s390/crypto/z90crypt.h    |   71 
 drivers/s390/crypto/z90hardware.c | 2531 ----------------------------
 drivers/s390/crypto/z90main.c     | 3379 --------------------------------------
 include/asm-s390/Kbuild           |    1 
 include/asm-s390/z90crypt.h       |  212 --
 8 files changed, 6379 deletions(-)

diff -urNp linux-2.6.18.s390x/drivers/s390/crypto/Makefile linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/Makefile
--- linux-2.6.18.s390x/drivers/s390/crypto/Makefile	2006-09-20 05:42:06.000000000 +0200
+++ linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/Makefile	1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +0,0 @@
-#
-# S/390 crypto devices
-#
-
-z90crypt-objs := z90main.o z90hardware.o
-obj-$(CONFIG_Z90CRYPT) += z90crypt.o
diff -urNp linux-2.6.18.s390x/drivers/s390/crypto/z90common.h linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/z90common.h
--- linux-2.6.18.s390x/drivers/s390/crypto/z90common.h	2006-09-20 05:42:06.000000000 +0200
+++ linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/z90common.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,166 +0,0 @@
-/*
- *  linux/drivers/s390/crypto/z90common.h
- *
- *  z90crypt 1.3.3
- *
- *  Copyright (C)  2001, 2005 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_H_
-#define _Z90COMMON_H_
-
-
-#define RESPBUFFSIZE 256
-#define PCI_FUNC_KEY_DECRYPT 0x5044
-#define PCI_FUNC_KEY_ENCRYPT 0x504B
-extern int ext_bitlens;
-
-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_NO_DEVICES		1
-#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_USE_PCICA	18
-
-#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 Z90CRYPT_NUM_TYPES	6
-#define PCICA		0
-#define PCICC		1
-#define PCIXCC_MCL2	2
-#define PCIXCC_MCL3	3
-#define CEX2C		4
-#define CEX2A		5
-#define NILDEV		-1
-#define ANYDEV		-1
-#define PCIXCC_UNK	-2
-
-enum hdevice_type {
-	PCICC_HW  = 3,
-	PCICA_HW  = 4,
-	PCIXCC_HW = 5,
-	CEX2A_HW  = 6,
-	CEX2C_HW  = 7
-};
-
-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];
-};
-
-#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 -urNp linux-2.6.18.s390x/drivers/s390/crypto/z90crypt.h linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/z90crypt.h
--- linux-2.6.18.s390x/drivers/s390/crypto/z90crypt.h	2006-09-20 05:42:06.000000000 +0200
+++ linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/z90crypt.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,71 +0,0 @@
-/*
- *  linux/drivers/s390/crypto/z90crypt.h
- *
- *  z90crypt 1.3.3 (kernel-private header)
- *
- *  Copyright (C)  2001, 2005 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 _Z90CRYPT_H_
-#define _Z90CRYPT_H_
-
-#include <asm/z90crypt.h>
-
-/**
- * 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 (retry may succeed)
-#define EGETBUFF  135	// Error getting buffer or hardware lacks capability
-			// (retry in software)
-
-/**
- * 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_MCL2, 4=PCIXCC_MCL3,
-	//         5=CEX2C
-	unsigned char status[MASK_LENGTH];
-	// qdepth: # work elements waiting for each device
-	unsigned char qdepth[MASK_LENGTH];
-};
-
-#endif /* _Z90CRYPT_H_ */
diff -urNp linux-2.6.18.s390x/drivers/s390/crypto/z90hardware.c linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/z90hardware.c
--- linux-2.6.18.s390x/drivers/s390/crypto/z90hardware.c	2006-09-20 05:42:06.000000000 +0200
+++ linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/z90hardware.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,2531 +0,0 @@
-/*
- *  linux/drivers/s390/crypto/z90hardware.c
- *
- *  z90crypt 1.3.3
- *
- *  Copyright (C)  2001, 2005 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"
-
-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 apfs[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 type6_msg {
-	struct type6_hdr header;
-	struct CPRB	 CPRB;
-};
-
-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 header;
-	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	  count4;
-	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_MCL2 = {
-	{0x50,0x44},
-	{0x00,0x0A},
-	{'P','K','C','S','-','1','.','2'}
-};
-
-static struct function_and_rules_block static_pke_function_and_rulesX_MCL2 = {
-	{0x50,0x4B},
-	{0x00,0x0A},
-	{'Z','E','R','O','-','P','A','D'}
-};
-
-static struct function_and_rules_block static_pkd_function_and_rulesX = {
-	{0x50,0x44},
-	{0x00,0x0A},
-	{'Z','E','R','O','-','P','A','D'}
-};
-
-static struct function_and_rules_block static_pke_function_and_rulesX = {
-	{0x50,0x4B},
-	{0x00,0x0A},
-	{'M','R','P',' ',' ',' ',' ',' '}
-};
-
-static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
-
-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
-
-#define MAX_RESPONSE_SIZE 0x00000710
-
-#define MAX_RESPONSEX_SIZE 0x0000077C
-
-#define RESPONSE_CPRB_SIZE  0x000006B8
-#define RESPONSE_CPRBX_SIZE 0x00000724
-
-struct type50_hdr {
-	u8    reserved1;
-	u8    msg_type_code;
-	u16   msg_len;
-	u8    reserved2;
-	u8    ignored;
-	u16   reserved3;
-};
-
-#define TYPE50_TYPE_CODE 0x50
-
-#define TYPE50_MEB1_LEN (sizeof(struct type50_meb1_msg))
-#define TYPE50_MEB2_LEN (sizeof(struct type50_meb2_msg))
-#define TYPE50_CRB1_LEN (sizeof(struct type50_crb1_msg))
-#define TYPE50_CRB2_LEN (sizeof(struct type50_crb2_msg))
-
-#define TYPE50_MEB1_FMT 0x0001
-#define TYPE50_MEB2_FMT 0x0002
-#define TYPE50_CRB1_FMT 0x0011
-#define TYPE50_CRB2_FMT 0x0012
-
-struct type50_meb1_msg {
-	struct type50_hdr	header;
-	u16			keyblock_type;
-	u8			reserved[6];
-	u8			exponent[128];
-	u8			modulus[128];
-	u8			message[128];
-};
-
-struct type50_meb2_msg {
-	struct type50_hdr	header;
-	u16			keyblock_type;
-	u8			reserved[6];
-	u8			exponent[256];
-	u8			modulus[256];
-	u8			message[256];
-};
-
-struct type50_crb1_msg {
-	struct type50_hdr	header;
-	u16			keyblock_type;
-	u8			reserved[6];
-	u8			p[64];
-	u8			q[64];
-	u8			dp[64];
-	u8			dq[64];
-	u8			u[64];
-	u8			message[128];
-};
-
-struct type50_crb2_msg {
-	struct type50_hdr	header;
-	u16			keyblock_type;
-	u8			reserved[6];
-	u8			p[128];
-	u8			q[128];
-	u8			dp[128];
-	u8			dq[128];
-	u8			u[128];
-	u8			message[256];
-};
-
-union type50_msg {
-	struct type50_meb1_msg meb1;
-	struct type50_meb2_msg meb2;
-	struct type50_crb1_msg crb1;
-	struct type50_crb2_msg crb2;
-};
-
-struct type80_hdr {
-	u8	reserved1;
-	u8	type;
-	u16	len;
-	u8	code;
-	u8	reserved2[3];
-	u8	reserved3[8];
-};
-
-#define TYPE80_RSP_CODE 0x80
-
-struct error_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 TYPE88_RSP_CODE 0x88
-
-#define REP82_ERROR_MACHINE_FAILURE  0x10
-#define REP82_ERROR_PREEMPT_FAILURE  0x12
-#define REP82_ERROR_CHECKPT_FAILURE  0x14
-#define REP82_ERROR_MESSAGE_TYPE     0x20
-#define REP82_ERROR_INVALID_COMM_CD  0x21
-#define REP82_ERROR_INVALID_MSG_LEN  0x23
-#define REP82_ERROR_RESERVD_FIELD    0x24
-#define REP82_ERROR_FORMAT_FIELD     0x29
-#define REP82_ERROR_INVALID_COMMAND  0x30
-#define REP82_ERROR_MALFORMED_MSG    0x40
-#define REP82_ERROR_RESERVED_FIELDO  0x50
-#define REP82_ERROR_WORD_ALIGNMENT   0x60
-#define REP82_ERROR_MESSAGE_LENGTH   0x80
-#define REP82_ERROR_OPERAND_INVALID  0x82
-#define REP82_ERROR_OPERAND_SIZE     0x84
-#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
-#define REP82_ERROR_RESERVED_FIELD   0x88
-#define REP82_ERROR_TRANSPORT_FAIL   0x90
-#define REP82_ERROR_PACKET_TRUNCATED 0xA0
-#define REP82_ERROR_ZERO_BUFFER_LEN  0xB0
-
-#define REP88_ERROR_MODULE_FAILURE   0x10
-#define REP88_ERROR_MODULE_TIMEOUT   0x11
-#define REP88_ERROR_MODULE_NOTINIT   0x13
-#define REP88_ERROR_MODULE_NOTAVAIL  0x14
-#define REP88_ERROR_MODULE_DISABLED  0x15
-#define REP88_ERROR_MODULE_IN_DIAGN  0x17
-#define REP88_ERROR_FASTPATH_DISABLD 0x19
-#define REP88_ERROR_MESSAGE_TYPE     0x20
-#define REP88_ERROR_MESSAGE_MALFORMD 0x22
-#define REP88_ERROR_MESSAGE_LENGTH   0x23
-#define REP88_ERROR_RESERVED_FIELD   0x24
-#define REP88_ERROR_KEY_TYPE         0x34
-#define REP88_ERROR_INVALID_KEY      0x82
-#define REP88_ERROR_OPERAND          0x84
-#define REP88_ERROR_OPERAND_EVEN_MOD 0x85
-
-#define CALLER_HEADER 12
-
-static inline int
-testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
-{
-	int ccode;
-
-	asm volatile
-#ifdef CONFIG_64BIT
-	("	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 CONFIG_64BIT
-	("	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 CONFIG_64BIT
-	("	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 CONFIG_64BIT
-	("	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 PCICA_HW:
-				*dev_type = PCICA;
-				break;
-			case PCICC_HW:
-				*dev_type = PCICC;
-				break;
-			case PCIXCC_HW:
-				*dev_type = PCIXCC_UNK;
-				break;
-			case CEX2C_HW:
-				*dev_type = CEX2C;
-				break;
-			case CEX2A_HW:
-				*dev_type = CEX2A;
-				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;
-			break;
-		}
-		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:
-			case AP_RESPONSE_DECONFIGURED:
-			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;
-			break;
-		}
-		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;
-	u32 *q_nr_p = (u32 *)msg_ext;
-
-	*q_nr_p = (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+CALLER_HEADER, 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;
-		break;
-	}
-
-	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;
-	static int deprecated_msg_count = 0;
-
-	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)) {
-		if (deprecated_msg_count < 20) {
-			PRINTK("Common public key used for modex decrypt\n");
-			deprecated_msg_count++;
-			if (deprecated_msg_count == 20)
-				PRINTK("No longer issuing messages about common"
-				       " public key 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))
-		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, *exp_p, *temp;
-	struct type6_hdr *tp6Hdr_p;
-	struct CPRB *cprb_p;
-	struct cca_public_key *key_p;
-	struct T6_keyBlock_hdr *keyb_p;
-
-	temp_exp = kmalloc(256, GFP_KERNEL);
-	if (!temp_exp)
-		return EGETBUFF;
-	mod_len = icaMsg_p->inputdatalength;
-	if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
-		kfree(temp_exp);
-		return SEN_RELEASED;
-	}
-	if (is_empty(temp_exp, mod_len)) {
-		kfree(temp_exp);
-		return SEN_USER_ERROR;
-	}
-
-	exp_p = temp_exp;
-	for (i = 0; i < mod_len; i++)
-		if (exp_p[i])
-			break;
-	if (i >= mod_len) {
-		kfree(temp_exp);
-		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)) {
-		kfree(temp_exp);
-		return SEN_RELEASED;
-	}
-	if (is_empty(temp, mod_len)) {
-		kfree(temp_exp);
-		return SEN_USER_ERROR;
-	}
-	if ((temp[0] != 0x00) || (temp[1] != 0x02)) {
-		kfree(temp_exp);
-		return SEN_NOT_AVAIL;
-	}
-	for (i = 2; i < mod_len; i++)
-		if (temp[i] == 0x00)
-			break;
-	if ((i < 9) || (i > (mod_len - 2))) {
-		kfree(temp_exp);
-		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);
-	kfree(temp_exp);
-	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 = CALLER_HEADER + 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 dev_type)
-{
-	int mod_len, exp_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
-	int key_len, i;
-	unsigned char *temp_exp, *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;
-
-	temp_exp = kmalloc(256, GFP_KERNEL);
-	if (!temp_exp)
-		return EGETBUFF;
-	mod_len = icaMsg_p->inputdatalength;
-	if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
-		kfree(temp_exp);
-		return SEN_RELEASED;
-	}
-	if (is_empty(temp_exp, mod_len)) {
-		kfree(temp_exp);
-		return SEN_USER_ERROR;
-	}
-	exp_p = temp_exp;
-	for (i = 0; i < mod_len; i++)
-		if (exp_p[i])
-			break;
-	if (i >= mod_len) {
-		kfree(temp_exp);
-		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);
-	if (dev_type == PCIXCC_MCL2)
-		memcpy(tgt_p, &static_pke_function_and_rulesX_MCL2,
-		       sizeof(struct function_and_rules_block));
-	else
-		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)) {
-		kfree(temp_exp);
-		return SEN_RELEASED;
-	}
-	if (is_empty(tgt_p, mod_len)) {
-		kfree(temp_exp);
-		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);
-	kfree(temp_exp);
-	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 = CALLER_HEADER + 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 dev_type)
-{
-	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);
-	if (dev_type == PCIXCC_MCL2)
-		memcpy(tgt_p, &static_pkd_function_and_rulesX_MCL2,
-		       sizeof(struct function_and_rules_block));
-	else
-		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;
-}
-
-static int
-ICAMEX_msg_to_type50MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
-			    union type50_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 type50_msg *tmp_type50_msg;
-
-	mod_len = icaMex_p->inputdatalength;
-
-	msg_size = ((mod_len <= 128) ? TYPE50_MEB1_LEN : TYPE50_MEB2_LEN) +
-		    CALLER_HEADER;
-
-	memset(z90cMsg_p, 0, msg_size);
-
-	tmp_type50_msg = (union type50_msg *)
-		((unsigned char *) z90cMsg_p + CALLER_HEADER);
-
-	tmp_type50_msg->meb1.header.msg_type_code = TYPE50_TYPE_CODE;
-
-	if (mod_len <= 128) {
-		tmp_type50_msg->meb1.header.msg_len = TYPE50_MEB1_LEN;
-		tmp_type50_msg->meb1.keyblock_type = TYPE50_MEB1_FMT;
-		mod_tgt = tmp_type50_msg->meb1.modulus;
-		mod_tgt_len = sizeof(tmp_type50_msg->meb1.modulus);
-		exp_tgt = tmp_type50_msg->meb1.exponent;
-		exp_tgt_len = sizeof(tmp_type50_msg->meb1.exponent);
-		inp_tgt = tmp_type50_msg->meb1.message;
-		inp_tgt_len = sizeof(tmp_type50_msg->meb1.message);
-	} else {
-		tmp_type50_msg->meb2.header.msg_len = TYPE50_MEB2_LEN;
-		tmp_type50_msg->meb2.keyblock_type = TYPE50_MEB2_FMT;
-		mod_tgt = tmp_type50_msg->meb2.modulus;
-		mod_tgt_len = sizeof(tmp_type50_msg->meb2.modulus);
-		exp_tgt = tmp_type50_msg->meb2.exponent;
-		exp_tgt_len = sizeof(tmp_type50_msg->meb2.exponent);
-		inp_tgt = tmp_type50_msg->meb2.message;
-		inp_tgt_len = sizeof(tmp_type50_msg->meb2.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_type50CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
-			    int *z90cMsg_l_p, union type50_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, long_offset;
-	unsigned char *p_tgt, *q_tgt, *dp_tgt, *dq_tgt, *u_tgt, *inp_tgt,
-		      temp[8];
-	union type50_msg *tmp_type50_msg;
-
-	mod_len = icaMsg_p->inputdatalength;
-	short_len = mod_len / 2;
-	long_len = mod_len / 2 + 8;
-	long_offset = 0;
-
-	if (long_len > 128) {
-		memset(temp, 0x00, sizeof(temp));
-		if (copy_from_user(temp, icaMsg_p->np_prime, long_len-128))
-			return SEN_RELEASED;
-		if (!is_empty(temp, 8))
-			return SEN_NOT_AVAIL;
-		if (copy_from_user(temp, icaMsg_p->bp_key, long_len-128))
-			return SEN_RELEASED;
-		if (!is_empty(temp, 8))
-			return SEN_NOT_AVAIL;
-		if (copy_from_user(temp, icaMsg_p->u_mult_inv, long_len-128))
-			return SEN_RELEASED;
-		if (!is_empty(temp, 8))
-			return SEN_NOT_AVAIL;
-		long_offset = long_len - 128;
-		long_len = 128;
-	}
-
-	tmp_size = ((long_len <= 64) ? TYPE50_CRB1_LEN : TYPE50_CRB2_LEN) +
-		    CALLER_HEADER;
-
-	memset(z90cMsg_p, 0, tmp_size);
-
-	tmp_type50_msg = (union type50_msg *)
-		((unsigned char *) z90cMsg_p + CALLER_HEADER);
-
-	tmp_type50_msg->crb1.header.msg_type_code = TYPE50_TYPE_CODE;
-	if (long_len <= 64) {
-		tmp_type50_msg->crb1.header.msg_len = TYPE50_CRB1_LEN;
-		tmp_type50_msg->crb1.keyblock_type = TYPE50_CRB1_FMT;
-		p_tgt = tmp_type50_msg->crb1.p;
-		p_tgt_len = sizeof(tmp_type50_msg->crb1.p);
-		q_tgt = tmp_type50_msg->crb1.q;
-		q_tgt_len = sizeof(tmp_type50_msg->crb1.q);
-		dp_tgt = tmp_type50_msg->crb1.dp;
-		dp_tgt_len = sizeof(tmp_type50_msg->crb1.dp);
-		dq_tgt = tmp_type50_msg->crb1.dq;
-		dq_tgt_len = sizeof(tmp_type50_msg->crb1.dq);
-		u_tgt = tmp_type50_msg->crb1.u;
-		u_tgt_len = sizeof(tmp_type50_msg->crb1.u);
-		inp_tgt = tmp_type50_msg->crb1.message;
-		inp_tgt_len = sizeof(tmp_type50_msg->crb1.message);
-	} else {
-		tmp_type50_msg->crb2.header.msg_len = TYPE50_CRB2_LEN;
-		tmp_type50_msg->crb2.keyblock_type = TYPE50_CRB2_FMT;
-		p_tgt = tmp_type50_msg->crb2.p;
-		p_tgt_len = sizeof(tmp_type50_msg->crb2.p);
-		q_tgt = tmp_type50_msg->crb2.q;
-		q_tgt_len = sizeof(tmp_type50_msg->crb2.q);
-		dp_tgt = tmp_type50_msg->crb2.dp;
-		dp_tgt_len = sizeof(tmp_type50_msg->crb2.dp);
-		dq_tgt = tmp_type50_msg->crb2.dq;
-		dq_tgt_len = sizeof(tmp_type50_msg->crb2.dq);
-		u_tgt = tmp_type50_msg->crb2.u;
-		u_tgt_len = sizeof(tmp_type50_msg->crb2.u);
-		inp_tgt = tmp_type50_msg->crb2.message;
-		inp_tgt_len = sizeof(tmp_type50_msg->crb2.message);
-	}
-
-	p_tgt += (p_tgt_len - long_len);
-	if (copy_from_user(p_tgt, icaMsg_p->np_prime + long_offset, 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_offset, 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_offset, 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;
-}
-
-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_MCL2) ||
-	    (dev_type == PCIXCC_MCL3) ||
-	    (dev_type == CEX2C)) {
-		if (func == ICARSACRT)
-			return ICACRT_msg_to_type6CRT_msgX(
-				(struct ica_rsa_modexpo_crt *) buffer,
-				cdx, msg_l_p, (struct type6_msg *) msg_p,
-				dev_type);
-		else
-			return ICAMEX_msg_to_type6MEX_msgX(
-				(struct ica_rsa_modexpo *) buffer,
-				cdx, msg_l_p, (struct type6_msg *) msg_p,
-				dev_type);
-	}
-	if (dev_type == CEX2A) {
-		if (func == ICARSACRT)
-			return ICACRT_msg_to_type50CRT_msg(
-				(struct ica_rsa_modexpo_crt *) buffer,
-				msg_l_p, (union type50_msg *) msg_p);
-		else
-			return ICAMEX_msg_to_type50MEX_msg(
-				(struct ica_rsa_modexpo *) buffer,
-				msg_l_p, (union type50_msg *) msg_p);
-	}
-
-	return 0;
-}
-
-int ext_bitlens_msg_count = 0;
-static inline void
-unset_ext_bitlens(void)
-{
-	if (!ext_bitlens_msg_count) {
-		PRINTK("Unable to use coprocessors for extended bitlengths. "
-		       "Using PCICAs/CEX2As (if present) for extended "
-		       "bitlengths. This is not an error.\n");
-		ext_bitlens_msg_count++;
-	}
-	ext_bitlens = 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 error_hdr *errh_p = (struct error_hdr *) response;
-	struct type80_hdr *t80h_p = (struct type80_hdr *) response;
-	struct type84_hdr *t84h_p = (struct type84_hdr *) response;
-	struct type86_fmt2_msg *t86m_p =  (struct type86_fmt2_msg *) response;
-	int 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;
-	switch (errh_p->type) {
-	case TYPE82_RSP_CODE:
-	case TYPE88_RSP_CODE:
-		reply_code = errh_p->reply_code;
-		src_p = (unsigned char *)errh_p;
-		PRINTK("Hardware error: Type %02X Message Header: "
-		       "%02x%02x%02x%02x%02x%02x%02x%02x\n",
-		       errh_p->type,
-		       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 TYPE80_RSP_CODE:
-		src_l = icaMsg_p->outputdatalength;
-		src_p = response + (int)t80h_p->len - src_l;
-		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 = t86m_p->header.reply_code;
-		if (reply_code != 0)
-			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("Bad block format on PCICC\n");
-				else if ((service_rc == 8) && (service_rs == 65))
-					PDEBUG("Probably an even modulus on "
-					       "PCICC\n");
-				else if ((service_rc == 8) && (service_rs == 770)) {
-					PDEBUG("Invalid key length on PCICC\n");
-					unset_ext_bitlens();
-					return REC_USE_PCICA;
-				}
-				else if ((service_rc == 8) && (service_rs == 783)) {
-					PDEBUG("Extended bitlengths not enabled"
-					       "on PCICC\n");
-					unset_ext_bitlens();
-					return REC_USE_PCICA;
-				}
-				else
-					PRINTK("service rc/rs (PCICC): %d/%d\n",
-					       service_rc, service_rs);
-				return REC_OPERAND_INV;
-			}
-			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("Bad block format on PCIXCC\n");
-				else if ((service_rc == 8) && (service_rs == 65))
-					PDEBUG("Probably an even modulus on "
-					       "PCIXCC\n");
-				else if ((service_rc == 8) && (service_rs == 770)) {
-					PDEBUG("Invalid key length on PCIXCC\n");
-					unset_ext_bitlens();
-					return REC_USE_PCICA;
-				}
-				else if ((service_rc == 8) && (service_rs == 783)) {
-					PDEBUG("Extended bitlengths not enabled"
-					       "on PCIXCC\n");
-					unset_ext_bitlens();
-					return REC_USE_PCICA;
-				}
-				else
-					PRINTK("service rc/rs (PCIXCC): %d/%d\n",
-					       service_rc, service_rs);
-				return REC_OPERAND_INV;
-			}
-			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:
-		src_p = (unsigned char *)errh_p;
-		PRINTK("Unrecognized 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]);
-		return REC_BAD_MESSAGE;
-	}
-
-	if (reply_code)
-		switch (reply_code) {
-		case REP82_ERROR_MACHINE_FAILURE:
-			if (errh_p->type == TYPE82_RSP_CODE)
-				PRINTKW("Machine check failure\n");
-			else
-				PRINTKW("Module failure\n");
-			return REC_HARDWAR_ERR;
-		case REP82_ERROR_OPERAND_INVALID:
-			return REC_OPERAND_INV;
-		case REP88_ERROR_MESSAGE_MALFORMD:
-			PRINTKW("Message malformed\n");
-			return REC_OPERAND_INV;
-		case REP82_ERROR_OPERAND_SIZE:
-			return REC_OPERAND_SIZE;
-		case REP82_ERROR_EVEN_MOD_IN_OPND:
-			return REC_EVEN_MOD;
-		case REP82_ERROR_MESSAGE_TYPE:
-			return WRONG_DEVICE_TYPE;
-		case REP82_ERROR_TRANSPORT_FAIL:
-			PRINTKW("Transport failed (APFS = %02X%02X%02X%02X)\n",
-				t86m_p->apfs[0], t86m_p->apfs[1],
-				t86m_p->apfs[2], t86m_p->apfs[3]);
-			return REC_HARDWAR_ERR;
-		default:
-			PRINTKW("reply code = %d\n", reply_code);
-			return REC_HARDWAR_ERR;
-		}
-
-	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 ((errh_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
-		memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l);
-		if (pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l))
-			return REC_INVALID_PAD;
-	}
-	*respbufflen_p = icaMsg_p->outputdatalength;
-	if (*respbufflen_p == 0)
-		PRINTK("Zero *respbufflen_p\n");
-
-	return 0;
-}
-
diff -urNp linux-2.6.18.s390x/drivers/s390/crypto/z90main.c linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/z90main.c
--- linux-2.6.18.s390x/drivers/s390/crypto/z90main.c	2006-09-20 05:42:06.000000000 +0200
+++ linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/z90main.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,3379 +0,0 @@
-/*
- *  linux/drivers/s390/crypto/z90main.c
- *
- *  z90crypt 1.3.3
- *
- *  Copyright (C)  2001, 2005 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>       // copy_(from|to)_user
-#include <linux/compat.h>
-#include <linux/compiler.h>
-#include <linux/delay.h>       // mdelay
-#include <linux/init.h>
-#include <linux/interrupt.h>   // for tasklets
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/proc_fs.h>
-#include <linux/syscalls.h>
-#include "z90crypt.h"
-#include "z90common.h"
-
-/**
- * Defaults that may be modified.
- */
-
-/**
- * You can specify a different minor at compile time.
- */
-#ifndef Z90CRYPT_MINOR
-#define Z90CRYPT_MINOR	MISC_DYNAMIC_MINOR
-#endif
-
-/**
- * You can specify a different domain at compile time or on the insmod
- * command line.
- */
-#ifndef DOMAIN_INDEX
-#define DOMAIN_INDEX	-1
-#endif
-
-/**
- * This is the name under which the device is registered in /proc/modules.
- */
-#define REG_NAME	"z90crypt"
-
-/**
- * Cleanup should run every CLEANUPTIME seconds and should clean up requests
- * older than CLEANUPTIME seconds in the past.
- */
-#ifndef CLEANUPTIME
-#define CLEANUPTIME 15
-#endif
-
-/**
- * Config should run every CONFIGTIME seconds
- */
-#ifndef CONFIGTIME
-#define CONFIGTIME 30
-#endif
-
-/**
- * The first execution of the config task should take place
- * immediately after initialization
- */
-#ifndef INITIAL_CONFIGTIME
-#define INITIAL_CONFIGTIME 1
-#endif
-
-/**
- * Reader should run every READERTIME milliseconds
- * With the 100Hz patch for s390, z90crypt can lock the system solid while
- * under heavy load. We'll try to avoid that.
- */
-#ifndef READERTIME
-#if HZ > 1000
-#define READERTIME 2
-#else
-#define READERTIME 10
-#endif
-#endif
-
-/**
- * turn long device array index into device pointer
- */
-#define LONG2DEVPTR(ndx) (z90crypt.device_p[(ndx)])
-
-/**
- * turn short device array index into long device array index
- */
-#define SHRT2LONG(ndx) (z90crypt.overall_device_x.device_index[(ndx)])
-
-/**
- * turn short device array index into device pointer
- */
-#define SHRT2DEVPTR(ndx) LONG2DEVPTR(SHRT2LONG(ndx))
-
-/**
- * Status for a work-element
- */
-#define STAT_DEFAULT	0x00 // request has not been processed
-
-#define STAT_ROUTED	0x80 // bit 7: requests get routed to specific device
-			     //	       else, device is determined each write
-#define STAT_FAILED	0x40 // bit 6: this bit is set if the request failed
-			     //	       before being sent to the hardware.
-#define STAT_WRITTEN	0x30 // bits 5-4: work to be done, not sent to device
-//			0x20 // UNUSED state
-#define STAT_READPEND	0x10 // bits 5-4: work done, we're returning data now
-#define STAT_NOWORK	0x00 // bits off: no work on any queue
-#define STAT_RDWRMASK	0x30 // mask for bits 5-4
-
-/**
- * Macros to check the status RDWRMASK
- */
-#define CHK_RDWRMASK(statbyte) ((statbyte) & STAT_RDWRMASK)
-#define SET_RDWRMASK(statbyte, newval) \
-	{(statbyte) &= ~STAT_RDWRMASK; (statbyte) |= newval;}
-
-/**
- * Audit Trail.	 Progress of a Work element
- * audit[0]: Unless noted otherwise, these bits are all set by the process
- */
-#define FP_COPYFROM	0x80 // Caller's buffer has been copied to work element
-#define FP_BUFFREQ	0x40 // Low Level buffer requested
-#define FP_BUFFGOT	0x20 // Low Level buffer obtained
-#define FP_SENT		0x10 // Work element sent to a crypto device
-			     // (may be set by process or by reader task)
-#define FP_PENDING	0x08 // Work element placed on pending queue
-			     // (may be set by process or by reader task)
-#define FP_REQUEST	0x04 // Work element placed on request queue
-#define FP_ASLEEP	0x02 // Work element about to sleep
-#define FP_AWAKE	0x01 // Work element has been awakened
-
-/**
- * audit[1]: These bits are set by the reader task and/or the cleanup task
- */
-#define FP_NOTPENDING	  0x80 // Work element removed from pending queue
-#define FP_AWAKENING	  0x40 // Caller about to be awakened
-#define FP_TIMEDOUT	  0x20 // Caller timed out
-#define FP_RESPSIZESET	  0x10 // Response size copied to work element
-#define FP_RESPADDRCOPIED 0x08 // Response address copied to work element
-#define FP_RESPBUFFCOPIED 0x04 // Response buffer copied to work element
-#define FP_REMREQUEST	  0x02 // Work element removed from request queue
-#define FP_SIGNALED	  0x01 // Work element was awakened by a signal
-
-/**
- * audit[2]: unused
- */
-
-/**
- * state of the file handle in private_data.status
- */
-#define STAT_OPEN 0
-#define STAT_CLOSED 1
-
-/**
- * PID() expands to the process ID of the current process
- */
-#define PID() (current->pid)
-
-/**
- * Selected Constants.	The number of APs and the number of devices
- */
-#ifndef Z90CRYPT_NUM_APS
-#define Z90CRYPT_NUM_APS 64
-#endif
-#ifndef Z90CRYPT_NUM_DEVS
-#define Z90CRYPT_NUM_DEVS Z90CRYPT_NUM_APS
-#endif
-
-/**
- * Buffer size for receiving responses. The maximum Response Size
- * is actually the maximum request size, since in an error condition
- * the request itself may be returned unchanged.
- */
-#define MAX_RESPONSE_SIZE 0x0000077C
-
-/**
- * A count and status-byte mask
- */
-struct status {
-	int	      st_count;		    // # of enabled devices
-	int	      disabled_count;	    // # of disabled devices
-	int	      user_disabled_count;  // # of devices disabled via proc fs
-	unsigned char st_mask[Z90CRYPT_NUM_APS]; // current status mask
-};
-
-/**
- * The array of device indexes is a mechanism for fast indexing into
- * a long (and sparse) array.  For instance, if APs 3, 9 and 47 are
- * installed, z90CDeviceIndex[0] is 3, z90CDeviceIndex[1] is 9, and
- * z90CDeviceIndex[2] is 47.
- */
-struct device_x {
-	int device_index[Z90CRYPT_NUM_DEVS];
-};
-
-/**
- * All devices are arranged in a single array: 64 APs
- */
-struct device {
-	int		 dev_type;	    // PCICA, PCICC, PCIXCC_MCL2,
-					    // PCIXCC_MCL3, CEX2C, CEX2A
-	enum devstat	 dev_stat;	    // current device status
-	int		 dev_self_x;	    // Index in array
-	int		 disabled;	    // Set when device is in error
-	int		 user_disabled;	    // Set when device is disabled by user
-	int		 dev_q_depth;	    // q depth
-	unsigned char *	 dev_resp_p;	    // Response buffer address
-	int		 dev_resp_l;	    // Response Buffer length
-	int		 dev_caller_count;  // Number of callers
-	int		 dev_total_req_cnt; // # requests for device since load
-	struct list_head dev_caller_list;   // List of callers
-};
-
-/**
- * There's a struct status and a struct device_x for each device type.
- */
-struct hdware_block {
-	struct status	hdware_mask;
-	struct status	type_mask[Z90CRYPT_NUM_TYPES];
-	struct device_x type_x_addr[Z90CRYPT_NUM_TYPES];
-	unsigned char	device_type_array[Z90CRYPT_NUM_APS];
-};
-
-/**
- * z90crypt is the topmost data structure in the hierarchy.
- */
-struct z90crypt {
-	int		     max_count;		// Nr of possible crypto devices
-	struct status	     mask;
-	int		     q_depth_array[Z90CRYPT_NUM_DEVS];
-	int		     dev_type_array[Z90CRYPT_NUM_DEVS];
-	struct device_x	     overall_device_x;	// array device indexes
-	struct device *	     device_p[Z90CRYPT_NUM_DEVS];
-	int		     terminating;
-	int		     domain_established;// TRUE:  domain has been found
-	int		     cdx;		// Crypto Domain Index
-	int		     len;		// Length of this data structure
-	struct hdware_block *hdware_info;
-};
-
-/**
- * An array of these structures is pointed to from dev_caller
- * The length of the array depends on the device type. For APs,
- * there are 8.
- *
- * The caller buffer is allocated to the user at OPEN. At WRITE,
- * it contains the request; at READ, the response. The function
- * send_to_crypto_device converts the request to device-dependent
- * form and use the caller's OPEN-allocated buffer for the response.
- *
- * For the contents of caller_dev_dep_req and caller_dev_dep_req_p
- * because that points to it, see the discussion in z90hardware.c.
- * Search for "extended request message block".
- */
-struct caller {
-	int		 caller_buf_l;		 // length of original request
-	unsigned char *	 caller_buf_p;		 // Original request on WRITE
-	int		 caller_dev_dep_req_l;	 // len device dependent request
-	unsigned char *	 caller_dev_dep_req_p;	 // Device dependent form
-	unsigned char	 caller_id[8];		 // caller-supplied message id
-	struct list_head caller_liste;
-	unsigned char	 caller_dev_dep_req[MAX_RESPONSE_SIZE];
-};
-
-/**
- * Function prototypes from z90hardware.c
- */
-enum hdstat query_online(int deviceNr, int cdx, int resetNr, int *q_depth,
-			 int *dev_type);
-enum devstat reset_device(int deviceNr, int cdx, int resetNr);
-enum devstat send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext);
-enum devstat receive_from_AP(int dev_nr, int cdx, int resplen,
-			     unsigned char *resp, unsigned char *psmid);
-int convert_request(unsigned char *buffer, int func, unsigned short function,
-		    int cdx, int dev_type, int *msg_l_p, unsigned char *msg_p);
-int convert_response(unsigned char *response, unsigned char *buffer,
-		     int *respbufflen_p, unsigned char *resp_buff);
-
-/**
- * Low level function prototypes
- */
-static int create_z90crypt(int *cdx_p);
-static int refresh_z90crypt(int *cdx_p);
-static int find_crypto_devices(struct status *deviceMask);
-static int create_crypto_device(int index);
-static int destroy_crypto_device(int index);
-static void destroy_z90crypt(void);
-static int refresh_index_array(struct status *status_str,
-			       struct device_x *index_array);
-static int probe_device_type(struct device *devPtr);
-static int probe_PCIXCC_type(struct device *devPtr);
-
-/**
- * proc fs definitions
- */
-static struct proc_dir_entry *z90crypt_entry;
-
-/**
- * data structures
- */
-
-/**
- * work_element.opener points back to this structure
- */
-struct priv_data {
-	pid_t	opener_pid;
-	unsigned char	status;		// 0: open  1: closed
-};
-
-/**
- * A work element is allocated for each request
- */
-struct work_element {
-	struct priv_data *priv_data;
-	pid_t		  pid;
-	int		  devindex;	  // index of device processing this w_e
-					  // (If request did not specify device,
-					  // -1 until placed onto a queue)
-	int		  devtype;
-	struct list_head  liste;	  // used for requestq and pendingq
-	char		  buffer[128];	  // local copy of user request
-	int		  buff_size;	  // size of the buffer for the request
-	char		  resp_buff[RESPBUFFSIZE];
-	int		  resp_buff_size;
-	char __user *	  resp_addr;	  // address of response in user space
-	unsigned int	  funccode;	  // function code of request
-	wait_queue_head_t waitq;
-	unsigned long	  requestsent;	  // time at which the request was sent
-	atomic_t	  alarmrung;	  // wake-up signal
-	unsigned char	  caller_id[8];	  // pid + counter, for this w_e
-	unsigned char	  status[1];	  // bits to mark status of the request
-	unsigned char	  audit[3];	  // record of work element's progress
-	unsigned char *	  requestptr;	  // address of request buffer
-	int		  retcode;	  // return code of request
-};
-
-/**
- * High level function prototypes
- */
-static int z90crypt_open(struct inode *, struct file *);
-static int z90crypt_release(struct inode *, struct file *);
-static ssize_t z90crypt_read(struct file *, char __user *, size_t, loff_t *);
-static ssize_t z90crypt_write(struct file *, const char __user *,
-							size_t, loff_t *);
-static long z90crypt_unlocked_ioctl(struct file *, unsigned int, unsigned long);
-static long z90crypt_compat_ioctl(struct file *, unsigned int, unsigned long);
-
-static void z90crypt_reader_task(unsigned long);
-static void z90crypt_schedule_reader_task(unsigned long);
-static void z90crypt_config_task(unsigned long);
-static void z90crypt_cleanup_task(unsigned long);
-
-static int z90crypt_status(char *, char **, off_t, int, int *, void *);
-static int z90crypt_status_write(struct file *, const char __user *,
-				 unsigned long, void *);
-
-/**
- * Storage allocated at initialization and used throughout the life of
- * this insmod
- */
-static int domain = DOMAIN_INDEX;
-static struct z90crypt z90crypt;
-static int quiesce_z90crypt;
-static spinlock_t queuespinlock;
-static struct list_head request_list;
-static int requestq_count;
-static struct list_head pending_list;
-static int pendingq_count;
-
-static struct tasklet_struct reader_tasklet;
-static struct timer_list reader_timer;
-static struct timer_list config_timer;
-static struct timer_list cleanup_timer;
-static atomic_t total_open;
-static atomic_t z90crypt_step;
-
-static struct file_operations z90crypt_fops = {
-	.owner		= THIS_MODULE,
-	.read		= z90crypt_read,
-	.write		= z90crypt_write,
-	.unlocked_ioctl	= z90crypt_unlocked_ioctl,
-#ifdef CONFIG_COMPAT
-	.compat_ioctl	= z90crypt_compat_ioctl,
-#endif
-	.open		= z90crypt_open,
-	.release	= z90crypt_release
-};
-
-static struct miscdevice z90crypt_misc_device = {
-	.minor	    = Z90CRYPT_MINOR,
-	.name	    = DEV_NAME,
-	.fops	    = &z90crypt_fops,
-};
-
-/**
- * Documentation values.
- */
-MODULE_AUTHOR("zSeries Linux Crypto Team: Robert H. Burroughs, Eric D. Rossman"
-	      "and Jochen Roehrig");
-MODULE_DESCRIPTION("zSeries Linux Cryptographic Coprocessor device driver, "
-		   "Copyright 2001, 2005 IBM Corporation");
-MODULE_LICENSE("GPL");
-module_param(domain, int, 0);
-MODULE_PARM_DESC(domain, "domain index for device");
-
-#ifdef CONFIG_COMPAT
-/**
- * ioctl32 conversion routines
- */
-struct ica_rsa_modexpo_32 { // For 32-bit callers
-	compat_uptr_t	inputdata;
-	unsigned int	inputdatalength;
-	compat_uptr_t	outputdata;
-	unsigned int	outputdatalength;
-	compat_uptr_t	b_key;
-	compat_uptr_t	n_modulus;
-};
-
-static long
-trans_modexpo32(struct file *filp, unsigned int cmd, unsigned long arg)
-{
-	struct ica_rsa_modexpo_32 __user *mex32u = compat_ptr(arg);
-	struct ica_rsa_modexpo_32  mex32k;
-	struct ica_rsa_modexpo __user *mex64;
-	long ret = 0;
-	unsigned int i;
-
-	if (!access_ok(VERIFY_WRITE, mex32u, sizeof(struct ica_rsa_modexpo_32)))
-		return -EFAULT;
-	mex64 = compat_alloc_user_space(sizeof(struct ica_rsa_modexpo));
-	if (!access_ok(VERIFY_WRITE, mex64, sizeof(struct ica_rsa_modexpo)))
-		return -EFAULT;
-	if (copy_from_user(&mex32k, mex32u, sizeof(struct ica_rsa_modexpo_32)))
-		return -EFAULT;
-	if (__put_user(compat_ptr(mex32k.inputdata), &mex64->inputdata)   ||
-	    __put_user(mex32k.inputdatalength, &mex64->inputdatalength)   ||
-	    __put_user(compat_ptr(mex32k.outputdata), &mex64->outputdata) ||
-	    __put_user(mex32k.outputdatalength, &mex64->outputdatalength) ||
-	    __put_user(compat_ptr(mex32k.b_key), &mex64->b_key)           ||
-	    __put_user(compat_ptr(mex32k.n_modulus), &mex64->n_modulus))
-		return -EFAULT;
-	ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)mex64);
-	if (!ret)
-		if (__get_user(i, &mex64->outputdatalength) ||
-		    __put_user(i, &mex32u->outputdatalength))
-			ret = -EFAULT;
-	return ret;
-}
-
-struct ica_rsa_modexpo_crt_32 { // For 32-bit callers
-	compat_uptr_t	inputdata;
-	unsigned int	inputdatalength;
-	compat_uptr_t	outputdata;
-	unsigned int	outputdatalength;
-	compat_uptr_t	bp_key;
-	compat_uptr_t	bq_key;
-	compat_uptr_t	np_prime;
-	compat_uptr_t	nq_prime;
-	compat_uptr_t	u_mult_inv;
-};
-
-static long
-trans_modexpo_crt32(struct file *filp, unsigned int cmd, unsigned long arg)
-{
-	struct ica_rsa_modexpo_crt_32 __user *crt32u = compat_ptr(arg);
-	struct ica_rsa_modexpo_crt_32  crt32k;
-	struct ica_rsa_modexpo_crt __user *crt64;
-	long ret = 0;
-	unsigned int i;
-
-	if (!access_ok(VERIFY_WRITE, crt32u,
-		       sizeof(struct ica_rsa_modexpo_crt_32)))
-		return -EFAULT;
-	crt64 = compat_alloc_user_space(sizeof(struct ica_rsa_modexpo_crt));
-	if (!access_ok(VERIFY_WRITE, crt64, sizeof(struct ica_rsa_modexpo_crt)))
-		return -EFAULT;
-	if (copy_from_user(&crt32k, crt32u,
-			   sizeof(struct ica_rsa_modexpo_crt_32)))
-		return -EFAULT;
-	if (__put_user(compat_ptr(crt32k.inputdata), &crt64->inputdata)   ||
-	    __put_user(crt32k.inputdatalength, &crt64->inputdatalength)   ||
-	    __put_user(compat_ptr(crt32k.outputdata), &crt64->outputdata) ||
-	    __put_user(crt32k.outputdatalength, &crt64->outputdatalength) ||
-	    __put_user(compat_ptr(crt32k.bp_key), &crt64->bp_key)         ||
-	    __put_user(compat_ptr(crt32k.bq_key), &crt64->bq_key)         ||
-	    __put_user(compat_ptr(crt32k.np_prime), &crt64->np_prime)     ||
-	    __put_user(compat_ptr(crt32k.nq_prime), &crt64->nq_prime)     ||
-	    __put_user(compat_ptr(crt32k.u_mult_inv), &crt64->u_mult_inv))
-		return -EFAULT;
-	ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)crt64);
-	if (!ret)
-		if (__get_user(i, &crt64->outputdatalength) ||
-		    __put_user(i, &crt32u->outputdatalength))
-			ret = -EFAULT;
-	return ret;
-}
-
-static long
-z90crypt_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
-	switch (cmd) {
-	case ICAZ90STATUS:
-	case Z90QUIESCE:
-	case Z90STAT_TOTALCOUNT:
-	case Z90STAT_PCICACOUNT:
-	case Z90STAT_PCICCCOUNT:
-	case Z90STAT_PCIXCCCOUNT:
-	case Z90STAT_PCIXCCMCL2COUNT:
-	case Z90STAT_PCIXCCMCL3COUNT:
-	case Z90STAT_CEX2CCOUNT:
-	case Z90STAT_REQUESTQ_COUNT:
-	case Z90STAT_PENDINGQ_COUNT:
-	case Z90STAT_TOTALOPEN_COUNT:
-	case Z90STAT_DOMAIN_INDEX:
-	case Z90STAT_STATUS_MASK:
-	case Z90STAT_QDEPTH_MASK:
-	case Z90STAT_PERDEV_REQCNT:
-		return z90crypt_unlocked_ioctl(filp, cmd, arg);
-	case ICARSAMODEXPO:
-		return trans_modexpo32(filp, cmd, arg);
-	case ICARSACRT:
-		return trans_modexpo_crt32(filp, cmd, arg);
-	default:
-		return -ENOIOCTLCMD;
-  	}
-}
-#endif
-
-/**
- * The module initialization code.
- */
-static int __init
-z90crypt_init_module(void)
-{
-	int result, nresult;
-	struct proc_dir_entry *entry;
-
-	PDEBUG("PID %d\n", PID());
-
-	if ((domain < -1) || (domain > 15)) {
-		PRINTKW("Invalid param: domain = %d.  Not loading.\n", domain);
-		return -EINVAL;
-	}
-
-	/* Register as misc device with given minor (or get a dynamic one). */
-	result = misc_register(&z90crypt_misc_device);
-	if (result < 0) {
-		PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n",
-			z90crypt_misc_device.minor, result);
-		return result;
-	}
-
-	PDEBUG("Registered " DEV_NAME " with result %d\n", result);
-
-	result = create_z90crypt(&domain);
-	if (result != 0) {
-		PRINTKW("create_z90crypt (domain index %d) failed with %d.\n",
-			domain, result);
-		result = -ENOMEM;
-		goto init_module_cleanup;
-	}
-
-	if (result == 0) {
-		PRINTKN("Version %d.%d.%d loaded, built on %s %s\n",
-			z90crypt_VERSION, z90crypt_RELEASE, z90crypt_VARIANT,
-			__DATE__, __TIME__);
-		PDEBUG("create_z90crypt (domain index %d) successful.\n",
-		       domain);
-	} else
-		PRINTK("No devices at startup\n");
-
-	/* Initialize globals. */
-	spin_lock_init(&queuespinlock);
-
-	INIT_LIST_HEAD(&pending_list);
-	pendingq_count = 0;
-
-	INIT_LIST_HEAD(&request_list);
-	requestq_count = 0;
-
-	quiesce_z90crypt = 0;
-
-	atomic_set(&total_open, 0);
-	atomic_set(&z90crypt_step, 0);
-
-	/* Set up the cleanup task. */
-	init_timer(&cleanup_timer);
-	cleanup_timer.function = z90crypt_cleanup_task;
-	cleanup_timer.data = 0;
-	cleanup_timer.expires = jiffies + (CLEANUPTIME * HZ);
-	add_timer(&cleanup_timer);
-
-	/* Set up the proc file system */
-	entry = create_proc_entry("driver/z90crypt", 0644, 0);
-	if (entry) {
-		entry->nlink = 1;
-		entry->data = 0;
-		entry->read_proc = z90crypt_status;
-		entry->write_proc = z90crypt_status_write;
-	}
-	else
-		PRINTK("Couldn't create z90crypt proc entry\n");
-	z90crypt_entry = entry;
-
-	/* Set up the configuration task. */
-	init_timer(&config_timer);
-	config_timer.function = z90crypt_config_task;
-	config_timer.data = 0;
-	config_timer.expires = jiffies + (INITIAL_CONFIGTIME * HZ);
-	add_timer(&config_timer);
-
-	/* Set up the reader task */
-	tasklet_init(&reader_tasklet, z90crypt_reader_task, 0);
-	init_timer(&reader_timer);
-	reader_timer.function = z90crypt_schedule_reader_task;
-	reader_timer.data = 0;
-	reader_timer.expires = jiffies + (READERTIME * HZ / 1000);
-	add_timer(&reader_timer);
-
-	return 0; // success
-
-init_module_cleanup:
-	if ((nresult = misc_deregister(&z90crypt_misc_device)))
-		PRINTK("misc_deregister failed with %d.\n", nresult);
-	else
-		PDEBUG("misc_deregister successful.\n");
-
-	return result; // failure
-}
-
-/**
- * The module termination code
- */
-static void __exit
-z90crypt_cleanup_module(void)
-{
-	int nresult;
-
-	PDEBUG("PID %d\n", PID());
-
-	remove_proc_entry("driver/z90crypt", 0);
-
-	if ((nresult = misc_deregister(&z90crypt_misc_device)))
-		PRINTK("misc_deregister failed with %d.\n", nresult);
-	else
-		PDEBUG("misc_deregister successful.\n");
-
-	/* Remove the tasks */
-	tasklet_kill(&reader_tasklet);
-	del_timer(&reader_timer);
-	del_timer(&config_timer);
-	del_timer(&cleanup_timer);
-
-	destroy_z90crypt();
-
-	PRINTKN("Unloaded.\n");
-}
-
-/**
- * Functions running under a process id
- *
- * The I/O functions:
- *     z90crypt_open
- *     z90crypt_release
- *     z90crypt_read
- *     z90crypt_write
- *     z90crypt_unlocked_ioctl
- *     z90crypt_status
- *     z90crypt_status_write
- *	 disable_card
- *	 enable_card
- *
- * Helper functions:
- *     z90crypt_rsa
- *	 z90crypt_prepare
- *	 z90crypt_send
- *	 z90crypt_process_results
- *
- */
-static int
-z90crypt_open(struct inode *inode, struct file *filp)
-{
-	struct priv_data *private_data_p;
-
-	if (quiesce_z90crypt)
-		return -EQUIESCE;
-
-	private_data_p = kzalloc(sizeof(struct priv_data), GFP_KERNEL);
-	if (!private_data_p) {
-		PRINTK("Memory allocate failed\n");
-		return -ENOMEM;
-	}
-
-	private_data_p->status = STAT_OPEN;
-	private_data_p->opener_pid = PID();
-	filp->private_data = private_data_p;
-	atomic_inc(&total_open);
-
-	return 0;
-}
-
-static int
-z90crypt_release(struct inode *inode, struct file *filp)
-{
-	struct priv_data *private_data_p = filp->private_data;
-
-	PDEBUG("PID %d (filp %p)\n", PID(), filp);
-
-	private_data_p->status = STAT_CLOSED;
-	memset(private_data_p, 0, sizeof(struct priv_data));
-	kfree(private_data_p);
-	atomic_dec(&total_open);
-
-	return 0;
-}
-
-/*
- * there are two read functions, of which compile options will choose one
- * without USE_GET_RANDOM_BYTES
- *   => read() always returns -EPERM;
- * otherwise
- *   => read() uses get_random_bytes() kernel function
- */
-#ifndef USE_GET_RANDOM_BYTES
-/**
- * z90crypt_read will not be supported beyond z90crypt 1.3.1
- */
-static ssize_t
-z90crypt_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
-{
-	PDEBUG("filp %p (PID %d)\n", filp, PID());
-	return -EPERM;
-}
-#else // we want to use get_random_bytes
-/**
- * read() just returns a string of random bytes.  Since we have no way
- * to generate these cryptographically, we just execute get_random_bytes
- * for the length specified.
- */
-#include <linux/random.h>
-static ssize_t
-z90crypt_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
-{
-	unsigned char *temp_buff;
-
-	PDEBUG("filp %p (PID %d)\n", filp, PID());
-
-	if (quiesce_z90crypt)
-		return -EQUIESCE;
-	if (count < 0) {
-		PRINTK("Requested random byte count negative: %ld\n", count);
-		return -EINVAL;
-	}
-	if (count > RESPBUFFSIZE) {
-		PDEBUG("count[%d] > RESPBUFFSIZE", count);
-		return -EINVAL;
-	}
-	if (count == 0)
-		return 0;
-	temp_buff = kmalloc(RESPBUFFSIZE, GFP_KERNEL);
-	if (!temp_buff) {
-		PRINTK("Memory allocate failed\n");
-		return -ENOMEM;
-	}
-	get_random_bytes(temp_buff, count);
-
-	if (copy_to_user(buf, temp_buff, count) != 0) {
-		kfree(temp_buff);
-		return -EFAULT;
-	}
-	kfree(temp_buff);
-	return count;
-}
-#endif
-
-/**
- * Write is is not allowed
- */
-static ssize_t
-z90crypt_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
-{
-	PDEBUG("filp %p (PID %d)\n", filp, PID());
-	return -EPERM;
-}
-
-/**
- * New status functions
- */
-static inline int
-get_status_totalcount(void)
-{
-	return z90crypt.hdware_info->hdware_mask.st_count;
-}
-
-static inline int
-get_status_PCICAcount(void)
-{
-	return z90crypt.hdware_info->type_mask[PCICA].st_count;
-}
-
-static inline int
-get_status_PCICCcount(void)
-{
-	return z90crypt.hdware_info->type_mask[PCICC].st_count;
-}
-
-static inline int
-get_status_PCIXCCcount(void)
-{
-	return z90crypt.hdware_info->type_mask[PCIXCC_MCL2].st_count +
-	       z90crypt.hdware_info->type_mask[PCIXCC_MCL3].st_count;
-}
-
-static inline int
-get_status_PCIXCCMCL2count(void)
-{
-	return z90crypt.hdware_info->type_mask[PCIXCC_MCL2].st_count;
-}
-
-static inline int
-get_status_PCIXCCMCL3count(void)
-{
-	return z90crypt.hdware_info->type_mask[PCIXCC_MCL3].st_count;
-}
-
-static inline int
-get_status_CEX2Ccount(void)
-{
-	return z90crypt.hdware_info->type_mask[CEX2C].st_count;
-}
-
-static inline int
-get_status_CEX2Acount(void)
-{
-	return z90crypt.hdware_info->type_mask[CEX2A].st_count;
-}
-
-static inline int
-get_status_requestq_count(void)
-{
-	return requestq_count;
-}
-
-static inline int
-get_status_pendingq_count(void)
-{
-	return pendingq_count;
-}
-
-static inline int
-get_status_totalopen_count(void)
-{
-	return atomic_read(&total_open);
-}
-
-static inline int
-get_status_domain_index(void)
-{
-	return z90crypt.cdx;
-}
-
-static inline unsigned char *
-get_status_status_mask(unsigned char status[Z90CRYPT_NUM_APS])
-{
-	int i, ix;
-
-	memcpy(status, z90crypt.hdware_info->device_type_array,
-	       Z90CRYPT_NUM_APS);
-
-	for (i = 0; i < get_status_totalcount(); i++) {
-		ix = SHRT2LONG(i);
-		if (LONG2DEVPTR(ix)->user_disabled)
-			status[ix] = 0x0d;
-	}
-
-	return status;
-}
-
-static inline unsigned char *
-get_status_qdepth_mask(unsigned char qdepth[Z90CRYPT_NUM_APS])
-{
-	int i, ix;
-
-	memset(qdepth, 0, Z90CRYPT_NUM_APS);
-
-	for (i = 0; i < get_status_totalcount(); i++) {
-		ix = SHRT2LONG(i);
-		qdepth[ix] = LONG2DEVPTR(ix)->dev_caller_count;
-	}
-
-	return qdepth;
-}
-
-static inline unsigned int *
-get_status_perdevice_reqcnt(unsigned int reqcnt[Z90CRYPT_NUM_APS])
-{
-	int i, ix;
-
-	memset(reqcnt, 0, Z90CRYPT_NUM_APS * sizeof(int));
-
-	for (i = 0; i < get_status_totalcount(); i++) {
-		ix = SHRT2LONG(i);
-		reqcnt[ix] = LONG2DEVPTR(ix)->dev_total_req_cnt;
-	}
-
-	return reqcnt;
-}
-
-static inline void
-init_work_element(struct work_element *we_p,
-		  struct priv_data *priv_data, pid_t pid)
-{
-	int step;
-
-	we_p->requestptr = (unsigned char *)we_p + sizeof(struct work_element);
-	/* Come up with a unique id for this caller. */
-	step = atomic_inc_return(&z90crypt_step);
-	memcpy(we_p->caller_id+0, (void *) &pid, sizeof(pid));
-	memcpy(we_p->caller_id+4, (void *) &step, sizeof(step));
-	we_p->pid = pid;
-	we_p->priv_data = priv_data;
-	we_p->status[0] = STAT_DEFAULT;
-	we_p->audit[0] = 0x00;
-	we_p->audit[1] = 0x00;
-	we_p->audit[2] = 0x00;
-	we_p->resp_buff_size = 0;
-	we_p->retcode = 0;
-	we_p->devindex = -1;
-	we_p->devtype = -1;
-	atomic_set(&we_p->alarmrung, 0);
-	init_waitqueue_head(&we_p->waitq);
-	INIT_LIST_HEAD(&(we_p->liste));
-}
-
-static inline int
-allocate_work_element(struct work_element **we_pp,
-		      struct priv_data *priv_data_p, pid_t pid)
-{
-	struct work_element *we_p;
-
-	we_p = (struct work_element *) get_zeroed_page(GFP_KERNEL);
-	if (!we_p)
-		return -ENOMEM;
-	init_work_element(we_p, priv_data_p, pid);
-	*we_pp = we_p;
-	return 0;
-}
-
-static inline void
-remove_device(struct device *device_p)
-{
-	if (!device_p || (device_p->disabled != 0))
-		return;
-	device_p->disabled = 1;
-	z90crypt.hdware_info->type_mask[device_p->dev_type].disabled_count++;
-	z90crypt.hdware_info->hdware_mask.disabled_count++;
-}
-
-/**
- * Bitlength limits for each card
- *
- * There are new MCLs which allow more bitlengths. See the table for details.
- * The MCL must be applied and the newer bitlengths enabled for these to work.
- *
- * Card Type    Old limit    New limit
- * PCICA          ??-2048     same (the lower limit is less than 128 bit...)
- * PCICC         512-1024     512-2048
- * PCIXCC_MCL2   512-2048     ----- (applying any GA LIC will make an MCL3 card)
- * PCIXCC_MCL3   -----        128-2048
- * CEX2C         512-2048     128-2048
- * CEX2A          ??-2048     same (the lower limit is less than 128 bit...)
- *
- * ext_bitlens (extended bitlengths) is a global, since you should not apply an
- * MCL to just one card in a machine. We assume, at first, that all cards have
- * these capabilities.
- */
-int ext_bitlens = 1; // This is global
-#define PCIXCC_MIN_MOD_SIZE	 16	//  128 bits
-#define OLD_PCIXCC_MIN_MOD_SIZE	 64	//  512 bits
-#define PCICC_MIN_MOD_SIZE	 64	//  512 bits
-#define OLD_PCICC_MAX_MOD_SIZE	128	// 1024 bits
-#define MAX_MOD_SIZE		256	// 2048 bits
-
-static inline int
-select_device_type(int *dev_type_p, int bytelength)
-{
-	static int count = 0;
-	int PCICA_avail, PCIXCC_MCL3_avail, CEX2C_avail, CEX2A_avail,
-	    index_to_use;
-	struct status *stat;
-	if ((*dev_type_p != PCICC) && (*dev_type_p != PCICA) &&
-	    (*dev_type_p != PCIXCC_MCL2) && (*dev_type_p != PCIXCC_MCL3) &&
-	    (*dev_type_p != CEX2C) && (*dev_type_p != CEX2A) &&
-	    (*dev_type_p != ANYDEV))
-		return -1;
-	if (*dev_type_p != ANYDEV) {
-		stat = &z90crypt.hdware_info->type_mask[*dev_type_p];
-		if (stat->st_count >
-		    (stat->disabled_count + stat->user_disabled_count))
-			return 0;
-		return -1;
-	}
-
-	/**
-	 * Assumption: PCICA, PCIXCC_MCL3, CEX2C, and CEX2A are all similar in
-	 * speed.
-	 *
-	 * PCICA and CEX2A do NOT co-exist, so it would be either one or the
-	 * other present.
-	 */
-	stat = &z90crypt.hdware_info->type_mask[PCICA];
-	PCICA_avail = stat->st_count -
-			(stat->disabled_count + stat->user_disabled_count);
-	stat = &z90crypt.hdware_info->type_mask[PCIXCC_MCL3];
-	PCIXCC_MCL3_avail = stat->st_count -
-			(stat->disabled_count + stat->user_disabled_count);
-	stat = &z90crypt.hdware_info->type_mask[CEX2C];
-	CEX2C_avail = stat->st_count -
-			(stat->disabled_count + stat->user_disabled_count);
-	stat = &z90crypt.hdware_info->type_mask[CEX2A];
-	CEX2A_avail = stat->st_count -
-			(stat->disabled_count + stat->user_disabled_count);
-	if (PCICA_avail || PCIXCC_MCL3_avail || CEX2C_avail || CEX2A_avail) {
-		/**
-		 * bitlength is a factor, PCICA or CEX2A are the most capable,
-		 * even with the new MCL for PCIXCC.
-		 */
-		if ((bytelength < PCIXCC_MIN_MOD_SIZE) ||
-		    (!ext_bitlens && (bytelength < OLD_PCIXCC_MIN_MOD_SIZE))) {
-			if (PCICA_avail) {
-				*dev_type_p = PCICA;
-				return 0;
-			}
-			if (CEX2A_avail) {
-				*dev_type_p = CEX2A;
-				return 0;
-			}
-			return -1;
-		}
-
-		index_to_use = count % (PCICA_avail + PCIXCC_MCL3_avail +
-					CEX2C_avail + CEX2A_avail);
-		if (index_to_use < PCICA_avail)
-			*dev_type_p = PCICA;
-		else if (index_to_use < (PCICA_avail + PCIXCC_MCL3_avail))
-			*dev_type_p = PCIXCC_MCL3;
-		else if (index_to_use < (PCICA_avail + PCIXCC_MCL3_avail +
-					 CEX2C_avail))
-			*dev_type_p = CEX2C;
-		else
-			*dev_type_p = CEX2A;
-		count++;
-		return 0;
-	}
-
-	/* Less than OLD_PCIXCC_MIN_MOD_SIZE cannot go to a PCIXCC_MCL2 */
-	if (bytelength < OLD_PCIXCC_MIN_MOD_SIZE)
-		return -1;
-	stat = &z90crypt.hdware_info->type_mask[PCIXCC_MCL2];
-	if (stat->st_count >
-	    (stat->disabled_count + stat->user_disabled_count)) {
-		*dev_type_p = PCIXCC_MCL2;
-		return 0;
-	}
-
-	/**
-	 * Less than PCICC_MIN_MOD_SIZE or more than OLD_PCICC_MAX_MOD_SIZE
-	 * (if we don't have the MCL applied and the newer bitlengths enabled)
-	 * cannot go to a PCICC
-	 */
-	if ((bytelength < PCICC_MIN_MOD_SIZE) ||
-	    (!ext_bitlens && (bytelength > OLD_PCICC_MAX_MOD_SIZE))) {
-		return -1;
-	}
-	stat = &z90crypt.hdware_info->type_mask[PCICC];
-	if (stat->st_count >
-	    (stat->disabled_count + stat->user_disabled_count)) {
-		*dev_type_p = PCICC;
-		return 0;
-	}
-
-	return -1;
-}
-
-/**
- * Try the selected number, then the selected type (can be ANYDEV)
- */
-static inline int
-select_device(int *dev_type_p, int *device_nr_p, int bytelength)
-{
-	int i, indx, devTp, low_count, low_indx;
-	struct device_x *index_p;
-	struct device *dev_ptr;
-
-	PDEBUG("device type = %d, index = %d\n", *dev_type_p, *device_nr_p);
-	if ((*device_nr_p >= 0) && (*device_nr_p < Z90CRYPT_NUM_DEVS)) {
-		PDEBUG("trying index = %d\n", *device_nr_p);
-		dev_ptr = z90crypt.device_p[*device_nr_p];
-
-		if (dev_ptr &&
-		    (dev_ptr->dev_stat != DEV_GONE) &&
-		    (dev_ptr->disabled == 0) &&
-		    (dev_ptr->user_disabled == 0)) {
-			PDEBUG("selected by number, index = %d\n",
-			       *device_nr_p);
-			*dev_type_p = dev_ptr->dev_type;
-			return *device_nr_p;
-		}
-	}
-	*device_nr_p = -1;
-	PDEBUG("trying type = %d\n", *dev_type_p);
-	devTp = *dev_type_p;
-	if (select_device_type(&devTp, bytelength) == -1) {
-		PDEBUG("failed to select by type\n");
-		return -1;
-	}
-	PDEBUG("selected type = %d\n", devTp);
-	index_p = &z90crypt.hdware_info->type_x_addr[devTp];
-	low_count = 0x0000FFFF;
-	low_indx = -1;
-	for (i = 0; i < z90crypt.hdware_info->type_mask[devTp].st_count; i++) {
-		indx = index_p->device_index[i];
-		dev_ptr = z90crypt.device_p[indx];
-		if (dev_ptr &&
-		    (dev_ptr->dev_stat != DEV_GONE) &&
-		    (dev_ptr->disabled == 0) &&
-		    (dev_ptr->user_disabled == 0) &&
-		    (devTp == dev_ptr->dev_type) &&
-		    (low_count > dev_ptr->dev_caller_count)) {
-			low_count = dev_ptr->dev_caller_count;
-			low_indx = indx;
-		}
-	}
-	*device_nr_p = low_indx;
-	return low_indx;
-}
-
-static inline int
-send_to_crypto_device(struct work_element *we_p)
-{
-	struct caller *caller_p;
-	struct device *device_p;
-	int dev_nr;
-	int bytelen = ((struct ica_rsa_modexpo *)we_p->buffer)->inputdatalength;
-
-	if (!we_p->requestptr)
-		return SEN_FATAL_ERROR;
-	caller_p = (struct caller *)we_p->requestptr;
-	dev_nr = we_p->devindex;
-	if (select_device(&we_p->devtype, &dev_nr, bytelen) == -1) {
-		if (z90crypt.hdware_info->hdware_mask.st_count != 0)
-			return SEN_RETRY;
-		else
-			return SEN_NOT_AVAIL;
-	}
-	we_p->devindex = dev_nr;
-	device_p = z90crypt.device_p[dev_nr];
-	if (!device_p)
-		return SEN_NOT_AVAIL;
-	if (device_p->dev_type != we_p->devtype)
-		return SEN_RETRY;
-	if (device_p->dev_caller_count >= device_p->dev_q_depth)
-		return SEN_QUEUE_FULL;
-	PDEBUG("device number prior to send: %d\n", dev_nr);
-	switch (send_to_AP(dev_nr, z90crypt.cdx,
-			   caller_p->caller_dev_dep_req_l,
-			   caller_p->caller_dev_dep_req_p)) {
-	case DEV_SEN_EXCEPTION:
-		PRINTKC("Exception during send to device %d\n", dev_nr);
-		z90crypt.terminating = 1;
-		return SEN_FATAL_ERROR;
-	case DEV_GONE:
-		PRINTK("Device %d not available\n", dev_nr);
-		remove_device(device_p);
-		return SEN_NOT_AVAIL;
-	case DEV_EMPTY:
-		return SEN_NOT_AVAIL;
-	case DEV_NO_WORK:
-		return SEN_FATAL_ERROR;
-	case DEV_BAD_MESSAGE:
-		return SEN_USER_ERROR;
-	case DEV_QUEUE_FULL:
-		return SEN_QUEUE_FULL;
-	default:
-	case DEV_ONLINE:
-		break;
-	}
-	list_add_tail(&(caller_p->caller_liste), &(device_p->dev_caller_list));
-	device_p->dev_caller_count++;
-	return 0;
-}
-
-/**
- * Send puts the user's work on one of two queues:
- *   the pending queue if the send was successful
- *   the request queue if the send failed because device full or busy
- */
-static inline int
-z90crypt_send(struct work_element *we_p, const char *buf)
-{
-	int rv;
-
-	PDEBUG("PID %d\n", PID());
-
-	if (CHK_RDWRMASK(we_p->status[0]) != STAT_NOWORK) {
-		PDEBUG("PID %d tried to send more work but has outstanding "
-		       "work.\n", PID());
-		return -EWORKPEND;
-	}
-	we_p->devindex = -1; // Reset device number
-	spin_lock_irq(&queuespinlock);
-	rv = send_to_crypto_device(we_p);
-	switch (rv) {
-	case 0:
-		we_p->requestsent = jiffies;
-		we_p->audit[0] |= FP_SENT;
-		list_add_tail(&we_p->liste, &pending_list);
-		++pendingq_count;
-		we_p->audit[0] |= FP_PENDING;
-		break;
-	case SEN_BUSY:
-	case SEN_QUEUE_FULL:
-		rv = 0;
-		we_p->devindex = -1; // any device will do
-		we_p->requestsent = jiffies;
-		list_add_tail(&we_p->liste, &request_list);
-		++requestq_count;
-		we_p->audit[0] |= FP_REQUEST;
-		break;
-	case SEN_RETRY:
-		rv = -ERESTARTSYS;
-		break;
-	case SEN_NOT_AVAIL:
-		PRINTK("*** No devices available.\n");
-		rv = we_p->retcode = -ENODEV;
-		we_p->status[0] |= STAT_FAILED;
-		break;
-	case REC_OPERAND_INV:
-	case REC_OPERAND_SIZE:
-	case REC_EVEN_MOD:
-	case REC_INVALID_PAD:
-		rv = we_p->retcode = -EINVAL;
-		we_p->status[0] |= STAT_FAILED;
-		break;
-	default:
-		we_p->retcode = rv;
-		we_p->status[0] |= STAT_FAILED;
-		break;
-	}
-	if (rv != -ERESTARTSYS)
-		SET_RDWRMASK(we_p->status[0], STAT_WRITTEN);
-	spin_unlock_irq(&queuespinlock);
-	if (rv == 0)
-		tasklet_schedule(&reader_tasklet);
-	return rv;
-}
-
-/**
- * process_results copies the user's work from kernel space.
- */
-static inline int
-z90crypt_process_results(struct work_element *we_p, char __user *buf)
-{
-	int rv;
-
-	PDEBUG("we_p %p (PID %d)\n", we_p, PID());
-
-	LONG2DEVPTR(we_p->devindex)->dev_total_req_cnt++;
-	SET_RDWRMASK(we_p->status[0], STAT_READPEND);
-
-	rv = 0;
-	if (!we_p->buffer) {
-		PRINTK("we_p %p PID %d in STAT_READPEND: buffer NULL.\n",
-			we_p, PID());
-		rv = -ENOBUFF;
-	}
-
-	if (!rv)
-		if ((rv = copy_to_user(buf, we_p->buffer, we_p->buff_size))) {
-			PDEBUG("copy_to_user failed: rv = %d\n", rv);
-			rv = -EFAULT;
-		}
-
-	if (!rv)
-		rv = we_p->retcode;
-	if (!rv)
-		if (we_p->resp_buff_size
-		    &&	copy_to_user(we_p->resp_addr, we_p->resp_buff,
-				     we_p->resp_buff_size))
-			rv = -EFAULT;
-
-	SET_RDWRMASK(we_p->status[0], STAT_NOWORK);
-	return rv;
-}
-
-static unsigned char NULL_psmid[8] =
-{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-/**
- * Used in device configuration functions
- */
-#define MAX_RESET 90
-
-/**
- * This is used only for PCICC support
- */
-static inline int
-is_PKCS11_padded(unsigned char *buffer, int length)
-{
-	int i;
-	if ((buffer[0] != 0x00) || (buffer[1] != 0x01))
-		return 0;
-	for (i = 2; i < length; i++)
-		if (buffer[i] != 0xFF)
-			break;
-	if ((i < 10) || (i == length))
-		return 0;
-	if (buffer[i] != 0x00)
-		return 0;
-	return 1;
-}
-
-/**
- * This is used only for PCICC support
- */
-static inline int
-is_PKCS12_padded(unsigned char *buffer, int length)
-{
-	int i;
-	if ((buffer[0] != 0x00) || (buffer[1] != 0x02))
-		return 0;
-	for (i = 2; i < length; i++)
-		if (buffer[i] == 0x00)
-			break;
-	if ((i < 10) || (i == length))
-		return 0;
-	if (buffer[i] != 0x00)
-		return 0;
-	return 1;
-}
-
-/**
- * builds struct caller and converts message from generic format to
- * device-dependent format
- * func is ICARSAMODEXPO or ICARSACRT
- * function is PCI_FUNC_KEY_ENCRYPT or PCI_FUNC_KEY_DECRYPT
- */
-static inline int
-build_caller(struct work_element *we_p, short function)
-{
-	int rv;
-	struct caller *caller_p = (struct caller *)we_p->requestptr;
-
-	if ((we_p->devtype != PCICC) && (we_p->devtype != PCICA) &&
-	    (we_p->devtype != PCIXCC_MCL2) && (we_p->devtype != PCIXCC_MCL3) &&
-	    (we_p->devtype != CEX2C) && (we_p->devtype != CEX2A))
-		return SEN_NOT_AVAIL;
-
-	memcpy(caller_p->caller_id, we_p->caller_id,
-	       sizeof(caller_p->caller_id));
-	caller_p->caller_dev_dep_req_p = caller_p->caller_dev_dep_req;
-	caller_p->caller_dev_dep_req_l = MAX_RESPONSE_SIZE;
-	caller_p->caller_buf_p = we_p->buffer;
-	INIT_LIST_HEAD(&(caller_p->caller_liste));
-
-	rv = convert_request(we_p->buffer, we_p->funccode, function,
-			     z90crypt.cdx, we_p->devtype,
-			     &caller_p->caller_dev_dep_req_l,
-			     caller_p->caller_dev_dep_req_p);
-	if (rv) {
-		if (rv == SEN_NOT_AVAIL)
-			PDEBUG("request can't be processed on hdwr avail\n");
-		else
-			PRINTK("Error from convert_request: %d\n", rv);
-	}
-	else
-		memcpy(&(caller_p->caller_dev_dep_req_p[4]), we_p->caller_id,8);
-	return rv;
-}
-
-static inline void
-unbuild_caller(struct device *device_p, struct caller *caller_p)
-{
-	if (!caller_p)
-		return;
-	if (caller_p->caller_liste.next && caller_p->caller_liste.prev)
-		if (!list_empty(&caller_p->caller_liste)) {
-			list_del_init(&caller_p->caller_liste);
-			device_p->dev_caller_count--;
-		}
-	memset(caller_p->caller_id, 0, sizeof(caller_p->caller_id));
-}
-
-static inline int
-get_crypto_request_buffer(struct work_element *we_p)
-{
-	struct ica_rsa_modexpo *mex_p;
-	struct ica_rsa_modexpo_crt *crt_p;
-	unsigned char *temp_buffer;
-	short function;
-	int rv;
-
-	mex_p =	(struct ica_rsa_modexpo *) we_p->buffer;
-	crt_p = (struct ica_rsa_modexpo_crt *) we_p->buffer;
-
-	PDEBUG("device type input = %d\n", we_p->devtype);
-
-	if (z90crypt.terminating)
-		return REC_NO_RESPONSE;
-	if (memcmp(we_p->caller_id, NULL_psmid, 8) == 0) {
-		PRINTK("psmid zeroes\n");
-		return SEN_FATAL_ERROR;
-	}
-	if (!we_p->buffer) {
-		PRINTK("buffer pointer NULL\n");
-		return SEN_USER_ERROR;
-	}
-	if (!we_p->requestptr) {
-		PRINTK("caller pointer NULL\n");
-		return SEN_USER_ERROR;
-	}
-
-	if ((we_p->devtype != PCICA) && (we_p->devtype != PCICC) &&
-	    (we_p->devtype != PCIXCC_MCL2) && (we_p->devtype != PCIXCC_MCL3) &&
-	    (we_p->devtype != CEX2C) && (we_p->devtype != CEX2A) &&
-	    (we_p->devtype != ANYDEV)) {
-		PRINTK("invalid device type\n");
-		return SEN_USER_ERROR;
-	}
-
-	if ((mex_p->inputdatalength < 1) ||
-	    (mex_p->inputdatalength > MAX_MOD_SIZE)) {
-		PRINTK("inputdatalength[%d] is not valid\n",
-		       mex_p->inputdatalength);
-		return SEN_USER_ERROR;
-	}
-
-	if (mex_p->outputdatalength < mex_p->inputdatalength) {
-		PRINTK("outputdatalength[%d] < inputdatalength[%d]\n",
-		       mex_p->outputdatalength, mex_p->inputdatalength);
-		return SEN_USER_ERROR;
-	}
-
-	if (!mex_p->inputdata || !mex_p->outputdata) {
-		PRINTK("inputdata[%p] or outputdata[%p] is NULL\n",
-		       mex_p->outputdata, mex_p->inputdata);
-		return SEN_USER_ERROR;
-	}
-
-	/**
-	 * As long as outputdatalength is big enough, we can set the
-	 * outputdatalength equal to the inputdatalength, since that is the
-	 * number of bytes we will copy in any case
-	 */
-	mex_p->outputdatalength = mex_p->inputdatalength;
-
-	rv = 0;
-	switch (we_p->funccode) {
-	case ICARSAMODEXPO:
-		if (!mex_p->b_key || !mex_p->n_modulus)
-			rv = SEN_USER_ERROR;
-		break;
-	case ICARSACRT:
-		if (!IS_EVEN(crt_p->inputdatalength)) {
-			PRINTK("inputdatalength[%d] is odd, CRT form\n",
-			       crt_p->inputdatalength);
-			rv = SEN_USER_ERROR;
-			break;
-		}
-		if (!crt_p->bp_key ||
-		    !crt_p->bq_key ||
-		    !crt_p->np_prime ||
-		    !crt_p->nq_prime ||
-		    !crt_p->u_mult_inv) {
-			PRINTK("CRT form, bad data: %p/%p/%p/%p/%p\n",
-			       crt_p->bp_key, crt_p->bq_key,
-			       crt_p->np_prime, crt_p->nq_prime,
-			       crt_p->u_mult_inv);
-			rv = SEN_USER_ERROR;
-		}
-		break;
-	default:
-		PRINTK("bad func = %d\n", we_p->funccode);
-		rv = SEN_USER_ERROR;
-		break;
-	}
-	if (rv != 0)
-		return rv;
-
-	if (select_device_type(&we_p->devtype, mex_p->inputdatalength) < 0)
-		return SEN_NOT_AVAIL;
-
-	temp_buffer = (unsigned char *)we_p + sizeof(struct work_element) +
-		      sizeof(struct caller);
-	if (copy_from_user(temp_buffer, mex_p->inputdata,
-			   mex_p->inputdatalength) != 0)
-		return SEN_RELEASED;
-
-	function = PCI_FUNC_KEY_ENCRYPT;
-	switch (we_p->devtype) {
-	/* PCICA and CEX2A do everything with a simple RSA mod-expo operation */
-	case PCICA:
-	case CEX2A:
-		function = PCI_FUNC_KEY_ENCRYPT;
-		break;
-	/**
-	 * PCIXCC_MCL2 does all Mod-Expo form with a simple RSA mod-expo
-	 * operation, and all CRT forms with a PKCS-1.2 format decrypt.
-	 * PCIXCC_MCL3 and CEX2C do all Mod-Expo and CRT forms with a simple RSA
-	 * mod-expo operation
-	 */
-	case PCIXCC_MCL2:
-		if (we_p->funccode == ICARSAMODEXPO)
-			function = PCI_FUNC_KEY_ENCRYPT;
-		else
-			function = PCI_FUNC_KEY_DECRYPT;
-		break;
-	case PCIXCC_MCL3:
-	case CEX2C:
-		if (we_p->funccode == ICARSAMODEXPO)
-			function = PCI_FUNC_KEY_ENCRYPT;
-		else
-			function = PCI_FUNC_KEY_DECRYPT;
-		break;
-	/**
-	 * PCICC does everything as a PKCS-1.2 format request
-	 */
-	case PCICC:
-		/* PCICC cannot handle input that is is PKCS#1.1 padded */
-		if (is_PKCS11_padded(temp_buffer, mex_p->inputdatalength)) {
-			return SEN_NOT_AVAIL;
-		}
-		if (we_p->funccode == ICARSAMODEXPO) {
-			if (is_PKCS12_padded(temp_buffer,
-					     mex_p->inputdatalength))
-				function = PCI_FUNC_KEY_ENCRYPT;
-			else
-				function = PCI_FUNC_KEY_DECRYPT;
-		} else
-			/* all CRT forms are decrypts */
-			function = PCI_FUNC_KEY_DECRYPT;
-		break;
-	}
-	PDEBUG("function: %04x\n", function);
-	rv = build_caller(we_p, function);
-	PDEBUG("rv from build_caller = %d\n", rv);
-	return rv;
-}
-
-static inline int
-z90crypt_prepare(struct work_element *we_p, unsigned int funccode,
-		 const char __user *buffer)
-{
-	int rv;
-
-	we_p->devindex = -1;
-	if (funccode == ICARSAMODEXPO)
-		we_p->buff_size = sizeof(struct ica_rsa_modexpo);
-	else
-		we_p->buff_size = sizeof(struct ica_rsa_modexpo_crt);
-
-	if (copy_from_user(we_p->buffer, buffer, we_p->buff_size))
-		return -EFAULT;
-
-	we_p->audit[0] |= FP_COPYFROM;
-	SET_RDWRMASK(we_p->status[0], STAT_WRITTEN);
-	we_p->funccode = funccode;
-	we_p->devtype = -1;
-	we_p->audit[0] |= FP_BUFFREQ;
-	rv = get_crypto_request_buffer(we_p);
-	switch (rv) {
-	case 0:
-		we_p->audit[0] |= FP_BUFFGOT;
-		break;
-	case SEN_USER_ERROR:
-		rv = -EINVAL;
-		break;
-	case SEN_QUEUE_FULL:
-		rv = 0;
-		break;
-	case SEN_RELEASED:
-		rv = -EFAULT;
-		break;
-	case REC_NO_RESPONSE:
-		rv = -ENODEV;
-		break;
-	case SEN_NOT_AVAIL:
-	case EGETBUFF:
-		rv = -EGETBUFF;
-		break;
-	default:
-		PRINTK("rv = %d\n", rv);
-		rv = -EGETBUFF;
-		break;
-	}
-	if (CHK_RDWRMASK(we_p->status[0]) == STAT_WRITTEN)
-		SET_RDWRMASK(we_p->status[0], STAT_DEFAULT);
-	return rv;
-}
-
-static inline void
-purge_work_element(struct work_element *we_p)
-{
-	struct list_head *lptr;
-
-	spin_lock_irq(&queuespinlock);
-	list_for_each(lptr, &request_list) {
-		if (lptr == &we_p->liste) {
-			list_del_init(lptr);
-			requestq_count--;
-			break;
-		}
-	}
-	list_for_each(lptr, &pending_list) {
-		if (lptr == &we_p->liste) {
-			list_del_init(lptr);
-			pendingq_count--;
-			break;
-		}
-	}
-	spin_unlock_irq(&queuespinlock);
-}
-
-/**
- * Build the request and send it.
- */
-static inline int
-z90crypt_rsa(struct priv_data *private_data_p, pid_t pid,
-	     unsigned int cmd, unsigned long arg)
-{
-	struct work_element *we_p;
-	int rv;
-
-	if ((rv = allocate_work_element(&we_p, private_data_p, pid))) {
-		PDEBUG("PID %d: allocate_work_element returned ENOMEM\n", pid);
-		return rv;
-	}
-	if ((rv = z90crypt_prepare(we_p, cmd, (const char __user *)arg)))
-		PDEBUG("PID %d: rv = %d from z90crypt_prepare\n", pid, rv);
-	if (!rv)
-		if ((rv = z90crypt_send(we_p, (const char *)arg)))
-			PDEBUG("PID %d: rv %d from z90crypt_send.\n", pid, rv);
-	if (!rv) {
-		we_p->audit[0] |= FP_ASLEEP;
-		wait_event(we_p->waitq, atomic_read(&we_p->alarmrung));
-		we_p->audit[0] |= FP_AWAKE;
-		rv = we_p->retcode;
-	}
-	if (!rv)
-		rv = z90crypt_process_results(we_p, (char __user *)arg);
-
-	if ((we_p->status[0] & STAT_FAILED)) {
-		switch (rv) {
-		/**
-		 * EINVAL *after* receive is almost always a padding error or
-		 * length error issued by a coprocessor (not an accelerator).
-		 * We convert this return value to -EGETBUFF which should
-		 * trigger a fallback to software.
-		 */
-		case -EINVAL:
-			if ((we_p->devtype != PCICA) &&
-			    (we_p->devtype != CEX2A))
-				rv = -EGETBUFF;
-			break;
-		case -ETIMEOUT:
-			if (z90crypt.mask.st_count > 0)
-				rv = -ERESTARTSYS; // retry with another
-			else
-				rv = -ENODEV; // no cards left
-		/* fall through to clean up request queue */
-		case -ERESTARTSYS:
-		case -ERELEASED:
-			switch (CHK_RDWRMASK(we_p->status[0])) {
-			case STAT_WRITTEN:
-				purge_work_element(we_p);
-				break;
-			case STAT_READPEND:
-			case STAT_NOWORK:
-			default:
-				break;
-			}
-			break;
-		default:
-			we_p->status[0] ^= STAT_FAILED;
-			break;
-		}
-	}
-	free_page((long)we_p);
-	return rv;
-}
-
-/**
- * This function is a little long, but it's really just one large switch
- * statement.
- */
-static long
-z90crypt_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
-	struct priv_data *private_data_p = filp->private_data;
-	unsigned char *status;
-	unsigned char *qdepth;
-	unsigned int *reqcnt;
-	struct ica_z90_status *pstat;
-	int ret, i, loopLim, tempstat;
-	static int deprecated_msg_count1 = 0;
-	static int deprecated_msg_count2 = 0;
-
-	PDEBUG("filp %p (PID %d), cmd 0x%08X\n", filp, PID(), cmd);
-	PDEBUG("cmd 0x%08X: dir %s, size 0x%04X, type 0x%02X, nr 0x%02X\n",
-		cmd,
-		!_IOC_DIR(cmd) ? "NO"
-		: ((_IOC_DIR(cmd) == (_IOC_READ|_IOC_WRITE)) ? "RW"
-		: ((_IOC_DIR(cmd) == _IOC_READ) ? "RD"
-		: "WR")),
-		_IOC_SIZE(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd));
-
-	if (_IOC_TYPE(cmd) != Z90_IOCTL_MAGIC) {
-		PRINTK("cmd 0x%08X contains bad magic\n", cmd);
-		return -ENOTTY;
-	}
-
-	ret = 0;
-	switch (cmd) {
-	case ICARSAMODEXPO:
-	case ICARSACRT:
-		if (quiesce_z90crypt) {
-			ret = -EQUIESCE;
-			break;
-		}
-		ret = -ENODEV; // Default if no devices
-		loopLim = z90crypt.hdware_info->hdware_mask.st_count -
-			(z90crypt.hdware_info->hdware_mask.disabled_count +
-			 z90crypt.hdware_info->hdware_mask.user_disabled_count);
-		for (i = 0; i < loopLim; i++) {
-			ret = z90crypt_rsa(private_data_p, PID(), cmd, arg);
-			if (ret != -ERESTARTSYS)
-				break;
-		}
-		if (ret == -ERESTARTSYS)
-			ret = -ENODEV;
-		break;
-
-	case Z90STAT_TOTALCOUNT:
-		tempstat = get_status_totalcount();
-		if (copy_to_user((int __user *)arg, &tempstat,sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90STAT_PCICACOUNT:
-		tempstat = get_status_PCICAcount();
-		if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90STAT_PCICCCOUNT:
-		tempstat = get_status_PCICCcount();
-		if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90STAT_PCIXCCMCL2COUNT:
-		tempstat = get_status_PCIXCCMCL2count();
-		if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90STAT_PCIXCCMCL3COUNT:
-		tempstat = get_status_PCIXCCMCL3count();
-		if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90STAT_CEX2CCOUNT:
-		tempstat = get_status_CEX2Ccount();
-		if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90STAT_CEX2ACOUNT:
-		tempstat = get_status_CEX2Acount();
-		if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90STAT_REQUESTQ_COUNT:
-		tempstat = get_status_requestq_count();
-		if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90STAT_PENDINGQ_COUNT:
-		tempstat = get_status_pendingq_count();
-		if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90STAT_TOTALOPEN_COUNT:
-		tempstat = get_status_totalopen_count();
-		if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90STAT_DOMAIN_INDEX:
-		tempstat = get_status_domain_index();
-		if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90STAT_STATUS_MASK:
-		status = kmalloc(Z90CRYPT_NUM_APS, GFP_KERNEL);
-		if (!status) {
-			PRINTK("kmalloc for status failed!\n");
-			ret = -ENOMEM;
-			break;
-		}
-		get_status_status_mask(status);
-		if (copy_to_user((char __user *) arg, status, Z90CRYPT_NUM_APS)
-									!= 0)
-			ret = -EFAULT;
-		kfree(status);
-		break;
-
-	case Z90STAT_QDEPTH_MASK:
-		qdepth = kmalloc(Z90CRYPT_NUM_APS, GFP_KERNEL);
-		if (!qdepth) {
-			PRINTK("kmalloc for qdepth failed!\n");
-			ret = -ENOMEM;
-			break;
-		}
-		get_status_qdepth_mask(qdepth);
-		if (copy_to_user((char __user *) arg, qdepth, Z90CRYPT_NUM_APS) != 0)
-			ret = -EFAULT;
-		kfree(qdepth);
-		break;
-
-	case Z90STAT_PERDEV_REQCNT:
-		reqcnt = kmalloc(sizeof(int) * Z90CRYPT_NUM_APS, GFP_KERNEL);
-		if (!reqcnt) {
-			PRINTK("kmalloc for reqcnt failed!\n");
-			ret = -ENOMEM;
-			break;
-		}
-		get_status_perdevice_reqcnt(reqcnt);
-		if (copy_to_user((char __user *) arg, reqcnt,
-				 Z90CRYPT_NUM_APS * sizeof(int)) != 0)
-			ret = -EFAULT;
-		kfree(reqcnt);
-		break;
-
-		/* THIS IS DEPRECATED.	USE THE NEW STATUS CALLS */
-	case ICAZ90STATUS:
-		if (deprecated_msg_count1 < 20) {
-			PRINTK("deprecated call to ioctl (ICAZ90STATUS)!\n");
-			deprecated_msg_count1++;
-			if (deprecated_msg_count1 == 20)
-				PRINTK("No longer issuing messages related to "
-				       "deprecated call to ICAZ90STATUS.\n");
-		}
-
-		pstat = kmalloc(sizeof(struct ica_z90_status), GFP_KERNEL);
-		if (!pstat) {
-			PRINTK("kmalloc for pstat failed!\n");
-			ret = -ENOMEM;
-			break;
-		}
-
-		pstat->totalcount	 = get_status_totalcount();
-		pstat->leedslitecount	 = get_status_PCICAcount();
-		pstat->leeds2count	 = get_status_PCICCcount();
-		pstat->requestqWaitCount = get_status_requestq_count();
-		pstat->pendingqWaitCount = get_status_pendingq_count();
-		pstat->totalOpenCount	 = get_status_totalopen_count();
-		pstat->cryptoDomain	 = get_status_domain_index();
-		get_status_status_mask(pstat->status);
-		get_status_qdepth_mask(pstat->qdepth);
-
-		if (copy_to_user((struct ica_z90_status __user *) arg, pstat,
-				 sizeof(struct ica_z90_status)) != 0)
-			ret = -EFAULT;
-		kfree(pstat);
-		break;
-
-		/* THIS IS DEPRECATED.	USE THE NEW STATUS CALLS */
-	case Z90STAT_PCIXCCCOUNT:
-		if (deprecated_msg_count2 < 20) {
-			PRINTK("deprecated ioctl (Z90STAT_PCIXCCCOUNT)!\n");
-			deprecated_msg_count2++;
-			if (deprecated_msg_count2 == 20)
-				PRINTK("No longer issuing messages about depre"
-				       "cated ioctl Z90STAT_PCIXCCCOUNT.\n");
-		}
-
-		tempstat = get_status_PCIXCCcount();
-		if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
-			ret = -EFAULT;
-		break;
-
-	case Z90QUIESCE:
-		if (current->euid != 0) {
-			PRINTK("QUIESCE fails: euid %d\n",
-			       current->euid);
-			ret = -EACCES;
-		} else {
-			PRINTK("QUIESCE device from PID %d\n", PID());
-			quiesce_z90crypt = 1;
-		}
-		break;
-
-	default:
-		/* user passed an invalid IOCTL number */
-		PDEBUG("cmd 0x%08X contains invalid ioctl code\n", cmd);
-		ret = -ENOTTY;
-		break;
-	}
-
-	return ret;
-}
-
-static inline int
-sprintcl(unsigned char *outaddr, unsigned char *addr, unsigned int len)
-{
-	int hl, i;
-
-	hl = 0;
-	for (i = 0; i < len; i++)
-		hl += sprintf(outaddr+hl, "%01x", (unsigned int) addr[i]);
-	hl += sprintf(outaddr+hl, " ");
-
-	return hl;
-}
-
-static inline int
-sprintrw(unsigned char *outaddr, unsigned char *addr, unsigned int len)
-{
-	int hl, inl, c, cx;
-
-	hl = sprintf(outaddr, "	   ");
-	inl = 0;
-	for (c = 0; c < (len / 16); c++) {
-		hl += sprintcl(outaddr+hl, addr+inl, 16);
-		inl += 16;
-	}
-
-	cx = len%16;
-	if (cx) {
-		hl += sprintcl(outaddr+hl, addr+inl, cx);
-		inl += cx;
-	}
-
-	hl += sprintf(outaddr+hl, "\n");
-
-	return hl;
-}
-
-static inline int
-sprinthx(unsigned char *title, unsigned char *outaddr,
-	 unsigned char *addr, unsigned int len)
-{
-	int hl, inl, r, rx;
-
-	hl = sprintf(outaddr, "\n%s\n", title);
-	inl = 0;
-	for (r = 0; r < (len / 64); r++) {
-		hl += sprintrw(outaddr+hl, addr+inl, 64);
-		inl += 64;
-	}
-	rx = len % 64;
-	if (rx) {
-		hl += sprintrw(outaddr+hl, addr+inl, rx);
-		inl += rx;
-	}
-
-	hl += sprintf(outaddr+hl, "\n");
-
-	return hl;
-}
-
-static inline int
-sprinthx4(unsigned char *title, unsigned char *outaddr,
-	  unsigned int *array, unsigned int len)
-{
-	int hl, r;
-
-	hl = sprintf(outaddr, "\n%s\n", title);
-
-	for (r = 0; r < len; r++) {
-		if ((r % 8) == 0)
-			hl += sprintf(outaddr+hl, "    ");
-		hl += sprintf(outaddr+hl, "%08X ", array[r]);
-		if ((r % 8) == 7)
-			hl += sprintf(outaddr+hl, "\n");
-	}
-
-	hl += sprintf(outaddr+hl, "\n");
-
-	return hl;
-}
-
-static int
-z90crypt_status(char *resp_buff, char **start, off_t offset,
-		int count, int *eof, void *data)
-{
-	unsigned char *workarea;
-	int len;
-
-	/* resp_buff is a page. Use the right half for a work area */
-	workarea = resp_buff+2000;
-	len = 0;
-	len += sprintf(resp_buff+len, "\nz90crypt version: %d.%d.%d\n",
-		z90crypt_VERSION, z90crypt_RELEASE, z90crypt_VARIANT);
-	len += sprintf(resp_buff+len, "Cryptographic domain: %d\n",
-		get_status_domain_index());
-	len += sprintf(resp_buff+len, "Total device count: %d\n",
-		get_status_totalcount());
-	len += sprintf(resp_buff+len, "PCICA count: %d\n",
-		get_status_PCICAcount());
-	len += sprintf(resp_buff+len, "PCICC count: %d\n",
-		get_status_PCICCcount());
-	len += sprintf(resp_buff+len, "PCIXCC MCL2 count: %d\n",
-		get_status_PCIXCCMCL2count());
-	len += sprintf(resp_buff+len, "PCIXCC MCL3 count: %d\n",
-		get_status_PCIXCCMCL3count());
-	len += sprintf(resp_buff+len, "CEX2C count: %d\n",
-		get_status_CEX2Ccount());
-	len += sprintf(resp_buff+len, "CEX2A count: %d\n",
-		get_status_CEX2Acount());
-	len += sprintf(resp_buff+len, "requestq count: %d\n",
-		get_status_requestq_count());
-	len += sprintf(resp_buff+len, "pendingq count: %d\n",
-		get_status_pendingq_count());
-	len += sprintf(resp_buff+len, "Total open handles: %d\n\n",
-		get_status_totalopen_count());
-	len += sprinthx(
-		"Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) "
-		"4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A",
-		resp_buff+len,
-		get_status_status_mask(workarea),
-		Z90CRYPT_NUM_APS);
-	len += sprinthx("Waiting work element counts",
-		resp_buff+len,
-		get_status_qdepth_mask(workarea),
-		Z90CRYPT_NUM_APS);
-	len += sprinthx4(
-		"Per-device successfully completed request counts",
-		resp_buff+len,
-		get_status_perdevice_reqcnt((unsigned int *)workarea),
-		Z90CRYPT_NUM_APS);
-	*eof = 1;
-	memset(workarea, 0, Z90CRYPT_NUM_APS * sizeof(unsigned int));
-	return len;
-}
-
-static inline void
-disable_card(int card_index)
-{
-	struct device *devp;
-
-	devp = LONG2DEVPTR(card_index);
-	if (!devp || devp->user_disabled)
-		return;
-	devp->user_disabled = 1;
-	z90crypt.hdware_info->hdware_mask.user_disabled_count++;
-	if (devp->dev_type == -1)
-		return;
-	z90crypt.hdware_info->type_mask[devp->dev_type].user_disabled_count++;
-}
-
-static inline void
-enable_card(int card_index)
-{
-	struct device *devp;
-
-	devp = LONG2DEVPTR(card_index);
-	if (!devp || !devp->user_disabled)
-		return;
-	devp->user_disabled = 0;
-	z90crypt.hdware_info->hdware_mask.user_disabled_count--;
-	if (devp->dev_type == -1)
-		return;
-	z90crypt.hdware_info->type_mask[devp->dev_type].user_disabled_count--;
-}
-
-static int
-z90crypt_status_write(struct file *file, const char __user *buffer,
-		      unsigned long count, void *data)
-{
-	int j, eol;
-	unsigned char *lbuf, *ptr;
-	unsigned int local_count;
-
-#define LBUFSIZE 1200
-	lbuf = kmalloc(LBUFSIZE, GFP_KERNEL);
-	if (!lbuf) {
-		PRINTK("kmalloc failed!\n");
-		return 0;
-	}
-
-	if (count <= 0)
-		return 0;
-
-	local_count = UMIN((unsigned int)count, LBUFSIZE-1);
-
-	if (copy_from_user(lbuf, buffer, local_count) != 0) {
-		kfree(lbuf);
-		return -EFAULT;
-	}
-
-	lbuf[local_count] = '\0';
-
-	ptr = strstr(lbuf, "Online devices");
-	if (ptr == 0) {
-		PRINTK("Unable to parse data (missing \"Online devices\")\n");
-		kfree(lbuf);
-		return count;
-	}
-
-	ptr = strstr(ptr, "\n");
-	if (ptr == 0) {
-		PRINTK("Unable to parse data (missing newline after \"Online devices\")\n");
-		kfree(lbuf);
-		return count;
-	}
-	ptr++;
-
-	if (strstr(ptr, "Waiting work element counts") == NULL) {
-		PRINTK("Unable to parse data (missing \"Waiting work element counts\")\n");
-		kfree(lbuf);
-		return count;
-	}
-
-	j = 0;
-	eol = 0;
-	while ((j < 64) && (*ptr != '\0')) {
-		switch (*ptr) {
-		case '\t':
-		case ' ':
-			break;
-		case '\n':
-		default:
-			eol = 1;
-			break;
-		case '0':	// no device
-		case '1':	// PCICA
-		case '2':	// PCICC
-		case '3':	// PCIXCC_MCL2
-		case '4':	// PCIXCC_MCL3
-		case '5':	// CEX2C
-		case '6':       // CEX2A
-			j++;
-			break;
-		case 'd':
-		case 'D':
-			disable_card(j);
-			j++;
-			break;
-		case 'e':
-		case 'E':
-			enable_card(j);
-			j++;
-			break;
-		}
-		if (eol)
-			break;
-		ptr++;
-	}
-
-	kfree(lbuf);
-	return count;
-}
-
-/**
- * Functions that run under a timer, with no process id
- *
- * The task functions:
- *     z90crypt_reader_task
- *	 helper_send_work
- *	 helper_handle_work_element
- *	 helper_receive_rc
- *     z90crypt_config_task
- *     z90crypt_cleanup_task
- *
- * Helper functions:
- *     z90crypt_schedule_reader_timer
- *     z90crypt_schedule_reader_task
- *     z90crypt_schedule_config_task
- *     z90crypt_schedule_cleanup_task
- */
-static inline int
-receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p,
-			   unsigned char *buff, unsigned char __user **dest_p_p)
-{
-	int dv, rv;
-	struct device *dev_ptr;
-	struct caller *caller_p;
-	struct ica_rsa_modexpo *icaMsg_p;
-	struct list_head *ptr, *tptr;
-
-	memcpy(psmid, NULL_psmid, sizeof(NULL_psmid));
-
-	if (z90crypt.terminating)
-		return REC_FATAL_ERROR;
-
-	caller_p = 0;
-	dev_ptr = z90crypt.device_p[index];
-	rv = 0;
-	do {
-		if (!dev_ptr || dev_ptr->disabled) {
-			rv = REC_NO_WORK; // a disabled device can't return work
-			break;
-		}
-		if (dev_ptr->dev_self_x != index) {
-			PRINTKC("Corrupt dev ptr\n");
-			z90crypt.terminating = 1;
-			rv = REC_FATAL_ERROR;
-			break;
-		}
-		if (!dev_ptr->dev_resp_l || !dev_ptr->dev_resp_p) {
-			dv = DEV_REC_EXCEPTION;
-			PRINTK("dev_resp_l = %d, dev_resp_p = %p\n",
-			       dev_ptr->dev_resp_l, dev_ptr->dev_resp_p);
-		} else {
-			PDEBUG("Dequeue called for device %d\n", index);
-			dv = receive_from_AP(index, z90crypt.cdx,
-					     dev_ptr->dev_resp_l,
-					     dev_ptr->dev_resp_p, psmid);
-		}
-		switch (dv) {
-		case DEV_REC_EXCEPTION:
-			rv = REC_FATAL_ERROR;
-			z90crypt.terminating = 1;
-			PRINTKC("Exception in receive from device %d\n",
-				index);
-			break;
-		case DEV_ONLINE:
-			rv = 0;
-			break;
-		case DEV_EMPTY:
-			rv = REC_EMPTY;
-			break;
-		case DEV_NO_WORK:
-			rv = REC_NO_WORK;
-			break;
-		case DEV_BAD_MESSAGE:
-		case DEV_GONE:
-		case REC_HARDWAR_ERR:
-		default:
-			rv = REC_NO_RESPONSE;
-			break;
-		}
-		if (rv)
-			break;
-		if (dev_ptr->dev_caller_count <= 0) {
-			rv = REC_USER_GONE;
-			break;
-	        }
-
-		list_for_each_safe(ptr, tptr, &dev_ptr->dev_caller_list) {
-			caller_p = list_entry(ptr, struct caller, caller_liste);
-			if (!memcmp(caller_p->caller_id, psmid,
-				    sizeof(caller_p->caller_id))) {
-				if (!list_empty(&caller_p->caller_liste)) {
-					list_del_init(ptr);
-					dev_ptr->dev_caller_count--;
-					break;
-				}
-			}
-			caller_p = 0;
-		}
-		if (!caller_p) {
-			PRINTKW("Unable to locate PSMID %02X%02X%02X%02X%02X"
-				"%02X%02X%02X in device list\n",
-				psmid[0], psmid[1], psmid[2], psmid[3],
-				psmid[4], psmid[5], psmid[6], psmid[7]);
-			rv = REC_USER_GONE;
-			break;
-		}
-
-		PDEBUG("caller_p after successful receive: %p\n", caller_p);
-		rv = convert_response(dev_ptr->dev_resp_p,
-				      caller_p->caller_buf_p, buff_len_p, buff);
-		switch (rv) {
-		case REC_USE_PCICA:
-			break;
-		case REC_OPERAND_INV:
-		case REC_OPERAND_SIZE:
-		case REC_EVEN_MOD:
-		case REC_INVALID_PAD:
-			PDEBUG("device %d: 'user error' %d\n", index, rv);
-			break;
-		case WRONG_DEVICE_TYPE:
-		case REC_HARDWAR_ERR:
-		case REC_BAD_MESSAGE:
-			PRINTKW("device %d: hardware error %d\n", index, rv);
-			rv = REC_NO_RESPONSE;
-			break;
-		default:
-			PDEBUG("device %d: rv = %d\n", index, rv);
-			break;
-		}
-	} while (0);
-
-	switch (rv) {
-	case 0:
-		PDEBUG("Successful receive from device %d\n", index);
-		icaMsg_p = (struct ica_rsa_modexpo *)caller_p->caller_buf_p;
-		*dest_p_p = icaMsg_p->outputdata;
-		if (*buff_len_p == 0)
-			PRINTK("Zero *buff_len_p\n");
-		break;
-	case REC_NO_RESPONSE:
-		PRINTKW("Removing device %d from availability\n", index);
-		remove_device(dev_ptr);
-		break;
-	}
-
-	if (caller_p)
-		unbuild_caller(dev_ptr, caller_p);
-
-	return rv;
-}
-
-static inline void
-helper_send_work(int index)
-{
-	struct work_element *rq_p;
-	int rv;
-
-	if (list_empty(&request_list))
-		return;
-	requestq_count--;
-	rq_p = list_entry(request_list.next, struct work_element, liste);
-	list_del_init(&rq_p->liste);
-	rq_p->audit[1] |= FP_REMREQUEST;
-	if (rq_p->devtype == SHRT2DEVPTR(index)->dev_type) {
-		rq_p->devindex = SHRT2LONG(index);
-		rv = send_to_crypto_device(rq_p);
-		if (rv == 0) {
-			rq_p->requestsent = jiffies;
-			rq_p->audit[0] |= FP_SENT;
-			list_add_tail(&rq_p->liste, &pending_list);
-			++pendingq_count;
-			rq_p->audit[0] |= FP_PENDING;
-		} else {
-			switch (rv) {
-			case REC_OPERAND_INV:
-			case REC_OPERAND_SIZE:
-			case REC_EVEN_MOD:
-			case REC_INVALID_PAD:
-				rq_p->retcode = -EINVAL;
-				break;
-			case SEN_NOT_AVAIL:
-			case SEN_RETRY:
-			case REC_NO_RESPONSE:
-			default:
-				if (z90crypt.mask.st_count > 1)
-					rq_p->retcode =
-						-ERESTARTSYS;
-				else
-					rq_p->retcode = -ENODEV;
-				break;
-			}
-			rq_p->status[0] |= STAT_FAILED;
-			rq_p->audit[1] |= FP_AWAKENING;
-			atomic_set(&rq_p->alarmrung, 1);
-			wake_up(&rq_p->waitq);
-		}
-	} else {
-		if (z90crypt.mask.st_count > 1)
-			rq_p->retcode = -ERESTARTSYS;
-		else
-			rq_p->retcode = -ENODEV;
-		rq_p->status[0] |= STAT_FAILED;
-		rq_p->audit[1] |= FP_AWAKENING;
-		atomic_set(&rq_p->alarmrung, 1);
-		wake_up(&rq_p->waitq);
-	}
-}
-
-static inline void
-helper_handle_work_element(int index, unsigned char psmid[8], int rc,
-			   int buff_len, unsigned char *buff,
-			   unsigned char __user *resp_addr)
-{
-	struct work_element *pq_p;
-	struct list_head *lptr, *tptr;
-
-	pq_p = 0;
-	list_for_each_safe(lptr, tptr, &pending_list) {
-		pq_p = list_entry(lptr, struct work_element, liste);
-		if (!memcmp(pq_p->caller_id, psmid, sizeof(pq_p->caller_id))) {
-			list_del_init(lptr);
-			pendingq_count--;
-			pq_p->audit[1] |= FP_NOTPENDING;
-			break;
-		}
-		pq_p = 0;
-	}
-
-	if (!pq_p) {
-		PRINTK("device %d has work but no caller exists on pending Q\n",
-		       SHRT2LONG(index));
-		return;
-	}
-
-	switch (rc) {
-		case 0:
-			pq_p->resp_buff_size = buff_len;
-			pq_p->audit[1] |= FP_RESPSIZESET;
-			if (buff_len) {
-				pq_p->resp_addr = resp_addr;
-				pq_p->audit[1] |= FP_RESPADDRCOPIED;
-				memcpy(pq_p->resp_buff, buff, buff_len);
-				pq_p->audit[1] |= FP_RESPBUFFCOPIED;
-			}
-			break;
-		case REC_OPERAND_INV:
-		case REC_OPERAND_SIZE:
-		case REC_EVEN_MOD:
-		case REC_INVALID_PAD:
-			PDEBUG("-EINVAL after application error %d\n", rc);
-			pq_p->retcode = -EINVAL;
-			pq_p->status[0] |= STAT_FAILED;
-			break;
-		case REC_USE_PCICA:
-			pq_p->retcode = -ERESTARTSYS;
-			pq_p->status[0] |= STAT_FAILED;
-			break;
-		case REC_NO_RESPONSE:
-		default:
-			if (z90crypt.mask.st_count > 1)
-				pq_p->retcode = -ERESTARTSYS;
-			else
-				pq_p->retcode = -ENODEV;
-			pq_p->status[0] |= STAT_FAILED;
-			break;
-	}
-	if ((pq_p->status[0] != STAT_FAILED) || (pq_p->retcode != -ERELEASED)) {
-		pq_p->audit[1] |= FP_AWAKENING;
-		atomic_set(&pq_p->alarmrung, 1);
-		wake_up(&pq_p->waitq);
-	}
-}
-
-/**
- * return TRUE if the work element should be removed from the queue
- */
-static inline int
-helper_receive_rc(int index, int *rc_p)
-{
-	switch (*rc_p) {
-	case 0:
-	case REC_OPERAND_INV:
-	case REC_OPERAND_SIZE:
-	case REC_EVEN_MOD:
-	case REC_INVALID_PAD:
-	case REC_USE_PCICA:
-		break;
-
-	case REC_BUSY:
-	case REC_NO_WORK:
-	case REC_EMPTY:
-	case REC_RETRY_DEV:
-	case REC_FATAL_ERROR:
-		return 0;
-
-	case REC_NO_RESPONSE:
-		break;
-
-	default:
-		PRINTK("rc %d, device %d converted to REC_NO_RESPONSE\n",
-		       *rc_p, SHRT2LONG(index));
-		*rc_p = REC_NO_RESPONSE;
-		break;
-	}
-	return 1;
-}
-
-static inline void
-z90crypt_schedule_reader_timer(void)
-{
-	if (timer_pending(&reader_timer))
-		return;
-	if (mod_timer(&reader_timer, jiffies+(READERTIME*HZ/1000)) != 0)
-		PRINTK("Timer pending while modifying reader timer\n");
-}
-
-static void
-z90crypt_reader_task(unsigned long ptr)
-{
-	int workavail, index, rc, buff_len;
-	unsigned char	psmid[8];
-	unsigned char __user *resp_addr;
-	static unsigned char buff[1024];
-
-	/**
-	 * we use workavail = 2 to ensure 2 passes with nothing dequeued before
-	 * exiting the loop. If (pendingq_count+requestq_count) == 0 after the
-	 * loop, there is no work remaining on the queues.
-	 */
-	resp_addr = 0;
-	workavail = 2;
-	buff_len = 0;
-	while (workavail) {
-		workavail--;
-		rc = 0;
-		spin_lock_irq(&queuespinlock);
-		memset(buff, 0x00, sizeof(buff));
-
-		/* Dequeue once from each device in round robin. */
-		for (index = 0; index < z90crypt.mask.st_count; index++) {
-			PDEBUG("About to receive.\n");
-			rc = receive_from_crypto_device(SHRT2LONG(index),
-							psmid,
-							&buff_len,
-							buff,
-							&resp_addr);
-			PDEBUG("Dequeued: rc = %d.\n", rc);
-
-			if (helper_receive_rc(index, &rc)) {
-				if (rc != REC_NO_RESPONSE) {
-					helper_send_work(index);
-					workavail = 2;
-				}
-
-				helper_handle_work_element(index, psmid, rc,
-							   buff_len, buff,
-							   resp_addr);
-			}
-
-			if (rc == REC_FATAL_ERROR)
-				PRINTKW("REC_FATAL_ERROR from device %d!\n",
-					SHRT2LONG(index));
-		}
-		spin_unlock_irq(&queuespinlock);
-	}
-
-	if (pendingq_count + requestq_count)
-		z90crypt_schedule_reader_timer();
-}
-
-static inline void
-z90crypt_schedule_config_task(unsigned int expiration)
-{
-	if (timer_pending(&config_timer))
-		return;
-	if (mod_timer(&config_timer, jiffies+(expiration*HZ)) != 0)
-		PRINTK("Timer pending while modifying config timer\n");
-}
-
-static void
-z90crypt_config_task(unsigned long ptr)
-{
-	int rc;
-
-	PDEBUG("jiffies %ld\n", jiffies);
-
-	if ((rc = refresh_z90crypt(&z90crypt.cdx)))
-		PRINTK("Error %d detected in refresh_z90crypt.\n", rc);
-	/* If return was fatal, don't bother reconfiguring */
-	if ((rc != TSQ_FATAL_ERROR) && (rc != RSQ_FATAL_ERROR))
-		z90crypt_schedule_config_task(CONFIGTIME);
-}
-
-static inline void
-z90crypt_schedule_cleanup_task(void)
-{
-	if (timer_pending(&cleanup_timer))
-		return;
-	if (mod_timer(&cleanup_timer, jiffies+(CLEANUPTIME*HZ)) != 0)
-		PRINTK("Timer pending while modifying cleanup timer\n");
-}
-
-static inline void
-helper_drain_queues(void)
-{
-	struct work_element *pq_p;
-	struct list_head *lptr, *tptr;
-
-	list_for_each_safe(lptr, tptr, &pending_list) {
-		pq_p = list_entry(lptr, struct work_element, liste);
-		pq_p->retcode = -ENODEV;
-		pq_p->status[0] |= STAT_FAILED;
-		unbuild_caller(LONG2DEVPTR(pq_p->devindex),
-			       (struct caller *)pq_p->requestptr);
-		list_del_init(lptr);
-		pendingq_count--;
-		pq_p->audit[1] |= FP_NOTPENDING;
-		pq_p->audit[1] |= FP_AWAKENING;
-		atomic_set(&pq_p->alarmrung, 1);
-		wake_up(&pq_p->waitq);
-	}
-
-	list_for_each_safe(lptr, tptr, &request_list) {
-		pq_p = list_entry(lptr, struct work_element, liste);
-		pq_p->retcode = -ENODEV;
-		pq_p->status[0] |= STAT_FAILED;
-		list_del_init(lptr);
-		requestq_count--;
-		pq_p->audit[1] |= FP_REMREQUEST;
-		pq_p->audit[1] |= FP_AWAKENING;
-		atomic_set(&pq_p->alarmrung, 1);
-		wake_up(&pq_p->waitq);
-	}
-}
-
-static inline void
-helper_timeout_requests(void)
-{
-	struct work_element *pq_p;
-	struct list_head *lptr, *tptr;
-	long timelimit;
-
-	timelimit = jiffies - (CLEANUPTIME * HZ);
-	/* The list is in strict chronological order */
-	list_for_each_safe(lptr, tptr, &pending_list) {
-		pq_p = list_entry(lptr, struct work_element, liste);
-		if (pq_p->requestsent >= timelimit)
-			break;
-		PRINTKW("Purging(PQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
-		       ((struct caller *)pq_p->requestptr)->caller_id[0],
-		       ((struct caller *)pq_p->requestptr)->caller_id[1],
-		       ((struct caller *)pq_p->requestptr)->caller_id[2],
-		       ((struct caller *)pq_p->requestptr)->caller_id[3],
-		       ((struct caller *)pq_p->requestptr)->caller_id[4],
-		       ((struct caller *)pq_p->requestptr)->caller_id[5],
-		       ((struct caller *)pq_p->requestptr)->caller_id[6],
-		       ((struct caller *)pq_p->requestptr)->caller_id[7]);
-		pq_p->retcode = -ETIMEOUT;
-		pq_p->status[0] |= STAT_FAILED;
-		/* get this off any caller queue it may be on */
-		unbuild_caller(LONG2DEVPTR(pq_p->devindex),
-			       (struct caller *) pq_p->requestptr);
-		list_del_init(lptr);
-		pendingq_count--;
-		pq_p->audit[1] |= FP_TIMEDOUT;
-		pq_p->audit[1] |= FP_NOTPENDING;
-		pq_p->audit[1] |= FP_AWAKENING;
-		atomic_set(&pq_p->alarmrung, 1);
-		wake_up(&pq_p->waitq);
-	}
-
-	/**
-	 * If pending count is zero, items left on the request queue may
-	 * never be processed.
-	 */
-	if (pendingq_count <= 0) {
-		list_for_each_safe(lptr, tptr, &request_list) {
-			pq_p = list_entry(lptr, struct work_element, liste);
-			if (pq_p->requestsent >= timelimit)
-				break;
-		PRINTKW("Purging(RQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
-		       ((struct caller *)pq_p->requestptr)->caller_id[0],
-		       ((struct caller *)pq_p->requestptr)->caller_id[1],
-		       ((struct caller *)pq_p->requestptr)->caller_id[2],
-		       ((struct caller *)pq_p->requestptr)->caller_id[3],
-		       ((struct caller *)pq_p->requestptr)->caller_id[4],
-		       ((struct caller *)pq_p->requestptr)->caller_id[5],
-		       ((struct caller *)pq_p->requestptr)->caller_id[6],
-		       ((struct caller *)pq_p->requestptr)->caller_id[7]);
-			pq_p->retcode = -ETIMEOUT;
-			pq_p->status[0] |= STAT_FAILED;
-			list_del_init(lptr);
-			requestq_count--;
-			pq_p->audit[1] |= FP_TIMEDOUT;
-			pq_p->audit[1] |= FP_REMREQUEST;
-			pq_p->audit[1] |= FP_AWAKENING;
-			atomic_set(&pq_p->alarmrung, 1);
-			wake_up(&pq_p->waitq);
-		}
-	}
-}
-
-static void
-z90crypt_cleanup_task(unsigned long ptr)
-{
-	PDEBUG("jiffies %ld\n", jiffies);
-	spin_lock_irq(&queuespinlock);
-	if (z90crypt.mask.st_count <= 0) // no devices!
-		helper_drain_queues();
-	else
-		helper_timeout_requests();
-	spin_unlock_irq(&queuespinlock);
-	z90crypt_schedule_cleanup_task();
-}
-
-static void
-z90crypt_schedule_reader_task(unsigned long ptr)
-{
-	tasklet_schedule(&reader_tasklet);
-}
-
-/**
- * Lowlevel Functions:
- *
- *   create_z90crypt:  creates and initializes basic data structures
- *   refresh_z90crypt:	re-initializes basic data structures
- *   find_crypto_devices: returns a count and mask of hardware status
- *   create_crypto_device:  builds the descriptor for a device
- *   destroy_crypto_device:  unallocates the descriptor for a device
- *   destroy_z90crypt:	drains all work, unallocates structs
- */
-
-/**
- * build the z90crypt root structure using the given domain index
- */
-static int
-create_z90crypt(int *cdx_p)
-{
-	struct hdware_block *hdware_blk_p;
-
-	memset(&z90crypt, 0x00, sizeof(struct z90crypt));
-	z90crypt.domain_established = 0;
-	z90crypt.len = sizeof(struct z90crypt);
-	z90crypt.max_count = Z90CRYPT_NUM_DEVS;
-	z90crypt.cdx = *cdx_p;
-
-	hdware_blk_p = kzalloc(sizeof(struct hdware_block), GFP_ATOMIC);
-	if (!hdware_blk_p) {
-		PDEBUG("kmalloc for hardware block failed\n");
-		return ENOMEM;
-	}
-	z90crypt.hdware_info = hdware_blk_p;
-
-	return 0;
-}
-
-static inline int
-helper_scan_devices(int cdx_array[16], int *cdx_p, int *correct_cdx_found)
-{
-	enum hdstat hd_stat;
-	int q_depth, dev_type;
-	int indx, chkdom, numdomains;
-
-	q_depth = dev_type = numdomains = 0;
-	for (chkdom = 0; chkdom <= 15; cdx_array[chkdom++] = -1);
-	for (indx = 0; indx < z90crypt.max_count; indx++) {
-		hd_stat = HD_NOT_THERE;
-		numdomains = 0;
-		for (chkdom = 0; chkdom <= 15; chkdom++) {
-			hd_stat = query_online(indx, chkdom, MAX_RESET,
-					       &q_depth, &dev_type);
-			if (hd_stat == HD_TSQ_EXCEPTION) {
-				z90crypt.terminating = 1;
-				PRINTKC("exception taken!\n");
-				break;
-			}
-			if (hd_stat == HD_ONLINE) {
-				cdx_array[numdomains++] = chkdom;
-				if (*cdx_p == chkdom) {
-					*correct_cdx_found  = 1;
-					break;
-				}
-			}
-		}
-		if ((*correct_cdx_found == 1) || (numdomains != 0))
-			break;
-		if (z90crypt.terminating)
-			break;
-	}
-	return numdomains;
-}
-
-static inline int
-probe_crypto_domain(int *cdx_p)
-{
-	int cdx_array[16];
-	char cdx_array_text[53], temp[5];
-	int correct_cdx_found, numdomains;
-
-	correct_cdx_found = 0;
-	numdomains = helper_scan_devices(cdx_array, cdx_p, &correct_cdx_found);
-
-	if (z90crypt.terminating)
-		return TSQ_FATAL_ERROR;
-
-	if (correct_cdx_found)
-		return 0;
-
-	if (numdomains == 0) {
-		PRINTKW("Unable to find crypto domain: No devices found\n");
-		return Z90C_NO_DEVICES;
-	}
-
-	if (numdomains == 1) {
-		if (*cdx_p == -1) {
-			*cdx_p = cdx_array[0];
-			return 0;
-		}
-		PRINTKW("incorrect domain: specified = %d, found = %d\n",
-		       *cdx_p, cdx_array[0]);
-		return Z90C_INCORRECT_DOMAIN;
-	}
-
-	numdomains--;
-	sprintf(cdx_array_text, "%d", cdx_array[numdomains]);
-	while (numdomains) {
-		numdomains--;
-		sprintf(temp, ", %d", cdx_array[numdomains]);
-		strcat(cdx_array_text, temp);
-	}
-
-	PRINTKW("ambiguous domain detected: specified = %d, found array = %s\n",
-		*cdx_p, cdx_array_text);
-	return Z90C_AMBIGUOUS_DOMAIN;
-}
-
-static int
-refresh_z90crypt(int *cdx_p)
-{
-	int i, j, indx, rv;
-	static struct status local_mask;
-	struct device *devPtr;
-	unsigned char oldStat, newStat;
-	int return_unchanged;
-
-	if (z90crypt.len != sizeof(z90crypt))
-		return ENOTINIT;
-	if (z90crypt.terminating)
-		return TSQ_FATAL_ERROR;
-	rv = 0;
-	if (!z90crypt.hdware_info->hdware_mask.st_count &&
-	    !z90crypt.domain_established) {
-		rv = probe_crypto_domain(cdx_p);
-		if (z90crypt.terminating)
-			return TSQ_FATAL_ERROR;
-		if (rv == Z90C_NO_DEVICES)
-			return 0; // try later
-		if (rv)
-			return rv;
-		z90crypt.cdx = *cdx_p;
-		z90crypt.domain_established = 1;
-	}
-	rv = find_crypto_devices(&local_mask);
-	if (rv) {
-		PRINTK("find crypto devices returned %d\n", rv);
-		return rv;
-	}
-	if (!memcmp(&local_mask, &z90crypt.hdware_info->hdware_mask,
-		    sizeof(struct status))) {
-		return_unchanged = 1;
-		for (i = 0; i < Z90CRYPT_NUM_TYPES; i++) {
-			/**
-			 * Check for disabled cards.  If any device is marked
-			 * disabled, destroy it.
-			 */
-			for (j = 0;
-			     j < z90crypt.hdware_info->type_mask[i].st_count;
-			     j++) {
-				indx = z90crypt.hdware_info->type_x_addr[i].
-								device_index[j];
-				devPtr = z90crypt.device_p[indx];
-				if (devPtr && devPtr->disabled) {
-					local_mask.st_mask[indx] = HD_NOT_THERE;
-					return_unchanged = 0;
-				}
-			}
-		}
-		if (return_unchanged == 1)
-			return 0;
-	}
-
-	spin_lock_irq(&queuespinlock);
-	for (i = 0; i < z90crypt.max_count; i++) {
-		oldStat = z90crypt.hdware_info->hdware_mask.st_mask[i];
-		newStat = local_mask.st_mask[i];
-		if ((oldStat == HD_ONLINE) && (newStat != HD_ONLINE))
-			destroy_crypto_device(i);
-		else if ((oldStat != HD_ONLINE) && (newStat == HD_ONLINE)) {
-			rv = create_crypto_device(i);
-			if (rv >= REC_FATAL_ERROR)
-				return rv;
-			if (rv != 0) {
-				local_mask.st_mask[i] = HD_NOT_THERE;
-				local_mask.st_count--;
-			}
-		}
-	}
-	memcpy(z90crypt.hdware_info->hdware_mask.st_mask, local_mask.st_mask,
-	       sizeof(local_mask.st_mask));
-	z90crypt.hdware_info->hdware_mask.st_count = local_mask.st_count;
-	z90crypt.hdware_info->hdware_mask.disabled_count =
-						      local_mask.disabled_count;
-	refresh_index_array(&z90crypt.mask, &z90crypt.overall_device_x);
-	for (i = 0; i < Z90CRYPT_NUM_TYPES; i++)
-		refresh_index_array(&(z90crypt.hdware_info->type_mask[i]),
-				    &(z90crypt.hdware_info->type_x_addr[i]));
-	spin_unlock_irq(&queuespinlock);
-
-	return rv;
-}
-
-static int
-find_crypto_devices(struct status *deviceMask)
-{
-	int i, q_depth, dev_type;
-	enum hdstat hd_stat;
-
-	deviceMask->st_count = 0;
-	deviceMask->disabled_count = 0;
-	deviceMask->user_disabled_count = 0;
-
-	for (i = 0; i < z90crypt.max_count; i++) {
-		hd_stat = query_online(i, z90crypt.cdx, MAX_RESET, &q_depth,
-				       &dev_type);
-		if (hd_stat == HD_TSQ_EXCEPTION) {
-			z90crypt.terminating = 1;
-			PRINTKC("Exception during probe for crypto devices\n");
-			return TSQ_FATAL_ERROR;
-		}
-		deviceMask->st_mask[i] = hd_stat;
-		if (hd_stat == HD_ONLINE) {
-			PDEBUG("Got an online crypto!: %d\n", i);
-			PDEBUG("Got a queue depth of %d\n", q_depth);
-			PDEBUG("Got a device type of %d\n", dev_type);
-			if (q_depth <= 0)
-				return TSQ_FATAL_ERROR;
-			deviceMask->st_count++;
-			z90crypt.q_depth_array[i] = q_depth;
-			z90crypt.dev_type_array[i] = dev_type;
-		}
-	}
-
-	return 0;
-}
-
-static int
-refresh_index_array(struct status *status_str, struct device_x *index_array)
-{
-	int i, count;
-	enum devstat stat;
-
-	i = -1;
-	count = 0;
-	do {
-		stat = status_str->st_mask[++i];
-		if (stat == DEV_ONLINE)
-			index_array->device_index[count++] = i;
-	} while ((i < Z90CRYPT_NUM_DEVS) && (count < status_str->st_count));
-
-	return count;
-}
-
-static int
-create_crypto_device(int index)
-{
-	int rv, devstat, total_size;
-	struct device *dev_ptr;
-	struct status *type_str_p;
-	int deviceType;
-
-	dev_ptr = z90crypt.device_p[index];
-	if (!dev_ptr) {
-		total_size = sizeof(struct device) +
-			     z90crypt.q_depth_array[index] * sizeof(int);
-
-		dev_ptr = kzalloc(total_size, GFP_ATOMIC);
-		if (!dev_ptr) {
-			PRINTK("kmalloc device %d failed\n", index);
-			return ENOMEM;
-		}
-		dev_ptr->dev_resp_p = kmalloc(MAX_RESPONSE_SIZE, GFP_ATOMIC);
-		if (!dev_ptr->dev_resp_p) {
-			kfree(dev_ptr);
-			PRINTK("kmalloc device %d rec buffer failed\n", index);
-			return ENOMEM;
-		}
-		dev_ptr->dev_resp_l = MAX_RESPONSE_SIZE;
-		INIT_LIST_HEAD(&(dev_ptr->dev_caller_list));
-	}
-
-	devstat = reset_device(index, z90crypt.cdx, MAX_RESET);
-	if (devstat == DEV_RSQ_EXCEPTION) {
-		PRINTK("exception during reset device %d\n", index);
-		kfree(dev_ptr->dev_resp_p);
-		kfree(dev_ptr);
-		return RSQ_FATAL_ERROR;
-	}
-	if (devstat == DEV_ONLINE) {
-		dev_ptr->dev_self_x = index;
-		dev_ptr->dev_type = z90crypt.dev_type_array[index];
-		if (dev_ptr->dev_type == NILDEV) {
-			rv = probe_device_type(dev_ptr);
-			if (rv) {
-				PRINTK("rv = %d from probe_device_type %d\n",
-				       rv, index);
-				kfree(dev_ptr->dev_resp_p);
-				kfree(dev_ptr);
-				return rv;
-			}
-		}
-		if (dev_ptr->dev_type == PCIXCC_UNK) {
-			rv = probe_PCIXCC_type(dev_ptr);
-			if (rv) {
-				PRINTK("rv = %d from probe_PCIXCC_type %d\n",
-				       rv, index);
-				kfree(dev_ptr->dev_resp_p);
-				kfree(dev_ptr);
-				return rv;
-			}
-		}
-		deviceType = dev_ptr->dev_type;
-		z90crypt.dev_type_array[index] = deviceType;
-		if (deviceType == PCICA)
-			z90crypt.hdware_info->device_type_array[index] = 1;
-		else if (deviceType == PCICC)
-			z90crypt.hdware_info->device_type_array[index] = 2;
-		else if (deviceType == PCIXCC_MCL2)
-			z90crypt.hdware_info->device_type_array[index] = 3;
-		else if (deviceType == PCIXCC_MCL3)
-			z90crypt.hdware_info->device_type_array[index] = 4;
-		else if (deviceType == CEX2C)
-			z90crypt.hdware_info->device_type_array[index] = 5;
-		else if (deviceType == CEX2A)
-			z90crypt.hdware_info->device_type_array[index] = 6;
-		else // No idea how this would happen.
-			z90crypt.hdware_info->device_type_array[index] = -1;
-	}
-
-	/**
-	 * 'q_depth' returned by the hardware is one less than
-	 * the actual depth
-	 */
-	dev_ptr->dev_q_depth = z90crypt.q_depth_array[index];
-	dev_ptr->dev_type = z90crypt.dev_type_array[index];
-	dev_ptr->dev_stat = devstat;
-	dev_ptr->disabled = 0;
-	z90crypt.device_p[index] = dev_ptr;
-
-	if (devstat == DEV_ONLINE) {
-		if (z90crypt.mask.st_mask[index] != DEV_ONLINE) {
-			z90crypt.mask.st_mask[index] = DEV_ONLINE;
-			z90crypt.mask.st_count++;
-		}
-		deviceType = dev_ptr->dev_type;
-		type_str_p = &z90crypt.hdware_info->type_mask[deviceType];
-		if (type_str_p->st_mask[index] != DEV_ONLINE) {
-			type_str_p->st_mask[index] = DEV_ONLINE;
-			type_str_p->st_count++;
-		}
-	}
-
-	return 0;
-}
-
-static int
-destroy_crypto_device(int index)
-{
-	struct device *dev_ptr;
-	int t, disabledFlag;
-
-	dev_ptr = z90crypt.device_p[index];
-
-	/* remember device type; get rid of device struct */
-	if (dev_ptr) {
-		disabledFlag = dev_ptr->disabled;
-		t = dev_ptr->dev_type;
-		kfree(dev_ptr->dev_resp_p);
-		kfree(dev_ptr);
-	} else {
-		disabledFlag = 0;
-		t = -1;
-	}
-	z90crypt.device_p[index] = 0;
-
-	/* if the type is valid, remove the device from the type_mask */
-	if ((t != -1) && z90crypt.hdware_info->type_mask[t].st_mask[index]) {
-		  z90crypt.hdware_info->type_mask[t].st_mask[index] = 0x00;
-		  z90crypt.hdware_info->type_mask[t].st_count--;
-		  if (disabledFlag == 1)
-			z90crypt.hdware_info->type_mask[t].disabled_count--;
-	}
-	if (z90crypt.mask.st_mask[index] != DEV_GONE) {
-		z90crypt.mask.st_mask[index] = DEV_GONE;
-		z90crypt.mask.st_count--;
-	}
-	z90crypt.hdware_info->device_type_array[index] = 0;
-
-	return 0;
-}
-
-static void
-destroy_z90crypt(void)
-{
-	int i;
-
-	for (i = 0; i < z90crypt.max_count; i++)
-		if (z90crypt.device_p[i])
-			destroy_crypto_device(i);
-	kfree(z90crypt.hdware_info);
-	memset((void *)&z90crypt, 0, sizeof(z90crypt));
-}
-
-static unsigned char static_testmsg[384] = {
-0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x00,0x06,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x43,0x43,
-0x41,0x2d,0x41,0x50,0x50,0x4c,0x20,0x20,0x20,0x01,0x01,0x01,0x00,0x00,0x00,0x00,
-0x50,0x4b,0x00,0x00,0x00,0x00,0x01,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x70,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x32,
-0x01,0x00,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0xb8,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x0a,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,0x50,0x4b,0x0a,0x00,0x50,0x4b,0x43,0x53,0x2d,0x31,0x2e,0x32,
-0x37,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,
-0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,
-0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,0x55,0x66,
-0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x5d,0x00,0x5b,0x00,0x77,0x88,0x1e,0x00,0x00,
-0x57,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x4f,0x00,0x00,0x00,0x03,0x02,0x00,0x00,
-0x40,0x01,0x00,0x01,0xce,0x02,0x68,0x2d,0x5f,0xa9,0xde,0x0c,0xf6,0xd2,0x7b,0x58,
-0x4b,0xf9,0x28,0x68,0x3d,0xb4,0xf4,0xef,0x78,0xd5,0xbe,0x66,0x63,0x42,0xef,0xf8,
-0xfd,0xa4,0xf8,0xb0,0x8e,0x29,0xc2,0xc9,0x2e,0xd8,0x45,0xb8,0x53,0x8c,0x6f,0x4e,
-0x72,0x8f,0x6c,0x04,0x9c,0x88,0xfc,0x1e,0xc5,0x83,0x55,0x57,0xf7,0xdd,0xfd,0x4f,
-0x11,0x36,0x95,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-};
-
-static int
-probe_device_type(struct device *devPtr)
-{
-	int rv, dv, i, index, length;
-	unsigned char psmid[8];
-	static unsigned char loc_testmsg[sizeof(static_testmsg)];
-
-	index = devPtr->dev_self_x;
-	rv = 0;
-	do {
-		memcpy(loc_testmsg, static_testmsg, sizeof(static_testmsg));
-		length = sizeof(static_testmsg) - 24;
-		/* the -24 allows for the header */
-		dv = send_to_AP(index, z90crypt.cdx, length, loc_testmsg);
-		if (dv) {
-			PDEBUG("dv returned by send during probe: %d\n", dv);
-			if (dv == DEV_SEN_EXCEPTION) {
-				rv = SEN_FATAL_ERROR;
-				PRINTKC("exception in send to AP %d\n", index);
-				break;
-			}
-			PDEBUG("return value from send_to_AP: %d\n", rv);
-			switch (dv) {
-			case DEV_GONE:
-				PDEBUG("dev %d not available\n", index);
-				rv = SEN_NOT_AVAIL;
-				break;
-			case DEV_ONLINE:
-				rv = 0;
-				break;
-			case DEV_EMPTY:
-				rv = SEN_NOT_AVAIL;
-				break;
-			case DEV_NO_WORK:
-				rv = SEN_FATAL_ERROR;
-				break;
-			case DEV_BAD_MESSAGE:
-				rv = SEN_USER_ERROR;
-				break;
-			case DEV_QUEUE_FULL:
-				rv = SEN_QUEUE_FULL;
-				break;
-			default:
-				PRINTK("unknown dv=%d for dev %d\n", dv, index);
-				rv = SEN_NOT_AVAIL;
-				break;
-			}
-		}
-
-		if (rv)
-			break;
-
-		for (i = 0; i < 6; i++) {
-			mdelay(300);
-			dv = receive_from_AP(index, z90crypt.cdx,
-					     devPtr->dev_resp_l,
-					     devPtr->dev_resp_p, psmid);
-			PDEBUG("dv returned by DQ = %d\n", dv);
-			if (dv == DEV_REC_EXCEPTION) {
-				rv = REC_FATAL_ERROR;
-				PRINTKC("exception in dequeue %d\n",
-					index);
-				break;
-			}
-			switch (dv) {
-			case DEV_ONLINE:
-				rv = 0;
-				break;
-			case DEV_EMPTY:
-				rv = REC_EMPTY;
-				break;
-			case DEV_NO_WORK:
-				rv = REC_NO_WORK;
-				break;
-			case DEV_BAD_MESSAGE:
-			case DEV_GONE:
-			default:
-				rv = REC_NO_RESPONSE;
-				break;
-			}
-			if ((rv != 0) && (rv != REC_NO_WORK))
-				break;
-			if (rv == 0)
-				break;
-		}
-		if (rv)
-			break;
-		rv = (devPtr->dev_resp_p[0] == 0x00) &&
-		     (devPtr->dev_resp_p[1] == 0x86);
-		if (rv)
-			devPtr->dev_type = PCICC;
-		else
-			devPtr->dev_type = PCICA;
-		rv = 0;
-	} while (0);
-	/* In a general error case, the card is not marked online */
-	return rv;
-}
-
-static unsigned char MCL3_testmsg[] = {
-0x00,0x00,0x00,0x00,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
-0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
-0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
-0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
-0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
-0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
-0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
-0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
-0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
-0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
-0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
-0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
-0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
-0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
-0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
-0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,0xF1,0x3D,0x93,0x53
-};
-
-static int
-probe_PCIXCC_type(struct device *devPtr)
-{
-	int rv, dv, i, index, length;
-	unsigned char psmid[8];
-	static unsigned char loc_testmsg[548];
-	struct CPRBX *cprbx_p;
-
-	index = devPtr->dev_self_x;
-	rv = 0;
-	do {
-		memcpy(loc_testmsg, MCL3_testmsg, sizeof(MCL3_testmsg));
-		length = sizeof(MCL3_testmsg) - 0x0C;
-		dv = send_to_AP(index, z90crypt.cdx, length, loc_testmsg);
-		if (dv) {
-			PDEBUG("dv returned = %d\n", dv);
-			if (dv == DEV_SEN_EXCEPTION) {
-				rv = SEN_FATAL_ERROR;
-				PRINTKC("exception in send to AP %d\n", index);
-				break;
-			}
-			PDEBUG("return value from send_to_AP: %d\n", rv);
-			switch (dv) {
-			case DEV_GONE:
-				PDEBUG("dev %d not available\n", index);
-				rv = SEN_NOT_AVAIL;
-				break;
-			case DEV_ONLINE:
-				rv = 0;
-				break;
-			case DEV_EMPTY:
-				rv = SEN_NOT_AVAIL;
-				break;
-			case DEV_NO_WORK:
-				rv = SEN_FATAL_ERROR;
-				break;
-			case DEV_BAD_MESSAGE:
-				rv = SEN_USER_ERROR;
-				break;
-			case DEV_QUEUE_FULL:
-				rv = SEN_QUEUE_FULL;
-				break;
-			default:
-				PRINTK("unknown dv=%d for dev %d\n", dv, index);
-				rv = SEN_NOT_AVAIL;
-				break;
-			}
-		}
-
-		if (rv)
-			break;
-
-		for (i = 0; i < 6; i++) {
-			mdelay(300);
-			dv = receive_from_AP(index, z90crypt.cdx,
-					     devPtr->dev_resp_l,
-					     devPtr->dev_resp_p, psmid);
-			PDEBUG("dv returned by DQ = %d\n", dv);
-			if (dv == DEV_REC_EXCEPTION) {
-				rv = REC_FATAL_ERROR;
-				PRINTKC("exception in dequeue %d\n",
-					index);
-				break;
-			}
-			switch (dv) {
-			case DEV_ONLINE:
-				rv = 0;
-				break;
-			case DEV_EMPTY:
-				rv = REC_EMPTY;
-				break;
-			case DEV_NO_WORK:
-				rv = REC_NO_WORK;
-				break;
-			case DEV_BAD_MESSAGE:
-			case DEV_GONE:
-			default:
-				rv = REC_NO_RESPONSE;
-				break;
-			}
-			if ((rv != 0) && (rv != REC_NO_WORK))
-				break;
-			if (rv == 0)
-				break;
-		}
-		if (rv)
-			break;
-		cprbx_p = (struct CPRBX *) (devPtr->dev_resp_p + 48);
-		if ((cprbx_p->ccp_rtcode == 8) && (cprbx_p->ccp_rscode == 33)) {
-			devPtr->dev_type = PCIXCC_MCL2;
-			PDEBUG("device %d is MCL2\n", index);
-		} else {
-			devPtr->dev_type = PCIXCC_MCL3;
-			PDEBUG("device %d is MCL3\n", index);
-		}
-	} while (0);
-	/* In a general error case, the card is not marked online */
-	return rv;
-}
-
-module_init(z90crypt_init_module);
-module_exit(z90crypt_cleanup_module);
diff -urNp linux-2.6.18.s390x/drivers/s390/Kconfig linux-2.6.18.s390x-remove_z90crypt/drivers/s390/Kconfig
--- linux-2.6.18.s390x/drivers/s390/Kconfig	2006-09-20 05:42:06.000000000 +0200
+++ linux-2.6.18.s390x-remove_z90crypt/drivers/s390/Kconfig	2007-01-29 16:52:36.000000000 +0100
@@ -214,16 +214,3 @@ config MONREADER
 	  Character device driver for reading z/VM monitor service records
 
 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
diff -urNp linux-2.6.18.s390x/include/asm-s390/Kbuild linux-2.6.18.s390x-remove_z90crypt/include/asm-s390/Kbuild
--- linux-2.6.18.s390x/include/asm-s390/Kbuild	2007-01-29 18:20:32.000000000 +0100
+++ linux-2.6.18.s390x-remove_z90crypt/include/asm-s390/Kbuild	2007-01-29 18:13:37.000000000 +0100
@@ -5,7 +5,6 @@ header-y += qeth.h
 header-y += tape390.h
 header-y += ucontext.h
 header-y += vtoc.h
-header-y += z90crypt.h
 
 unifdef-y += cmb.h
 unifdef-y += debug.h
diff -urNp linux-2.6.18.s390x/include/asm-s390/z90crypt.h linux-2.6.18.s390x-remove_z90crypt/include/asm-s390/z90crypt.h
--- linux-2.6.18.s390x/include/asm-s390/z90crypt.h	2006-09-20 05:42:06.000000000 +0200
+++ linux-2.6.18.s390x-remove_z90crypt/include/asm-s390/z90crypt.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,212 +0,0 @@
-/*
- *  include/asm-s390/z90crypt.h
- *
- *  z90crypt 1.3.3 (user-visible header)
- *
- *  Copyright (C)  2001, 2005 IBM Corporation
- *  Author(s): Robert Burroughs
- *             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 __ASM_S390_Z90CRYPT_H
-#define __ASM_S390_Z90CRYPT_H
-#include <linux/ioctl.h>
-
-#define z90crypt_VERSION 1
-#define z90crypt_RELEASE 3	// 2 = PCIXCC, 3 = rewrite for coding standards
-#define z90crypt_VARIANT 3	// 3 = CEX2A support
-
-/**
- * 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 __user *	inputdata;
-	unsigned int	inputdatalength;
-	char __user *	outputdata;
-	unsigned int	outputdatalength;
-	char __user *	b_key;
-	char __user *	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 __user *	inputdata;
-	unsigned int	inputdatalength;
-	char __user *	outputdata;
-	unsigned int	outputdatalength;
-	char __user *	bp_key;
-	char __user *	bq_key;
-	char __user *	np_prime;
-	char __user *	nq_prime;
-	char __user *	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_PCIXCCMCL2COUNT
- *     Return an integer count of all MCL2 PCIXCCs.
- *
- *   Z90STAT_PCIXCCMCL3COUNT
- *     Return an integer count of all MCL3 PCIXCCs.
- *
- *   Z90STAT_CEX2CCOUNT
- *     Return an integer count of all CEX2Cs.
- *
- *   Z90STAT_CEX2ACOUNT
- *     Return an integer count of all CEX2As.
- *
- *   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_MCL2
- *       0x04: PCIXCC_MCL3
- *       0x05: CEX2C
- *       0x06: CEX2A
- *       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
- *
- *   Z90STAT_PCIXCCCOUNT (deprecated)
- *     Return an integer count of all PCIXCCs (MCL2 + MCL3).
- *     This is DEPRECATED now that MCL3 PCIXCCs are treated differently from
- *     MCL2 PCIXCCs.
- *
- *   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 calls (bound for removal at some point) */
-#define ICAZ90STATUS	_IOR(Z90_IOCTL_MAGIC, 0x10, struct ica_z90_status)
-#define Z90STAT_PCIXCCCOUNT	_IOR(Z90_IOCTL_MAGIC, 0x43, int)
-
-/* 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_PCIXCCMCL2COUNT	_IOR(Z90_IOCTL_MAGIC, 0x4b, int)
-#define Z90STAT_PCIXCCMCL3COUNT	_IOR(Z90_IOCTL_MAGIC, 0x4c, int)
-#define Z90STAT_CEX2CCOUNT	_IOR(Z90_IOCTL_MAGIC, 0x4d, int)
-#define Z90STAT_CEX2ACOUNT	_IOR(Z90_IOCTL_MAGIC, 0x4e, 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])
-
-#endif /* __ASM_S390_Z90CRYPT_H */

 drivers/s390/Kconfig                 |   25 
 drivers/s390/crypto/Makefile         |   17 
 drivers/s390/crypto/ap_bus.c         | 1245 +++++++++++++++++++++++++++++++++++
 drivers/s390/crypto/ap_bus.h         |  158 ++++
 drivers/s390/crypto/zcrypt_api.c     | 1091 ++++++++++++++++++++++++++++++
 drivers/s390/crypto/zcrypt_api.h     |  141 +++
 drivers/s390/crypto/zcrypt_cca_key.h |  350 +++++++++
 drivers/s390/crypto/zcrypt_cex2a.c   |  435 ++++++++++++
 drivers/s390/crypto/zcrypt_cex2a.h   |  126 +++
 drivers/s390/crypto/zcrypt_error.h   |  133 +++
 drivers/s390/crypto/zcrypt_mono.c    |  100 ++
 drivers/s390/crypto/zcrypt_pcica.c   |  418 +++++++++++
 drivers/s390/crypto/zcrypt_pcica.h   |  117 +++
 drivers/s390/crypto/zcrypt_pcicc.c   |  630 +++++++++++++++++
 drivers/s390/crypto/zcrypt_pcicc.h   |  176 ++++
 drivers/s390/crypto/zcrypt_pcixcc.c  |  951 ++++++++++++++++++++++++++
 drivers/s390/crypto/zcrypt_pcixcc.h  |   79 ++
 include/asm-s390/Kbuild              |    1 
 include/asm-s390/zcrypt.h            |  276 +++++++
 include/linux/mod_devicetable.h      |   11 
 scripts/mod/file2alias.c             |   11 
 21 files changed, 6491 insertions(+)

diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/ap_bus.c linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/ap_bus.c
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/ap_bus.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/ap_bus.c	2007-01-29 17:06:10.000000000 +0100
@@ -0,0 +1,1245 @@
+/*
+ * linux/drivers/s390/crypto/ap_bus.c
+ *
+ * Copyright (C) 2006 IBM Corporation
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ *	      Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *	      Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *
+ * Adjunct processor bus.
+ *
+ * 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <asm/s390_rdev.h>
+
+#include "ap_bus.h"
+
+/* Some prototypes. */
+static void ap_scan_bus(void *);
+static void ap_poll_all(unsigned long);
+static void ap_poll_timeout(unsigned long);
+static int ap_poll_thread_start(void);
+static void ap_poll_thread_stop(void);
+
+/**
+ * Module description.
+ */
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("Adjunct Processor Bus driver, "
+		   "Copyright 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+
+/**
+ * Module parameter
+ */
+int ap_domain_index = -1;	/* Adjunct Processor Domain Index */
+module_param_named(domain, ap_domain_index, int, 0000);
+MODULE_PARM_DESC(domain, "domain index for ap devices");
+EXPORT_SYMBOL(ap_domain_index);
+
+static int ap_thread_flag = 1;
+module_param_named(poll_thread, ap_thread_flag, int, 0000);
+MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 1 (on).");
+
+static struct device *ap_root_device = NULL;
+
+/**
+ * Workqueue & timer for bus rescan.
+ */
+static struct workqueue_struct *ap_work_queue;
+static struct timer_list ap_config_timer;
+static int ap_config_time = AP_CONFIG_TIME;
+static DECLARE_WORK(ap_config_work, ap_scan_bus, NULL);
+
+/**
+ * Tasklet & timer for AP request polling.
+ */
+static struct timer_list ap_poll_timer = TIMER_INITIALIZER(ap_poll_timeout,0,0);
+static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0);
+static atomic_t ap_poll_requests = ATOMIC_INIT(0);
+static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait);
+static struct task_struct *ap_poll_kthread = NULL;
+static DEFINE_MUTEX(ap_poll_thread_mutex);
+
+/**
+ * Test if ap instructions are available.
+ *
+ * Returns 0 if the ap instructions are installed.
+ */
+static inline int ap_instructions_available(void)
+{
+	register unsigned long reg0 asm ("0") = AP_MKQID(0,0);
+	register unsigned long reg1 asm ("1") = -ENODEV;
+	register unsigned long reg2 asm ("2") = 0UL;
+
+	asm volatile(
+		"   .long 0xb2af0000\n"		/* PQAP(TAPQ) */
+		"0: la    %1,0\n"
+		"1:\n"
+#ifndef __s390x__
+		".section __ex_table,\"a\"\n"
+		"	.align 4\n"
+		"	.long  0b,1b\n"
+		".previous\n"
+#else
+		".section __ex_table,\"a\"\n"
+		"	.align 8\n"
+		"	.quad  0b,1b\n"
+		".previous\n"
+#endif
+		: "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc" );
+	return reg1;
+}
+
+/**
+ * Test adjunct processor queue.
+ * @qid: the ap queue number
+ * @queue_depth: pointer to queue depth value
+ * @device_type: pointer to device type value
+ *
+ * Returns ap queue status structure.
+ */
+static inline struct ap_queue_status
+ap_test_queue(ap_qid_t qid, int *queue_depth, int *device_type)
+{
+	register unsigned long reg0 asm ("0") = qid;
+	register struct ap_queue_status reg1 asm ("1");
+	register unsigned long reg2 asm ("2") = 0UL;
+
+	asm volatile(".long 0xb2af0000"		/* PQAP(TAPQ) */
+		     : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
+	*device_type = (int) (reg2 >> 24);
+	*queue_depth = (int) (reg2 & 0xff);
+	return reg1;
+}
+
+/**
+ * Reset adjunct processor queue.
+ * @qid: the ap queue number
+ *
+ * Returns ap queue status structure.
+ */
+static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid)
+{
+	register unsigned long reg0 asm ("0") = qid | 0x01000000UL;
+	register struct ap_queue_status reg1 asm ("1");
+	register unsigned long reg2 asm ("2") = 0UL;
+
+	asm volatile(
+		".long 0xb2af0000"		/* PQAP(RAPQ) */
+		: "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
+	return reg1;
+}
+
+/**
+ * Send message to adjunct processor queue.
+ * @qid: the ap queue number
+ * @psmid: the program supplied message identifier
+ * @msg: the message text
+ * @length: the message length
+ *
+ * Returns ap queue status structure.
+ *
+ * Condition code 1 on NQAP can't happen because the L bit is 1.
+ *
+ * Condition code 2 on NQAP also means the send is incomplete,
+ * because a segment boundary was reached. The NQAP is repeated.
+ */
+static inline struct ap_queue_status
+__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
+{
+	typedef struct { char _[length]; } msgblock;
+	register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
+	register struct ap_queue_status reg1 asm ("1");
+	register unsigned long reg2 asm ("2") = (unsigned long) msg;
+	register unsigned long reg3 asm ("3") = (unsigned long) length;
+	register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
+	register unsigned long reg5 asm ("5") = (unsigned int) psmid;
+
+	asm volatile (
+		"0: .long 0xb2ad0042\n"		/* DQAP */
+		"   brc   2,0b"
+		: "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3)
+		: "d" (reg4), "d" (reg5), "m" (*(msgblock *) msg)
+		: "cc" );
+	return reg1;
+}
+
+int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
+{
+	struct ap_queue_status status;
+
+	status = __ap_send(qid, psmid, msg, length);
+	switch (status.response_code) {
+	case AP_RESPONSE_NORMAL:
+		return 0;
+	case AP_RESPONSE_Q_FULL:
+		return -EBUSY;
+	default:	/* Device is gone. */
+		return -ENODEV;
+	}
+}
+EXPORT_SYMBOL(ap_send);
+
+/*
+ * Receive message from adjunct processor queue.
+ * @qid: the ap queue number
+ * @psmid: pointer to program supplied message identifier
+ * @msg: the message text
+ * @length: the message length
+ *
+ * Returns ap queue status structure.
+ *
+ * Condition code 1 on DQAP means the receive has taken place
+ * but only partially.	The response is incomplete, hence the
+ * DQAP is repeated.
+ *
+ * Condition code 2 on DQAP also means the receive is incomplete,
+ * this time because a segment boundary was reached. Again, the
+ * DQAP is repeated.
+ *
+ * Note that gpr2 is used by the DQAP instruction to keep track of
+ * any 'residual' length, in case the instruction gets interrupted.
+ * Hence it gets zeroed before the instruction.
+ */
+static inline struct ap_queue_status
+__ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
+{
+	typedef struct { char _[length]; } msgblock;
+	register unsigned long reg0 asm("0") = qid | 0x80000000UL;
+	register struct ap_queue_status reg1 asm ("1");
+	register unsigned long reg2 asm("2") = 0UL;
+	register unsigned long reg4 asm("4") = (unsigned long) msg;
+	register unsigned long reg5 asm("5") = (unsigned long) length;
+	register unsigned long reg6 asm("6") = 0UL;
+	register unsigned long reg7 asm("7") = 0UL;
+
+
+	asm volatile(
+		"0: .long 0xb2ae0064\n"
+		"   brc   6,0b\n"
+		: "+d" (reg0), "=d" (reg1), "+d" (reg2),
+		"+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7),
+		"=m" (*(msgblock *) msg) : : "cc" );
+	*psmid = (((unsigned long long) reg6) << 32) + reg7;
+	return reg1;
+}
+
+int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
+{
+	struct ap_queue_status status;
+
+	status = __ap_recv(qid, psmid, msg, length);
+	switch (status.response_code) {
+	case AP_RESPONSE_NORMAL:
+		return 0;
+	case AP_RESPONSE_NO_PENDING_REPLY:
+		if (status.queue_empty)
+			return -ENOENT;
+		return -EBUSY;
+	default:
+		return -ENODEV;
+	}
+}
+EXPORT_SYMBOL(ap_recv);
+
+/**
+ * Check if an AP queue is available. The test is repeated for
+ * AP_MAX_RESET times.
+ * @qid: the ap queue number
+ * @queue_depth: pointer to queue depth value
+ * @device_type: pointer to device type value
+ */
+static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type)
+{
+	struct ap_queue_status status;
+	int t_depth, t_device_type, rc, i;
+
+	rc = -EBUSY;
+	for (i = 0; i < AP_MAX_RESET; i++) {
+		status = ap_test_queue(qid, &t_depth, &t_device_type);
+		switch (status.response_code) {
+		case AP_RESPONSE_NORMAL:
+			*queue_depth = t_depth + 1;
+			*device_type = t_device_type;
+			rc = 0;
+			break;
+		case AP_RESPONSE_Q_NOT_AVAIL:
+			rc = -ENODEV;
+			break;
+		case AP_RESPONSE_RESET_IN_PROGRESS:
+			break;
+		case AP_RESPONSE_DECONFIGURED:
+			rc = -ENODEV;
+			break;
+		case AP_RESPONSE_CHECKSTOPPED:
+			rc = -ENODEV;
+			break;
+		case AP_RESPONSE_BUSY:
+			break;
+		default:
+			BUG();
+		}
+		if (rc != -EBUSY)
+			break;
+		if (i < AP_MAX_RESET - 1)
+			udelay(5);
+	}
+	return rc;
+}
+
+/**
+ * Reset an AP queue and wait for it to become available again.
+ * @qid: the ap queue number
+ */
+static int ap_init_queue(ap_qid_t qid)
+{
+	struct ap_queue_status status;
+	int rc, dummy, i;
+
+	rc = -ENODEV;
+	status = ap_reset_queue(qid);
+	for (i = 0; i < AP_MAX_RESET; i++) {
+		switch (status.response_code) {
+		case AP_RESPONSE_NORMAL:
+			if (status.queue_empty)
+				rc = 0;
+			break;
+		case AP_RESPONSE_Q_NOT_AVAIL:
+		case AP_RESPONSE_DECONFIGURED:
+		case AP_RESPONSE_CHECKSTOPPED:
+			i = AP_MAX_RESET;	/* return with -ENODEV */
+			break;
+		case AP_RESPONSE_RESET_IN_PROGRESS:
+		case AP_RESPONSE_BUSY:
+		default:
+			break;
+		}
+		if (rc != -ENODEV)
+			break;
+		if (i < AP_MAX_RESET - 1) {
+			udelay(5);
+			status = ap_test_queue(qid, &dummy, &dummy);
+		}
+	}
+	return rc;
+}
+
+/**
+ * AP device related attributes.
+ */
+static ssize_t ap_hwtype_show(struct device *dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+	return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->device_type);
+}
+static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL);
+
+static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+	return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->queue_depth);
+}
+static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL);
+
+static ssize_t ap_request_count_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+	int rc;
+
+	spin_lock_bh(&ap_dev->lock);
+	rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->total_request_count);
+	spin_unlock_bh(&ap_dev->lock);
+	return rc;
+}
+
+static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL);
+
+static ssize_t ap_modalias_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "ap:t%02X", to_ap_dev(dev)->device_type);
+}
+
+static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL);
+
+static struct attribute *ap_dev_attrs[] = {
+	&dev_attr_hwtype.attr,
+	&dev_attr_depth.attr,
+	&dev_attr_request_count.attr,
+	&dev_attr_modalias.attr,
+	NULL
+};
+static struct attribute_group ap_dev_attr_group = {
+	.attrs = ap_dev_attrs
+};
+
+/**
+ * AP bus driver registration/unregistration.
+ */
+static int ap_bus_match(struct device *dev, struct device_driver *drv)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+	struct ap_driver *ap_drv = to_ap_drv(drv);
+	struct ap_device_id *id;
+
+	/**
+	 * Compare device type of the device with the list of
+	 * supported types of the device_driver.
+	 */
+	for (id = ap_drv->ids; id->match_flags; id++) {
+		if ((id->match_flags & AP_DEVICE_ID_MATCH_DEVICE_TYPE) &&
+		    (id->dev_type != ap_dev->device_type))
+			continue;
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ * uevent function for AP devices. It sets up a single environment
+ * variable DEV_TYPE which contains the hardware device type.
+ */
+static int ap_uevent (struct device *dev, char **envp, int num_envp,
+		       char *buffer, int buffer_size)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+	int length;
+
+	if (!ap_dev)
+		return -ENODEV;
+
+	/* Set up DEV_TYPE environment variable. */
+	envp[0] = buffer;
+	length = scnprintf(buffer, buffer_size, "DEV_TYPE=%04X",
+			   ap_dev->device_type);
+	if (buffer_size - length <= 0)
+		return -ENOMEM;
+	buffer += length;
+	buffer_size -= length;
+	/* Add MODALIAS= */
+	envp[1] = buffer;
+	length = scnprintf(buffer, buffer_size, "MODALIAS=ap:t%02X",
+			   ap_dev->device_type);
+	if (buffer_size - length <= 0)
+		return -ENOMEM;
+	envp[2] = NULL;
+	return 0;
+}
+
+static struct bus_type ap_bus_type = {
+	.name = "ap",
+	.match = &ap_bus_match,
+	.uevent = &ap_uevent,
+};
+
+static int ap_device_probe(struct device *dev)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+	struct ap_driver *ap_drv = to_ap_drv(dev->driver);
+	int rc;
+
+	ap_dev->drv = ap_drv;
+	rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;
+	return rc;
+}
+
+/**
+ * Flush all requests from the request/pending queue of an AP device.
+ * @ap_dev: pointer to the AP device.
+ */
+static inline void __ap_flush_queue(struct ap_device *ap_dev)
+{
+	struct ap_message *ap_msg, *next;
+
+	list_for_each_entry_safe(ap_msg, next, &ap_dev->pendingq, list) {
+		list_del_init(&ap_msg->list);
+		ap_dev->pendingq_count--;
+		ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+	}
+	list_for_each_entry_safe(ap_msg, next, &ap_dev->requestq, list) {
+		list_del_init(&ap_msg->list);
+		ap_dev->requestq_count--;
+		ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+	}
+}
+
+void ap_flush_queue(struct ap_device *ap_dev)
+{
+	spin_lock_bh(&ap_dev->lock);
+	__ap_flush_queue(ap_dev);
+	spin_unlock_bh(&ap_dev->lock);
+}
+EXPORT_SYMBOL(ap_flush_queue);
+
+static int ap_device_remove(struct device *dev)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+	struct ap_driver *ap_drv = ap_dev->drv;
+
+	ap_flush_queue(ap_dev);
+	if (ap_drv->remove)
+		ap_drv->remove(ap_dev);
+	return 0;
+}
+
+int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,
+		       char *name)
+{
+	struct device_driver *drv = &ap_drv->driver;
+
+	drv->bus = &ap_bus_type;
+	drv->probe = ap_device_probe;
+	drv->remove = ap_device_remove;
+	drv->owner = owner;
+	drv->name = name;
+	return driver_register(drv);
+}
+EXPORT_SYMBOL(ap_driver_register);
+
+void ap_driver_unregister(struct ap_driver *ap_drv)
+{
+	driver_unregister(&ap_drv->driver);
+}
+EXPORT_SYMBOL(ap_driver_unregister);
+
+/**
+ * AP bus attributes.
+ */
+static ssize_t ap_domain_show(struct bus_type *bus, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index);
+}
+
+static BUS_ATTR(ap_domain, 0444, ap_domain_show, NULL);
+
+static ssize_t ap_config_time_show(struct bus_type *bus, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time);
+}
+
+static ssize_t ap_config_time_store(struct bus_type *bus,
+				    const char *buf, size_t count)
+{
+	int time;
+
+	if (sscanf(buf, "%d\n", &time) != 1 || time < 5 || time > 120)
+		return -EINVAL;
+	ap_config_time = time;
+	if (!timer_pending(&ap_config_timer) ||
+	    !mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ)) {
+		ap_config_timer.expires = jiffies + ap_config_time * HZ;
+		add_timer(&ap_config_timer);
+	}
+	return count;
+}
+
+static BUS_ATTR(config_time, 0644, ap_config_time_show, ap_config_time_store);
+
+static ssize_t ap_poll_thread_show(struct bus_type *bus, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0);
+}
+
+static ssize_t ap_poll_thread_store(struct bus_type *bus,
+				    const char *buf, size_t count)
+{
+	int flag, rc;
+
+	if (sscanf(buf, "%d\n", &flag) != 1)
+		return -EINVAL;
+	if (flag) {
+		rc = ap_poll_thread_start();
+		if (rc)
+			return rc;
+	}
+	else
+		ap_poll_thread_stop();
+	return count;
+}
+
+static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store);
+
+static struct bus_attribute *const ap_bus_attrs[] = {
+	&bus_attr_ap_domain,
+	&bus_attr_config_time,
+	&bus_attr_poll_thread,
+	NULL
+};
+
+/**
+ * Pick one of the 16 ap domains.
+ */
+static inline int ap_select_domain(void)
+{
+	int queue_depth, device_type, count, max_count, best_domain;
+	int rc, i, j;
+
+	/**
+	 * We want to use a single domain. Either the one specified with
+	 * the "domain=" parameter or the domain with the maximum number
+	 * of devices.
+	 */
+	if (ap_domain_index >= 0 && ap_domain_index < AP_DOMAINS)
+		/* Domain has already been selected. */
+		return 0;
+	best_domain = -1;
+	max_count = 0;
+	for (i = 0; i < AP_DOMAINS; i++) {
+		count = 0;
+		for (j = 0; j < AP_DEVICES; j++) {
+			ap_qid_t qid = AP_MKQID(j, i);
+			rc = ap_query_queue(qid, &queue_depth, &device_type);
+			if (rc)
+				continue;
+			count++;
+		}
+		if (count > max_count) {
+			max_count = count;
+			best_domain = i;
+		}
+	}
+	if (best_domain >= 0){
+		ap_domain_index = best_domain;
+		return 0;
+	}
+	return -ENODEV;
+}
+
+/**
+ * Find the device type if query queue returned a device type of 0.
+ * @ap_dev: pointer to the AP device.
+ */
+static int ap_probe_device_type(struct ap_device *ap_dev)
+{
+	static unsigned char msg[] = {
+		0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x01,0x00,0x43,0x43,0x41,0x2d,0x41,0x50,
+		0x50,0x4c,0x20,0x20,0x20,0x01,0x01,0x01,
+		0x00,0x00,0x00,0x00,0x50,0x4b,0x00,0x00,
+		0x00,0x00,0x01,0x1c,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x05,0xb8,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x70,0x00,0x41,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x54,0x32,0x01,0x00,0xa0,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0xb8,0x05,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x0a,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,
+		0x50,0x4b,0x0a,0x00,0x50,0x4b,0x43,0x53,
+		0x2d,0x31,0x2e,0x32,0x37,0x00,0x11,0x22,
+		0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,
+		0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,
+		0x99,0x00,0x11,0x22,0x33,0x44,0x55,0x66,
+		0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,
+		0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,
+		0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,
+		0x11,0x22,0x33,0x5d,0x00,0x5b,0x00,0x77,
+		0x88,0x1e,0x00,0x00,0x57,0x00,0x00,0x00,
+		0x00,0x04,0x00,0x00,0x4f,0x00,0x00,0x00,
+		0x03,0x02,0x00,0x00,0x40,0x01,0x00,0x01,
+		0xce,0x02,0x68,0x2d,0x5f,0xa9,0xde,0x0c,
+		0xf6,0xd2,0x7b,0x58,0x4b,0xf9,0x28,0x68,
+		0x3d,0xb4,0xf4,0xef,0x78,0xd5,0xbe,0x66,
+		0x63,0x42,0xef,0xf8,0xfd,0xa4,0xf8,0xb0,
+		0x8e,0x29,0xc2,0xc9,0x2e,0xd8,0x45,0xb8,
+		0x53,0x8c,0x6f,0x4e,0x72,0x8f,0x6c,0x04,
+		0x9c,0x88,0xfc,0x1e,0xc5,0x83,0x55,0x57,
+		0xf7,0xdd,0xfd,0x4f,0x11,0x36,0x95,0x5d,
+	};
+	struct ap_queue_status status;
+	unsigned long long psmid;
+	char *reply;
+	int rc, i;
+
+	reply = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!reply) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	status = __ap_send(ap_dev->qid, 0x0102030405060708ULL,
+			   msg, sizeof(msg));
+	if (status.response_code != AP_RESPONSE_NORMAL) {
+		rc = -ENODEV;
+		goto out_free;
+	}
+
+	/* Wait for the test message to complete. */
+	for (i = 0; i < 6; i++) {
+		mdelay(300);
+		status = __ap_recv(ap_dev->qid, &psmid, reply, 4096);
+		if (status.response_code == AP_RESPONSE_NORMAL &&
+		    psmid == 0x0102030405060708ULL)
+			break;
+	}
+	if (i < 6) {
+		/* Got an answer. */
+		if (reply[0] == 0x00 && reply[1] == 0x86)
+			ap_dev->device_type = AP_DEVICE_TYPE_PCICC;
+		else
+			ap_dev->device_type = AP_DEVICE_TYPE_PCICA;
+		rc = 0;
+	} else
+		rc = -ENODEV;
+
+out_free:
+	free_page((unsigned long) reply);
+out:
+	return rc;
+}
+
+/**
+ * Scan the ap bus for new devices.
+ */
+static int __ap_scan_bus(struct device *dev, void *data)
+{
+	return to_ap_dev(dev)->qid == (ap_qid_t)(unsigned long) data;
+}
+
+static void ap_device_release(struct device *dev)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+
+	kfree(ap_dev);
+}
+
+static void ap_scan_bus(void *data)
+{
+	struct ap_device *ap_dev;
+	struct device *dev;
+	ap_qid_t qid;
+	int queue_depth, device_type;
+	int rc, i;
+
+	if (ap_select_domain() != 0)
+		return;
+	for (i = 0; i < AP_DEVICES; i++) {
+		qid = AP_MKQID(i, ap_domain_index);
+		dev = bus_find_device(&ap_bus_type, NULL,
+				      (void *)(unsigned long)qid,
+				      __ap_scan_bus);
+		rc = ap_query_queue(qid, &queue_depth, &device_type);
+		if (dev && rc) {
+			put_device(dev);
+			device_unregister(dev);
+			continue;
+		}
+		if (dev) {
+			put_device(dev);
+			continue;
+		}
+		if (rc)
+			continue;
+		rc = ap_init_queue(qid);
+		if (rc)
+			continue;
+		ap_dev = kzalloc(sizeof(*ap_dev), GFP_KERNEL);
+		if (!ap_dev)
+			break;
+		ap_dev->qid = qid;
+		ap_dev->queue_depth = queue_depth;
+		ap_dev->unregistered = 1;
+		spin_lock_init(&ap_dev->lock);
+		INIT_LIST_HEAD(&ap_dev->pendingq);
+		INIT_LIST_HEAD(&ap_dev->requestq);
+		if (device_type == 0)
+			ap_probe_device_type(ap_dev);
+		else
+			ap_dev->device_type = device_type;
+
+		ap_dev->device.bus = &ap_bus_type;
+		ap_dev->device.parent = ap_root_device;
+		snprintf(ap_dev->device.bus_id, BUS_ID_SIZE, "card%02x",
+			 AP_QID_DEVICE(ap_dev->qid));
+		ap_dev->device.release = ap_device_release;
+		rc = device_register(&ap_dev->device);
+		if (rc) {
+			kfree(ap_dev);
+			continue;
+		}
+		/* Add device attributes. */
+		rc = sysfs_create_group(&ap_dev->device.kobj,
+					&ap_dev_attr_group);
+		if (!rc) {
+			spin_lock_bh(&ap_dev->lock);
+			ap_dev->unregistered = 0;
+			spin_unlock_bh(&ap_dev->lock);
+		}
+		else
+			device_unregister(&ap_dev->device);
+	}
+}
+
+static void
+ap_config_timeout(unsigned long ptr)
+{
+	queue_work(ap_work_queue, &ap_config_work);
+	ap_config_timer.expires = jiffies + ap_config_time * HZ;
+	add_timer(&ap_config_timer);
+}
+
+/**
+ * Set up the timer to run the poll tasklet
+ */
+static inline void ap_schedule_poll_timer(void)
+{
+	if (timer_pending(&ap_poll_timer))
+		return;
+	mod_timer(&ap_poll_timer, jiffies + AP_POLL_TIME);
+}
+
+/**
+ * Receive pending reply messages from an AP device.
+ * @ap_dev: pointer to the AP device
+ * @flags: pointer to control flags, bit 2^0 is set if another poll is
+ *	   required, bit 2^1 is set if the poll timer needs to get armed
+ * Returns 0 if the device is still present, -ENODEV if not.
+ */
+static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
+{
+	struct ap_queue_status status;
+	struct ap_message *ap_msg;
+
+	if (ap_dev->queue_count <= 0)
+		return 0;
+	status = __ap_recv(ap_dev->qid, &ap_dev->reply->psmid,
+			   ap_dev->reply->message, ap_dev->reply->length);
+	switch (status.response_code) {
+	case AP_RESPONSE_NORMAL:
+		atomic_dec(&ap_poll_requests);
+		ap_dev->queue_count--;
+		list_for_each_entry(ap_msg, &ap_dev->pendingq, list) {
+			if (ap_msg->psmid != ap_dev->reply->psmid)
+				continue;
+			list_del_init(&ap_msg->list);
+			ap_dev->pendingq_count--;
+			ap_dev->drv->receive(ap_dev, ap_msg, ap_dev->reply);
+			break;
+		}
+		if (ap_dev->queue_count > 0)
+			*flags |= 1;
+		break;
+	case AP_RESPONSE_NO_PENDING_REPLY:
+		if (status.queue_empty) {
+			/* The card shouldn't forget requests but who knows. */
+			ap_dev->queue_count = 0;
+			list_splice_init(&ap_dev->pendingq, &ap_dev->requestq);
+			ap_dev->requestq_count += ap_dev->pendingq_count;
+			ap_dev->pendingq_count = 0;
+		} else
+			*flags |= 2;
+		break;
+	default:
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/**
+ * Send messages from the request queue to an AP device.
+ * @ap_dev: pointer to the AP device
+ * @flags: pointer to control flags, bit 2^0 is set if another poll is
+ *	   required, bit 2^1 is set if the poll timer needs to get armed
+ * Returns 0 if the device is still present, -ENODEV if not.
+ */
+static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
+{
+	struct ap_queue_status status;
+	struct ap_message *ap_msg;
+
+	if (ap_dev->requestq_count <= 0 ||
+	    ap_dev->queue_count >= ap_dev->queue_depth)
+		return 0;
+	/* Start the next request on the queue. */
+	ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list);
+	status = __ap_send(ap_dev->qid, ap_msg->psmid,
+			   ap_msg->message, ap_msg->length);
+	switch (status.response_code) {
+	case AP_RESPONSE_NORMAL:
+		atomic_inc(&ap_poll_requests);
+		ap_dev->queue_count++;
+		list_move_tail(&ap_msg->list, &ap_dev->pendingq);
+		ap_dev->requestq_count--;
+		ap_dev->pendingq_count++;
+		if (ap_dev->queue_count < ap_dev->queue_depth &&
+		    ap_dev->requestq_count > 0)
+			*flags |= 1;
+		*flags |= 2;
+		break;
+	case AP_RESPONSE_Q_FULL:
+		*flags |= 2;
+		break;
+	case AP_RESPONSE_MESSAGE_TOO_BIG:
+		return -EINVAL;
+	default:
+		return -ENODEV;
+	}
+	return 0;
+}
+
+/**
+ * Poll AP device for pending replies and send new messages. If either
+ * ap_poll_read or ap_poll_write returns -ENODEV unregister the device.
+ * @ap_dev: pointer to the bus device
+ * @flags: pointer to control flags, bit 2^0 is set if another poll is
+ *	   required, bit 2^1 is set if the poll timer needs to get armed
+ * Returns 0.
+ */
+static inline int ap_poll_queue(struct ap_device *ap_dev, unsigned long *flags)
+{
+	int rc;
+
+	rc = ap_poll_read(ap_dev, flags);
+	if (rc)
+		return rc;
+	return ap_poll_write(ap_dev, flags);
+}
+
+/**
+ * Queue a message to a device.
+ * @ap_dev: pointer to the AP device
+ * @ap_msg: the message to be queued
+ */
+static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
+{
+	struct ap_queue_status status;
+
+	if (list_empty(&ap_dev->requestq) &&
+	    ap_dev->queue_count < ap_dev->queue_depth) {
+		status = __ap_send(ap_dev->qid, ap_msg->psmid,
+				   ap_msg->message, ap_msg->length);
+		switch (status.response_code) {
+		case AP_RESPONSE_NORMAL:
+			list_add_tail(&ap_msg->list, &ap_dev->pendingq);
+			atomic_inc(&ap_poll_requests);
+			ap_dev->pendingq_count++;
+			ap_dev->queue_count++;
+			ap_dev->total_request_count++;
+			break;
+		case AP_RESPONSE_Q_FULL:
+			list_add_tail(&ap_msg->list, &ap_dev->requestq);
+			ap_dev->requestq_count++;
+			ap_dev->total_request_count++;
+			return -EBUSY;
+		case AP_RESPONSE_MESSAGE_TOO_BIG:
+			ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL));
+			return -EINVAL;
+		default:	/* Device is gone. */
+			ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+			return -ENODEV;
+		}
+	} else {
+		list_add_tail(&ap_msg->list, &ap_dev->requestq);
+		ap_dev->requestq_count++;
+		ap_dev->total_request_count++;
+		return -EBUSY;
+	}
+	ap_schedule_poll_timer();
+	return 0;
+}
+
+void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
+{
+	unsigned long flags;
+	int rc;
+
+	spin_lock_bh(&ap_dev->lock);
+	if (!ap_dev->unregistered) {
+		/* Make room on the queue by polling for finished requests. */
+		rc = ap_poll_queue(ap_dev, &flags);
+		if (!rc)
+			rc = __ap_queue_message(ap_dev, ap_msg);
+		if (!rc)
+			wake_up(&ap_poll_wait);
+		if (rc == -ENODEV)
+			ap_dev->unregistered = 1;
+	} else {
+		ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+		rc = 0;
+	}
+	spin_unlock_bh(&ap_dev->lock);
+	if (rc == -ENODEV)
+		device_unregister(&ap_dev->device);
+}
+EXPORT_SYMBOL(ap_queue_message);
+
+/**
+ * Cancel a crypto request. This is done by removing the request
+ * from the devive pendingq or requestq queue. Note that the
+ * request stays on the AP queue. When it finishes the message
+ * reply will be discarded because the psmid can't be found.
+ * @ap_dev: AP device that has the message queued
+ * @ap_msg: the message that is to be removed
+ */
+void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
+{
+	struct ap_message *tmp;
+
+	spin_lock_bh(&ap_dev->lock);
+	if (!list_empty(&ap_msg->list)) {
+		list_for_each_entry(tmp, &ap_dev->pendingq, list)
+			if (tmp->psmid == ap_msg->psmid) {
+				ap_dev->pendingq_count--;
+				goto found;
+			}
+		ap_dev->requestq_count--;
+	found:
+		list_del_init(&ap_msg->list);
+	}
+	spin_unlock_bh(&ap_dev->lock);
+}
+EXPORT_SYMBOL(ap_cancel_message);
+
+/**
+ * AP receive polling for finished AP requests
+ */
+static void ap_poll_timeout(unsigned long unused)
+{
+	tasklet_schedule(&ap_tasklet);
+}
+
+/**
+ * Poll all AP devices on the bus in a round robin fashion. Continue
+ * polling until bit 2^0 of the control flags is not set. If bit 2^1
+ * of the control flags has been set arm the poll timer.
+ */
+static int __ap_poll_all(struct device *dev, void *data)
+{
+	struct ap_device *ap_dev = to_ap_dev(dev);
+	int rc;
+
+	spin_lock(&ap_dev->lock);
+	if (!ap_dev->unregistered) {
+		rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data);
+		if (rc)
+			ap_dev->unregistered = 1;
+	} else
+		rc = 0;
+	spin_unlock(&ap_dev->lock);
+	if (rc)
+		device_unregister(&ap_dev->device);
+	return 0;
+}
+
+static void ap_poll_all(unsigned long dummy)
+{
+	unsigned long flags;
+
+	do {
+		flags = 0;
+		bus_for_each_dev(&ap_bus_type, NULL, &flags, __ap_poll_all);
+	} while (flags & 1);
+	if (flags & 2)
+		ap_schedule_poll_timer();
+}
+
+/**
+ * AP bus poll thread. The purpose of this thread is to poll for
+ * finished requests in a loop if there is a "free" cpu - that is
+ * a cpu that doesn't have anything better to do. The polling stops
+ * as soon as there is another task or if all messages have been
+ * delivered.
+ */
+static int ap_poll_thread(void *data)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long flags;
+	int requests;
+
+	set_user_nice(current, 19);
+	while (1) {
+		if (need_resched()) {
+			schedule();
+			continue;
+		}
+		add_wait_queue(&ap_poll_wait, &wait);
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (kthread_should_stop())
+			break;
+		requests = atomic_read(&ap_poll_requests);
+		if (requests <= 0)
+			schedule();
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&ap_poll_wait, &wait);
+
+		local_bh_disable();
+		flags = 0;
+		bus_for_each_dev(&ap_bus_type, NULL, &flags, __ap_poll_all);
+		local_bh_enable();
+	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&ap_poll_wait, &wait);
+	return 0;
+}
+
+static int ap_poll_thread_start(void)
+{
+	int rc;
+
+	mutex_lock(&ap_poll_thread_mutex);
+	if (!ap_poll_kthread) {
+		ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll");
+		rc = IS_ERR(ap_poll_kthread) ? PTR_ERR(ap_poll_kthread) : 0;
+		if (rc)
+			ap_poll_kthread = NULL;
+	}
+	else
+		rc = 0;
+	mutex_unlock(&ap_poll_thread_mutex);
+	return rc;
+}
+
+static void ap_poll_thread_stop(void)
+{
+	mutex_lock(&ap_poll_thread_mutex);
+	if (ap_poll_kthread) {
+		kthread_stop(ap_poll_kthread);
+		ap_poll_kthread = NULL;
+	}
+	mutex_unlock(&ap_poll_thread_mutex);
+}
+
+/**
+ * The module initialization code.
+ */
+int __init ap_module_init(void)
+{
+	int rc, i;
+
+	if (ap_domain_index < -1 || ap_domain_index >= AP_DOMAINS) {
+		printk(KERN_WARNING "Invalid param: domain = %d. "
+		       " Not loading.\n", ap_domain_index);
+		return -EINVAL;
+	}
+	if (ap_instructions_available() != 0) {
+		printk(KERN_WARNING "AP instructions not installed.\n");
+		return -ENODEV;
+	}
+
+	/* Create /sys/bus/ap. */
+	rc = bus_register(&ap_bus_type);
+	if (rc)
+		goto out;
+	for (i = 0; ap_bus_attrs[i]; i++) {
+		rc = bus_create_file(&ap_bus_type, ap_bus_attrs[i]);
+		if (rc)
+			goto out_bus;
+	}
+
+	/* Create /sys/devices/ap. */
+	ap_root_device = s390_root_dev_register("ap");
+	rc = IS_ERR(ap_root_device) ? PTR_ERR(ap_root_device) : 0;
+	if (rc)
+		goto out_bus;
+
+	ap_work_queue = create_singlethread_workqueue("kapwork");
+	if (!ap_work_queue) {
+		rc = -ENOMEM;
+		goto out_root;
+	}
+
+	if (ap_select_domain() == 0)
+		ap_scan_bus(NULL);
+
+	/* Setup the ap bus rescan timer. */
+	init_timer(&ap_config_timer);
+	ap_config_timer.function = ap_config_timeout;
+	ap_config_timer.data = 0;
+	ap_config_timer.expires = jiffies + ap_config_time * HZ;
+	add_timer(&ap_config_timer);
+
+	/* Start the low priority AP bus poll thread. */
+	if (ap_thread_flag) {
+		rc = ap_poll_thread_start();
+		if (rc)
+			goto out_work;
+	}
+
+	return 0;
+
+out_work:
+	del_timer_sync(&ap_config_timer);
+	del_timer_sync(&ap_poll_timer);
+	destroy_workqueue(ap_work_queue);
+out_root:
+	s390_root_dev_unregister(ap_root_device);
+out_bus:
+	while (i--)
+		bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
+	bus_unregister(&ap_bus_type);
+out:
+	return rc;
+}
+
+static int __ap_match_all(struct device *dev, void *data)
+{
+	return 1;
+}
+
+/**
+ * The module termination code
+ */
+void ap_module_exit(void)
+{
+	int i;
+	struct device *dev;
+
+	ap_poll_thread_stop();
+	del_timer_sync(&ap_config_timer);
+	del_timer_sync(&ap_poll_timer);
+	destroy_workqueue(ap_work_queue);
+	s390_root_dev_unregister(ap_root_device);
+	while ((dev = bus_find_device(&ap_bus_type, NULL, NULL,
+		    __ap_match_all)))
+	{
+		device_unregister(dev);
+		put_device(dev);
+	}
+	for (i = 0; ap_bus_attrs[i]; i++)
+		bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
+	bus_unregister(&ap_bus_type);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(ap_module_init);
+module_exit(ap_module_exit);
+#endif
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/ap_bus.h linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/ap_bus.h
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/ap_bus.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/ap_bus.h	2007-01-29 17:06:10.000000000 +0100
@@ -0,0 +1,158 @@
+/*
+ * linux/drivers/s390/crypto/ap_bus.h
+ *
+ * Copyright (C) 2006 IBM Corporation
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ *	      Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *	      Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *
+ * Adjunct processor bus header file.
+ *
+ * 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 _AP_BUS_H_
+#define _AP_BUS_H_
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/types.h>
+
+#define AP_DEVICES 64		/* Number of AP devices. */
+#define AP_DOMAINS 16		/* Number of AP domains. */
+#define AP_MAX_RESET 90		/* Maximum number of resets. */
+#define AP_CONFIG_TIME 30	/* Time in seconds between AP bus rescans. */
+#define AP_POLL_TIME 1		/* Time in ticks between receive polls. */
+
+extern int ap_domain_index;
+
+/**
+ * The ap_qid_t identifier of an ap queue. It contains a
+ * 6 bit device index and a 4 bit queue index (domain).
+ */
+typedef unsigned int ap_qid_t;
+
+#define AP_MKQID(_device,_queue) (((_device) & 63) << 8 | ((_queue) & 15))
+#define AP_QID_DEVICE(_qid) (((_qid) >> 8) & 63)
+#define AP_QID_QUEUE(_qid) ((_qid) & 15)
+
+/**
+ * The ap queue status word is returned by all three AP functions
+ * (PQAP, NQAP and DQAP).  There's a set of flags in the first
+ * byte, followed by a 1 byte response code.
+ */
+struct ap_queue_status {
+	unsigned int queue_empty	: 1;
+	unsigned int replies_waiting	: 1;
+	unsigned int queue_full		: 1;
+	unsigned int pad1		: 5;
+	unsigned int response_code	: 8;
+	unsigned int pad2		: 16;
+};
+
+#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
+
+/**
+ * Known device types
+ */
+#define AP_DEVICE_TYPE_PCICC	3
+#define AP_DEVICE_TYPE_PCICA	4
+#define AP_DEVICE_TYPE_PCIXCC	5
+#define AP_DEVICE_TYPE_CEX2A	6
+#define AP_DEVICE_TYPE_CEX2C	7
+
+struct ap_device;
+struct ap_message;
+
+struct ap_driver {
+	struct device_driver driver;
+	struct ap_device_id *ids;
+
+	int (*probe)(struct ap_device *);
+	void (*remove)(struct ap_device *);
+	/* receive is called from tasklet context */
+	void (*receive)(struct ap_device *, struct ap_message *,
+			struct ap_message *);
+};
+
+#define to_ap_drv(x) container_of((x), struct ap_driver, driver)
+
+int ap_driver_register(struct ap_driver *, struct module *, char *);
+void ap_driver_unregister(struct ap_driver *);
+
+struct ap_device {
+	struct device device;
+	struct ap_driver *drv;		/* Pointer to AP device driver. */
+	spinlock_t lock;		/* Per device lock. */
+
+	ap_qid_t qid;			/* AP queue id. */
+	int queue_depth;		/* AP queue depth.*/
+	int device_type;		/* AP device type. */
+	int unregistered;		/* marks AP device as unregistered */
+
+	int queue_count;		/* # messages currently on AP queue. */
+
+	struct list_head pendingq;	/* List of message sent to AP queue. */
+	int pendingq_count;		/* # requests on pendingq list. */
+	struct list_head requestq;	/* List of message yet to be sent. */
+	int requestq_count;		/* # requests on requestq list. */
+	int total_request_count;	/* # requests ever for this AP device. */
+
+	struct ap_message *reply;	/* Per device reply message. */
+
+	void *private;			/* ap driver private pointer. */
+};
+
+#define to_ap_dev(x) container_of((x), struct ap_device, device)
+
+struct ap_message {
+	struct list_head list;		/* Request queueing. */
+	unsigned long long psmid;	/* Message id. */
+	void *message;			/* Pointer to message buffer. */
+	size_t length;			/* Message length. */
+
+	void *private;			/* ap driver private pointer. */
+};
+
+#define AP_DEVICE(dt)					\
+	.dev_type=(dt),					\
+	.match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE,
+
+/**
+ * Note: don't use ap_send/ap_recv after using ap_queue_message
+ * for the first time. Otherwise the ap message queue will get
+ * confused.
+ */
+int ap_send(ap_qid_t, unsigned long long, void *, size_t);
+int ap_recv(ap_qid_t, unsigned long long *, void *, size_t);
+
+void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
+void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
+void ap_flush_queue(struct ap_device *ap_dev);
+
+int ap_module_init(void);
+void ap_module_exit(void);
+
+#endif /* _AP_BUS_H_ */
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/Makefile linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/Makefile
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/Makefile	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/Makefile	2007-01-29 17:06:10.000000000 +0100
@@ -0,0 +1,17 @@
+#
+# S/390 crypto devices
+#
+
+ifdef CONFIG_ZCRYPT_MONOLITHIC
+
+z90crypt-objs := zcrypt_mono.o ap_bus.o zcrypt_api.o \
+		zcrypt_pcica.o zcrypt_pcicc.o zcrypt_pcixcc.o zcrypt_cex2a.o
+obj-$(CONFIG_ZCRYPT) += z90crypt.o
+
+else
+
+ap-objs := ap_bus.o
+obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcicc.o zcrypt_pcixcc.o
+obj-$(CONFIG_ZCRYPT) += zcrypt_pcica.o zcrypt_cex2a.o
+
+endif
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_api.c linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_api.c
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_api.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_api.c	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,1091 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_api.c
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *	       Cornelia Huck <cornelia.huck@de.ibm.com>
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *				  Ralph Wuerthner <rwuerthn@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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/compat.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "zcrypt_api.h"
+
+/**
+ * Module description.
+ */
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("Cryptographic Coprocessor interface, "
+		   "Copyright 2001, 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+
+static DEFINE_SPINLOCK(zcrypt_device_lock);
+static LIST_HEAD(zcrypt_device_list);
+static int zcrypt_device_count = 0;
+static atomic_t zcrypt_open_count = ATOMIC_INIT(0);
+
+/**
+ * Device attributes common for all crypto devices.
+ */
+static ssize_t zcrypt_type_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct zcrypt_device *zdev = to_ap_dev(dev)->private;
+	return snprintf(buf, PAGE_SIZE, "%s\n", zdev->type_string);
+}
+
+static DEVICE_ATTR(type, 0444, zcrypt_type_show, NULL);
+
+static ssize_t zcrypt_online_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct zcrypt_device *zdev = to_ap_dev(dev)->private;
+	return snprintf(buf, PAGE_SIZE, "%d\n", zdev->online);
+}
+
+static ssize_t zcrypt_online_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct zcrypt_device *zdev = to_ap_dev(dev)->private;
+	int online;
+
+	if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
+		return -EINVAL;
+	zdev->online = online;
+	if (!online)
+		ap_flush_queue(zdev->ap_dev);
+	return count;
+}
+
+static DEVICE_ATTR(online, 0644, zcrypt_online_show, zcrypt_online_store);
+
+static struct attribute * zcrypt_device_attrs[] = {
+	&dev_attr_type.attr,
+	&dev_attr_online.attr,
+	NULL,
+};
+
+static struct attribute_group zcrypt_device_attr_group = {
+	.attrs = zcrypt_device_attrs,
+};
+
+/**
+ * Move the device towards the head of the device list.
+ * Need to be called while holding the zcrypt device list lock.
+ * Note: cards with speed_rating of 0 are kept at the end of the list.
+ */
+static void __zcrypt_increase_preference(struct zcrypt_device *zdev)
+{
+	struct zcrypt_device *tmp;
+	struct list_head *l;
+
+	if (zdev->speed_rating == 0)
+		return;
+	for (l = zdev->list.prev; l != &zcrypt_device_list; l = l->prev) {
+		tmp = list_entry(l, struct zcrypt_device, list);
+		if ((tmp->request_count + 1) * tmp->speed_rating <=
+		    (zdev->request_count + 1) * zdev->speed_rating &&
+		    tmp->speed_rating != 0)
+			break;
+	}
+	if (l == zdev->list.prev)
+		return;
+	/* Move zdev behind l */
+	list_del(&zdev->list);
+	list_add(&zdev->list, l);
+}
+
+/**
+ * Move the device towards the tail of the device list.
+ * Need to be called while holding the zcrypt device list lock.
+ * Note: cards with speed_rating of 0 are kept at the end of the list.
+ */
+static void __zcrypt_decrease_preference(struct zcrypt_device *zdev)
+{
+	struct zcrypt_device *tmp;
+	struct list_head *l;
+
+	if (zdev->speed_rating == 0)
+		return;
+	for (l = zdev->list.next; l != &zcrypt_device_list; l = l->next) {
+		tmp = list_entry(l, struct zcrypt_device, list);
+		if ((tmp->request_count + 1) * tmp->speed_rating >
+		    (zdev->request_count + 1) * zdev->speed_rating ||
+		    tmp->speed_rating == 0)
+			break;
+	}
+	if (l == zdev->list.next)
+		return;
+	/* Move zdev before l */
+	list_del(&zdev->list);
+	list_add_tail(&zdev->list, l);
+}
+
+static void zcrypt_device_release(struct kref *kref)
+{
+	struct zcrypt_device *zdev =
+		container_of(kref, struct zcrypt_device, refcount);
+	zcrypt_device_free(zdev);
+}
+
+void zcrypt_device_get(struct zcrypt_device *zdev)
+{
+	kref_get(&zdev->refcount);
+}
+EXPORT_SYMBOL(zcrypt_device_get);
+
+int zcrypt_device_put(struct zcrypt_device *zdev)
+{
+	return kref_put(&zdev->refcount, zcrypt_device_release);
+}
+EXPORT_SYMBOL(zcrypt_device_put);
+
+struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size)
+{
+	struct zcrypt_device *zdev;
+
+	zdev = kzalloc(sizeof(struct zcrypt_device), GFP_KERNEL);
+	if (!zdev)
+		return NULL;
+	zdev->reply.message = kmalloc(max_response_size, GFP_KERNEL);
+	if (!zdev->reply.message)
+		goto out_free;
+	zdev->reply.length = max_response_size;
+	spin_lock_init(&zdev->lock);
+	INIT_LIST_HEAD(&zdev->list);
+	return zdev;
+
+out_free:
+	kfree(zdev);
+	return NULL;
+}
+EXPORT_SYMBOL(zcrypt_device_alloc);
+
+void zcrypt_device_free(struct zcrypt_device *zdev)
+{
+	kfree(zdev->reply.message);
+	kfree(zdev);
+}
+EXPORT_SYMBOL(zcrypt_device_free);
+
+/**
+ * Register a crypto device.
+ */
+int zcrypt_device_register(struct zcrypt_device *zdev)
+{
+	int rc;
+
+	rc = sysfs_create_group(&zdev->ap_dev->device.kobj,
+				&zcrypt_device_attr_group);
+	if (rc)
+		goto out;
+	get_device(&zdev->ap_dev->device);
+	kref_init(&zdev->refcount);
+	spin_lock_bh(&zcrypt_device_lock);
+	zdev->online = 1;	/* New devices are online by default. */
+	list_add_tail(&zdev->list, &zcrypt_device_list);
+	__zcrypt_increase_preference(zdev);
+	zcrypt_device_count++;
+	spin_unlock_bh(&zcrypt_device_lock);
+out:
+	return rc;
+}
+EXPORT_SYMBOL(zcrypt_device_register);
+
+/**
+ * Unregister a crypto device.
+ */
+void zcrypt_device_unregister(struct zcrypt_device *zdev)
+{
+	spin_lock_bh(&zcrypt_device_lock);
+	zcrypt_device_count--;
+	list_del_init(&zdev->list);
+	spin_unlock_bh(&zcrypt_device_lock);
+	sysfs_remove_group(&zdev->ap_dev->device.kobj,
+			   &zcrypt_device_attr_group);
+	put_device(&zdev->ap_dev->device);
+	zcrypt_device_put(zdev);
+}
+EXPORT_SYMBOL(zcrypt_device_unregister);
+
+/**
+ * zcrypt_read is not be supported beyond zcrypt 1.3.1
+ */
+static ssize_t zcrypt_read(struct file *filp, char __user *buf,
+			   size_t count, loff_t *f_pos)
+{
+	return -EPERM;
+}
+
+/**
+ * Write is is not allowed
+ */
+static ssize_t zcrypt_write(struct file *filp, const char __user *buf,
+			    size_t count, loff_t *f_pos)
+{
+	return -EPERM;
+}
+
+/**
+ * Device open/close functions to count number of users.
+ */
+static int zcrypt_open(struct inode *inode, struct file *filp)
+{
+	atomic_inc(&zcrypt_open_count);
+	return 0;
+}
+
+static int zcrypt_release(struct inode *inode, struct file *filp)
+{
+	atomic_dec(&zcrypt_open_count);
+	return 0;
+}
+
+/**
+ * zcrypt ioctls.
+ */
+static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
+{
+	struct zcrypt_device *zdev;
+	int rc;
+
+	if (mex->outputdatalength < mex->inputdatalength)
+		return -EINVAL;
+	/**
+	 * As long as outputdatalength is big enough, we can set the
+	 * outputdatalength equal to the inputdatalength, since that is the
+	 * number of bytes we will copy in any case
+	 */
+	mex->outputdatalength = mex->inputdatalength;
+
+	spin_lock_bh(&zcrypt_device_lock);
+	list_for_each_entry(zdev, &zcrypt_device_list, list) {
+		if (!zdev->online ||
+		    !zdev->ops->rsa_modexpo ||
+		    zdev->min_mod_size > mex->inputdatalength ||
+		    zdev->max_mod_size < mex->inputdatalength)
+			continue;
+		zcrypt_device_get(zdev);
+		get_device(&zdev->ap_dev->device);
+		zdev->request_count++;
+		__zcrypt_decrease_preference(zdev);
+		spin_unlock_bh(&zcrypt_device_lock);
+		if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
+			rc = zdev->ops->rsa_modexpo(zdev, mex);
+			module_put(zdev->ap_dev->drv->driver.owner);
+		}
+		else
+			rc = -EAGAIN;
+		spin_lock_bh(&zcrypt_device_lock);
+		zdev->request_count--;
+		__zcrypt_increase_preference(zdev);
+		put_device(&zdev->ap_dev->device);
+		zcrypt_device_put(zdev);
+		spin_unlock_bh(&zcrypt_device_lock);
+		return rc;
+	}
+	spin_unlock_bh(&zcrypt_device_lock);
+	return -ENODEV;
+}
+
+static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
+{
+	struct zcrypt_device *zdev;
+	unsigned long long z1, z2, z3;
+	int rc, copied;
+
+	if (crt->outputdatalength < crt->inputdatalength ||
+	    (crt->inputdatalength & 1))
+		return -EINVAL;
+	/**
+	 * As long as outputdatalength is big enough, we can set the
+	 * outputdatalength equal to the inputdatalength, since that is the
+	 * number of bytes we will copy in any case
+	 */
+	crt->outputdatalength = crt->inputdatalength;
+
+	copied = 0;
+ restart:
+	spin_lock_bh(&zcrypt_device_lock);
+	list_for_each_entry(zdev, &zcrypt_device_list, list) {
+		if (!zdev->online ||
+		    !zdev->ops->rsa_modexpo_crt ||
+		    zdev->min_mod_size > crt->inputdatalength ||
+		    zdev->max_mod_size < crt->inputdatalength)
+			continue;
+		if (zdev->short_crt && crt->inputdatalength > 240) {
+			/**
+			 * Check inputdata for leading zeros for cards
+			 * that can't handle np_prime, bp_key, or
+			 * u_mult_inv > 128 bytes.
+			 */
+			if (copied == 0) {
+				int len;
+				spin_unlock_bh(&zcrypt_device_lock);
+				/* len is max 256 / 2 - 120 = 8 */
+				len = crt->inputdatalength / 2 - 120;
+				z1 = z2 = z3 = 0;
+				if (copy_from_user(&z1, crt->np_prime, len) ||
+				    copy_from_user(&z2, crt->bp_key, len) ||
+				    copy_from_user(&z3, crt->u_mult_inv, len))
+					return -EFAULT;
+				copied = 1;
+				/**
+				 * We have to restart device lookup -
+				 * the device list may have changed by now.
+				 */
+				goto restart;
+			}
+			if (z1 != 0ULL || z2 != 0ULL || z3 != 0ULL)
+				/* The device can't handle this request. */
+				continue;
+		}
+		zcrypt_device_get(zdev);
+		get_device(&zdev->ap_dev->device);
+		zdev->request_count++;
+		__zcrypt_decrease_preference(zdev);
+		spin_unlock_bh(&zcrypt_device_lock);
+		if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
+			rc = zdev->ops->rsa_modexpo_crt(zdev, crt);
+			module_put(zdev->ap_dev->drv->driver.owner);
+		}
+		else
+			rc = -EAGAIN;
+		spin_lock_bh(&zcrypt_device_lock);
+		zdev->request_count--;
+		__zcrypt_increase_preference(zdev);
+		put_device(&zdev->ap_dev->device);
+		zcrypt_device_put(zdev);
+		spin_unlock_bh(&zcrypt_device_lock);
+		return rc;
+	}
+	spin_unlock_bh(&zcrypt_device_lock);
+	return -ENODEV;
+}
+
+static long zcrypt_send_cprb(struct ica_xcRB *xcRB)
+{
+	struct zcrypt_device *zdev;
+	int rc;
+
+	spin_lock_bh(&zcrypt_device_lock);
+	list_for_each_entry(zdev, &zcrypt_device_list, list) {
+		if (!zdev->online || !zdev->ops->send_cprb ||
+		    (xcRB->user_defined != AUTOSELECT &&
+			AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)
+		    )
+			continue;
+		zcrypt_device_get(zdev);
+		get_device(&zdev->ap_dev->device);
+		zdev->request_count++;
+		__zcrypt_decrease_preference(zdev);
+		spin_unlock_bh(&zcrypt_device_lock);
+		if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
+			rc = zdev->ops->send_cprb(zdev, xcRB);
+			module_put(zdev->ap_dev->drv->driver.owner);
+		}
+		else
+			rc = -EAGAIN;
+		spin_lock_bh(&zcrypt_device_lock);
+		zdev->request_count--;
+		__zcrypt_increase_preference(zdev);
+		put_device(&zdev->ap_dev->device);
+		zcrypt_device_put(zdev);
+		spin_unlock_bh(&zcrypt_device_lock);
+		return rc;
+	}
+	spin_unlock_bh(&zcrypt_device_lock);
+	return -ENODEV;
+}
+
+static void zcrypt_status_mask(char status[AP_DEVICES])
+{
+	struct zcrypt_device *zdev;
+
+	memset(status, 0, sizeof(char) * AP_DEVICES);
+	spin_lock_bh(&zcrypt_device_lock);
+	list_for_each_entry(zdev, &zcrypt_device_list, list)
+		status[AP_QID_DEVICE(zdev->ap_dev->qid)] =
+			zdev->online ? zdev->user_space_type : 0x0d;
+	spin_unlock_bh(&zcrypt_device_lock);
+}
+
+static void zcrypt_qdepth_mask(char qdepth[AP_DEVICES])
+{
+	struct zcrypt_device *zdev;
+
+	memset(qdepth, 0, sizeof(char)	* AP_DEVICES);
+	spin_lock_bh(&zcrypt_device_lock);
+	list_for_each_entry(zdev, &zcrypt_device_list, list) {
+		spin_lock(&zdev->ap_dev->lock);
+		qdepth[AP_QID_DEVICE(zdev->ap_dev->qid)] =
+			zdev->ap_dev->pendingq_count +
+			zdev->ap_dev->requestq_count;
+		spin_unlock(&zdev->ap_dev->lock);
+	}
+	spin_unlock_bh(&zcrypt_device_lock);
+}
+
+static void zcrypt_perdev_reqcnt(int reqcnt[AP_DEVICES])
+{
+	struct zcrypt_device *zdev;
+
+	memset(reqcnt, 0, sizeof(int) * AP_DEVICES);
+	spin_lock_bh(&zcrypt_device_lock);
+	list_for_each_entry(zdev, &zcrypt_device_list, list) {
+		spin_lock(&zdev->ap_dev->lock);
+		reqcnt[AP_QID_DEVICE(zdev->ap_dev->qid)] =
+			zdev->ap_dev->total_request_count;
+		spin_unlock(&zdev->ap_dev->lock);
+	}
+	spin_unlock_bh(&zcrypt_device_lock);
+}
+
+static int zcrypt_pendingq_count(void)
+{
+	struct zcrypt_device *zdev;
+	int pendingq_count = 0;
+
+	spin_lock_bh(&zcrypt_device_lock);
+	list_for_each_entry(zdev, &zcrypt_device_list, list) {
+		spin_lock(&zdev->ap_dev->lock);
+		pendingq_count += zdev->ap_dev->pendingq_count;
+		spin_unlock(&zdev->ap_dev->lock);
+	}
+	spin_unlock_bh(&zcrypt_device_lock);
+	return pendingq_count;
+}
+
+static int zcrypt_requestq_count(void)
+{
+	struct zcrypt_device *zdev;
+	int requestq_count = 0;
+
+	spin_lock_bh(&zcrypt_device_lock);
+	list_for_each_entry(zdev, &zcrypt_device_list, list) {
+		spin_lock(&zdev->ap_dev->lock);
+		requestq_count += zdev->ap_dev->requestq_count;
+		spin_unlock(&zdev->ap_dev->lock);
+	}
+	spin_unlock_bh(&zcrypt_device_lock);
+	return requestq_count;
+}
+
+static int zcrypt_count_type(int type)
+{
+	struct zcrypt_device *zdev;
+	int device_count = 0;
+
+	spin_lock_bh(&zcrypt_device_lock);
+	list_for_each_entry(zdev, &zcrypt_device_list, list)
+		if (zdev->user_space_type == type)
+			device_count++;
+	spin_unlock_bh(&zcrypt_device_lock);
+	return device_count;
+}
+
+/**
+ * Old, deprecated combi status call.
+ */
+static long zcrypt_ica_status(struct file *filp, unsigned long arg)
+{
+	struct ica_z90_status *pstat;
+	int ret;
+
+	pstat = kzalloc(sizeof(*pstat), GFP_KERNEL);
+	if (!pstat)
+		return -ENOMEM;
+	pstat->totalcount = zcrypt_device_count;
+	pstat->leedslitecount = zcrypt_count_type(ZCRYPT_PCICA);
+	pstat->leeds2count = zcrypt_count_type(ZCRYPT_PCICC);
+	pstat->requestqWaitCount = zcrypt_requestq_count();
+	pstat->pendingqWaitCount = zcrypt_pendingq_count();
+	pstat->totalOpenCount = atomic_read(&zcrypt_open_count);
+	pstat->cryptoDomain = ap_domain_index;
+	zcrypt_status_mask(pstat->status);
+	zcrypt_qdepth_mask(pstat->qdepth);
+	ret = 0;
+	if (copy_to_user((void __user *) arg, pstat, sizeof(*pstat)))
+		ret = -EFAULT;
+	kfree(pstat);
+	return ret;
+}
+
+static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
+				  unsigned long arg)
+{
+	int rc;
+
+	switch (cmd) {
+	case ICARSAMODEXPO: {
+		struct ica_rsa_modexpo __user *umex = (void __user *) arg;
+		struct ica_rsa_modexpo mex;
+		if (copy_from_user(&mex, umex, sizeof(mex)))
+			return -EFAULT;
+		do {
+			rc = zcrypt_rsa_modexpo(&mex);
+		} while (rc == -EAGAIN);
+		if (rc)
+			return rc;
+		return put_user(mex.outputdatalength, &umex->outputdatalength);
+	}
+	case ICARSACRT: {
+		struct ica_rsa_modexpo_crt __user *ucrt = (void __user *) arg;
+		struct ica_rsa_modexpo_crt crt;
+		if (copy_from_user(&crt, ucrt, sizeof(crt)))
+			return -EFAULT;
+		do {
+			rc = zcrypt_rsa_crt(&crt);
+		} while (rc == -EAGAIN);
+		if (rc)
+			return rc;
+		return put_user(crt.outputdatalength, &ucrt->outputdatalength);
+	}
+	case ZSECSENDCPRB: {
+		struct ica_xcRB __user *uxcRB = (void __user *) arg;
+		struct ica_xcRB xcRB;
+		if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB)))
+			return -EFAULT;
+		do {
+			rc = zcrypt_send_cprb(&xcRB);
+		} while (rc == -EAGAIN);
+		if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
+			return -EFAULT;
+		return rc;
+	}
+	case Z90STAT_STATUS_MASK: {
+		char status[AP_DEVICES];
+		zcrypt_status_mask(status);
+		if (copy_to_user((char __user *) arg, status,
+				 sizeof(char) * AP_DEVICES))
+			return -EFAULT;
+		return 0;
+	}
+	case Z90STAT_QDEPTH_MASK: {
+		char qdepth[AP_DEVICES];
+		zcrypt_qdepth_mask(qdepth);
+		if (copy_to_user((char __user *) arg, qdepth,
+				 sizeof(char) * AP_DEVICES))
+			return -EFAULT;
+		return 0;
+	}
+	case Z90STAT_PERDEV_REQCNT: {
+		int reqcnt[AP_DEVICES];
+		zcrypt_perdev_reqcnt(reqcnt);
+		if (copy_to_user((int __user *) arg, reqcnt,
+				 sizeof(int) * AP_DEVICES))
+			return -EFAULT;
+		return 0;
+	}
+	case Z90STAT_REQUESTQ_COUNT:
+		return put_user(zcrypt_requestq_count(), (int __user *) arg);
+	case Z90STAT_PENDINGQ_COUNT:
+		return put_user(zcrypt_pendingq_count(), (int __user *) arg);
+	case Z90STAT_TOTALOPEN_COUNT:
+		return put_user(atomic_read(&zcrypt_open_count),
+				(int __user *) arg);
+	case Z90STAT_DOMAIN_INDEX:
+		return put_user(ap_domain_index, (int __user *) arg);
+	/**
+	 * Deprecated ioctls. Don't add another device count ioctl,
+	 * you can count them yourself in the user space with the
+	 * output of the Z90STAT_STATUS_MASK ioctl.
+	 */
+	case ICAZ90STATUS:
+		return zcrypt_ica_status(filp, arg);
+	case Z90STAT_TOTALCOUNT:
+		return put_user(zcrypt_device_count, (int __user *) arg);
+	case Z90STAT_PCICACOUNT:
+		return put_user(zcrypt_count_type(ZCRYPT_PCICA),
+				(int __user *) arg);
+	case Z90STAT_PCICCCOUNT:
+		return put_user(zcrypt_count_type(ZCRYPT_PCICC),
+				(int __user *) arg);
+	case Z90STAT_PCIXCCMCL2COUNT:
+		return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL2),
+				(int __user *) arg);
+	case Z90STAT_PCIXCCMCL3COUNT:
+		return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL3),
+				(int __user *) arg);
+	case Z90STAT_PCIXCCCOUNT:
+		return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL2) +
+				zcrypt_count_type(ZCRYPT_PCIXCC_MCL3),
+				(int __user *) arg);
+	case Z90STAT_CEX2CCOUNT:
+		return put_user(zcrypt_count_type(ZCRYPT_CEX2C),
+				(int __user *) arg);
+	case Z90STAT_CEX2ACOUNT:
+		return put_user(zcrypt_count_type(ZCRYPT_CEX2A),
+				(int __user *) arg);
+	default:
+		/* unknown ioctl number */
+		return -ENOIOCTLCMD;
+	}
+}
+
+#ifdef CONFIG_COMPAT
+/**
+ * ioctl32 conversion routines
+ */
+struct compat_ica_rsa_modexpo {
+	compat_uptr_t	inputdata;
+	unsigned int	inputdatalength;
+	compat_uptr_t	outputdata;
+	unsigned int	outputdatalength;
+	compat_uptr_t	b_key;
+	compat_uptr_t	n_modulus;
+};
+
+static long trans_modexpo32(struct file *filp, unsigned int cmd,
+			    unsigned long arg)
+{
+	struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg);
+	struct compat_ica_rsa_modexpo mex32;
+	struct ica_rsa_modexpo mex64;
+	long rc;
+
+	if (copy_from_user(&mex32, umex32, sizeof(mex32)))
+		return -EFAULT;
+	mex64.inputdata = compat_ptr(mex32.inputdata);
+	mex64.inputdatalength = mex32.inputdatalength;
+	mex64.outputdata = compat_ptr(mex32.outputdata);
+	mex64.outputdatalength = mex32.outputdatalength;
+	mex64.b_key = compat_ptr(mex32.b_key);
+	mex64.n_modulus = compat_ptr(mex32.n_modulus);
+	do {
+		rc = zcrypt_rsa_modexpo(&mex64);
+	} while (rc == -EAGAIN);
+	if (!rc)
+		rc = put_user(mex64.outputdatalength,
+			      &umex32->outputdatalength);
+	return rc;
+}
+
+struct compat_ica_rsa_modexpo_crt {
+	compat_uptr_t	inputdata;
+	unsigned int	inputdatalength;
+	compat_uptr_t	outputdata;
+	unsigned int	outputdatalength;
+	compat_uptr_t	bp_key;
+	compat_uptr_t	bq_key;
+	compat_uptr_t	np_prime;
+	compat_uptr_t	nq_prime;
+	compat_uptr_t	u_mult_inv;
+};
+
+static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
+				unsigned long arg)
+{
+	struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg);
+	struct compat_ica_rsa_modexpo_crt crt32;
+	struct ica_rsa_modexpo_crt crt64;
+	long rc;
+
+	if (copy_from_user(&crt32, ucrt32, sizeof(crt32)))
+		return -EFAULT;
+	crt64.inputdata = compat_ptr(crt32.inputdata);
+	crt64.inputdatalength = crt32.inputdatalength;
+	crt64.outputdata=  compat_ptr(crt32.outputdata);
+	crt64.outputdatalength = crt32.outputdatalength;
+	crt64.bp_key = compat_ptr(crt32.bp_key);
+	crt64.bq_key = compat_ptr(crt32.bq_key);
+	crt64.np_prime = compat_ptr(crt32.np_prime);
+	crt64.nq_prime = compat_ptr(crt32.nq_prime);
+	crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv);
+	do {
+		rc = zcrypt_rsa_crt(&crt64);
+	} while (rc == -EAGAIN);
+	if (!rc)
+		rc = put_user(crt64.outputdatalength,
+			      &ucrt32->outputdatalength);
+	return rc;
+}
+
+struct compat_ica_xcRB {
+	unsigned short	agent_ID;
+	unsigned int	user_defined;
+	unsigned short	request_ID;
+	unsigned int	request_control_blk_length;
+	unsigned char	padding1[16 - sizeof (compat_uptr_t)];
+	compat_uptr_t	request_control_blk_addr;
+	unsigned int	request_data_length;
+	char		padding2[16 - sizeof (compat_uptr_t)];
+	compat_uptr_t	request_data_address;
+	unsigned int	reply_control_blk_length;
+	char		padding3[16 - sizeof (compat_uptr_t)];
+	compat_uptr_t	reply_control_blk_addr;
+	unsigned int	reply_data_length;
+	char		padding4[16 - sizeof (compat_uptr_t)];
+	compat_uptr_t	reply_data_addr;
+	unsigned short	priority_window;
+	unsigned int	status;
+} __attribute__((packed));
+
+static long trans_xcRB32(struct file *filp, unsigned int cmd,
+			 unsigned long arg)
+{
+	struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg);
+	struct compat_ica_xcRB xcRB32;
+	struct ica_xcRB xcRB64;
+	long rc;
+
+	if (copy_from_user(&xcRB32, uxcRB32, sizeof(xcRB32)))
+		return -EFAULT;
+	xcRB64.agent_ID = xcRB32.agent_ID;
+	xcRB64.user_defined = xcRB32.user_defined;
+	xcRB64.request_ID = xcRB32.request_ID;
+	xcRB64.request_control_blk_length =
+		xcRB32.request_control_blk_length;
+	xcRB64.request_control_blk_addr =
+		compat_ptr(xcRB32.request_control_blk_addr);
+	xcRB64.request_data_length =
+		xcRB32.request_data_length;
+	xcRB64.request_data_address =
+		compat_ptr(xcRB32.request_data_address);
+	xcRB64.reply_control_blk_length =
+		xcRB32.reply_control_blk_length;
+	xcRB64.reply_control_blk_addr =
+		compat_ptr(xcRB32.reply_control_blk_addr);
+	xcRB64.reply_data_length = xcRB32.reply_data_length;
+	xcRB64.reply_data_addr =
+		compat_ptr(xcRB32.reply_data_addr);
+	xcRB64.priority_window = xcRB32.priority_window;
+	xcRB64.status = xcRB32.status;
+	do {
+		rc = zcrypt_send_cprb(&xcRB64);
+	} while (rc == -EAGAIN);
+	xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
+	xcRB32.reply_data_length = xcRB64.reply_data_length;
+	xcRB32.status = xcRB64.status;
+	if (copy_to_user(uxcRB32, &xcRB32, sizeof(xcRB32)))
+			return -EFAULT;
+	return rc;
+}
+
+long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
+			 unsigned long arg)
+{
+	if (cmd == ICARSAMODEXPO)
+		return trans_modexpo32(filp, cmd, arg);
+	if (cmd == ICARSACRT)
+		return trans_modexpo_crt32(filp, cmd, arg);
+	if (cmd == ZSECSENDCPRB)
+		return trans_xcRB32(filp, cmd, arg);
+	return zcrypt_unlocked_ioctl(filp, cmd, arg);
+}
+#endif
+
+/**
+ * Misc device file operations.
+ */
+static struct file_operations zcrypt_fops = {
+	.owner		= THIS_MODULE,
+	.read		= zcrypt_read,
+	.write		= zcrypt_write,
+	.unlocked_ioctl	= zcrypt_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= zcrypt_compat_ioctl,
+#endif
+	.open		= zcrypt_open,
+	.release	= zcrypt_release
+};
+
+/**
+ * Misc device.
+ */
+static struct miscdevice zcrypt_misc_device = {
+	.minor	    = MISC_DYNAMIC_MINOR,
+	.name	    = "z90crypt",
+	.fops	    = &zcrypt_fops,
+};
+
+/**
+ * Deprecated /proc entry support.
+ */
+static struct proc_dir_entry *zcrypt_entry;
+
+static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
+			   unsigned int len)
+{
+	int hl, i;
+
+	hl = 0;
+	for (i = 0; i < len; i++)
+		hl += sprintf(outaddr+hl, "%01x", (unsigned int) addr[i]);
+	hl += sprintf(outaddr+hl, " ");
+	return hl;
+}
+
+static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
+			   unsigned int len)
+{
+	int hl, inl, c, cx;
+
+	hl = sprintf(outaddr, "	   ");
+	inl = 0;
+	for (c = 0; c < (len / 16); c++) {
+		hl += sprintcl(outaddr+hl, addr+inl, 16);
+		inl += 16;
+	}
+	cx = len%16;
+	if (cx) {
+		hl += sprintcl(outaddr+hl, addr+inl, cx);
+		inl += cx;
+	}
+	hl += sprintf(outaddr+hl, "\n");
+	return hl;
+}
+
+static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
+			   unsigned char *addr, unsigned int len)
+{
+	int hl, inl, r, rx;
+
+	hl = sprintf(outaddr, "\n%s\n", title);
+	inl = 0;
+	for (r = 0; r < (len / 64); r++) {
+		hl += sprintrw(outaddr+hl, addr+inl, 64);
+		inl += 64;
+	}
+	rx = len % 64;
+	if (rx) {
+		hl += sprintrw(outaddr+hl, addr+inl, rx);
+		inl += rx;
+	}
+	hl += sprintf(outaddr+hl, "\n");
+	return hl;
+}
+
+static inline int sprinthx4(unsigned char *title, unsigned char *outaddr,
+			    unsigned int *array, unsigned int len)
+{
+	int hl, r;
+
+	hl = sprintf(outaddr, "\n%s\n", title);
+	for (r = 0; r < len; r++) {
+		if ((r % 8) == 0)
+			hl += sprintf(outaddr+hl, "    ");
+		hl += sprintf(outaddr+hl, "%08X ", array[r]);
+		if ((r % 8) == 7)
+			hl += sprintf(outaddr+hl, "\n");
+	}
+	hl += sprintf(outaddr+hl, "\n");
+	return hl;
+}
+
+static int zcrypt_status_read(char *resp_buff, char **start, off_t offset,
+			      int count, int *eof, void *data)
+{
+	unsigned char *workarea;
+	int len;
+
+	len = 0;
+
+	/* resp_buff is a page. Use the right half for a work area */
+	workarea = resp_buff + 2000;
+	len += sprintf(resp_buff + len, "\nzcrypt version: %d.%d.%d\n",
+		ZCRYPT_VERSION, ZCRYPT_RELEASE, ZCRYPT_VARIANT);
+	len += sprintf(resp_buff + len, "Cryptographic domain: %d\n",
+		       ap_domain_index);
+	len += sprintf(resp_buff + len, "Total device count: %d\n",
+		       zcrypt_device_count);
+	len += sprintf(resp_buff + len, "PCICA count: %d\n",
+		       zcrypt_count_type(ZCRYPT_PCICA));
+	len += sprintf(resp_buff + len, "PCICC count: %d\n",
+		       zcrypt_count_type(ZCRYPT_PCICC));
+	len += sprintf(resp_buff + len, "PCIXCC MCL2 count: %d\n",
+		       zcrypt_count_type(ZCRYPT_PCIXCC_MCL2));
+	len += sprintf(resp_buff + len, "PCIXCC MCL3 count: %d\n",
+		       zcrypt_count_type(ZCRYPT_PCIXCC_MCL3));
+	len += sprintf(resp_buff + len, "CEX2C count: %d\n",
+		       zcrypt_count_type(ZCRYPT_CEX2C));
+	len += sprintf(resp_buff + len, "CEX2A count: %d\n",
+		       zcrypt_count_type(ZCRYPT_CEX2A));
+	len += sprintf(resp_buff + len, "requestq count: %d\n",
+		       zcrypt_requestq_count());
+	len += sprintf(resp_buff + len, "pendingq count: %d\n",
+		       zcrypt_pendingq_count());
+	len += sprintf(resp_buff + len, "Total open handles: %d\n\n",
+		       atomic_read(&zcrypt_open_count));
+	zcrypt_status_mask(workarea);
+	len += sprinthx("Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) "
+			"4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A",
+			resp_buff+len, workarea, AP_DEVICES);
+	zcrypt_qdepth_mask(workarea);
+	len += sprinthx("Waiting work element counts",
+			resp_buff+len, workarea, AP_DEVICES);
+	zcrypt_perdev_reqcnt((unsigned int *) workarea);
+	len += sprinthx4("Per-device successfully completed request counts",
+			 resp_buff+len,(unsigned int *) workarea, AP_DEVICES);
+	*eof = 1;
+	memset((void *) workarea, 0x00, AP_DEVICES * sizeof(unsigned int));
+	return len;
+}
+
+static void zcrypt_disable_card(int index)
+{
+	struct zcrypt_device *zdev;
+
+	spin_lock_bh(&zcrypt_device_lock);
+	list_for_each_entry(zdev, &zcrypt_device_list, list)
+		if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) {
+			zdev->online = 0;
+			ap_flush_queue(zdev->ap_dev);
+			break;
+		}
+	spin_unlock_bh(&zcrypt_device_lock);
+}
+
+static void zcrypt_enable_card(int index)
+{
+	struct zcrypt_device *zdev;
+
+	spin_lock_bh(&zcrypt_device_lock);
+	list_for_each_entry(zdev, &zcrypt_device_list, list)
+		if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) {
+			zdev->online = 1;
+			break;
+		}
+	spin_unlock_bh(&zcrypt_device_lock);
+}
+
+static int zcrypt_status_write(struct file *file, const char __user *buffer,
+			       unsigned long count, void *data)
+{
+	unsigned char *lbuf, *ptr;
+	unsigned long local_count;
+	int j;
+
+	if (count <= 0)
+		return 0;
+
+#define LBUFSIZE 1200UL
+	lbuf = kmalloc(LBUFSIZE, GFP_KERNEL);
+	if (!lbuf) {
+		PRINTK("kmalloc failed!\n");
+		return 0;
+	}
+
+	local_count = min(LBUFSIZE - 1, count);
+	if (copy_from_user(lbuf, buffer, local_count) != 0) {
+		kfree(lbuf);
+		return -EFAULT;
+	}
+	lbuf[local_count] = '\0';
+
+	ptr = strstr(lbuf, "Online devices");
+	if (!ptr) {
+		PRINTK("Unable to parse data (missing \"Online devices\")\n");
+		goto out;
+	}
+	ptr = strstr(ptr, "\n");
+	if (!ptr) {
+		PRINTK("Unable to parse data (missing newline "
+		       "after \"Online devices\")\n");
+		goto out;
+	}
+	ptr++;
+
+	if (strstr(ptr, "Waiting work element counts") == NULL) {
+		PRINTK("Unable to parse data (missing "
+		       "\"Waiting work element counts\")\n");
+		goto out;
+	}
+
+	for (j = 0; j < 64 && *ptr; ptr++) {
+		/**
+		 * '0' for no device, '1' for PCICA, '2' for PCICC,
+		 * '3' for PCIXCC_MCL2, '4' for PCIXCC_MCL3,
+		 * '5' for CEX2C and '6' for CEX2A'
+		 */
+		if (*ptr >= '0' && *ptr <= '6')
+			j++;
+		else if (*ptr == 'd' || *ptr == 'D')
+			zcrypt_disable_card(j++);
+		else if (*ptr == 'e' || *ptr == 'E')
+			zcrypt_enable_card(j++);
+		else if (*ptr != ' ' && *ptr != '\t')
+			break;
+	}
+out:
+	kfree(lbuf);
+	return count;
+}
+
+/**
+ * The module initialization code.
+ */
+int __init zcrypt_api_init(void)
+{
+	int rc;
+
+	/* Register the request sprayer. */
+	rc = misc_register(&zcrypt_misc_device);
+	if (rc < 0) {
+		PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n",
+			zcrypt_misc_device.minor, rc);
+		goto out;
+	}
+
+	/* Set up the proc file system */
+	zcrypt_entry = create_proc_entry("driver/z90crypt", 0644, NULL);
+	if (!zcrypt_entry) {
+		PRINTK("Couldn't create z90crypt proc entry\n");
+		rc = -ENOMEM;
+		goto out_misc;
+	}
+	zcrypt_entry->nlink = 1;
+	zcrypt_entry->data = NULL;
+	zcrypt_entry->read_proc = zcrypt_status_read;
+	zcrypt_entry->write_proc = zcrypt_status_write;
+
+	return 0;
+
+out_misc:
+	misc_deregister(&zcrypt_misc_device);
+out:
+	return rc;
+}
+
+/**
+ * The module termination code.
+ */
+void zcrypt_api_exit(void)
+{
+	remove_proc_entry("driver/z90crypt", NULL);
+	misc_deregister(&zcrypt_misc_device);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(zcrypt_api_init);
+module_exit(zcrypt_api_exit);
+#endif
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_api.h linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_api.h
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_api.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_api.h	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,141 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_api.h
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *	       Cornelia Huck <cornelia.huck@de.ibm.com>
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *				  Ralph Wuerthner <rwuerthn@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 _ZCRYPT_API_H_
+#define _ZCRYPT_API_H_
+
+/**
+ * Macro definitions
+ *
+ * PDEBUG debugs in the form "zcrypt: function_name -> message"
+ *
+ * PRINTK is like PDEBUG, except that it is always enabled
+ * PRINTKN is like PRINTK, except that it does not include the function name
+ * PRINTKW is like PRINTK, except that it uses KERN_WARNING
+ * PRINTKC is like PRINTK, except that it uses KERN_CRIT
+ */
+#define DEV_NAME	"zcrypt"
+
+#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 ZCRYPT_DEBUG
+#define PDEBUG(fmt, args...) \
+	printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+#else
+#define PDEBUG(fmt, args...) do {} while (0)
+#endif
+
+#include "ap_bus.h"
+#include <asm/zcrypt.h>
+
+/* deprecated status calls */
+#define ICAZ90STATUS		_IOR(ZCRYPT_IOCTL_MAGIC, 0x10, struct ica_z90_status)
+#define Z90STAT_PCIXCCCOUNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x43, int)
+
+/**
+ * This structure is deprecated and the corresponding ioctl() has been
+ * replaced with individual ioctl()s for each piece of data!
+ */
+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_MCL2, 4=PCIXCC_MCL3,
+	//	   5=CEX2C
+	unsigned char status[64];
+	// qdepth: # work elements waiting for each device
+	unsigned char qdepth[64];
+};
+
+/**
+ * device type for an actual device is either PCICA, PCICC, PCIXCC_MCL2,
+ * PCIXCC_MCL3, CEX2C, or CEX2A
+ *
+ * NOTE: PCIXCC_MCL3 refers to a PCIXCC with May 2004 version of Licensed
+ *	 Internal Code (LIC) (EC J12220 level 29).
+ *	 PCIXCC_MCL2 refers to any LIC before this level.
+ */
+#define ZCRYPT_PCICA		1
+#define ZCRYPT_PCICC		2
+#define ZCRYPT_PCIXCC_MCL2	3
+#define ZCRYPT_PCIXCC_MCL3	4
+#define ZCRYPT_CEX2C		5
+#define ZCRYPT_CEX2A		6
+
+struct zcrypt_device;
+
+struct zcrypt_ops {
+	long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *);
+	long (*rsa_modexpo_crt)(struct zcrypt_device *,
+				struct ica_rsa_modexpo_crt *);
+	long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *);
+};
+
+struct zcrypt_device {
+	struct list_head list;		/* Device list. */
+	spinlock_t lock;		/* Per device lock. */
+	struct kref refcount;		/* device refcounting */
+	struct ap_device *ap_dev;	/* The "real" ap device. */
+	struct zcrypt_ops *ops;		/* Crypto operations. */
+	int online;			/* User online/offline */
+
+	int user_space_type;		/* User space device id. */
+	char *type_string;		/* User space device name. */
+	int min_mod_size;		/* Min number of bits. */
+	int max_mod_size;		/* Max number of bits. */
+	int short_crt;			/* Card has crt length restriction. */
+	int speed_rating;		/* Speed of the crypto device. */
+
+	int request_count;		/* # current requests. */
+
+	struct ap_message reply;	/* Per-device reply structure. */
+};
+
+struct zcrypt_device *zcrypt_device_alloc(size_t);
+void zcrypt_device_free(struct zcrypt_device *);
+void zcrypt_device_get(struct zcrypt_device *);
+int zcrypt_device_put(struct zcrypt_device *);
+int zcrypt_device_register(struct zcrypt_device *);
+void zcrypt_device_unregister(struct zcrypt_device *);
+int zcrypt_api_init(void);
+void zcrypt_api_exit(void);
+
+#endif /* _ZCRYPT_API_H_ */
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_cca_key.h linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_cca_key.h
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_cca_key.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_cca_key.h	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,350 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_cca_key.h
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@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 _ZCRYPT_CCA_KEY_H_
+#define _ZCRYPT_CCA_KEY_H_
+
+struct T6_keyBlock_hdr {
+	unsigned short blen;
+	unsigned short ulen;
+	unsigned short flags;
+};
+
+/**
+ * mapping for the cca private ME key token.
+ * Three parts of interest here: the header, the private section and
+ * the public section.
+ *
+ * mapping for the cca key token header
+ */
+struct cca_token_hdr {
+	unsigned char  token_identifier;
+	unsigned char  version;
+	unsigned short token_length;
+	unsigned char  reserved[4];
+} __attribute__((packed));
+
+#define CCA_TKN_HDR_ID_EXT 0x1E
+
+/**
+ * mapping for the cca private ME section
+ */
+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];
+} __attribute__((packed));
+
+#define CCA_PVT_USAGE_ALL 0x80
+
+/**
+ * mapping for the cca public section
+ * In a private key, the modulus doesn't appear in the public
+ * section. So, an arbitrary public exponent of 0x010001 will be
+ * used, for a section length of 0x0F always.
+ */
+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;    /* In a private key, this is 0 */
+} __attribute__((packed));
+
+/**
+ * mapping for the cca private CRT key 'token'
+ * The first three parts (the only parts considered in this release)
+ * are: the header, the private section and the public section.
+ * The header and public section are the same as for the
+ * struct cca_private_ext_ME
+ *
+ * Following the structure are the quantities p, q, dp, dq, u, pad,
+ * and modulus, in that order, where pad_len is the modulo 8
+ * complement of the residue modulo 8 of the sum of
+ * (p_len + q_len + dp_len + dq_len + u_len).
+ */
+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];
+} __attribute__((packed));
+
+#define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08
+#define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40
+
+/**
+ * Set up private key fields of a type6 MEX message.
+ * Note that all numerics in the key token are big-endian,
+ * while the entries in the key block header are little-endian.
+ *
+ * @mex: pointer to user input data
+ * @p: pointer to memory area for the key
+ *
+ * Returns the size of the key area or -EFAULT
+ */
+static inline int zcrypt_type6_mex_key_de(struct ica_rsa_modexpo *mex,
+					  void *p, int big_endian)
+{
+	static struct cca_token_hdr static_pvt_me_hdr = {
+		.token_identifier	=  0x1E,
+		.token_length		=  0x0183,
+	};
+	static struct cca_private_ext_ME_sec static_pvt_me_sec = {
+		.section_identifier	=  0x02,
+		.section_length		=  0x016C,
+		.key_use_flags		= {0x80,0x00,0x00,0x00},
+	};
+	static struct cca_public_sec static_pub_me_sec = {
+		.section_identifier	=  0x04,
+		.section_length		=  0x000F,
+		.exponent_len		=  0x0003,
+	};
+	static char pk_exponent[3] = { 0x01, 0x00, 0x01 };
+	struct {
+		struct T6_keyBlock_hdr t6_hdr;
+		struct cca_token_hdr pvtMeHdr;
+		struct cca_private_ext_ME_sec pvtMeSec;
+		struct cca_public_sec pubMeSec;
+		char exponent[3];
+	} __attribute__((packed)) *key = p;
+	unsigned char *temp;
+
+	memset(key, 0, sizeof(*key));
+
+	if (big_endian) {
+		key->t6_hdr.blen = cpu_to_be16(0x189);
+		key->t6_hdr.ulen = cpu_to_be16(0x189 - 2);
+	} else {
+		key->t6_hdr.blen = cpu_to_le16(0x189);
+		key->t6_hdr.ulen = cpu_to_le16(0x189 - 2);
+	}
+	key->pvtMeHdr = static_pvt_me_hdr;
+	key->pvtMeSec = static_pvt_me_sec;
+	key->pubMeSec = static_pub_me_sec;
+	/**
+	 * In a private key, the modulus doesn't appear in the public
+	 * section. So, an arbitrary public exponent of 0x010001 will be
+	 * used.
+	 */
+	memcpy(key->exponent, pk_exponent, 3);
+
+	/* key parameter block */
+	temp = key->pvtMeSec.exponent +
+		sizeof(key->pvtMeSec.exponent) - mex->inputdatalength;
+	if (copy_from_user(temp, mex->b_key, mex->inputdatalength))
+		return -EFAULT;
+
+	/* modulus */
+	temp = key->pvtMeSec.modulus +
+		sizeof(key->pvtMeSec.modulus) - mex->inputdatalength;
+	if (copy_from_user(temp, mex->n_modulus, mex->inputdatalength))
+		return -EFAULT;
+	key->pubMeSec.modulus_bit_len = 8 * mex->inputdatalength;
+	return sizeof(*key);
+}
+
+/**
+ * Set up private key fields of a type6 MEX message. The _pad variant
+ * strips leading zeroes from the b_key.
+ * Note that all numerics in the key token are big-endian,
+ * while the entries in the key block header are little-endian.
+ *
+ * @mex: pointer to user input data
+ * @p: pointer to memory area for the key
+ *
+ * Returns the size of the key area or -EFAULT
+ */
+static inline int zcrypt_type6_mex_key_en(struct ica_rsa_modexpo *mex,
+					  void *p, int big_endian)
+{
+	static struct cca_token_hdr static_pub_hdr = {
+		.token_identifier	=  0x1E,
+	};
+	static struct cca_public_sec static_pub_sec = {
+		.section_identifier	=  0x04,
+	};
+	struct {
+		struct T6_keyBlock_hdr t6_hdr;
+		struct cca_token_hdr pubHdr;
+		struct cca_public_sec pubSec;
+		char exponent[0];
+	} __attribute__((packed)) *key = p;
+	unsigned char *temp;
+	int i;
+
+	memset(key, 0, sizeof(*key));
+
+	key->pubHdr = static_pub_hdr;
+	key->pubSec = static_pub_sec;
+
+	/* key parameter block */
+	temp = key->exponent;
+	if (copy_from_user(temp, mex->b_key, mex->inputdatalength))
+		return -EFAULT;
+	/* Strip leading zeroes from b_key. */
+	for (i = 0; i < mex->inputdatalength; i++)
+		if (temp[i])
+			break;
+	if (i >= mex->inputdatalength)
+		return -EINVAL;
+	memmove(temp, temp + i, mex->inputdatalength - i);
+	temp += mex->inputdatalength - i;
+	/* modulus */
+	if (copy_from_user(temp, mex->n_modulus, mex->inputdatalength))
+		return -EFAULT;
+
+	key->pubSec.modulus_bit_len = 8 * mex->inputdatalength;
+	key->pubSec.modulus_byte_len = mex->inputdatalength;
+	key->pubSec.exponent_len = mex->inputdatalength - i;
+	key->pubSec.section_length = sizeof(key->pubSec) +
+					2*mex->inputdatalength - i;
+	key->pubHdr.token_length =
+		key->pubSec.section_length + sizeof(key->pubHdr);
+	if (big_endian) {
+		key->t6_hdr.ulen = cpu_to_be16(key->pubHdr.token_length + 4);
+		key->t6_hdr.blen = cpu_to_be16(key->pubHdr.token_length + 6);
+	} else {
+		key->t6_hdr.ulen = cpu_to_le16(key->pubHdr.token_length + 4);
+		key->t6_hdr.blen = cpu_to_le16(key->pubHdr.token_length + 6);
+	}
+	return sizeof(*key) + 2*mex->inputdatalength - i;
+}
+
+/**
+ * Set up private key fields of a type6 CRT message.
+ * Note that all numerics in the key token are big-endian,
+ * while the entries in the key block header are little-endian.
+ *
+ * @mex: pointer to user input data
+ * @p: pointer to memory area for the key
+ *
+ * Returns the size of the key area or -EFAULT
+ */
+static inline int zcrypt_type6_crt_key(struct ica_rsa_modexpo_crt *crt,
+				       void *p, int big_endian)
+{
+	static struct cca_public_sec static_cca_pub_sec = {
+		.section_identifier = 4,
+		.section_length = 0x000f,
+		.exponent_len = 0x0003,
+	};
+	static char pk_exponent[3] = { 0x01, 0x00, 0x01 };
+	struct {
+		struct T6_keyBlock_hdr t6_hdr;
+		struct cca_token_hdr token;
+		struct cca_pvt_ext_CRT_sec pvt;
+		char key_parts[0];
+	} __attribute__((packed)) *key = p;
+	struct cca_public_sec *pub;
+	int short_len, long_len, pad_len, key_len, size;
+
+	memset(key, 0, sizeof(*key));
+
+	short_len = crt->inputdatalength / 2;
+	long_len = short_len + 8;
+	pad_len = -(3*long_len + 2*short_len) & 7;
+	key_len = 3*long_len + 2*short_len + pad_len + crt->inputdatalength;
+	size = sizeof(*key) + key_len + sizeof(*pub) + 3;
+
+	/* parameter block.key block */
+	if (big_endian) {
+		key->t6_hdr.blen = cpu_to_be16(size);
+		key->t6_hdr.ulen = cpu_to_be16(size - 2);
+	} else {
+		key->t6_hdr.blen = cpu_to_le16(size);
+		key->t6_hdr.ulen = cpu_to_le16(size - 2);
+	}
+
+	/* key token header */
+	key->token.token_identifier = CCA_TKN_HDR_ID_EXT;
+	key->token.token_length = size - 6;
+
+	/* private section */
+	key->pvt.section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
+	key->pvt.section_length = sizeof(key->pvt) + key_len;
+	key->pvt.key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
+	key->pvt.key_use_flags[0] = CCA_PVT_USAGE_ALL;
+	key->pvt.p_len = key->pvt.dp_len = key->pvt.u_len = long_len;
+	key->pvt.q_len = key->pvt.dq_len = short_len;
+	key->pvt.mod_len = crt->inputdatalength;
+	key->pvt.pad_len = pad_len;
+
+	/* key parts */
+	if (copy_from_user(key->key_parts, crt->np_prime, long_len) ||
+	    copy_from_user(key->key_parts + long_len,
+					crt->nq_prime, short_len) ||
+	    copy_from_user(key->key_parts + long_len + short_len,
+					crt->bp_key, long_len) ||
+	    copy_from_user(key->key_parts + 2*long_len + short_len,
+					crt->bq_key, short_len) ||
+	    copy_from_user(key->key_parts + 2*long_len + 2*short_len,
+					crt->u_mult_inv, long_len))
+		return -EFAULT;
+	memset(key->key_parts + 3*long_len + 2*short_len + pad_len,
+	       0xff, crt->inputdatalength);
+	pub = (struct cca_public_sec *)(key->key_parts + key_len);
+	*pub = static_cca_pub_sec;
+	pub->modulus_bit_len = 8 * crt->inputdatalength;
+	/**
+	 * In a private key, the modulus doesn't appear in the public
+	 * section. So, an arbitrary public exponent of 0x010001 will be
+	 * used.
+	 */
+	memcpy((char *) (pub + 1), pk_exponent, 3);
+	return size;
+}
+
+#endif /* _ZCRYPT_CCA_KEY_H_ */
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_cex2a.c linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_cex2a.c
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_cex2a.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_cex2a.c	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,435 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_cex2a.c
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *				  Ralph Wuerthner <rwuerthn@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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_error.h"
+#include "zcrypt_cex2a.h"
+
+#define CEX2A_MIN_MOD_SIZE	  1	/*    8 bits	*/
+#define CEX2A_MAX_MOD_SIZE	256	/* 2048 bits	*/
+
+#define CEX2A_SPEED_RATING	970
+
+#define CEX2A_MAX_MESSAGE_SIZE	0x390	/* sizeof(struct type50_crb2_msg)    */
+#define CEX2A_MAX_RESPONSE_SIZE 0x110	/* max outputdatalength + type80_hdr */
+
+#define CEX2A_CLEANUP_TIME	(15*HZ)
+
+static struct ap_device_id zcrypt_cex2a_ids[] = {
+	{ AP_DEVICE(AP_DEVICE_TYPE_CEX2A) },
+	{ /* end of list */ },
+};
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids);
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, "
+		   "Copyright 2001, 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+#endif
+
+static int zcrypt_cex2a_probe(struct ap_device *ap_dev);
+static void zcrypt_cex2a_remove(struct ap_device *ap_dev);
+static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *,
+				 struct ap_message *);
+
+static struct ap_driver zcrypt_cex2a_driver = {
+	.probe = zcrypt_cex2a_probe,
+	.remove = zcrypt_cex2a_remove,
+	.receive = zcrypt_cex2a_receive,
+	.ids = zcrypt_cex2a_ids,
+};
+
+/**
+ * Convert a ICAMEX message to a type50 MEX message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @mex: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev,
+				       struct ap_message *ap_msg,
+				       struct ica_rsa_modexpo *mex)
+{
+	unsigned char *mod, *exp, *inp;
+	int mod_len;
+
+	mod_len = mex->inputdatalength;
+
+	if (mod_len <= 128) {
+		struct type50_meb1_msg *meb1 = ap_msg->message;
+		memset(meb1, 0, sizeof(*meb1));
+		ap_msg->length = sizeof(*meb1);
+		meb1->header.msg_type_code = TYPE50_TYPE_CODE;
+		meb1->header.msg_len = sizeof(*meb1);
+		meb1->keyblock_type = TYPE50_MEB1_FMT;
+		mod = meb1->modulus + sizeof(meb1->modulus) - mod_len;
+		exp = meb1->exponent + sizeof(meb1->exponent) - mod_len;
+		inp = meb1->message + sizeof(meb1->message) - mod_len;
+	} else {
+		struct type50_meb2_msg *meb2 = ap_msg->message;
+		memset(meb2, 0, sizeof(*meb2));
+		ap_msg->length = sizeof(*meb2);
+		meb2->header.msg_type_code = TYPE50_TYPE_CODE;
+		meb2->header.msg_len = sizeof(*meb2);
+		meb2->keyblock_type = TYPE50_MEB2_FMT;
+		mod = meb2->modulus + sizeof(meb2->modulus) - mod_len;
+		exp = meb2->exponent + sizeof(meb2->exponent) - mod_len;
+		inp = meb2->message + sizeof(meb2->message) - mod_len;
+	}
+
+	if (copy_from_user(mod, mex->n_modulus, mod_len) ||
+	    copy_from_user(exp, mex->b_key, mod_len) ||
+	    copy_from_user(inp, mex->inputdata, mod_len))
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ * Convert a ICACRT message to a type50 CRT message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @crt: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
+				       struct ap_message *ap_msg,
+				       struct ica_rsa_modexpo_crt *crt)
+{
+	int mod_len, short_len, long_len, long_offset;
+	unsigned char *p, *q, *dp, *dq, *u, *inp;
+
+	mod_len = crt->inputdatalength;
+	short_len = mod_len / 2;
+	long_len = mod_len / 2 + 8;
+
+	/*
+	 * CEX2A cannot handle p, dp, or U > 128 bytes.
+	 * If we have one of these, we need to do extra checking.
+	 */
+	if (long_len > 128) {
+		/*
+		 * zcrypt_rsa_crt already checked for the leading
+		 * zeroes of np_prime, bp_key and u_mult_inc.
+		 */
+		long_offset = long_len - 128;
+		long_len = 128;
+	} else
+		long_offset = 0;
+
+	/*
+	 * Instead of doing extra work for p, dp, U > 64 bytes, we'll just use
+	 * the larger message structure.
+	 */
+	if (long_len <= 64) {
+		struct type50_crb1_msg *crb1 = ap_msg->message;
+		memset(crb1, 0, sizeof(*crb1));
+		ap_msg->length = sizeof(*crb1);
+		crb1->header.msg_type_code = TYPE50_TYPE_CODE;
+		crb1->header.msg_len = sizeof(*crb1);
+		crb1->keyblock_type = TYPE50_CRB1_FMT;
+		p = crb1->p + sizeof(crb1->p) - long_len;
+		q = crb1->q + sizeof(crb1->q) - short_len;
+		dp = crb1->dp + sizeof(crb1->dp) - long_len;
+		dq = crb1->dq + sizeof(crb1->dq) - short_len;
+		u = crb1->u + sizeof(crb1->u) - long_len;
+		inp = crb1->message + sizeof(crb1->message) - mod_len;
+	} else {
+		struct type50_crb2_msg *crb2 = ap_msg->message;
+		memset(crb2, 0, sizeof(*crb2));
+		ap_msg->length = sizeof(*crb2);
+		crb2->header.msg_type_code = TYPE50_TYPE_CODE;
+		crb2->header.msg_len = sizeof(*crb2);
+		crb2->keyblock_type = TYPE50_CRB2_FMT;
+		p = crb2->p + sizeof(crb2->p) - long_len;
+		q = crb2->q + sizeof(crb2->q) - short_len;
+		dp = crb2->dp + sizeof(crb2->dp) - long_len;
+		dq = crb2->dq + sizeof(crb2->dq) - short_len;
+		u = crb2->u + sizeof(crb2->u) - long_len;
+		inp = crb2->message + sizeof(crb2->message) - mod_len;
+	}
+
+	if (copy_from_user(p, crt->np_prime + long_offset, long_len) ||
+	    copy_from_user(q, crt->nq_prime, short_len) ||
+	    copy_from_user(dp, crt->bp_key + long_offset, long_len) ||
+	    copy_from_user(dq, crt->bq_key, short_len) ||
+	    copy_from_user(u, crt->u_mult_inv + long_offset, long_len) ||
+	    copy_from_user(inp, crt->inputdata, mod_len))
+		return -EFAULT;
+
+
+	return 0;
+}
+
+/**
+ * Copy results from a type 80 reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @data: pointer to user output data
+ * @length: size of user output data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int convert_type80(struct zcrypt_device *zdev,
+			  struct ap_message *reply,
+			  char __user *outputdata,
+			  unsigned int outputdatalength)
+{
+	struct type80_hdr *t80h = reply->message;
+	unsigned char *data;
+
+	if (t80h->len < sizeof(*t80h) + outputdatalength) {
+		/* The result is too short, the CEX2A card may not do that.. */
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+	BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE);
+	data = reply->message + t80h->len - outputdatalength;
+	if (copy_to_user(outputdata, data, outputdatalength))
+		return -EFAULT;
+	return 0;
+}
+
+static int convert_response(struct zcrypt_device *zdev,
+			    struct ap_message *reply,
+			    char __user *outputdata,
+			    unsigned int outputdatalength)
+{
+	/* Response type byte is the second byte in the response. */
+	switch (((unsigned char *) reply->message)[1]) {
+	case TYPE82_RSP_CODE:
+	case TYPE88_RSP_CODE:
+		return convert_error(zdev, reply);
+	case TYPE80_RSP_CODE:
+		return convert_type80(zdev, reply,
+				      outputdata, outputdatalength);
+	default: /* Unknown response type, this should NEVER EVER happen */
+		PRINTK("Unrecognized Message Header: %08x%08x\n",
+		       *(unsigned int *) reply->message,
+		       *(unsigned int *) (reply->message+4));
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+}
+
+/**
+ * This function is called from the AP bus code after a crypto request
+ * "msg" has finished with the reply message "reply".
+ * It is called from tasklet context.
+ * @ap_dev: pointer to the AP device
+ * @msg: pointer to the AP message
+ * @reply: pointer to the AP reply message
+ */
+static void zcrypt_cex2a_receive(struct ap_device *ap_dev,
+				 struct ap_message *msg,
+				 struct ap_message *reply)
+{
+	static struct error_hdr error_reply = {
+		.type = TYPE82_RSP_CODE,
+		.reply_code = REP82_ERROR_MACHINE_FAILURE,
+	};
+	struct type80_hdr *t80h = reply->message;
+	int length;
+
+	/* Copy the reply message to the request message buffer. */
+	if (IS_ERR(reply))
+		memcpy(msg->message, &error_reply, sizeof(error_reply));
+	else if (t80h->type == TYPE80_RSP_CODE) {
+		length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len);
+		memcpy(msg->message, reply->message, length);
+	} else
+		memcpy(msg->message, reply->message, sizeof error_reply);
+	complete((struct completion *) msg->private);
+}
+
+static atomic_t zcrypt_step = ATOMIC_INIT(0);
+
+/**
+ * The request distributor calls this function if it picked the CEX2A
+ * device to handle a modexpo request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  CEX2A device to the request distributor
+ * @mex: pointer to the modexpo request buffer
+ */
+static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
+				 struct ica_rsa_modexpo *mex)
+{
+	struct ap_message ap_msg;
+	struct completion work;
+	int rc;
+
+	ap_msg.message = (void *) kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &work;
+	rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex);
+	if (rc)
+		goto out_free;
+	init_completion(&work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible_timeout(
+				&work, CEX2A_CLEANUP_TIME);
+	if (rc > 0)
+		rc = convert_response(zdev, &ap_msg, mex->outputdata,
+				      mex->outputdatalength);
+	else {
+		/* Signal pending or message timed out. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+		if (rc == 0)
+			/* Message timed out. */
+			rc = -ETIME;
+	}
+out_free:
+	kfree(ap_msg.message);
+	return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the CEX2A
+ * device to handle a modexpo_crt request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  CEX2A device to the request distributor
+ * @crt: pointer to the modexpoc_crt request buffer
+ */
+static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
+				     struct ica_rsa_modexpo_crt *crt)
+{
+	struct ap_message ap_msg;
+	struct completion work;
+	int rc;
+
+	ap_msg.message = (void *) kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &work;
+	rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt);
+	if (rc)
+		goto out_free;
+	init_completion(&work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible_timeout(
+				&work, CEX2A_CLEANUP_TIME);
+	if (rc > 0)
+		rc = convert_response(zdev, &ap_msg, crt->outputdata,
+				      crt->outputdatalength);
+	else {
+		/* Signal pending or message timed out. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+		if (rc == 0)
+			/* Message timed out. */
+			rc = -ETIME;
+	}
+out_free:
+	kfree(ap_msg.message);
+	return rc;
+}
+
+/**
+ * The crypto operations for a CEX2A card.
+ */
+static struct zcrypt_ops zcrypt_cex2a_ops = {
+	.rsa_modexpo = zcrypt_cex2a_modexpo,
+	.rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt,
+};
+
+/**
+ * Probe function for CEX2A cards. It always accepts the AP device
+ * since the bus_match already checked the hardware type.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
+{
+	struct zcrypt_device *zdev;
+	int rc;
+
+	zdev = zcrypt_device_alloc(CEX2A_MAX_RESPONSE_SIZE);
+	if (!zdev)
+		return -ENOMEM;
+	zdev->ap_dev = ap_dev;
+	zdev->ops = &zcrypt_cex2a_ops;
+	zdev->online = 1;
+	zdev->user_space_type = ZCRYPT_CEX2A;
+	zdev->type_string = "CEX2A";
+	zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
+	zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
+	zdev->short_crt = 1;
+	zdev->speed_rating = CEX2A_SPEED_RATING;
+	ap_dev->reply = &zdev->reply;
+	ap_dev->private = zdev;
+	rc = zcrypt_device_register(zdev);
+	if (rc)
+		goto out_free;
+	return 0;
+
+out_free:
+	ap_dev->private = NULL;
+	zcrypt_device_free(zdev);
+	return rc;
+}
+
+/**
+ * This is called to remove the extended CEX2A driver information
+ * if an AP device is removed.
+ */
+static void zcrypt_cex2a_remove(struct ap_device *ap_dev)
+{
+	struct zcrypt_device *zdev = ap_dev->private;
+
+	zcrypt_device_unregister(zdev);
+}
+
+int __init zcrypt_cex2a_init(void)
+{
+	return ap_driver_register(&zcrypt_cex2a_driver, THIS_MODULE, "cex2a");
+}
+
+void __exit zcrypt_cex2a_exit(void)
+{
+	ap_driver_unregister(&zcrypt_cex2a_driver);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(zcrypt_cex2a_init);
+module_exit(zcrypt_cex2a_exit);
+#endif
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_cex2a.h linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_cex2a.h
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_cex2a.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_cex2a.h	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,126 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_cex2a.h
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@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 _ZCRYPT_CEX2A_H_
+#define _ZCRYPT_CEX2A_H_
+
+/**
+ * The type 50 message family is associated with a CEX2A card.
+ *
+ * The four members of the family are described below.
+ *
+ * Note that all unsigned char arrays are right-justified and left-padded
+ * with zeroes.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+struct type50_hdr {
+	unsigned char	reserved1;
+	unsigned char	msg_type_code;	/* 0x50 */
+	unsigned short	msg_len;
+	unsigned char	reserved2;
+	unsigned char	ignored;
+	unsigned short	reserved3;
+} __attribute__((packed));
+
+#define TYPE50_TYPE_CODE	0x50
+
+#define TYPE50_MEB1_FMT		0x0001
+#define TYPE50_MEB2_FMT		0x0002
+#define TYPE50_CRB1_FMT		0x0011
+#define TYPE50_CRB2_FMT		0x0012
+
+/* Mod-Exp, with a small modulus */
+struct type50_meb1_msg {
+	struct type50_hdr header;
+	unsigned short	keyblock_type;	/* 0x0001 */
+	unsigned char	reserved[6];
+	unsigned char	exponent[128];
+	unsigned char	modulus[128];
+	unsigned char	message[128];
+} __attribute__((packed));
+
+/* Mod-Exp, with a large modulus */
+struct type50_meb2_msg {
+	struct type50_hdr header;
+	unsigned short	keyblock_type;	/* 0x0002 */
+	unsigned char	reserved[6];
+	unsigned char	exponent[256];
+	unsigned char	modulus[256];
+	unsigned char	message[256];
+} __attribute__((packed));
+
+/* CRT, with a small modulus */
+struct type50_crb1_msg {
+	struct type50_hdr header;
+	unsigned short	keyblock_type;	/* 0x0011 */
+	unsigned char	reserved[6];
+	unsigned char	p[64];
+	unsigned char	q[64];
+	unsigned char	dp[64];
+	unsigned char	dq[64];
+	unsigned char	u[64];
+	unsigned char	message[128];
+} __attribute__((packed));
+
+/* CRT, with a large modulus */
+struct type50_crb2_msg {
+	struct type50_hdr header;
+	unsigned short	keyblock_type;	/* 0x0012 */
+	unsigned char	reserved[6];
+	unsigned char	p[128];
+	unsigned char	q[128];
+	unsigned char	dp[128];
+	unsigned char	dq[128];
+	unsigned char	u[128];
+	unsigned char	message[256];
+} __attribute__((packed));
+
+/**
+ * The type 80 response family is associated with a CEX2A card.
+ *
+ * Note that all unsigned char arrays are right-justified and left-padded
+ * with zeroes.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+
+#define TYPE80_RSP_CODE 0x80
+
+struct type80_hdr {
+	unsigned char	reserved1;
+	unsigned char	type;		/* 0x80 */
+	unsigned short	len;
+	unsigned char	code;		/* 0x00 */
+	unsigned char	reserved2[3];
+	unsigned char	reserved3[8];
+} __attribute__((packed));
+
+int zcrypt_cex2a_init(void);
+void zcrypt_cex2a_exit(void);
+
+#endif /* _ZCRYPT_CEX2A_H_ */
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_error.h linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_error.h
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_error.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_error.h	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,133 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_error.h
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@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 _ZCRYPT_ERROR_H_
+#define _ZCRYPT_ERROR_H_
+
+#include "zcrypt_api.h"
+
+/**
+ * Reply Messages
+ *
+ * Error reply messages are of two types:
+ *    82:  Error (see below)
+ *    88:  Error (see below)
+ * Both type 82 and type 88 have the same structure in the header.
+ *
+ * Request reply messages are of three known types:
+ *    80:  Reply from a Type 50 Request (see CEX2A-RELATED STRUCTS)
+ *    84:  Reply from a Type 4 Request (see PCICA-RELATED STRUCTS)
+ *    86:  Reply from a Type 6 Request (see PCICC/PCIXCC/CEX2C-RELATED STRUCTS)
+ *
+ */
+struct error_hdr {
+	unsigned char reserved1;	/* 0x00			*/
+	unsigned char type;		/* 0x82 or 0x88		*/
+	unsigned char reserved2[2];	/* 0x0000		*/
+	unsigned char reply_code;	/* reply code		*/
+	unsigned char reserved3[3];	/* 0x000000		*/
+};
+
+#define TYPE82_RSP_CODE 0x82
+#define TYPE88_RSP_CODE 0x88
+
+#define REP82_ERROR_MACHINE_FAILURE  0x10
+#define REP82_ERROR_PREEMPT_FAILURE  0x12
+#define REP82_ERROR_CHECKPT_FAILURE  0x14
+#define REP82_ERROR_MESSAGE_TYPE     0x20
+#define REP82_ERROR_INVALID_COMM_CD  0x21	/* Type 84	*/
+#define REP82_ERROR_INVALID_MSG_LEN  0x23
+#define REP82_ERROR_RESERVD_FIELD    0x24	/* was 0x50	*/
+#define REP82_ERROR_FORMAT_FIELD     0x29
+#define REP82_ERROR_INVALID_COMMAND  0x30
+#define REP82_ERROR_MALFORMED_MSG    0x40
+#define REP82_ERROR_RESERVED_FIELDO  0x50	/* old value	*/
+#define REP82_ERROR_WORD_ALIGNMENT   0x60
+#define REP82_ERROR_MESSAGE_LENGTH   0x80
+#define REP82_ERROR_OPERAND_INVALID  0x82
+#define REP82_ERROR_OPERAND_SIZE     0x84
+#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
+#define REP82_ERROR_RESERVED_FIELD   0x88
+#define REP82_ERROR_TRANSPORT_FAIL   0x90
+#define REP82_ERROR_PACKET_TRUNCATED 0xA0
+#define REP82_ERROR_ZERO_BUFFER_LEN  0xB0
+
+#define REP88_ERROR_MODULE_FAILURE   0x10
+
+#define REP88_ERROR_MESSAGE_TYPE     0x20
+#define REP88_ERROR_MESSAGE_MALFORMD 0x22
+#define REP88_ERROR_MESSAGE_LENGTH   0x23
+#define REP88_ERROR_RESERVED_FIELD   0x24
+#define REP88_ERROR_KEY_TYPE	     0x34
+#define REP88_ERROR_INVALID_KEY      0x82	/* CEX2A	*/
+#define REP88_ERROR_OPERAND	     0x84	/* CEX2A	*/
+#define REP88_ERROR_OPERAND_EVEN_MOD 0x85	/* CEX2A	*/
+
+static inline int convert_error(struct zcrypt_device *zdev,
+				struct ap_message *reply)
+{
+	struct error_hdr *ehdr = reply->message;
+
+	PRINTK("Hardware error : Type %02x Message Header: %08x%08x\n",
+	       ehdr->type, *(unsigned int *) reply->message,
+	       *(unsigned int *) (reply->message + 4));
+
+	switch (ehdr->reply_code) {
+	case REP82_ERROR_OPERAND_INVALID:
+	case REP82_ERROR_OPERAND_SIZE:
+	case REP82_ERROR_EVEN_MOD_IN_OPND:
+	case REP88_ERROR_MESSAGE_MALFORMD:
+	//   REP88_ERROR_INVALID_KEY		// '82' CEX2A
+	//   REP88_ERROR_OPERAND		// '84' CEX2A
+	//   REP88_ERROR_OPERAND_EVEN_MOD	// '85' CEX2A
+		/* Invalid input data. */
+		return -EINVAL;
+	case REP82_ERROR_MESSAGE_TYPE:
+	//   REP88_ERROR_MESSAGE_TYPE		// '20' CEX2A
+		/**
+		 * To sent a message of the wrong type is a bug in the
+		 * device driver. Warn about it, disable the device
+		 * and then repeat the request.
+		 */
+		WARN_ON(1);
+		zdev->online = 0;
+		return -EAGAIN;
+	case REP82_ERROR_TRANSPORT_FAIL:
+	case REP82_ERROR_MACHINE_FAILURE:
+	//   REP88_ERROR_MODULE_FAILURE		// '10' CEX2A
+		/* If a card fails disable it and repeat the request. */
+		zdev->online = 0;
+		return -EAGAIN;
+	default:
+		PRINTKW("unknown type %02x reply code = %d\n",
+			ehdr->type, ehdr->reply_code);
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+}
+
+#endif /* _ZCRYPT_ERROR_H_ */
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_mono.c linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_mono.c
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_mono.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_mono.c	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,100 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_mono.c
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/compat.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_pcica.h"
+#include "zcrypt_pcicc.h"
+#include "zcrypt_pcixcc.h"
+#include "zcrypt_cex2a.h"
+
+/**
+ * The module initialization code.
+ */
+int __init zcrypt_init(void)
+{
+	int rc;
+
+	rc = ap_module_init();
+	if (rc)
+		goto out;
+	rc = zcrypt_api_init();
+	if (rc)
+		goto out_ap;
+	rc = zcrypt_pcica_init();
+	if (rc)
+		goto out_api;
+	rc = zcrypt_pcicc_init();
+	if (rc)
+		goto out_pcica;
+	rc = zcrypt_pcixcc_init();
+	if (rc)
+		goto out_pcicc;
+	rc = zcrypt_cex2a_init();
+	if (rc)
+		goto out_pcixcc;
+	return 0;
+
+out_pcixcc:
+	zcrypt_pcixcc_exit();
+out_pcicc:
+	zcrypt_pcicc_exit();
+out_pcica:
+	zcrypt_pcica_exit();
+out_api:
+	zcrypt_api_exit();
+out_ap:
+	ap_module_exit();
+out:
+	return rc;
+}
+
+/**
+ * The module termination code.
+ */
+void __exit zcrypt_exit(void)
+{
+	zcrypt_cex2a_exit();
+	zcrypt_pcixcc_exit();
+	zcrypt_pcicc_exit();
+	zcrypt_pcica_exit();
+	zcrypt_api_exit();
+	ap_module_exit();
+}
+
+module_init(zcrypt_init);
+module_exit(zcrypt_exit);
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcica.c linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcica.c
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcica.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcica.c	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,418 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_pcica.c
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *				  Ralph Wuerthner <rwuerthn@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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_error.h"
+#include "zcrypt_pcica.h"
+
+#define PCICA_MIN_MOD_SIZE	  1	/*    8 bits	*/
+#define PCICA_MAX_MOD_SIZE	256	/* 2048 bits	*/
+
+#define PCICA_SPEED_RATING	2800
+
+#define PCICA_MAX_MESSAGE_SIZE	0x3a0	/* sizeof(struct type4_lcr)	     */
+#define PCICA_MAX_RESPONSE_SIZE 0x110	/* max outputdatalength + type80_hdr */
+
+#define PCICA_CLEANUP_TIME	(15*HZ)
+
+static struct ap_device_id zcrypt_pcica_ids[] = {
+	{ AP_DEVICE(AP_DEVICE_TYPE_PCICA) },
+	{ /* end of list */ },
+};
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+MODULE_DEVICE_TABLE(ap, zcrypt_pcica_ids);
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("PCICA Cryptographic Coprocessor device driver, "
+		   "Copyright 2001, 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+#endif
+
+static int zcrypt_pcica_probe(struct ap_device *ap_dev);
+static void zcrypt_pcica_remove(struct ap_device *ap_dev);
+static void zcrypt_pcica_receive(struct ap_device *, struct ap_message *,
+				 struct ap_message *);
+
+static struct ap_driver zcrypt_pcica_driver = {
+	.probe = zcrypt_pcica_probe,
+	.remove = zcrypt_pcica_remove,
+	.receive = zcrypt_pcica_receive,
+	.ids = zcrypt_pcica_ids,
+};
+
+/**
+ * Convert a ICAMEX message to a type4 MEX message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @mex: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICAMEX_msg_to_type4MEX_msg(struct zcrypt_device *zdev,
+				      struct ap_message *ap_msg,
+				      struct ica_rsa_modexpo *mex)
+{
+	unsigned char *modulus, *exponent, *message;
+	int mod_len;
+
+	mod_len = mex->inputdatalength;
+
+	if (mod_len <= 128) {
+		struct type4_sme *sme = ap_msg->message;
+		memset(sme, 0, sizeof(*sme));
+		ap_msg->length = sizeof(*sme);
+		sme->header.msg_fmt = TYPE4_SME_FMT;
+		sme->header.msg_len = sizeof(*sme);
+		sme->header.msg_type_code = TYPE4_TYPE_CODE;
+		sme->header.request_code = TYPE4_REQU_CODE;
+		modulus = sme->modulus + sizeof(sme->modulus) - mod_len;
+		exponent = sme->exponent + sizeof(sme->exponent) - mod_len;
+		message = sme->message + sizeof(sme->message) - mod_len;
+	} else {
+		struct type4_lme *lme = ap_msg->message;
+		memset(lme, 0, sizeof(*lme));
+		ap_msg->length = sizeof(*lme);
+		lme->header.msg_fmt = TYPE4_LME_FMT;
+		lme->header.msg_len = sizeof(*lme);
+		lme->header.msg_type_code = TYPE4_TYPE_CODE;
+		lme->header.request_code = TYPE4_REQU_CODE;
+		modulus = lme->modulus + sizeof(lme->modulus) - mod_len;
+		exponent = lme->exponent + sizeof(lme->exponent) - mod_len;
+		message = lme->message + sizeof(lme->message) - mod_len;
+	}
+
+	if (copy_from_user(modulus, mex->n_modulus, mod_len) ||
+	    copy_from_user(exponent, mex->b_key, mod_len) ||
+	    copy_from_user(message, mex->inputdata, mod_len))
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ * Convert a ICACRT message to a type4 CRT message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @crt: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICACRT_msg_to_type4CRT_msg(struct zcrypt_device *zdev,
+				      struct ap_message *ap_msg,
+				      struct ica_rsa_modexpo_crt *crt)
+{
+	unsigned char *p, *q, *dp, *dq, *u, *inp;
+	int mod_len, short_len, long_len;
+
+	mod_len = crt->inputdatalength;
+	short_len = mod_len / 2;
+	long_len = mod_len / 2 + 8;
+
+	if (mod_len <= 128) {
+		struct type4_scr *scr = ap_msg->message;
+		memset(scr, 0, sizeof(*scr));
+		ap_msg->length = sizeof(*scr);
+		scr->header.msg_type_code = TYPE4_TYPE_CODE;
+		scr->header.request_code = TYPE4_REQU_CODE;
+		scr->header.msg_fmt = TYPE4_SCR_FMT;
+		scr->header.msg_len = sizeof(*scr);
+		p = scr->p + sizeof(scr->p) - long_len;
+		q = scr->q + sizeof(scr->q) - short_len;
+		dp = scr->dp + sizeof(scr->dp) - long_len;
+		dq = scr->dq + sizeof(scr->dq) - short_len;
+		u = scr->u + sizeof(scr->u) - long_len;
+		inp = scr->message + sizeof(scr->message) - mod_len;
+	} else {
+		struct type4_lcr *lcr = ap_msg->message;
+		memset(lcr, 0, sizeof(*lcr));
+		ap_msg->length = sizeof(*lcr);
+		lcr->header.msg_type_code = TYPE4_TYPE_CODE;
+		lcr->header.request_code = TYPE4_REQU_CODE;
+		lcr->header.msg_fmt = TYPE4_LCR_FMT;
+		lcr->header.msg_len = sizeof(*lcr);
+		p = lcr->p + sizeof(lcr->p) - long_len;
+		q = lcr->q + sizeof(lcr->q) - short_len;
+		dp = lcr->dp + sizeof(lcr->dp) - long_len;
+		dq = lcr->dq + sizeof(lcr->dq) - short_len;
+		u = lcr->u + sizeof(lcr->u) - long_len;
+		inp = lcr->message + sizeof(lcr->message) - mod_len;
+	}
+
+	if (copy_from_user(p, crt->np_prime, long_len) ||
+	    copy_from_user(q, crt->nq_prime, short_len) ||
+	    copy_from_user(dp, crt->bp_key, long_len) ||
+	    copy_from_user(dq, crt->bq_key, short_len) ||
+	    copy_from_user(u, crt->u_mult_inv, long_len) ||
+	    copy_from_user(inp, crt->inputdata, mod_len))
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ * Copy results from a type 84 reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @data: pointer to user output data
+ * @length: size of user output data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static inline int convert_type84(struct zcrypt_device *zdev,
+				 struct ap_message *reply,
+				 char __user *outputdata,
+				 unsigned int outputdatalength)
+{
+	struct type84_hdr *t84h = reply->message;
+	char *data;
+
+	if (t84h->len < sizeof(*t84h) + outputdatalength) {
+		/* The result is too short, the PCICA card may not do that.. */
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+	BUG_ON(t84h->len > PCICA_MAX_RESPONSE_SIZE);
+	data = reply->message + t84h->len - outputdatalength;
+	if (copy_to_user(outputdata, data, outputdatalength))
+		return -EFAULT;
+	return 0;
+}
+
+static int convert_response(struct zcrypt_device *zdev,
+			    struct ap_message *reply,
+			    char __user *outputdata,
+			    unsigned int outputdatalength)
+{
+	/* Response type byte is the second byte in the response. */
+	switch (((unsigned char *) reply->message)[1]) {
+	case TYPE82_RSP_CODE:
+	case TYPE88_RSP_CODE:
+		return convert_error(zdev, reply);
+	case TYPE84_RSP_CODE:
+		return convert_type84(zdev, reply,
+				      outputdata, outputdatalength);
+	default: /* Unknown response type, this should NEVER EVER happen */
+		PRINTK("Unrecognized Message Header: %08x%08x\n",
+		       *(unsigned int *) reply->message,
+		       *(unsigned int *) (reply->message+4));
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+}
+
+/**
+ * This function is called from the AP bus code after a crypto request
+ * "msg" has finished with the reply message "reply".
+ * It is called from tasklet context.
+ * @ap_dev: pointer to the AP device
+ * @msg: pointer to the AP message
+ * @reply: pointer to the AP reply message
+ */
+static void zcrypt_pcica_receive(struct ap_device *ap_dev,
+				 struct ap_message *msg,
+				 struct ap_message *reply)
+{
+	static struct error_hdr error_reply = {
+		.type = TYPE82_RSP_CODE,
+		.reply_code = REP82_ERROR_MACHINE_FAILURE,
+	};
+	struct type84_hdr *t84h = reply->message;
+	int length;
+
+	/* Copy the reply message to the request message buffer. */
+	if (IS_ERR(reply))
+		memcpy(msg->message, &error_reply, sizeof(error_reply));
+	else if (t84h->code == TYPE84_RSP_CODE) {
+		length = min(PCICA_MAX_RESPONSE_SIZE, (int) t84h->len);
+		memcpy(msg->message, reply->message, length);
+	} else
+		memcpy(msg->message, reply->message, sizeof error_reply);
+	complete((struct completion *) msg->private);
+}
+
+static atomic_t zcrypt_step = ATOMIC_INIT(0);
+
+/**
+ * The request distributor calls this function if it picked the PCICA
+ * device to handle a modexpo request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  PCICA device to the request distributor
+ * @mex: pointer to the modexpo request buffer
+ */
+static long zcrypt_pcica_modexpo(struct zcrypt_device *zdev,
+				 struct ica_rsa_modexpo *mex)
+{
+	struct ap_message ap_msg;
+	struct completion work;
+	int rc;
+
+	ap_msg.message = (void *) kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &work;
+	rc = ICAMEX_msg_to_type4MEX_msg(zdev, &ap_msg, mex);
+	if (rc)
+		goto out_free;
+	init_completion(&work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible_timeout(
+				&work, PCICA_CLEANUP_TIME);
+	if (rc > 0)
+		rc = convert_response(zdev, &ap_msg, mex->outputdata,
+				      mex->outputdatalength);
+	else {
+		/* Signal pending or message timed out. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+		if (rc == 0)
+			/* Message timed out. */
+			rc = -ETIME;
+	}
+out_free:
+	kfree(ap_msg.message);
+	return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the PCICA
+ * device to handle a modexpo_crt request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  PCICA device to the request distributor
+ * @crt: pointer to the modexpoc_crt request buffer
+ */
+static long zcrypt_pcica_modexpo_crt(struct zcrypt_device *zdev,
+				     struct ica_rsa_modexpo_crt *crt)
+{
+	struct ap_message ap_msg;
+	struct completion work;
+	int rc;
+
+	ap_msg.message = (void *) kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &work;
+	rc = ICACRT_msg_to_type4CRT_msg(zdev, &ap_msg, crt);
+	if (rc)
+		goto out_free;
+	init_completion(&work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible_timeout(
+				&work, PCICA_CLEANUP_TIME);
+	if (rc > 0)
+		rc = convert_response(zdev, &ap_msg, crt->outputdata,
+				      crt->outputdatalength);
+	else {
+		/* Signal pending or message timed out. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+		if (rc == 0)
+			/* Message timed out. */
+			rc = -ETIME;
+	}
+out_free:
+	kfree(ap_msg.message);
+	return rc;
+}
+
+/**
+ * The crypto operations for a PCICA card.
+ */
+static struct zcrypt_ops zcrypt_pcica_ops = {
+	.rsa_modexpo = zcrypt_pcica_modexpo,
+	.rsa_modexpo_crt = zcrypt_pcica_modexpo_crt,
+};
+
+/**
+ * Probe function for PCICA cards. It always accepts the AP device
+ * since the bus_match already checked the hardware type.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_pcica_probe(struct ap_device *ap_dev)
+{
+	struct zcrypt_device *zdev;
+	int rc;
+
+	zdev = zcrypt_device_alloc(PCICA_MAX_RESPONSE_SIZE);
+	if (!zdev)
+		return -ENOMEM;
+	zdev->ap_dev = ap_dev;
+	zdev->ops = &zcrypt_pcica_ops;
+	zdev->online = 1;
+	zdev->user_space_type = ZCRYPT_PCICA;
+	zdev->type_string = "PCICA";
+	zdev->min_mod_size = PCICA_MIN_MOD_SIZE;
+	zdev->max_mod_size = PCICA_MAX_MOD_SIZE;
+	zdev->speed_rating = PCICA_SPEED_RATING;
+	ap_dev->reply = &zdev->reply;
+	ap_dev->private = zdev;
+	rc = zcrypt_device_register(zdev);
+	if (rc)
+		goto out_free;
+	return 0;
+
+out_free:
+	ap_dev->private = NULL;
+	zcrypt_device_free(zdev);
+	return rc;
+}
+
+/**
+ * This is called to remove the extended PCICA driver information
+ * if an AP device is removed.
+ */
+static void zcrypt_pcica_remove(struct ap_device *ap_dev)
+{
+	struct zcrypt_device *zdev = ap_dev->private;
+
+	zcrypt_device_unregister(zdev);
+}
+
+int __init zcrypt_pcica_init(void)
+{
+	return ap_driver_register(&zcrypt_pcica_driver, THIS_MODULE, "pcica");
+}
+
+void zcrypt_pcica_exit(void)
+{
+	ap_driver_unregister(&zcrypt_pcica_driver);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(zcrypt_pcica_init);
+module_exit(zcrypt_pcica_exit);
+#endif
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcica.h linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcica.h
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcica.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcica.h	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,117 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_pcica.h
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@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 _ZCRYPT_PCICA_H_
+#define _ZCRYPT_PCICA_H_
+
+/**
+ * The type 4 message family is associated with a PCICA card.
+ *
+ * The four members of the family are described below.
+ *
+ * Note that all unsigned char arrays are right-justified and left-padded
+ * with zeroes.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+struct type4_hdr {
+	unsigned char  reserved1;
+	unsigned char  msg_type_code;	/* 0x04 */
+	unsigned short msg_len;
+	unsigned char  request_code;	/* 0x40 */
+	unsigned char  msg_fmt;
+	unsigned short reserved2;
+} __attribute__((packed));
+
+#define TYPE4_TYPE_CODE 0x04
+#define TYPE4_REQU_CODE 0x40
+
+#define TYPE4_SME_FMT 0x00
+#define TYPE4_LME_FMT 0x10
+#define TYPE4_SCR_FMT 0x40
+#define TYPE4_LCR_FMT 0x50
+
+/* Mod-Exp, with a small modulus */
+struct type4_sme {
+	struct type4_hdr header;
+	unsigned char	 message[128];
+	unsigned char	 exponent[128];
+	unsigned char	 modulus[128];
+} __attribute__((packed));
+
+/* Mod-Exp, with a large modulus */
+struct type4_lme {
+	struct type4_hdr header;
+	unsigned char	 message[256];
+	unsigned char	 exponent[256];
+	unsigned char	 modulus[256];
+} __attribute__((packed));
+
+/* CRT, with a small modulus */
+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];
+} __attribute__((packed));
+
+/* CRT, with a large modulus */
+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];
+} __attribute__((packed));
+
+/**
+ * The type 84 response family is associated with a PCICA card.
+ *
+ * Note that all unsigned char arrays are right-justified and left-padded
+ * with zeroes.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+
+struct type84_hdr {
+	unsigned char  reserved1;
+	unsigned char  code;
+	unsigned short len;
+	unsigned char  reserved2[4];
+} __attribute__((packed));
+
+#define TYPE84_RSP_CODE 0x84
+
+int zcrypt_pcica_init(void);
+void zcrypt_pcica_exit(void);
+
+#endif /* _ZCRYPT_PCICA_H_ */
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcicc.c linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcicc.c
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcicc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcicc.c	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,630 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_pcicc.c
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *				  Ralph Wuerthner <rwuerthn@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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_error.h"
+#include "zcrypt_pcicc.h"
+#include "zcrypt_cca_key.h"
+
+#define PCICC_MIN_MOD_SIZE	 64	/*  512 bits */
+#define PCICC_MAX_MOD_SIZE_OLD	128	/* 1024 bits */
+#define PCICC_MAX_MOD_SIZE	256	/* 2048 bits */
+
+/**
+ * PCICC cards need a speed rating of 0. This keeps them at the end of
+ * the zcrypt device list (see zcrypt_api.c). PCICC cards are only
+ * used if no other cards are present because they are slow and can only
+ * cope with PKCS12 padded requests. The logic is queer. PKCS11 padded
+ * requests are rejected. The modexpo function encrypts PKCS12 padded data
+ * and decrypts any non-PKCS12 padded data (except PKCS11) in the assumption
+ * that it's encrypted PKCS12 data. The modexpo_crt function always decrypts
+ * the data in the assumption that its PKCS12 encrypted data.
+ */
+#define PCICC_SPEED_RATING	0
+
+#define PCICC_MAX_MESSAGE_SIZE 0x710	/* max size type6 v1 crt message */
+#define PCICC_MAX_RESPONSE_SIZE 0x710	/* max size type86 v1 reply	 */
+
+#define PCICC_CLEANUP_TIME	(15*HZ)
+
+static struct ap_device_id zcrypt_pcicc_ids[] = {
+	{ AP_DEVICE(AP_DEVICE_TYPE_PCICC) },
+	{ /* end of list */ },
+};
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+MODULE_DEVICE_TABLE(ap, zcrypt_pcicc_ids);
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("PCICC Cryptographic Coprocessor device driver, "
+		   "Copyright 2001, 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+#endif
+
+static int zcrypt_pcicc_probe(struct ap_device *ap_dev);
+static void zcrypt_pcicc_remove(struct ap_device *ap_dev);
+static void zcrypt_pcicc_receive(struct ap_device *, struct ap_message *,
+				 struct ap_message *);
+
+static struct ap_driver zcrypt_pcicc_driver = {
+	.probe = zcrypt_pcicc_probe,
+	.remove = zcrypt_pcicc_remove,
+	.receive = zcrypt_pcicc_receive,
+	.ids = zcrypt_pcicc_ids,
+};
+
+/**
+ * The following is used to initialize the CPRB passed to the PCICC card
+ * in a type6 message. The 3 fields that must be filled in at execution
+ * time are  req_parml, rpl_parml and usage_domain. Note that all three
+ * fields are *little*-endian. Actually, everything about this interface
+ * is ascii/little-endian, since the device has 'Intel inside'.
+ *
+ * The CPRB is followed immediately by the parm block.
+ * The parm block contains:
+ * - function code ('PD' 0x5044 or 'PK' 0x504B)
+ * - rule block (0x0A00 'PKCS-1.2' or 0x0A00 'ZERO-PAD')
+ * - VUD block
+ */
+static struct CPRB static_cprb = {
+	.cprb_len	= __constant_cpu_to_le16(0x0070),
+	.cprb_ver_id	=  0x41,
+	.func_id	= {0x54,0x32},
+	.checkpoint_flag=  0x01,
+	.svr_namel	= __constant_cpu_to_le16(0x0008),
+	.svr_name	= {'I','C','S','F',' ',' ',' ',' '}
+};
+
+/**
+ * Check the message for PKCS11 padding.
+ */
+static inline int is_PKCS11_padded(unsigned char *buffer, int length)
+{
+	int i;
+	if ((buffer[0] != 0x00) || (buffer[1] != 0x01))
+		return 0;
+	for (i = 2; i < length; i++)
+		if (buffer[i] != 0xFF)
+			break;
+	if (i < 10 || i == length)
+		return 0;
+	if (buffer[i] != 0x00)
+		return 0;
+	return 1;
+}
+
+/**
+ * Check the message for PKCS12 padding.
+ */
+static inline int is_PKCS12_padded(unsigned char *buffer, int length)
+{
+	int i;
+	if ((buffer[0] != 0x00) || (buffer[1] != 0x02))
+		return 0;
+	for (i = 2; i < length; i++)
+		if (buffer[i] == 0x00)
+			break;
+	if ((i < 10) || (i == length))
+		return 0;
+	if (buffer[i] != 0x00)
+		return 0;
+	return 1;
+}
+
+/**
+ * Convert a ICAMEX message to a type6 MEX message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @mex: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICAMEX_msg_to_type6MEX_msg(struct zcrypt_device *zdev,
+				      struct ap_message *ap_msg,
+				      struct ica_rsa_modexpo *mex)
+{
+	static struct type6_hdr static_type6_hdr = {
+		.type		=  0x06,
+		.offset1	=  0x00000058,
+		.agent_id	= {0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50,
+				   0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01},
+		.function_code	= {'P','K'},
+	};
+	static struct function_and_rules_block static_pke_function_and_rules ={
+		.function_code	= {'P','K'},
+		.ulen		= __constant_cpu_to_le16(10),
+		.only_rule	= {'P','K','C','S','-','1','.','2'}
+	};
+	struct {
+		struct type6_hdr hdr;
+		struct CPRB cprb;
+		struct function_and_rules_block fr;
+		unsigned short length;
+		char text[0];
+	} __attribute__((packed)) *msg = ap_msg->message;
+	int vud_len, pad_len, size;
+
+	/* VUD.ciphertext */
+	if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
+		return -EFAULT;
+
+	if (is_PKCS11_padded(msg->text, mex->inputdatalength))
+		return -EINVAL;
+
+	/* static message header and f&r */
+	msg->hdr = static_type6_hdr;
+	msg->fr = static_pke_function_and_rules;
+
+	if (is_PKCS12_padded(msg->text, mex->inputdatalength)) {
+		/* strip the padding and adjust the data length */
+		pad_len = strnlen(msg->text + 2, mex->inputdatalength - 2) + 3;
+		if (pad_len <= 9 || pad_len >= mex->inputdatalength)
+			return -ENODEV;
+		vud_len = mex->inputdatalength - pad_len;
+		memmove(msg->text, msg->text + pad_len, vud_len);
+		msg->length = cpu_to_le16(vud_len + 2);
+
+		/* Set up key after the variable length text. */
+		size = zcrypt_type6_mex_key_en(mex, msg->text + vud_len, 0);
+		if (size < 0)
+			return size;
+		size += sizeof(*msg) + vud_len;	/* total size of msg */
+	} else {
+		vud_len = mex->inputdatalength;
+		msg->length = cpu_to_le16(2 + vud_len);
+
+		msg->hdr.function_code[1] = 'D';
+		msg->fr.function_code[1] = 'D';
+
+		/* Set up key after the variable length text. */
+		size = zcrypt_type6_mex_key_de(mex, msg->text + vud_len, 0);
+		if (size < 0)
+			return size;
+		size += sizeof(*msg) + vud_len;	/* total size of msg */
+	}
+
+	/* message header, cprb and f&r */
+	msg->hdr.ToCardLen1 = (size - sizeof(msg->hdr) + 3) & -4;
+	msg->hdr.FromCardLen1 = PCICC_MAX_RESPONSE_SIZE - sizeof(msg->hdr);
+
+	msg->cprb = static_cprb;
+	msg->cprb.usage_domain[0]= AP_QID_QUEUE(zdev->ap_dev->qid);
+	msg->cprb.req_parml = cpu_to_le16(size - sizeof(msg->hdr) -
+					   sizeof(msg->cprb));
+	msg->cprb.rpl_parml = cpu_to_le16(msg->hdr.FromCardLen1);
+
+	ap_msg->length = (size + 3) & -4;
+	return 0;
+}
+
+/**
+ * Convert a ICACRT message to a type6 CRT message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @crt: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICACRT_msg_to_type6CRT_msg(struct zcrypt_device *zdev,
+				      struct ap_message *ap_msg,
+				      struct ica_rsa_modexpo_crt *crt)
+{
+	static struct type6_hdr static_type6_hdr = {
+		.type		=  0x06,
+		.offset1	=  0x00000058,
+		.agent_id	= {0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50,
+				   0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01},
+		.function_code	= {'P','D'},
+	};
+	static struct function_and_rules_block static_pkd_function_and_rules ={
+		.function_code	= {'P','D'},
+		.ulen		= __constant_cpu_to_le16(10),
+		.only_rule	= {'P','K','C','S','-','1','.','2'}
+	};
+	struct {
+		struct type6_hdr hdr;
+		struct CPRB cprb;
+		struct function_and_rules_block fr;
+		unsigned short length;
+		char text[0];
+	} __attribute__((packed)) *msg = ap_msg->message;
+	int size;
+
+	/* VUD.ciphertext */
+	msg->length = cpu_to_le16(2 + crt->inputdatalength);
+	if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
+		return -EFAULT;
+
+	if (is_PKCS11_padded(msg->text, crt->inputdatalength))
+		return -EINVAL;
+
+	/* Set up key after the variable length text. */
+	size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 0);
+	if (size < 0)
+		return size;
+	size += sizeof(*msg) + crt->inputdatalength;	/* total size of msg */
+
+	/* message header, cprb and f&r */
+	msg->hdr = static_type6_hdr;
+	msg->hdr.ToCardLen1 = (size -  sizeof(msg->hdr) + 3) & -4;
+	msg->hdr.FromCardLen1 = PCICC_MAX_RESPONSE_SIZE - sizeof(msg->hdr);
+
+	msg->cprb = static_cprb;
+	msg->cprb.usage_domain[0] = AP_QID_QUEUE(zdev->ap_dev->qid);
+	msg->cprb.req_parml = msg->cprb.rpl_parml =
+		cpu_to_le16(size - sizeof(msg->hdr) - sizeof(msg->cprb));
+
+	msg->fr = static_pkd_function_and_rules;
+
+	ap_msg->length = (size + 3) & -4;
+	return 0;
+}
+
+/**
+ * Copy results from a type 86 reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @data: pointer to user output data
+ * @length: size of user output data
+ *
+ * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
+ */
+struct type86_reply {
+	struct type86_hdr hdr;
+	struct type86_fmt2_ext fmt2;
+	struct CPRB cprb;
+	unsigned char pad[4];	/* 4 byte function code/rules block ? */
+	unsigned short length;
+	char text[0];
+} __attribute__((packed));
+
+static int convert_type86(struct zcrypt_device *zdev,
+			  struct ap_message *reply,
+			  char __user *outputdata,
+			  unsigned int outputdatalength)
+{
+	static unsigned char static_pad[] = {
+		0x00,0x02,
+		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
+	};
+	struct type86_reply *msg = reply->message;
+	unsigned short service_rc, service_rs;
+	unsigned int reply_len, pad_len;
+	char *data;
+
+	service_rc = le16_to_cpu(msg->cprb.ccp_rtcode);
+	if (unlikely(service_rc != 0)) {
+		service_rs = le16_to_cpu(msg->cprb.ccp_rscode);
+		if (service_rc == 8 && service_rs == 66) {
+			PDEBUG("Bad block format on PCICC\n");
+			return -EINVAL;
+		}
+		if (service_rc == 8 && service_rs == 65) {
+			PDEBUG("Probably an even modulus on PCICC\n");
+			return -EINVAL;
+		}
+		if (service_rc == 8 && service_rs == 770) {
+			PDEBUG("Invalid key length on PCICC\n");
+			zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD;
+			return -EAGAIN;
+		}
+		if (service_rc == 8 && service_rs == 783) {
+			PDEBUG("Extended bitlengths not enabled on PCICC\n");
+			zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD;
+			return -EAGAIN;
+		}
+		PRINTK("Unknown service rc/rs (PCICC): %d/%d\n",
+		       service_rc, service_rs);
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+	data = msg->text;
+	reply_len = le16_to_cpu(msg->length) - 2;
+	if (reply_len > outputdatalength)
+		return -EINVAL;
+	/**
+	 * For all encipher requests, the length of the ciphertext (reply_len)
+	 * will always equal the modulus length. For MEX decipher requests
+	 * the output needs to get padded. Minimum pad size is 10.
+	 *
+	 * Currently, the cases where padding will be added is for:
+	 * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
+	 *   ZERO-PAD and CRT is only supported for PKD requests)
+	 * - PCICC, always
+	 */
+	pad_len = outputdatalength - reply_len;
+	if (pad_len > 0) {
+		if (pad_len < 10)
+			return -EINVAL;
+		/* 'restore' padding left in the PCICC/PCIXCC card. */
+		if (copy_to_user(outputdata, static_pad, pad_len - 1))
+			return -EFAULT;
+		if (put_user(0, outputdata + pad_len - 1))
+			return -EFAULT;
+	}
+	/* Copy the crypto response to user space. */
+	if (copy_to_user(outputdata + pad_len, data, reply_len))
+		return -EFAULT;
+	return 0;
+}
+
+static int convert_response(struct zcrypt_device *zdev,
+			    struct ap_message *reply,
+			    char __user *outputdata,
+			    unsigned int outputdatalength)
+{
+	struct type86_reply *msg = reply->message;
+
+	/* Response type byte is the second byte in the response. */
+	switch (msg->hdr.type) {
+	case TYPE82_RSP_CODE:
+	case TYPE88_RSP_CODE:
+		return convert_error(zdev, reply);
+	case TYPE86_RSP_CODE:
+		if (msg->hdr.reply_code)
+			return convert_error(zdev, reply);
+		if (msg->cprb.cprb_ver_id == 0x01)
+			return convert_type86(zdev, reply,
+					      outputdata, outputdatalength);
+		/* no break, incorrect cprb version is an unknown response */
+	default: /* Unknown response type, this should NEVER EVER happen */
+		PRINTK("Unrecognized Message Header: %08x%08x\n",
+		       *(unsigned int *) reply->message,
+		       *(unsigned int *) (reply->message+4));
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+}
+
+/**
+ * This function is called from the AP bus code after a crypto request
+ * "msg" has finished with the reply message "reply".
+ * It is called from tasklet context.
+ * @ap_dev: pointer to the AP device
+ * @msg: pointer to the AP message
+ * @reply: pointer to the AP reply message
+ */
+static void zcrypt_pcicc_receive(struct ap_device *ap_dev,
+				 struct ap_message *msg,
+				 struct ap_message *reply)
+{
+	static struct error_hdr error_reply = {
+		.type = TYPE82_RSP_CODE,
+		.reply_code = REP82_ERROR_MACHINE_FAILURE,
+	};
+	struct type86_reply *t86r = reply->message;
+	int length;
+
+	/* Copy the reply message to the request message buffer. */
+	if (IS_ERR(reply))
+		memcpy(msg->message, &error_reply, sizeof(error_reply));
+	else if (t86r->hdr.type == TYPE86_RSP_CODE &&
+		 t86r->cprb.cprb_ver_id == 0x01) {
+		length = sizeof(struct type86_reply) + t86r->length - 2;
+		length = min(PCICC_MAX_RESPONSE_SIZE, length);
+		memcpy(msg->message, reply->message, length);
+	} else
+		memcpy(msg->message, reply->message, sizeof error_reply);
+	complete((struct completion *) msg->private);
+}
+
+static atomic_t zcrypt_step = ATOMIC_INIT(0);
+
+/**
+ * The request distributor calls this function if it picked the PCICC
+ * device to handle a modexpo request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  PCICC device to the request distributor
+ * @mex: pointer to the modexpo request buffer
+ */
+static long zcrypt_pcicc_modexpo(struct zcrypt_device *zdev,
+				 struct ica_rsa_modexpo *mex)
+{
+	struct ap_message ap_msg;
+	struct completion work;
+	int rc;
+
+	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.length = PAGE_SIZE;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &work;
+	rc = ICAMEX_msg_to_type6MEX_msg(zdev, &ap_msg, mex);
+	if (rc)
+		goto out_free;
+	init_completion(&work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible_timeout(
+				&work, PCICC_CLEANUP_TIME);
+	if (rc > 0)
+		rc = convert_response(zdev, &ap_msg, mex->outputdata,
+				      mex->outputdatalength);
+	else {
+		/* Signal pending or message timed out. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+		if (rc == 0)
+			/* Message timed out. */
+			rc = -ETIME;
+	}
+out_free:
+	free_page((unsigned long) ap_msg.message);
+	return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the PCICC
+ * device to handle a modexpo_crt request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  PCICC device to the request distributor
+ * @crt: pointer to the modexpoc_crt request buffer
+ */
+static long zcrypt_pcicc_modexpo_crt(struct zcrypt_device *zdev,
+				     struct ica_rsa_modexpo_crt *crt)
+{
+	struct ap_message ap_msg;
+	struct completion work;
+	int rc;
+
+	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.length = PAGE_SIZE;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &work;
+	rc = ICACRT_msg_to_type6CRT_msg(zdev, &ap_msg, crt);
+	if (rc)
+		goto out_free;
+	init_completion(&work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible_timeout(
+				&work, PCICC_CLEANUP_TIME);
+	if (rc > 0)
+		rc = convert_response(zdev, &ap_msg, crt->outputdata,
+				      crt->outputdatalength);
+	else {
+		/* Signal pending or message timed out. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+		if (rc == 0)
+			/* Message timed out. */
+			rc = -ETIME;
+	}
+out_free:
+	free_page((unsigned long) ap_msg.message);
+	return rc;
+}
+
+/**
+ * The crypto operations for a PCICC card.
+ */
+static struct zcrypt_ops zcrypt_pcicc_ops = {
+	.rsa_modexpo = zcrypt_pcicc_modexpo,
+	.rsa_modexpo_crt = zcrypt_pcicc_modexpo_crt,
+};
+
+/**
+ * Probe function for PCICC cards. It always accepts the AP device
+ * since the bus_match already checked the hardware type.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_pcicc_probe(struct ap_device *ap_dev)
+{
+	struct zcrypt_device *zdev;
+	int rc;
+
+	zdev = zcrypt_device_alloc(PCICC_MAX_RESPONSE_SIZE);
+	if (!zdev)
+		return -ENOMEM;
+	zdev->ap_dev = ap_dev;
+	zdev->ops = &zcrypt_pcicc_ops;
+	zdev->online = 1;
+	zdev->user_space_type = ZCRYPT_PCICC;
+	zdev->type_string = "PCICC";
+	zdev->min_mod_size = PCICC_MIN_MOD_SIZE;
+	zdev->max_mod_size = PCICC_MAX_MOD_SIZE;
+	zdev->speed_rating = PCICC_SPEED_RATING;
+	ap_dev->reply = &zdev->reply;
+	ap_dev->private = zdev;
+	rc = zcrypt_device_register(zdev);
+	if (rc)
+		goto out_free;
+	return 0;
+
+ out_free:
+	ap_dev->private = NULL;
+	zcrypt_device_free(zdev);
+	return rc;
+}
+
+/**
+ * This is called to remove the extended PCICC driver information
+ * if an AP device is removed.
+ */
+static void zcrypt_pcicc_remove(struct ap_device *ap_dev)
+{
+	struct zcrypt_device *zdev = ap_dev->private;
+
+	zcrypt_device_unregister(zdev);
+}
+
+int __init zcrypt_pcicc_init(void)
+{
+	return ap_driver_register(&zcrypt_pcicc_driver, THIS_MODULE, "pcicc");
+}
+
+void zcrypt_pcicc_exit(void)
+{
+	ap_driver_unregister(&zcrypt_pcicc_driver);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(zcrypt_pcicc_init);
+module_exit(zcrypt_pcicc_exit);
+#endif
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcicc.h linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcicc.h
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcicc.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcicc.h	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,176 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_pcicc.h
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@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 _ZCRYPT_PCICC_H_
+#define _ZCRYPT_PCICC_H_
+
+/**
+ * The type 6 message family is associated with PCICC or PCIXCC cards.
+ *
+ * It contains a message header followed by a CPRB, both of which
+ * are described below.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+struct type6_hdr {
+	unsigned char reserved1;	/* 0x00				*/
+	unsigned char type;		/* 0x06				*/
+	unsigned char reserved2[2];	/* 0x0000			*/
+	unsigned char right[4];		/* 0x00000000			*/
+	unsigned char reserved3[2];	/* 0x0000			*/
+	unsigned char reserved4[2];	/* 0x0000			*/
+	unsigned char apfs[4];		/* 0x00000000			*/
+	unsigned int  offset1;		/* 0x00000058 (offset to CPRB)	*/
+	unsigned int  offset2;		/* 0x00000000			*/
+	unsigned int  offset3;		/* 0x00000000			*/
+	unsigned int  offset4;		/* 0x00000000			*/
+	unsigned char agent_id[16];	/* PCICC:			*/
+					/*    0x0100			*/
+					/*    0x4343412d4150504c202020	*/
+					/*    0x010101			*/
+					/* PCIXCC:			*/
+					/*    0x4341000000000000	*/
+					/*    0x0000000000000000	*/
+	unsigned char rqid[2];		/* rqid.  internal to 603	*/
+	unsigned char reserved5[2];	/* 0x0000			*/
+	unsigned char function_code[2];	/* for PKD, 0x5044 (ascii 'PD')	*/
+	unsigned char reserved6[2];	/* 0x0000			*/
+	unsigned int  ToCardLen1;	/* (request CPRB len + 3) & -4	*/
+	unsigned int  ToCardLen2;	/* db len 0x00000000 for PKD	*/
+	unsigned int  ToCardLen3;	/* 0x00000000			*/
+	unsigned int  ToCardLen4;	/* 0x00000000			*/
+	unsigned int  FromCardLen1;	/* response buffer length	*/
+	unsigned int  FromCardLen2;	/* db len 0x00000000 for PKD	*/
+	unsigned int  FromCardLen3;	/* 0x00000000			*/
+	unsigned int  FromCardLen4;	/* 0x00000000			*/
+} __attribute__((packed));
+
+/**
+ * CPRB
+ *	  Note that all shorts, ints and longs are little-endian.
+ *	  All pointer fields are 32-bits long, and mean nothing
+ *
+ *	  A request CPRB is followed by a request_parameter_block.
+ *
+ *	  The request (or reply) parameter block is organized thus:
+ *	    function code
+ *	    VUD block
+ *	    key block
+ */
+struct CPRB {
+	unsigned short cprb_len;	/* CPRB length			 */
+	unsigned char cprb_ver_id;	/* CPRB version id.		 */
+	unsigned char pad_000;		/* Alignment pad byte.		 */
+	unsigned char srpi_rtcode[4];	/* SRPI return code LELONG	 */
+	unsigned char srpi_verb;	/* SRPI verb type		 */
+	unsigned char flags;		/* flags			 */
+	unsigned char func_id[2];	/* function id			 */
+	unsigned char checkpoint_flag;	/*				 */
+	unsigned char resv2;		/* reserved			 */
+	unsigned short req_parml;	/* request parameter buffer	 */
+					/* length 16-bit little endian	 */
+	unsigned char req_parmp[4];	/* request parameter buffer	 *
+					 * pointer (means nothing: the	 *
+					 * parameter buffer follows	 *
+					 * the CPRB).			 */
+	unsigned char req_datal[4];	/* request data buffer		 */
+					/* length	  ULELONG	 */
+	unsigned char req_datap[4];	/* request data buffer		 */
+					/* pointer			 */
+	unsigned short rpl_parml;	/* reply  parameter buffer	 */
+					/* length 16-bit little endian	 */
+	unsigned char pad_001[2];	/* Alignment pad bytes. ULESHORT */
+	unsigned char rpl_parmp[4];	/* reply parameter buffer	 *
+					 * pointer (means nothing: the	 *
+					 * parameter buffer follows	 *
+					 * the CPRB).			 */
+	unsigned char rpl_datal[4];	/* reply data buffer len ULELONG */
+	unsigned char rpl_datap[4];	/* reply data buffer		 */
+					/* pointer			 */
+	unsigned short ccp_rscode;	/* server reason code	ULESHORT */
+	unsigned short ccp_rtcode;	/* server return code	ULESHORT */
+	unsigned char repd_parml[2];	/* replied parameter len ULESHORT*/
+	unsigned char mac_data_len[2];	/* Mac Data Length	ULESHORT */
+	unsigned char repd_datal[4];	/* replied data length	ULELONG	 */
+	unsigned char req_pc[2];	/* PC identifier		 */
+	unsigned char res_origin[8];	/* resource origin		 */
+	unsigned char mac_value[8];	/* Mac Value			 */
+	unsigned char logon_id[8];	/* Logon Identifier		 */
+	unsigned char usage_domain[2];	/* cdx				 */
+	unsigned char resv3[18];	/* reserved for requestor	 */
+	unsigned short svr_namel;	/* server name length  ULESHORT	 */
+	unsigned char svr_name[8];	/* server name			 */
+} __attribute__((packed));
+
+/**
+ * The type 86 message family is associated with PCICC and PCIXCC cards.
+ *
+ * It contains a message header followed by a CPRB.  The CPRB is
+ * the same as the request CPRB, which is described above.
+ *
+ * If format is 1, an error condition exists and no data beyond
+ * the 8-byte message header is of interest.
+ *
+ * The non-error message is shown below.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+struct type86_hdr {
+	unsigned char reserved1;	/* 0x00				*/
+	unsigned char type;		/* 0x86				*/
+	unsigned char format;		/* 0x01 (error) or 0x02 (ok)	*/
+	unsigned char reserved2;	/* 0x00				*/
+	unsigned char reply_code;	/* reply code (see above)	*/
+	unsigned char reserved3[3];	/* 0x000000			*/
+} __attribute__((packed));
+
+#define TYPE86_RSP_CODE 0x86
+#define TYPE86_FMT2	0x02
+
+struct type86_fmt2_ext {
+	unsigned char	  reserved[4];	/* 0x00000000			*/
+	unsigned char	  apfs[4];	/* final status			*/
+	unsigned int	  count1;	/* length of CPRB + parameters	*/
+	unsigned int	  offset1;	/* offset to CPRB		*/
+	unsigned int	  count2;	/* 0x00000000			*/
+	unsigned int	  offset2;	/* db offset 0x00000000 for PKD	*/
+	unsigned int	  count3;	/* 0x00000000			*/
+	unsigned int	  offset3;	/* 0x00000000			*/
+	unsigned int	  count4;	/* 0x00000000			*/
+	unsigned int	  offset4;	/* 0x00000000			*/
+} __attribute__((packed));
+
+struct function_and_rules_block {
+	unsigned char function_code[2];
+	unsigned short ulen;
+	unsigned char only_rule[8];
+} __attribute__((packed));
+
+int zcrypt_pcicc_init(void);
+void zcrypt_pcicc_exit(void);
+
+#endif /* _ZCRYPT_PCICC_H_ */
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcixcc.c linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcixcc.c
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcixcc.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcixcc.c	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,951 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_pcixcc.c
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *				  Ralph Wuerthner <rwuerthn@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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_error.h"
+#include "zcrypt_pcicc.h"
+#include "zcrypt_pcixcc.h"
+#include "zcrypt_cca_key.h"
+
+#define PCIXCC_MIN_MOD_SIZE	 16	/*  128 bits	*/
+#define PCIXCC_MIN_MOD_SIZE_OLD	 64	/*  512 bits	*/
+#define PCIXCC_MAX_MOD_SIZE	256	/* 2048 bits	*/
+
+#define PCIXCC_MCL2_SPEED_RATING	7870	/* FIXME: needs finetuning */
+#define PCIXCC_MCL3_SPEED_RATING	7870
+#define CEX2C_SPEED_RATING		8540
+
+#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c  /* max size type6 v2 crt message */
+#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply	    */
+
+#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024)
+#define PCIXCC_MAX_XCRB_RESPONSE_SIZE PCIXCC_MAX_XCRB_MESSAGE_SIZE
+#define PCIXCC_MAX_XCRB_DATA_SIZE (11*1024)
+#define PCIXCC_MAX_XCRB_REPLY_SIZE (5*1024)
+
+#define PCIXCC_MAX_RESPONSE_SIZE PCIXCC_MAX_XCRB_RESPONSE_SIZE
+
+#define PCIXCC_CLEANUP_TIME	(15*HZ)
+
+#define CEIL4(x) ((((x)+3)/4)*4)
+
+struct response_type {
+	struct completion work;
+	int type;
+};
+#define PCIXCC_RESPONSE_TYPE_ICA  0
+#define PCIXCC_RESPONSE_TYPE_XCRB 1
+
+static struct ap_device_id zcrypt_pcixcc_ids[] = {
+	{ AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
+	{ AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
+	{ /* end of list */ },
+};
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids);
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, "
+		   "Copyright 2001, 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+#endif
+
+static int zcrypt_pcixcc_probe(struct ap_device *ap_dev);
+static void zcrypt_pcixcc_remove(struct ap_device *ap_dev);
+static void zcrypt_pcixcc_receive(struct ap_device *, struct ap_message *,
+				 struct ap_message *);
+
+static struct ap_driver zcrypt_pcixcc_driver = {
+	.probe = zcrypt_pcixcc_probe,
+	.remove = zcrypt_pcixcc_remove,
+	.receive = zcrypt_pcixcc_receive,
+	.ids = zcrypt_pcixcc_ids,
+};
+
+/**
+ * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
+ * card in a type6 message. The 3 fields that must be filled in at execution
+ * time are  req_parml, rpl_parml and usage_domain.
+ * Everything about this interface is ascii/big-endian, since the
+ * device does *not* have 'Intel inside'.
+ *
+ * The CPRBX is followed immediately by the parm block.
+ * The parm block contains:
+ * - function code ('PD' 0x5044 or 'PK' 0x504B)
+ * - rule block (one of:)
+ *   + 0x000A 'PKCS-1.2' (MCL2 'PD')
+ *   + 0x000A 'ZERO-PAD' (MCL2 'PK')
+ *   + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD')
+ *   + 0x000A 'MRP     ' (MCL3 'PK' or CEX2C 'PK')
+ * - VUD block
+ */
+static struct CPRBX static_cprbx = {
+	.cprb_len	=  0x00DC,
+	.cprb_ver_id	=  0x02,
+	.func_id	= {0x54,0x32},
+};
+
+/**
+ * Convert a ICAMEX message to a type6 MEX message.
+ *
+ * @zdev: crypto device pointer
+ * @ap_msg: pointer to AP message
+ * @mex: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
+				       struct ap_message *ap_msg,
+				       struct ica_rsa_modexpo *mex)
+{
+	static struct type6_hdr static_type6_hdrX = {
+		.type		=  0x06,
+		.offset1	=  0x00000058,
+		.agent_id	= {'C','A',},
+		.function_code	= {'P','K'},
+	};
+	static struct function_and_rules_block static_pke_fnr = {
+		.function_code	= {'P','K'},
+		.ulen		= 10,
+		.only_rule	= {'M','R','P',' ',' ',' ',' ',' '}
+	};
+	static struct function_and_rules_block static_pke_fnr_MCL2 = {
+		.function_code	= {'P','K'},
+		.ulen		= 10,
+		.only_rule	= {'Z','E','R','O','-','P','A','D'}
+	};
+	struct {
+		struct type6_hdr hdr;
+		struct CPRBX cprbx;
+		struct function_and_rules_block fr;
+		unsigned short length;
+		char text[0];
+	} __attribute__((packed)) *msg = ap_msg->message;
+	int size;
+
+	/* VUD.ciphertext */
+	msg->length = mex->inputdatalength + 2;
+	if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
+		return -EFAULT;
+
+	/* Set up key which is located after the variable length text. */
+	size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1);
+	if (size < 0)
+		return size;
+	size += sizeof(*msg) + mex->inputdatalength;
+
+	/* message header, cprbx and f&r */
+	msg->hdr = static_type6_hdrX;
+	msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
+	msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
+
+	msg->cprbx = static_cprbx;
+	msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
+	msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1;
+
+	msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
+		static_pke_fnr_MCL2 : static_pke_fnr;
+
+	msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx);
+
+	ap_msg->length = size;
+	return 0;
+}
+
+/**
+ * Convert a ICACRT message to a type6 CRT message.
+ *
+ * @zdev: crypto device pointer
+ * @ap_msg: pointer to AP message
+ * @crt: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
+				       struct ap_message *ap_msg,
+				       struct ica_rsa_modexpo_crt *crt)
+{
+	static struct type6_hdr static_type6_hdrX = {
+		.type		=  0x06,
+		.offset1	=  0x00000058,
+		.agent_id	= {'C','A',},
+		.function_code	= {'P','D'},
+	};
+	static struct function_and_rules_block static_pkd_fnr = {
+		.function_code	= {'P','D'},
+		.ulen		= 10,
+		.only_rule	= {'Z','E','R','O','-','P','A','D'}
+	};
+
+	static struct function_and_rules_block static_pkd_fnr_MCL2 = {
+		.function_code	= {'P','D'},
+		.ulen		= 10,
+		.only_rule	= {'P','K','C','S','-','1','.','2'}
+	};
+	struct {
+		struct type6_hdr hdr;
+		struct CPRBX cprbx;
+		struct function_and_rules_block fr;
+		unsigned short length;
+		char text[0];
+	} __attribute__((packed)) *msg = ap_msg->message;
+	int size;
+
+	/* VUD.ciphertext */
+	msg->length = crt->inputdatalength + 2;
+	if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
+		return -EFAULT;
+
+	/* Set up key which is located after the variable length text. */
+	size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1);
+	if (size < 0)
+		return size;
+	size += sizeof(*msg) + crt->inputdatalength;	/* total size of msg */
+
+	/* message header, cprbx and f&r */
+	msg->hdr = static_type6_hdrX;
+	msg->hdr.ToCardLen1 = size -  sizeof(msg->hdr);
+	msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
+
+	msg->cprbx = static_cprbx;
+	msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
+	msg->cprbx.req_parml = msg->cprbx.rpl_msgbl =
+		size - sizeof(msg->hdr) - sizeof(msg->cprbx);
+
+	msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
+		static_pkd_fnr_MCL2 : static_pkd_fnr;
+
+	ap_msg->length = size;
+	return 0;
+}
+
+/**
+ * Convert a XCRB message to a type6 CPRB message.
+ *
+ * @zdev: crypto device pointer
+ * @ap_msg: pointer to AP message
+ * @xcRB: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+struct type86_fmt2_msg {
+	struct type86_hdr hdr;
+	struct type86_fmt2_ext fmt2;
+} __attribute__((packed));
+
+static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
+				       struct ap_message *ap_msg,
+				       struct ica_xcRB *xcRB)
+{
+	static struct type6_hdr static_type6_hdrX = {
+		.type		=  0x06,
+		.offset1	=  0x00000058,
+	};
+	struct {
+		struct type6_hdr hdr;
+		struct ica_CPRBX cprbx;
+	} __attribute__((packed)) *msg = ap_msg->message;
+
+	int rcblen = CEIL4(xcRB->request_control_blk_length);
+	int replylen;
+	char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
+	char *function_code;
+
+	/* length checks */
+	ap_msg->length = sizeof(struct type6_hdr) +
+		CEIL4(xcRB->request_control_blk_length) +
+		xcRB->request_data_length;
+	if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) {
+		PRINTK("Combined message is too large (%ld/%d/%d).\n",
+		    sizeof(struct type6_hdr),
+		    xcRB->request_control_blk_length,
+		    xcRB->request_data_length);
+		return -EFAULT;
+	}
+	if (CEIL4(xcRB->reply_control_blk_length) >
+	    PCIXCC_MAX_XCRB_REPLY_SIZE) {
+		PDEBUG("Reply CPRB length is too large (%d).\n",
+		    xcRB->request_control_blk_length);
+		return -EFAULT;
+	}
+	if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE) {
+		PDEBUG("Reply data block length is too large (%d).\n",
+		    xcRB->reply_data_length);
+		return -EFAULT;
+	}
+	replylen = CEIL4(xcRB->reply_control_blk_length) +
+		CEIL4(xcRB->reply_data_length) +
+		sizeof(struct type86_fmt2_msg);
+	if (replylen > PCIXCC_MAX_XCRB_RESPONSE_SIZE) {
+		PDEBUG("Reply CPRB + data block > PCIXCC_MAX_XCRB_RESPONSE_SIZE"
+		       " (%d/%d/%d).\n",
+		       sizeof(struct type86_fmt2_msg),
+		       xcRB->reply_control_blk_length,
+		       xcRB->reply_data_length);
+		xcRB->reply_control_blk_length = PCIXCC_MAX_XCRB_RESPONSE_SIZE -
+			(sizeof(struct type86_fmt2_msg) +
+			    CEIL4(xcRB->reply_data_length));
+		PDEBUG("Capping Reply CPRB length at %d\n",
+		       xcRB->reply_control_blk_length);
+	}
+
+	/* prepare type6 header */
+	msg->hdr = static_type6_hdrX;
+	memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
+	msg->hdr.ToCardLen1 = xcRB->request_control_blk_length;
+	if (xcRB->request_data_length) {
+		msg->hdr.offset2 = msg->hdr.offset1 + rcblen;
+		msg->hdr.ToCardLen2 = xcRB->request_data_length;
+	}
+	msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length;
+	msg->hdr.FromCardLen2 = xcRB->reply_data_length;
+
+	/* prepare CPRB */
+	if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr,
+		    xcRB->request_control_blk_length))
+		return -EFAULT;
+	if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
+	    xcRB->request_control_blk_length) {
+		PDEBUG("cprb_len too large (%d/%d)\n", msg->cprbx.cprb_len,
+		    xcRB->request_control_blk_length);
+		return -EFAULT;
+	}
+	function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
+	memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
+
+	/* copy data block */
+	if (xcRB->request_data_length &&
+	    copy_from_user(req_data, xcRB->request_data_address,
+		xcRB->request_data_length))
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ * Copy results from a type 86 ICA reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @data: pointer to user output data
+ * @length: size of user output data
+ *
+ * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
+ */
+struct type86x_reply {
+	struct type86_hdr hdr;
+	struct type86_fmt2_ext fmt2;
+	struct CPRBX cprbx;
+	unsigned char pad[4];	/* 4 byte function code/rules block ? */
+	unsigned short length;
+	char text[0];
+} __attribute__((packed));
+
+static int convert_type86_ica(struct zcrypt_device *zdev,
+			  struct ap_message *reply,
+			  char __user *outputdata,
+			  unsigned int outputdatalength)
+{
+	static unsigned char static_pad[] = {
+		0x00,0x02,
+		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
+	};
+	struct type86x_reply *msg = reply->message;
+	unsigned short service_rc, service_rs;
+	unsigned int reply_len, pad_len;
+	char *data;
+
+	service_rc = msg->cprbx.ccp_rtcode;
+	if (unlikely(service_rc != 0)) {
+		service_rs = msg->cprbx.ccp_rscode;
+		if (service_rc == 8 && service_rs == 66) {
+			PDEBUG("Bad block format on PCIXCC/CEX2C\n");
+			return -EINVAL;
+		}
+		if (service_rc == 8 && service_rs == 65) {
+			PDEBUG("Probably an even modulus on PCIXCC/CEX2C\n");
+			return -EINVAL;
+		}
+		if (service_rc == 8 && service_rs == 770) {
+			PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
+			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
+			return -EAGAIN;
+		}
+		if (service_rc == 8 && service_rs == 783) {
+			PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
+			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
+			return -EAGAIN;
+		}
+		PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
+		       service_rc, service_rs);
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+	data = msg->text;
+	reply_len = msg->length - 2;
+	if (reply_len > outputdatalength)
+		return -EINVAL;
+	/**
+	 * For all encipher requests, the length of the ciphertext (reply_len)
+	 * will always equal the modulus length. For MEX decipher requests
+	 * the output needs to get padded. Minimum pad size is 10.
+	 *
+	 * Currently, the cases where padding will be added is for:
+	 * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
+	 *   ZERO-PAD and CRT is only supported for PKD requests)
+	 * - PCICC, always
+	 */
+	pad_len = outputdatalength - reply_len;
+	if (pad_len > 0) {
+		if (pad_len < 10)
+			return -EINVAL;
+		/* 'restore' padding left in the PCICC/PCIXCC card. */
+		if (copy_to_user(outputdata, static_pad, pad_len - 1))
+			return -EFAULT;
+		if (put_user(0, outputdata + pad_len - 1))
+			return -EFAULT;
+	}
+	/* Copy the crypto response to user space. */
+	if (copy_to_user(outputdata + pad_len, data, reply_len))
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ * Copy results from a type 86 XCRB reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @xcRB: pointer to XCRB
+ *
+ * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
+ */
+static int convert_type86_xcrb(struct zcrypt_device *zdev,
+			       struct ap_message *reply,
+			       struct ica_xcRB *xcRB)
+{
+	struct type86_fmt2_msg *msg = reply->message;
+	char *data = reply->message;
+
+	/* Copy CPRB to user */
+	if (copy_to_user(xcRB->reply_control_blk_addr,
+		data + msg->fmt2.offset1, msg->fmt2.count1))
+		return -EFAULT;
+	xcRB->reply_control_blk_length = msg->fmt2.count1;
+
+	/* Copy data buffer to user */
+	if (msg->fmt2.count2)
+		if (copy_to_user(xcRB->reply_data_addr,
+			data + msg->fmt2.offset2, msg->fmt2.count2))
+			return -EFAULT;
+	xcRB->reply_data_length = msg->fmt2.count2;
+	return 0;
+}
+
+static int convert_response_ica(struct zcrypt_device *zdev,
+			    struct ap_message *reply,
+			    char __user *outputdata,
+			    unsigned int outputdatalength)
+{
+	struct type86x_reply *msg = reply->message;
+
+	/* Response type byte is the second byte in the response. */
+	switch (((unsigned char *) reply->message)[1]) {
+	case TYPE82_RSP_CODE:
+	case TYPE88_RSP_CODE:
+		return convert_error(zdev, reply);
+	case TYPE86_RSP_CODE:
+		if (msg->hdr.reply_code)
+			return convert_error(zdev, reply);
+		if (msg->cprbx.cprb_ver_id == 0x02)
+			return convert_type86_ica(zdev, reply,
+						  outputdata, outputdatalength);
+		/* no break, incorrect cprb version is an unknown response */
+	default: /* Unknown response type, this should NEVER EVER happen */
+		PRINTK("Unrecognized Message Header: %08x%08x\n",
+		       *(unsigned int *) reply->message,
+		       *(unsigned int *) (reply->message+4));
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+}
+
+static int convert_response_xcrb(struct zcrypt_device *zdev,
+			    struct ap_message *reply,
+			    struct ica_xcRB *xcRB)
+{
+	struct type86x_reply *msg = reply->message;
+
+	/* Response type byte is the second byte in the response. */
+	switch (((unsigned char *) reply->message)[1]) {
+	case TYPE82_RSP_CODE:
+	case TYPE88_RSP_CODE:
+		xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
+		return convert_error(zdev, reply);
+	case TYPE86_RSP_CODE:
+		if (msg->hdr.reply_code) {
+			memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32));
+			return convert_error(zdev, reply);
+		}
+		if (msg->cprbx.cprb_ver_id == 0x02)
+			return convert_type86_xcrb(zdev, reply, xcRB);
+		/* no break, incorrect cprb version is an unknown response */
+	default: /* Unknown response type, this should NEVER EVER happen */
+		PRINTK("Unrecognized Message Header: %08x%08x\n",
+		       *(unsigned int *) reply->message,
+		       *(unsigned int *) (reply->message+4));
+		xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
+		zdev->online = 0;
+		return -EAGAIN;	/* repeat the request on a different device. */
+	}
+}
+
+/**
+ * This function is called from the AP bus code after a crypto request
+ * "msg" has finished with the reply message "reply".
+ * It is called from tasklet context.
+ * @ap_dev: pointer to the AP device
+ * @msg: pointer to the AP message
+ * @reply: pointer to the AP reply message
+ */
+static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,
+				  struct ap_message *msg,
+				  struct ap_message *reply)
+{
+	static struct error_hdr error_reply = {
+		.type = TYPE82_RSP_CODE,
+		.reply_code = REP82_ERROR_MACHINE_FAILURE,
+	};
+	struct response_type *resp_type =
+		(struct response_type *) msg->private;
+	struct type86x_reply *t86r = reply->message;
+	int length;
+
+	/* Copy the reply message to the request message buffer. */
+	if (IS_ERR(reply))
+		memcpy(msg->message, &error_reply, sizeof(error_reply));
+	else if (t86r->hdr.type == TYPE86_RSP_CODE &&
+		 t86r->cprbx.cprb_ver_id == 0x02) {
+		switch (resp_type->type) {
+		case PCIXCC_RESPONSE_TYPE_ICA:
+			length = sizeof(struct type86x_reply)
+				+ t86r->length - 2;
+			length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
+			memcpy(msg->message, reply->message, length);
+			break;
+		case PCIXCC_RESPONSE_TYPE_XCRB:
+			length = t86r->fmt2.offset2 + t86r->fmt2.count2;
+			length = min(PCIXCC_MAX_XCRB_RESPONSE_SIZE, length);
+			memcpy(msg->message, reply->message, length);
+			break;
+		default:
+			PRINTK("Invalid internal response type: %i\n",
+			    resp_type->type);
+			memcpy(msg->message, &error_reply,
+			    sizeof error_reply);
+		}
+	} else
+		memcpy(msg->message, reply->message, sizeof error_reply);
+	complete(&(resp_type->work));
+}
+
+static atomic_t zcrypt_step = ATOMIC_INIT(0);
+
+/**
+ * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * device to handle a modexpo request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  PCIXCC/CEX2C device to the request distributor
+ * @mex: pointer to the modexpo request buffer
+ */
+static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,
+				  struct ica_rsa_modexpo *mex)
+{
+	struct ap_message ap_msg;
+	struct response_type resp_type = {
+		.type = PCIXCC_RESPONSE_TYPE_ICA,
+	};
+	int rc;
+
+	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &resp_type;
+	rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
+	if (rc)
+		goto out_free;
+	init_completion(&resp_type.work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible_timeout(
+				&resp_type.work, PCIXCC_CLEANUP_TIME);
+	if (rc > 0)
+		rc = convert_response_ica(zdev, &ap_msg, mex->outputdata,
+					  mex->outputdatalength);
+	else {
+		/* Signal pending or message timed out. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+		if (rc == 0)
+			/* Message timed out. */
+			rc = -ETIME;
+	}
+out_free:
+	free_page((unsigned long) ap_msg.message);
+	return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * device to handle a modexpo_crt request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  PCIXCC/CEX2C device to the request distributor
+ * @crt: pointer to the modexpoc_crt request buffer
+ */
+static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,
+				      struct ica_rsa_modexpo_crt *crt)
+{
+	struct ap_message ap_msg;
+	struct response_type resp_type = {
+		.type = PCIXCC_RESPONSE_TYPE_ICA,
+	};
+	int rc;
+
+	ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &resp_type;
+	rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
+	if (rc)
+		goto out_free;
+	init_completion(&resp_type.work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible_timeout(
+				&resp_type.work, PCIXCC_CLEANUP_TIME);
+	if (rc > 0)
+		rc = convert_response_ica(zdev, &ap_msg, crt->outputdata,
+					  crt->outputdatalength);
+	else {
+		/* Signal pending or message timed out. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+		if (rc == 0)
+			/* Message timed out. */
+			rc = -ETIME;
+	}
+out_free:
+	free_page((unsigned long) ap_msg.message);
+	return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * device to handle a send_cprb request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ *	  PCIXCC/CEX2C device to the request distributor
+ * @xcRB: pointer to the send_cprb request buffer
+ */
+long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB)
+{
+	struct ap_message ap_msg;
+	struct response_type resp_type = {
+		.type = PCIXCC_RESPONSE_TYPE_XCRB,
+	};
+	int rc;
+
+	ap_msg.message = (void *) kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
+	if (!ap_msg.message)
+		return -ENOMEM;
+	ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+				atomic_inc_return(&zcrypt_step);
+	ap_msg.private = &resp_type;
+	rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB);
+	if (rc)
+		goto out_free;
+	init_completion(&resp_type.work);
+	ap_queue_message(zdev->ap_dev, &ap_msg);
+	rc = wait_for_completion_interruptible_timeout(
+				&resp_type.work, PCIXCC_CLEANUP_TIME);
+	if (rc > 0)
+		rc = convert_response_xcrb(zdev, &ap_msg, xcRB);
+	else {
+		/* Signal pending or message timed out. */
+		ap_cancel_message(zdev->ap_dev, &ap_msg);
+		if (rc == 0)
+			/* Message timed out. */
+			rc = -ETIME;
+	}
+out_free:
+	memset(ap_msg.message, 0x0, ap_msg.length);
+	kfree(ap_msg.message);
+	return rc;
+}
+
+/**
+ * The crypto operations for a PCIXCC/CEX2C card.
+ */
+static struct zcrypt_ops zcrypt_pcixcc_ops = {
+	.rsa_modexpo = zcrypt_pcixcc_modexpo,
+	.rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt,
+	.send_cprb = zcrypt_pcixcc_send_cprb,
+};
+
+/**
+ * Micro-code detection function. Its sends a message to a pcixcc card
+ * to find out the microcode level.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev)
+{
+	static unsigned char msg[] = {
+		0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,
+		0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,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,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+		0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,
+		0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
+		0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,
+		0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
+		0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,
+		0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
+		0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,
+		0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
+		0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,
+		0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
+		0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,
+		0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
+		0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,
+		0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
+		0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,
+		0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
+		0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,
+		0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
+		0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,
+		0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
+		0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,
+		0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
+		0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,
+		0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
+		0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,
+		0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
+		0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,
+		0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
+		0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,
+		0xF1,0x3D,0x93,0x53
+	};
+	unsigned long long psmid;
+	struct CPRBX *cprbx;
+	char *reply;
+	int rc, i;
+
+	reply = (void *) get_zeroed_page(GFP_KERNEL);
+	if (!reply)
+		return -ENOMEM;
+
+	rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, msg, sizeof(msg));
+	if (rc)
+		goto out_free;
+
+	/* Wait for the test message to complete. */
+	for (i = 0; i < 6; i++) {
+		mdelay(300);
+		rc = ap_recv(ap_dev->qid, &psmid, reply, 4096);
+		if (rc == 0 && psmid == 0x0102030405060708ULL)
+			break;
+	}
+
+	if (i >= 6) {
+		/* Got no answer. */
+		rc = -ENODEV;
+		goto out_free;
+	}
+
+	cprbx = (struct CPRBX *) (reply + 48);
+	if (cprbx->ccp_rtcode == 8 && cprbx->ccp_rscode == 33)
+		rc = ZCRYPT_PCIXCC_MCL2;
+	else
+		rc = ZCRYPT_PCIXCC_MCL3;
+out_free:
+	free_page((unsigned long) reply);
+	return rc;
+}
+
+/**
+ * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device
+ * since the bus_match already checked the hardware type. The PCIXCC
+ * cards come in two flavours: micro code level 2 and micro code level 3.
+ * This is checked by sending a test message to the device.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
+{
+	struct zcrypt_device *zdev;
+	int rc;
+
+	zdev = zcrypt_device_alloc(PCIXCC_MAX_RESPONSE_SIZE);
+	if (!zdev)
+		return -ENOMEM;
+	zdev->ap_dev = ap_dev;
+	zdev->ops = &zcrypt_pcixcc_ops;
+	zdev->online = 1;
+	if (ap_dev->device_type == AP_DEVICE_TYPE_PCIXCC) {
+		rc = zcrypt_pcixcc_mcl(ap_dev);
+		if (rc < 0) {
+			zcrypt_device_free(zdev);
+			return rc;
+		}
+		zdev->user_space_type = rc;
+		if (rc == ZCRYPT_PCIXCC_MCL2) {
+			zdev->type_string = "PCIXCC_MCL2";
+			zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING;
+			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
+			zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+		} else {
+			zdev->type_string = "PCIXCC_MCL3";
+			zdev->speed_rating = PCIXCC_MCL3_SPEED_RATING;
+			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
+			zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+		}
+	} else {
+		zdev->user_space_type = ZCRYPT_CEX2C;
+		zdev->type_string = "CEX2C";
+		zdev->speed_rating = CEX2C_SPEED_RATING;
+		zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
+		zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+	}
+	ap_dev->reply = &zdev->reply;
+	ap_dev->private = zdev;
+	rc = zcrypt_device_register(zdev);
+	if (rc)
+		goto out_free;
+	return 0;
+
+ out_free:
+	ap_dev->private = NULL;
+	zcrypt_device_free(zdev);
+	return rc;
+}
+
+/**
+ * This is called to remove the extended PCIXCC/CEX2C driver information
+ * if an AP device is removed.
+ */
+static void zcrypt_pcixcc_remove(struct ap_device *ap_dev)
+{
+	struct zcrypt_device *zdev = ap_dev->private;
+
+	zcrypt_device_unregister(zdev);
+}
+
+int __init zcrypt_pcixcc_init(void)
+{
+	return ap_driver_register(&zcrypt_pcixcc_driver, THIS_MODULE, "pcixcc");
+}
+
+void zcrypt_pcixcc_exit(void)
+{
+	ap_driver_unregister(&zcrypt_pcixcc_driver);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(zcrypt_pcixcc_init);
+module_exit(zcrypt_pcixcc_exit);
+#endif
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcixcc.h linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcixcc.h
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/crypto/zcrypt_pcixcc.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/crypto/zcrypt_pcixcc.h	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,79 @@
+/*
+ *  linux/drivers/s390/crypto/zcrypt_pcixcc.h
+ *
+ *  zcrypt 2.1.0
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       Eric Rossman (edrossma@us.ibm.com)
+ *
+ *  Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ *  Major cleanup & driver split: Martin Schwidefsky <schwidefsky@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 _ZCRYPT_PCIXCC_H_
+#define _ZCRYPT_PCIXCC_H_
+
+/**
+ * CPRBX
+ *	  Note that all shorts and ints are big-endian.
+ *	  All pointer fields are 16 bytes long, and mean nothing.
+ *
+ *	  A request CPRB is followed by a request_parameter_block.
+ *
+ *	  The request (or reply) parameter block is organized thus:
+ *	    function code
+ *	    VUD block
+ *	    key block
+ */
+struct CPRBX {
+	unsigned short cprb_len;	/* CPRB length	      220	 */
+	unsigned char  cprb_ver_id;	/* CPRB version id.   0x02	 */
+	unsigned char  pad_000[3];	/* Alignment pad bytes		 */
+	unsigned char  func_id[2];	/* function id	      0x5432	 */
+	unsigned char  cprb_flags[4];	/* Flags			 */
+	unsigned int   req_parml;	/* request parameter buffer len	 */
+	unsigned int   req_datal;	/* request data buffer		 */
+	unsigned int   rpl_msgbl;	/* reply  message block length	 */
+	unsigned int   rpld_parml;	/* replied parameter block len	 */
+	unsigned int   rpl_datal;	/* reply data block len		 */
+	unsigned int   rpld_datal;	/* replied data block len	 */
+	unsigned int   req_extbl;	/* request extension block len	 */
+	unsigned char  pad_001[4];	/* reserved			 */
+	unsigned int   rpld_extbl;	/* replied extension block len	 */
+	unsigned char  req_parmb[16];	/* request parm block 'address'	 */
+	unsigned char  req_datab[16];	/* request data block 'address'	 */
+	unsigned char  rpl_parmb[16];	/* reply parm block 'address'	 */
+	unsigned char  rpl_datab[16];	/* reply data block 'address'	 */
+	unsigned char  req_extb[16];	/* request extension block 'addr'*/
+	unsigned char  rpl_extb[16];	/* reply extension block 'addres'*/
+	unsigned short ccp_rtcode;	/* server return code		 */
+	unsigned short ccp_rscode;	/* server reason code		 */
+	unsigned int   mac_data_len;	/* Mac Data Length		 */
+	unsigned char  logon_id[8];	/* Logon Identifier		 */
+	unsigned char  mac_value[8];	/* Mac Value			 */
+	unsigned char  mac_content_flgs;/* Mac content flag byte	 */
+	unsigned char  pad_002;		/* Alignment			 */
+	unsigned short domain;		/* Domain			 */
+	unsigned char  pad_003[12];	/* Domain masks			 */
+	unsigned char  pad_004[36];	/* reserved			 */
+} __attribute__((packed));
+
+int zcrypt_pcixcc_init(void);
+void zcrypt_pcixcc_exit(void);
+
+#endif /* _ZCRYPT_PCIXCC_H_ */
diff -urNp linux-2.6.18.s390x-remove_z90crypt/drivers/s390/Kconfig linux-2.6.18.s390x-add_zcrypt/drivers/s390/Kconfig
--- linux-2.6.18.s390x-remove_z90crypt/drivers/s390/Kconfig	2007-01-29 16:52:36.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/drivers/s390/Kconfig	2007-01-29 17:10:16.000000000 +0100
@@ -214,3 +214,28 @@ config MONREADER
 	  Character device driver for reading z/VM monitor service records
 
 endmenu
+
+menu "Cryptographic devices"
+
+config ZCRYPT
+	tristate "Support for PCI-attached cryptographic adapters"
+	select ZCRYPT_MONOLITHIC if ZCRYPT="y"
+	default "m"
+	help
+	  Select this option if you want to use a PCI-attached cryptographic
+	  adapter like:
+	  + PCI Cryptographic Accelerator (PCICA)
+	  + PCI Cryptographic Coprocessor (PCICC)
+	  + PCI-X Cryptographic Coprocessor (PCIXCC)
+	  + Crypto Express2 Coprocessor (CEX2C)
+	  + Crypto Express2 Accelerator (CEX2A)
+
+config ZCRYPT_MONOLITHIC
+	bool "Monolithic zcrypt module"
+	depends on ZCRYPT="m"
+	help
+	  Select this option if you want to have a single module z90crypt.ko
+	  that contains all parts of the crypto device driver (ap bus,
+	  request router and all the card drivers).
+
+endmenu
diff -urNp linux-2.6.18.s390x-remove_z90crypt/include/asm-s390/Kbuild linux-2.6.18.s390x-add_zcrypt/include/asm-s390/Kbuild
--- linux-2.6.18.s390x-remove_z90crypt/include/asm-s390/Kbuild	2007-01-29 18:13:37.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/include/asm-s390/Kbuild	2007-01-29 18:05:44.000000000 +0100
@@ -5,6 +5,7 @@ header-y += qeth.h
 header-y += tape390.h
 header-y += ucontext.h
 header-y += vtoc.h
+header-y += zcrypt.h
 
 unifdef-y += cmb.h
 unifdef-y += debug.h
diff -urNp linux-2.6.18.s390x-remove_z90crypt/include/asm-s390/zcrypt.h linux-2.6.18.s390x-add_zcrypt/include/asm-s390/zcrypt.h
--- linux-2.6.18.s390x-remove_z90crypt/include/asm-s390/zcrypt.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.18.s390x-add_zcrypt/include/asm-s390/zcrypt.h	2007-01-29 17:06:31.000000000 +0100
@@ -0,0 +1,276 @@
+/*
+ *  include/asm-s390/zcrypt.h
+ *
+ *  zcrypt 2.1.0 (user-visible header)
+ *
+ *  Copyright (C)  2001, 2006 IBM Corporation
+ *  Author(s): Robert Burroughs
+ *	       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 __ASM_S390_ZCRYPT_H
+#define __ASM_S390_ZCRYPT_H
+
+#define ZCRYPT_VERSION 2
+#define ZCRYPT_RELEASE 1
+#define ZCRYPT_VARIANT 0
+
+#include <linux/ioctl.h>
+#include <linux/compiler.h>
+
+/**
+ * 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 __user *	inputdata;
+	unsigned int	inputdatalength;
+	char __user *	outputdata;
+	unsigned int	outputdatalength;
+	char __user *	b_key;
+	char __user *	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 __user *	inputdata;
+	unsigned int	inputdatalength;
+	char __user *	outputdata;
+	unsigned int	outputdatalength;
+	char __user *	bp_key;
+	char __user *	bq_key;
+	char __user *	np_prime;
+	char __user *	nq_prime;
+	char __user *	u_mult_inv;
+};
+
+/**
+ * CPRBX
+ *	  Note that all shorts and ints are big-endian.
+ *	  All pointer fields are 16 bytes long, and mean nothing.
+ *
+ *	  A request CPRB is followed by a request_parameter_block.
+ *
+ *	  The request (or reply) parameter block is organized thus:
+ *	    function code
+ *	    VUD block
+ *	    key block
+ */
+struct ica_CPRBX {
+	unsigned short	cprb_len;	/* CPRB length	      220	 */
+	unsigned char	cprb_ver_id;	/* CPRB version id.   0x02	 */
+	unsigned char	pad_000[3];	/* Alignment pad bytes		 */
+	unsigned char	func_id[2];	/* function id	      0x5432	 */
+	unsigned char	cprb_flags[4];	/* Flags			 */
+	unsigned int	req_parml;	/* request parameter buffer len	 */
+	unsigned int	req_datal;	/* request data buffer		 */
+	unsigned int	rpl_msgbl;	/* reply  message block length	 */
+	unsigned int	rpld_parml;	/* replied parameter block len	 */
+	unsigned int	rpl_datal;	/* reply data block len		 */
+	unsigned int	rpld_datal;	/* replied data block len	 */
+	unsigned int	req_extbl;	/* request extension block len	 */
+	unsigned char	pad_001[4];	/* reserved			 */
+	unsigned int	rpld_extbl;	/* replied extension block len	 */
+	unsigned char	padx000[16 - sizeof (char *)];
+	unsigned char *	req_parmb;	/* request parm block 'address'	 */
+	unsigned char	padx001[16 - sizeof (char *)];
+	unsigned char *	req_datab;	/* request data block 'address'	 */
+	unsigned char	padx002[16 - sizeof (char *)];
+	unsigned char *	rpl_parmb;	/* reply parm block 'address'	 */
+	unsigned char	padx003[16 - sizeof (char *)];
+	unsigned char *	rpl_datab;	/* reply data block 'address'	 */
+	unsigned char	padx004[16 - sizeof (char *)];
+	unsigned char *	req_extb;	/* request extension block 'addr'*/
+	unsigned char	padx005[16 - sizeof (char *)];
+	unsigned char *	rpl_extb;	/* reply extension block 'addres'*/
+	unsigned short	ccp_rtcode;	/* server return code		 */
+	unsigned short	ccp_rscode;	/* server reason code		 */
+	unsigned int	mac_data_len;	/* Mac Data Length		 */
+	unsigned char	logon_id[8];	/* Logon Identifier		 */
+	unsigned char	mac_value[8];	/* Mac Value			 */
+	unsigned char	mac_content_flgs;/* Mac content flag byte	 */
+	unsigned char	pad_002;	/* Alignment			 */
+	unsigned short	domain;		/* Domain			 */
+	unsigned char	usage_domain[4];/* Usage domain			 */
+	unsigned char	cntrl_domain[4];/* Control domain		 */
+	unsigned char	S390enf_mask[4];/* S/390 enforcement mask	 */
+	unsigned char	pad_004[36];	/* reserved			 */
+};
+
+/**
+ * xcRB
+ */
+struct ica_xcRB {
+	unsigned short	agent_ID;
+	unsigned int	user_defined;
+	unsigned short	request_ID;
+	unsigned int	request_control_blk_length;
+	unsigned char	padding1[16 - sizeof (char *)];
+	char __user *	request_control_blk_addr;
+	unsigned int	request_data_length;
+	char		padding2[16 - sizeof (char *)];
+	char __user *	request_data_address;
+	unsigned int	reply_control_blk_length;
+	char		padding3[16 - sizeof (char *)];
+	char __user *	reply_control_blk_addr;
+	unsigned int	reply_data_length;
+	char		padding4[16 - sizeof (char *)];
+	char __user *	reply_data_addr;
+	unsigned short	priority_window;
+	unsigned int	status;
+} __attribute__((packed));
+#define AUTOSELECT ((unsigned int)0xFFFFFFFF)
+
+#define ZCRYPT_IOCTL_MAGIC 'z'
+
+/**
+ * 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
+ *
+ *   ZSECSENDCPRB
+ *     Send an arbitrary CPRB to a crypto card.
+ *
+ *   Z90STAT_STATUS_MASK
+ *     Return an 64 element array of unsigned chars for the status of
+ *     all devices.
+ *	 0x01: PCICA
+ *	 0x02: PCICC
+ *	 0x03: PCIXCC_MCL2
+ *	 0x04: PCIXCC_MCL3
+ *	 0x05: CEX2C
+ *	 0x06: CEX2A
+ *	 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.
+ *
+ *   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 all
+ *     devices 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.
+ *
+ *   The following ioctls are deprecated and should be no longer used:
+ *
+ *   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_PCIXCCMCL2COUNT
+ *     Return an integer count of all MCL2 PCIXCCs.
+ *
+ *   Z90STAT_PCIXCCMCL3COUNT
+ *     Return an integer count of all MCL3 PCIXCCs.
+ *
+ *   Z90STAT_CEX2CCOUNT
+ *     Return an integer count of all CEX2Cs.
+ *
+ *   Z90STAT_CEX2ACOUNT
+ *     Return an integer count of all CEX2As.
+ *
+ *   ICAZ90STATUS
+ *     Return some device driver status in a ica_z90_status struct
+ *     This takes an ica_z90_status struct as its arg.
+ *
+ *   Z90STAT_PCIXCCCOUNT
+ *     Return an integer count of all PCIXCCs (MCL2 + MCL3).
+ *     This is DEPRECATED now that MCL3 PCIXCCs are treated differently from
+ *     MCL2 PCIXCCs.
+ */
+
+/**
+ * Supported ioctl calls
+ */
+#define ICARSAMODEXPO	_IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x05, 0)
+#define ICARSACRT	_IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x06, 0)
+#define ZSECSENDCPRB	_IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x81, 0)
+
+/* New status calls */
+#define Z90STAT_TOTALCOUNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x40, int)
+#define Z90STAT_PCICACOUNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x41, int)
+#define Z90STAT_PCICCCOUNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x42, int)
+#define Z90STAT_PCIXCCMCL2COUNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x4b, int)
+#define Z90STAT_PCIXCCMCL3COUNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x4c, int)
+#define Z90STAT_CEX2CCOUNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x4d, int)
+#define Z90STAT_CEX2ACOUNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x4e, int)
+#define Z90STAT_REQUESTQ_COUNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x44, int)
+#define Z90STAT_PENDINGQ_COUNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x45, int)
+#define Z90STAT_TOTALOPEN_COUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x46, int)
+#define Z90STAT_DOMAIN_INDEX	_IOR(ZCRYPT_IOCTL_MAGIC, 0x47, int)
+#define Z90STAT_STATUS_MASK	_IOR(ZCRYPT_IOCTL_MAGIC, 0x48, char[64])
+#define Z90STAT_QDEPTH_MASK	_IOR(ZCRYPT_IOCTL_MAGIC, 0x49, char[64])
+#define Z90STAT_PERDEV_REQCNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x4a, int[64])
+
+#endif /* __ASM_S390_ZCRYPT_H */
diff -urNp linux-2.6.18.s390x-remove_z90crypt/include/linux/mod_devicetable.h linux-2.6.18.s390x-add_zcrypt/include/linux/mod_devicetable.h
--- linux-2.6.18.s390x-remove_z90crypt/include/linux/mod_devicetable.h	2006-09-20 05:42:06.000000000 +0200
+++ linux-2.6.18.s390x-add_zcrypt/include/linux/mod_devicetable.h	2007-01-29 17:06:31.000000000 +0100
@@ -148,6 +148,17 @@ struct ccw_device_id {
 #define CCW_DEVICE_ID_MATCH_DEVICE_TYPE		0x04
 #define CCW_DEVICE_ID_MATCH_DEVICE_MODEL	0x08
 
+/* s390 AP bus devices */
+struct ap_device_id {
+	__u16 match_flags;	/* which fields to match against */
+	__u8 dev_type;		/* device type */
+	__u8 pad1;
+	__u32 pad2;
+	kernel_ulong_t driver_info;
+};
+
+#define AP_DEVICE_ID_MATCH_DEVICE_TYPE		0x01
+
 
 #define PNP_ID_LEN	8
 #define PNP_MAX_DEVICES	8
diff -urNp linux-2.6.18.s390x-remove_z90crypt/scripts/mod/file2alias.c linux-2.6.18.s390x-add_zcrypt/scripts/mod/file2alias.c
--- linux-2.6.18.s390x-remove_z90crypt/scripts/mod/file2alias.c	2006-09-20 05:42:06.000000000 +0200
+++ linux-2.6.18.s390x-add_zcrypt/scripts/mod/file2alias.c	2007-01-29 18:10:48.000000000 +0100
@@ -265,6 +265,14 @@ static int do_ccw_entry(const char *file
 	return 1;
 }
 
+/* looks like: "ap:tN" */
+static int do_ap_entry(const char *filename,
+		       struct ap_device_id *id, char *alias)
+{
+	sprintf(alias, "ap:t%02X", id->dev_type);
+	return 1;
+}
+
 /* Looks like: "serio:tyNprNidNexN" */
 static int do_serio_entry(const char *filename,
 			  struct serio_device_id *id, char *alias)
@@ -503,6 +511,9 @@ void handle_moddevtable(struct module *m
 		do_table(symval, sym->st_size,
 			 sizeof(struct ccw_device_id), "ccw",
 			 do_ccw_entry, mod);
+	else if (sym_is(symname, "__mod_ap_device_table"))
+		do_table(symval, sym->st_size, sizeof(struct ap_device_id), "ap",
+			 do_ap_entry, mod);
 	else if (sym_is(symname, "__mod_serio_device_table"))
 		do_table(symval, sym->st_size,
 			 sizeof(struct serio_device_id), "serio",