blob: f7cc43401816d503e33ec3fb75b628c60b9ad400 [file] [log] [blame]
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001/*
2 * linux/drivers/s390/crypto/zcrypt_pcixcc.c
3 *
Ralph Wuerthner54321142006-09-20 15:58:36 +02004 * zcrypt 2.1.0
Martin Schwidefsky6684af12006-09-20 15:58:32 +02005 *
6 * Copyright (C) 2001, 2006 IBM Corporation
7 * Author(s): Robert Burroughs
8 * Eric Rossman (edrossma@us.ibm.com)
9 *
10 * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
11 * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
12 * Ralph Wuerthner <rwuerthn@de.ibm.com>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
17 * any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29#include <linux/module.h>
30#include <linux/init.h>
31#include <linux/err.h>
32#include <linux/delay.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090033#include <linux/slab.h>
Arun Sharma600634972011-07-26 16:09:06 -070034#include <linux/atomic.h>
Martin Schwidefsky6684af12006-09-20 15:58:32 +020035#include <asm/uaccess.h>
36
37#include "ap_bus.h"
38#include "zcrypt_api.h"
39#include "zcrypt_error.h"
40#include "zcrypt_pcicc.h"
41#include "zcrypt_pcixcc.h"
42#include "zcrypt_cca_key.h"
43
44#define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */
45#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
46#define PCIXCC_MAX_MOD_SIZE 256 /* 2048 bits */
Felix Beck8e89b6b2009-12-07 12:51:57 +010047#define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE
Felix Beck2ade1fa2011-01-05 12:47:46 +010048#define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */
Martin Schwidefsky6684af12006-09-20 15:58:32 +020049
Felix Beck18278df2009-12-07 12:51:58 +010050#define PCIXCC_MCL2_SPEED_RATING 7870
Martin Schwidefsky6684af12006-09-20 15:58:32 +020051#define PCIXCC_MCL3_SPEED_RATING 7870
Felix Beck18278df2009-12-07 12:51:58 +010052#define CEX2C_SPEED_RATING 7000
Felix Beck2ade1fa2011-01-05 12:47:46 +010053#define CEX3C_SPEED_RATING 6500
Martin Schwidefsky6684af12006-09-20 15:58:32 +020054
55#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
56#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
57
58#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024)
Martin Schwidefsky6684af12006-09-20 15:58:32 +020059
60#define PCIXCC_CLEANUP_TIME (15*HZ)
61
Ralph Wuerthner54321142006-09-20 15:58:36 +020062#define CEIL4(x) ((((x)+3)/4)*4)
63
64struct response_type {
65 struct completion work;
66 int type;
67};
68#define PCIXCC_RESPONSE_TYPE_ICA 0
69#define PCIXCC_RESPONSE_TYPE_XCRB 1
70
Martin Schwidefsky6684af12006-09-20 15:58:32 +020071static struct ap_device_id zcrypt_pcixcc_ids[] = {
72 { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
73 { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
Felix Beckffda4f72009-12-07 12:51:56 +010074 { AP_DEVICE(AP_DEVICE_TYPE_CEX3C) },
Martin Schwidefsky6684af12006-09-20 15:58:32 +020075 { /* end of list */ },
76};
77
Martin Schwidefsky6684af12006-09-20 15:58:32 +020078MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids);
79MODULE_AUTHOR("IBM Corporation");
80MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, "
81 "Copyright 2001, 2006 IBM Corporation");
82MODULE_LICENSE("GPL");
Martin Schwidefsky6684af12006-09-20 15:58:32 +020083
84static int zcrypt_pcixcc_probe(struct ap_device *ap_dev);
85static void zcrypt_pcixcc_remove(struct ap_device *ap_dev);
86static void zcrypt_pcixcc_receive(struct ap_device *, struct ap_message *,
87 struct ap_message *);
88
89static struct ap_driver zcrypt_pcixcc_driver = {
90 .probe = zcrypt_pcixcc_probe,
91 .remove = zcrypt_pcixcc_remove,
Martin Schwidefsky6684af12006-09-20 15:58:32 +020092 .ids = zcrypt_pcixcc_ids,
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +020093 .request_timeout = PCIXCC_CLEANUP_TIME,
Martin Schwidefsky6684af12006-09-20 15:58:32 +020094};
95
96/**
97 * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
98 * card in a type6 message. The 3 fields that must be filled in at execution
99 * time are req_parml, rpl_parml and usage_domain.
100 * Everything about this interface is ascii/big-endian, since the
101 * device does *not* have 'Intel inside'.
102 *
103 * The CPRBX is followed immediately by the parm block.
104 * The parm block contains:
105 * - function code ('PD' 0x5044 or 'PK' 0x504B)
106 * - rule block (one of:)
107 * + 0x000A 'PKCS-1.2' (MCL2 'PD')
108 * + 0x000A 'ZERO-PAD' (MCL2 'PK')
109 * + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD')
110 * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK')
111 * - VUD block
112 */
113static struct CPRBX static_cprbx = {
114 .cprb_len = 0x00DC,
115 .cprb_ver_id = 0x02,
116 .func_id = {0x54,0x32},
117};
118
119/**
120 * Convert a ICAMEX message to a type6 MEX message.
121 *
122 * @zdev: crypto device pointer
123 * @ap_msg: pointer to AP message
124 * @mex: pointer to user input data
125 *
126 * Returns 0 on success or -EFAULT.
127 */
128static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
129 struct ap_message *ap_msg,
130 struct ica_rsa_modexpo *mex)
131{
132 static struct type6_hdr static_type6_hdrX = {
133 .type = 0x06,
134 .offset1 = 0x00000058,
135 .agent_id = {'C','A',},
136 .function_code = {'P','K'},
137 };
138 static struct function_and_rules_block static_pke_fnr = {
139 .function_code = {'P','K'},
140 .ulen = 10,
141 .only_rule = {'M','R','P',' ',' ',' ',' ',' '}
142 };
143 static struct function_and_rules_block static_pke_fnr_MCL2 = {
144 .function_code = {'P','K'},
145 .ulen = 10,
146 .only_rule = {'Z','E','R','O','-','P','A','D'}
147 };
148 struct {
149 struct type6_hdr hdr;
150 struct CPRBX cprbx;
151 struct function_and_rules_block fr;
152 unsigned short length;
153 char text[0];
154 } __attribute__((packed)) *msg = ap_msg->message;
155 int size;
156
157 /* VUD.ciphertext */
158 msg->length = mex->inputdatalength + 2;
159 if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
160 return -EFAULT;
161
162 /* Set up key which is located after the variable length text. */
163 size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1);
164 if (size < 0)
165 return size;
166 size += sizeof(*msg) + mex->inputdatalength;
167
168 /* message header, cprbx and f&r */
169 msg->hdr = static_type6_hdrX;
170 msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
171 msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
172
173 msg->cprbx = static_cprbx;
174 msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
175 msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1;
176
177 msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
178 static_pke_fnr_MCL2 : static_pke_fnr;
179
180 msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx);
181
182 ap_msg->length = size;
183 return 0;
184}
185
186/**
187 * Convert a ICACRT message to a type6 CRT message.
188 *
189 * @zdev: crypto device pointer
190 * @ap_msg: pointer to AP message
191 * @crt: pointer to user input data
192 *
193 * Returns 0 on success or -EFAULT.
194 */
195static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
196 struct ap_message *ap_msg,
197 struct ica_rsa_modexpo_crt *crt)
198{
199 static struct type6_hdr static_type6_hdrX = {
200 .type = 0x06,
201 .offset1 = 0x00000058,
202 .agent_id = {'C','A',},
203 .function_code = {'P','D'},
204 };
205 static struct function_and_rules_block static_pkd_fnr = {
206 .function_code = {'P','D'},
207 .ulen = 10,
208 .only_rule = {'Z','E','R','O','-','P','A','D'}
209 };
210
211 static struct function_and_rules_block static_pkd_fnr_MCL2 = {
212 .function_code = {'P','D'},
213 .ulen = 10,
214 .only_rule = {'P','K','C','S','-','1','.','2'}
215 };
216 struct {
217 struct type6_hdr hdr;
218 struct CPRBX cprbx;
219 struct function_and_rules_block fr;
220 unsigned short length;
221 char text[0];
222 } __attribute__((packed)) *msg = ap_msg->message;
223 int size;
224
225 /* VUD.ciphertext */
226 msg->length = crt->inputdatalength + 2;
227 if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
228 return -EFAULT;
229
230 /* Set up key which is located after the variable length text. */
231 size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1);
232 if (size < 0)
233 return size;
234 size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */
235
236 /* message header, cprbx and f&r */
237 msg->hdr = static_type6_hdrX;
238 msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
239 msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
240
241 msg->cprbx = static_cprbx;
242 msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
243 msg->cprbx.req_parml = msg->cprbx.rpl_msgbl =
244 size - sizeof(msg->hdr) - sizeof(msg->cprbx);
245
246 msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
247 static_pkd_fnr_MCL2 : static_pkd_fnr;
248
249 ap_msg->length = size;
250 return 0;
251}
252
253/**
Ralph Wuerthner54321142006-09-20 15:58:36 +0200254 * Convert a XCRB message to a type6 CPRB message.
255 *
256 * @zdev: crypto device pointer
257 * @ap_msg: pointer to AP message
258 * @xcRB: pointer to user input data
259 *
Holger Dengler2389aef2011-12-27 11:27:20 +0100260 * Returns 0 on success or -EFAULT, -EINVAL.
Ralph Wuerthner54321142006-09-20 15:58:36 +0200261 */
262struct type86_fmt2_msg {
263 struct type86_hdr hdr;
264 struct type86_fmt2_ext fmt2;
265} __attribute__((packed));
266
267static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
268 struct ap_message *ap_msg,
269 struct ica_xcRB *xcRB)
270{
271 static struct type6_hdr static_type6_hdrX = {
272 .type = 0x06,
273 .offset1 = 0x00000058,
274 };
275 struct {
276 struct type6_hdr hdr;
Ralph Wuerthner16db63f2007-10-12 16:11:28 +0200277 struct CPRBX cprbx;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200278 } __attribute__((packed)) *msg = ap_msg->message;
279
280 int rcblen = CEIL4(xcRB->request_control_blk_length);
281 int replylen;
282 char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
283 char *function_code;
284
285 /* length checks */
286 ap_msg->length = sizeof(struct type6_hdr) +
287 CEIL4(xcRB->request_control_blk_length) +
288 xcRB->request_data_length;
Felix Beck1a89dd82008-07-14 09:59:27 +0200289 if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE)
Holger Dengler2389aef2011-12-27 11:27:20 +0100290 return -EINVAL;
Holger Dengler7fe6f092011-12-27 11:27:19 +0100291 replylen = sizeof(struct type86_fmt2_msg) +
292 CEIL4(xcRB->reply_control_blk_length) +
293 xcRB->reply_data_length;
294 if (replylen > PCIXCC_MAX_XCRB_MESSAGE_SIZE)
Holger Dengler2389aef2011-12-27 11:27:20 +0100295 return -EINVAL;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200296
297 /* prepare type6 header */
298 msg->hdr = static_type6_hdrX;
299 memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
300 msg->hdr.ToCardLen1 = xcRB->request_control_blk_length;
301 if (xcRB->request_data_length) {
302 msg->hdr.offset2 = msg->hdr.offset1 + rcblen;
303 msg->hdr.ToCardLen2 = xcRB->request_data_length;
304 }
305 msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length;
306 msg->hdr.FromCardLen2 = xcRB->reply_data_length;
307
308 /* prepare CPRB */
309 if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr,
310 xcRB->request_control_blk_length))
311 return -EFAULT;
312 if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
Felix Beck1a89dd82008-07-14 09:59:27 +0200313 xcRB->request_control_blk_length)
Holger Dengler2389aef2011-12-27 11:27:20 +0100314 return -EINVAL;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200315 function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
316 memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
317
Felix Becka6a5d732009-12-07 12:51:55 +0100318 if (memcmp(function_code, "US", 2) == 0)
319 ap_msg->special = 1;
320 else
321 ap_msg->special = 0;
322
Ralph Wuerthner54321142006-09-20 15:58:36 +0200323 /* copy data block */
324 if (xcRB->request_data_length &&
325 copy_from_user(req_data, xcRB->request_data_address,
326 xcRB->request_data_length))
327 return -EFAULT;
328 return 0;
329}
330
331/**
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200332 * Prepare a type6 CPRB message for random number generation
333 *
334 * @ap_dev: AP device pointer
335 * @ap_msg: pointer to AP message
336 */
337static void rng_type6CPRB_msgX(struct ap_device *ap_dev,
338 struct ap_message *ap_msg,
339 unsigned random_number_length)
340{
341 struct {
342 struct type6_hdr hdr;
343 struct CPRBX cprbx;
344 char function_code[2];
345 short int rule_length;
346 char rule[8];
347 short int verb_length;
348 short int key_length;
349 } __attribute__((packed)) *msg = ap_msg->message;
350 static struct type6_hdr static_type6_hdrX = {
351 .type = 0x06,
352 .offset1 = 0x00000058,
353 .agent_id = {'C', 'A'},
354 .function_code = {'R', 'L'},
355 .ToCardLen1 = sizeof *msg - sizeof(msg->hdr),
356 .FromCardLen1 = sizeof *msg - sizeof(msg->hdr),
357 };
Felix Beck6458abc2009-10-06 10:34:09 +0200358 static struct CPRBX local_cprbx = {
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200359 .cprb_len = 0x00dc,
360 .cprb_ver_id = 0x02,
361 .func_id = {0x54, 0x32},
362 .req_parml = sizeof *msg - sizeof(msg->hdr) -
363 sizeof(msg->cprbx),
364 .rpl_msgbl = sizeof *msg - sizeof(msg->hdr),
365 };
366
367 msg->hdr = static_type6_hdrX;
368 msg->hdr.FromCardLen2 = random_number_length,
Felix Beck6458abc2009-10-06 10:34:09 +0200369 msg->cprbx = local_cprbx;
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200370 msg->cprbx.rpl_datal = random_number_length,
371 msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid);
372 memcpy(msg->function_code, msg->hdr.function_code, 0x02);
373 msg->rule_length = 0x0a;
374 memcpy(msg->rule, "RANDOM ", 8);
375 msg->verb_length = 0x02;
376 msg->key_length = 0x02;
377 ap_msg->length = sizeof *msg;
378}
379
380/**
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200381 * Copy results from a type 86 ICA reply message back to user space.
382 *
383 * @zdev: crypto device pointer
384 * @reply: reply AP message.
385 * @data: pointer to user output data
386 * @length: size of user output data
387 *
388 * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
389 */
390struct type86x_reply {
391 struct type86_hdr hdr;
392 struct type86_fmt2_ext fmt2;
393 struct CPRBX cprbx;
394 unsigned char pad[4]; /* 4 byte function code/rules block ? */
395 unsigned short length;
396 char text[0];
397} __attribute__((packed));
398
399static int convert_type86_ica(struct zcrypt_device *zdev,
400 struct ap_message *reply,
401 char __user *outputdata,
402 unsigned int outputdatalength)
403{
404 static unsigned char static_pad[] = {
405 0x00,0x02,
406 0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,
407 0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
408 0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,
409 0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
410 0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,
411 0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
412 0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,
413 0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
414 0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,
415 0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
416 0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,
417 0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
418 0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,
419 0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
420 0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,
421 0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
422 0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,
423 0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
424 0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,
425 0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
426 0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,
427 0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
428 0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,
429 0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
430 0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,
431 0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
432 0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,
433 0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
434 0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,
435 0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
436 0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,
437 0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
438 };
439 struct type86x_reply *msg = reply->message;
440 unsigned short service_rc, service_rs;
441 unsigned int reply_len, pad_len;
442 char *data;
443
444 service_rc = msg->cprbx.ccp_rtcode;
445 if (unlikely(service_rc != 0)) {
446 service_rs = msg->cprbx.ccp_rscode;
Felix Beck1a89dd82008-07-14 09:59:27 +0200447 if (service_rc == 8 && service_rs == 66)
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200448 return -EINVAL;
Felix Beck1a89dd82008-07-14 09:59:27 +0200449 if (service_rc == 8 && service_rs == 65)
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200450 return -EINVAL;
Felix Beck1a89dd82008-07-14 09:59:27 +0200451 if (service_rc == 8 && service_rs == 770)
Ralph Wuerthner2af48082007-10-12 16:11:30 +0200452 return -EINVAL;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200453 if (service_rc == 8 && service_rs == 783) {
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200454 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
455 return -EAGAIN;
456 }
Felix Beck1a89dd82008-07-14 09:59:27 +0200457 if (service_rc == 12 && service_rs == 769)
Ralph Wuerthner2af48082007-10-12 16:11:30 +0200458 return -EINVAL;
Felix Beck19b123e2010-01-27 10:12:39 +0100459 if (service_rc == 8 && service_rs == 72)
460 return -EINVAL;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200461 zdev->online = 0;
462 return -EAGAIN; /* repeat the request on a different device. */
463 }
464 data = msg->text;
465 reply_len = msg->length - 2;
466 if (reply_len > outputdatalength)
467 return -EINVAL;
Felix Beck1749a812008-04-17 07:46:28 +0200468 /*
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200469 * For all encipher requests, the length of the ciphertext (reply_len)
470 * will always equal the modulus length. For MEX decipher requests
471 * the output needs to get padded. Minimum pad size is 10.
472 *
473 * Currently, the cases where padding will be added is for:
474 * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
475 * ZERO-PAD and CRT is only supported for PKD requests)
476 * - PCICC, always
477 */
478 pad_len = outputdatalength - reply_len;
479 if (pad_len > 0) {
480 if (pad_len < 10)
481 return -EINVAL;
482 /* 'restore' padding left in the PCICC/PCIXCC card. */
483 if (copy_to_user(outputdata, static_pad, pad_len - 1))
484 return -EFAULT;
485 if (put_user(0, outputdata + pad_len - 1))
486 return -EFAULT;
487 }
488 /* Copy the crypto response to user space. */
489 if (copy_to_user(outputdata + pad_len, data, reply_len))
490 return -EFAULT;
491 return 0;
492}
493
Ralph Wuerthner54321142006-09-20 15:58:36 +0200494/**
495 * Copy results from a type 86 XCRB reply message back to user space.
496 *
497 * @zdev: crypto device pointer
498 * @reply: reply AP message.
499 * @xcRB: pointer to XCRB
500 *
501 * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
502 */
503static int convert_type86_xcrb(struct zcrypt_device *zdev,
504 struct ap_message *reply,
505 struct ica_xcRB *xcRB)
506{
507 struct type86_fmt2_msg *msg = reply->message;
508 char *data = reply->message;
509
510 /* Copy CPRB to user */
511 if (copy_to_user(xcRB->reply_control_blk_addr,
512 data + msg->fmt2.offset1, msg->fmt2.count1))
513 return -EFAULT;
514 xcRB->reply_control_blk_length = msg->fmt2.count1;
515
516 /* Copy data buffer to user */
517 if (msg->fmt2.count2)
518 if (copy_to_user(xcRB->reply_data_addr,
519 data + msg->fmt2.offset2, msg->fmt2.count2))
520 return -EFAULT;
521 xcRB->reply_data_length = msg->fmt2.count2;
522 return 0;
523}
524
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200525static int convert_type86_rng(struct zcrypt_device *zdev,
526 struct ap_message *reply,
527 char *buffer)
528{
529 struct {
530 struct type86_hdr hdr;
531 struct type86_fmt2_ext fmt2;
532 struct CPRBX cprbx;
533 } __attribute__((packed)) *msg = reply->message;
534 char *data = reply->message;
535
Felix Beck1a89dd82008-07-14 09:59:27 +0200536 if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0)
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200537 return -EINVAL;
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200538 memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2);
539 return msg->fmt2.count2;
540}
541
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200542static int convert_response_ica(struct zcrypt_device *zdev,
543 struct ap_message *reply,
544 char __user *outputdata,
545 unsigned int outputdatalength)
546{
547 struct type86x_reply *msg = reply->message;
548
549 /* Response type byte is the second byte in the response. */
550 switch (((unsigned char *) reply->message)[1]) {
551 case TYPE82_RSP_CODE:
552 case TYPE88_RSP_CODE:
553 return convert_error(zdev, reply);
554 case TYPE86_RSP_CODE:
Felix Beckc2567f82011-01-05 12:47:47 +0100555 if (msg->cprbx.ccp_rtcode &&
556 (msg->cprbx.ccp_rscode == 0x14f) &&
557 (outputdatalength > 256)) {
558 if (zdev->max_exp_bit_length <= 17) {
559 zdev->max_exp_bit_length = 17;
560 return -EAGAIN;
561 } else
562 return -EINVAL;
563 }
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200564 if (msg->hdr.reply_code)
565 return convert_error(zdev, reply);
566 if (msg->cprbx.cprb_ver_id == 0x02)
567 return convert_type86_ica(zdev, reply,
568 outputdata, outputdatalength);
Felix Beck942b7e62009-10-06 10:34:10 +0200569 /* Fall through, no break, incorrect cprb version is an unknown
570 * response */
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200571 default: /* Unknown response type, this should NEVER EVER happen */
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200572 zdev->online = 0;
573 return -EAGAIN; /* repeat the request on a different device. */
574 }
575}
576
Ralph Wuerthner54321142006-09-20 15:58:36 +0200577static int convert_response_xcrb(struct zcrypt_device *zdev,
578 struct ap_message *reply,
579 struct ica_xcRB *xcRB)
580{
581 struct type86x_reply *msg = reply->message;
582
583 /* Response type byte is the second byte in the response. */
584 switch (((unsigned char *) reply->message)[1]) {
585 case TYPE82_RSP_CODE:
586 case TYPE88_RSP_CODE:
587 xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
588 return convert_error(zdev, reply);
589 case TYPE86_RSP_CODE:
590 if (msg->hdr.reply_code) {
591 memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32));
592 return convert_error(zdev, reply);
593 }
594 if (msg->cprbx.cprb_ver_id == 0x02)
595 return convert_type86_xcrb(zdev, reply, xcRB);
Felix Beck942b7e62009-10-06 10:34:10 +0200596 /* Fall through, no break, incorrect cprb version is an unknown
597 * response */
Ralph Wuerthner54321142006-09-20 15:58:36 +0200598 default: /* Unknown response type, this should NEVER EVER happen */
Ralph Wuerthner54321142006-09-20 15:58:36 +0200599 xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
600 zdev->online = 0;
601 return -EAGAIN; /* repeat the request on a different device. */
602 }
603}
604
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200605static int convert_response_rng(struct zcrypt_device *zdev,
606 struct ap_message *reply,
607 char *data)
608{
609 struct type86x_reply *msg = reply->message;
610
611 switch (msg->hdr.type) {
612 case TYPE82_RSP_CODE:
613 case TYPE88_RSP_CODE:
614 return -EINVAL;
615 case TYPE86_RSP_CODE:
616 if (msg->hdr.reply_code)
617 return -EINVAL;
618 if (msg->cprbx.cprb_ver_id == 0x02)
619 return convert_type86_rng(zdev, reply, data);
Felix Beck942b7e62009-10-06 10:34:10 +0200620 /* Fall through, no break, incorrect cprb version is an unknown
621 * response */
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200622 default: /* Unknown response type, this should NEVER EVER happen */
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200623 zdev->online = 0;
624 return -EAGAIN; /* repeat the request on a different device. */
625 }
626}
627
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200628/**
629 * This function is called from the AP bus code after a crypto request
630 * "msg" has finished with the reply message "reply".
631 * It is called from tasklet context.
632 * @ap_dev: pointer to the AP device
633 * @msg: pointer to the AP message
634 * @reply: pointer to the AP reply message
635 */
636static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,
637 struct ap_message *msg,
638 struct ap_message *reply)
639{
640 static struct error_hdr error_reply = {
641 .type = TYPE82_RSP_CODE,
642 .reply_code = REP82_ERROR_MACHINE_FAILURE,
643 };
Ralph Wuerthner54321142006-09-20 15:58:36 +0200644 struct response_type *resp_type =
645 (struct response_type *) msg->private;
Julia Lawall21e7b2c2008-12-25 13:39:28 +0100646 struct type86x_reply *t86r;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200647 int length;
648
649 /* Copy the reply message to the request message buffer. */
Julia Lawall21e7b2c2008-12-25 13:39:28 +0100650 if (IS_ERR(reply)) {
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200651 memcpy(msg->message, &error_reply, sizeof(error_reply));
Julia Lawall21e7b2c2008-12-25 13:39:28 +0100652 goto out;
653 }
654 t86r = reply->message;
655 if (t86r->hdr.type == TYPE86_RSP_CODE &&
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200656 t86r->cprbx.cprb_ver_id == 0x02) {
Ralph Wuerthner54321142006-09-20 15:58:36 +0200657 switch (resp_type->type) {
658 case PCIXCC_RESPONSE_TYPE_ICA:
659 length = sizeof(struct type86x_reply)
660 + t86r->length - 2;
661 length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
662 memcpy(msg->message, reply->message, length);
663 break;
664 case PCIXCC_RESPONSE_TYPE_XCRB:
665 length = t86r->fmt2.offset2 + t86r->fmt2.count2;
Holger Dengler7fe6f092011-12-27 11:27:19 +0100666 length = min(PCIXCC_MAX_XCRB_MESSAGE_SIZE, length);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200667 memcpy(msg->message, reply->message, length);
668 break;
669 default:
Felix Beck1a89dd82008-07-14 09:59:27 +0200670 memcpy(msg->message, &error_reply, sizeof error_reply);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200671 }
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200672 } else
673 memcpy(msg->message, reply->message, sizeof error_reply);
Julia Lawall21e7b2c2008-12-25 13:39:28 +0100674out:
Ralph Wuerthner54321142006-09-20 15:58:36 +0200675 complete(&(resp_type->work));
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200676}
677
678static atomic_t zcrypt_step = ATOMIC_INIT(0);
679
680/**
681 * The request distributor calls this function if it picked the PCIXCC/CEX2C
682 * device to handle a modexpo request.
683 * @zdev: pointer to zcrypt_device structure that identifies the
684 * PCIXCC/CEX2C device to the request distributor
685 * @mex: pointer to the modexpo request buffer
686 */
687static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,
688 struct ica_rsa_modexpo *mex)
689{
690 struct ap_message ap_msg;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200691 struct response_type resp_type = {
692 .type = PCIXCC_RESPONSE_TYPE_ICA,
693 };
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200694 int rc;
695
Felix Beck468ffdd2009-12-07 12:51:54 +0100696 ap_init_message(&ap_msg);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200697 ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
698 if (!ap_msg.message)
699 return -ENOMEM;
Holger Dengler54a8f562012-05-16 14:08:22 +0200700 ap_msg.receive = zcrypt_pcixcc_receive;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200701 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
702 atomic_inc_return(&zcrypt_step);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200703 ap_msg.private = &resp_type;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200704 rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
705 if (rc)
706 goto out_free;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200707 init_completion(&resp_type.work);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200708 ap_queue_message(zdev->ap_dev, &ap_msg);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200709 rc = wait_for_completion_interruptible(&resp_type.work);
710 if (rc == 0)
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200711 rc = convert_response_ica(zdev, &ap_msg, mex->outputdata,
712 mex->outputdatalength);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200713 else
714 /* Signal pending. */
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200715 ap_cancel_message(zdev->ap_dev, &ap_msg);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200716out_free:
717 free_page((unsigned long) ap_msg.message);
718 return rc;
719}
720
721/**
722 * The request distributor calls this function if it picked the PCIXCC/CEX2C
723 * device to handle a modexpo_crt request.
724 * @zdev: pointer to zcrypt_device structure that identifies the
725 * PCIXCC/CEX2C device to the request distributor
726 * @crt: pointer to the modexpoc_crt request buffer
727 */
728static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,
729 struct ica_rsa_modexpo_crt *crt)
730{
731 struct ap_message ap_msg;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200732 struct response_type resp_type = {
733 .type = PCIXCC_RESPONSE_TYPE_ICA,
734 };
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200735 int rc;
736
Felix Beck468ffdd2009-12-07 12:51:54 +0100737 ap_init_message(&ap_msg);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200738 ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
739 if (!ap_msg.message)
740 return -ENOMEM;
Holger Dengler54a8f562012-05-16 14:08:22 +0200741 ap_msg.receive = zcrypt_pcixcc_receive;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200742 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
743 atomic_inc_return(&zcrypt_step);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200744 ap_msg.private = &resp_type;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200745 rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
746 if (rc)
747 goto out_free;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200748 init_completion(&resp_type.work);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200749 ap_queue_message(zdev->ap_dev, &ap_msg);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200750 rc = wait_for_completion_interruptible(&resp_type.work);
751 if (rc == 0)
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200752 rc = convert_response_ica(zdev, &ap_msg, crt->outputdata,
753 crt->outputdatalength);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200754 else
755 /* Signal pending. */
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200756 ap_cancel_message(zdev->ap_dev, &ap_msg);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200757out_free:
758 free_page((unsigned long) ap_msg.message);
759 return rc;
760}
761
762/**
Ralph Wuerthner54321142006-09-20 15:58:36 +0200763 * The request distributor calls this function if it picked the PCIXCC/CEX2C
764 * device to handle a send_cprb request.
765 * @zdev: pointer to zcrypt_device structure that identifies the
766 * PCIXCC/CEX2C device to the request distributor
767 * @xcRB: pointer to the send_cprb request buffer
768 */
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100769static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,
770 struct ica_xcRB *xcRB)
Ralph Wuerthner54321142006-09-20 15:58:36 +0200771{
772 struct ap_message ap_msg;
773 struct response_type resp_type = {
774 .type = PCIXCC_RESPONSE_TYPE_XCRB,
775 };
776 int rc;
777
Felix Beck468ffdd2009-12-07 12:51:54 +0100778 ap_init_message(&ap_msg);
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800779 ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200780 if (!ap_msg.message)
781 return -ENOMEM;
Holger Dengler54a8f562012-05-16 14:08:22 +0200782 ap_msg.receive = zcrypt_pcixcc_receive;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200783 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
784 atomic_inc_return(&zcrypt_step);
785 ap_msg.private = &resp_type;
786 rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB);
787 if (rc)
788 goto out_free;
789 init_completion(&resp_type.work);
790 ap_queue_message(zdev->ap_dev, &ap_msg);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200791 rc = wait_for_completion_interruptible(&resp_type.work);
792 if (rc == 0)
Ralph Wuerthner54321142006-09-20 15:58:36 +0200793 rc = convert_response_xcrb(zdev, &ap_msg, xcRB);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200794 else
795 /* Signal pending. */
Ralph Wuerthner54321142006-09-20 15:58:36 +0200796 ap_cancel_message(zdev->ap_dev, &ap_msg);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200797out_free:
Johannes Weiner3e75a902009-03-26 15:24:48 +0100798 kzfree(ap_msg.message);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200799 return rc;
800}
801
802/**
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200803 * The request distributor calls this function if it picked the PCIXCC/CEX2C
804 * device to generate random data.
805 * @zdev: pointer to zcrypt_device structure that identifies the
806 * PCIXCC/CEX2C device to the request distributor
807 * @buffer: pointer to a memory page to return random data
808 */
809
810static long zcrypt_pcixcc_rng(struct zcrypt_device *zdev,
811 char *buffer)
812{
813 struct ap_message ap_msg;
814 struct response_type resp_type = {
815 .type = PCIXCC_RESPONSE_TYPE_XCRB,
816 };
817 int rc;
818
Felix Beck468ffdd2009-12-07 12:51:54 +0100819 ap_init_message(&ap_msg);
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200820 ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
821 if (!ap_msg.message)
822 return -ENOMEM;
Holger Dengler54a8f562012-05-16 14:08:22 +0200823 ap_msg.receive = zcrypt_pcixcc_receive;
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200824 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
825 atomic_inc_return(&zcrypt_step);
826 ap_msg.private = &resp_type;
827 rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE);
828 init_completion(&resp_type.work);
829 ap_queue_message(zdev->ap_dev, &ap_msg);
830 rc = wait_for_completion_interruptible(&resp_type.work);
831 if (rc == 0)
832 rc = convert_response_rng(zdev, &ap_msg, buffer);
833 else
834 /* Signal pending. */
835 ap_cancel_message(zdev->ap_dev, &ap_msg);
836 kfree(ap_msg.message);
837 return rc;
838}
839
840/**
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200841 * The crypto operations for a PCIXCC/CEX2C card.
842 */
843static struct zcrypt_ops zcrypt_pcixcc_ops = {
844 .rsa_modexpo = zcrypt_pcixcc_modexpo,
845 .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt,
Ralph Wuerthner54321142006-09-20 15:58:36 +0200846 .send_cprb = zcrypt_pcixcc_send_cprb,
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200847};
848
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200849static struct zcrypt_ops zcrypt_pcixcc_with_rng_ops = {
850 .rsa_modexpo = zcrypt_pcixcc_modexpo,
851 .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt,
852 .send_cprb = zcrypt_pcixcc_send_cprb,
853 .rng = zcrypt_pcixcc_rng,
854};
855
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200856/**
857 * Micro-code detection function. Its sends a message to a pcixcc card
858 * to find out the microcode level.
859 * @ap_dev: pointer to the AP device.
860 */
861static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev)
862{
863 static unsigned char msg[] = {
864 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
865 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
866 0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
867 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
868 0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
869 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
870 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,
871 0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
872 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
873 0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
874 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
875 0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
876 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,
877 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
878 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
879 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
880 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
881 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
882 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
883 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
884 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
885 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
886 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
887 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
888 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
889 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
890 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
891 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
892 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
893 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
894 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
895 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
896 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
897 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
898 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
899 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
900 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
901 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
902 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,
903 0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
904 0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,
905 0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
906 0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,
907 0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
908 0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,
909 0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
910 0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,
911 0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
912 0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,
913 0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
914 0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,
915 0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
916 0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,
917 0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
918 0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,
919 0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
920 0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,
921 0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
922 0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,
923 0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
924 0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,
925 0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
926 0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,
927 0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
928 0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,
929 0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
930 0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,
931 0xF1,0x3D,0x93,0x53
932 };
933 unsigned long long psmid;
934 struct CPRBX *cprbx;
935 char *reply;
936 int rc, i;
937
938 reply = (void *) get_zeroed_page(GFP_KERNEL);
939 if (!reply)
940 return -ENOMEM;
941
942 rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, msg, sizeof(msg));
943 if (rc)
944 goto out_free;
945
946 /* Wait for the test message to complete. */
947 for (i = 0; i < 6; i++) {
948 mdelay(300);
949 rc = ap_recv(ap_dev->qid, &psmid, reply, 4096);
950 if (rc == 0 && psmid == 0x0102030405060708ULL)
951 break;
952 }
953
954 if (i >= 6) {
955 /* Got no answer. */
956 rc = -ENODEV;
957 goto out_free;
958 }
959
960 cprbx = (struct CPRBX *) (reply + 48);
961 if (cprbx->ccp_rtcode == 8 && cprbx->ccp_rscode == 33)
962 rc = ZCRYPT_PCIXCC_MCL2;
963 else
964 rc = ZCRYPT_PCIXCC_MCL3;
965out_free:
966 free_page((unsigned long) reply);
967 return rc;
968}
969
970/**
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200971 * Large random number detection function. Its sends a message to a pcixcc
972 * card to find out if large random numbers are supported.
973 * @ap_dev: pointer to the AP device.
974 *
975 * Returns 1 if large random numbers are supported, 0 if not and < 0 on error.
976 */
977static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
978{
979 struct ap_message ap_msg;
980 unsigned long long psmid;
981 struct {
982 struct type86_hdr hdr;
983 struct type86_fmt2_ext fmt2;
984 struct CPRBX cprbx;
985 } __attribute__((packed)) *reply;
986 int rc, i;
987
Felix Beck468ffdd2009-12-07 12:51:54 +0100988 ap_init_message(&ap_msg);
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200989 ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
990 if (!ap_msg.message)
991 return -ENOMEM;
992
993 rng_type6CPRB_msgX(ap_dev, &ap_msg, 4);
994 rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message,
995 ap_msg.length);
996 if (rc)
997 goto out_free;
998
999 /* Wait for the test message to complete. */
1000 for (i = 0; i < 2 * HZ; i++) {
1001 msleep(1000 / HZ);
1002 rc = ap_recv(ap_dev->qid, &psmid, ap_msg.message, 4096);
1003 if (rc == 0 && psmid == 0x0102030405060708ULL)
1004 break;
1005 }
1006
1007 if (i >= 2 * HZ) {
1008 /* Got no answer. */
1009 rc = -ENODEV;
1010 goto out_free;
1011 }
1012
1013 reply = ap_msg.message;
1014 if (reply->cprbx.ccp_rtcode == 0 && reply->cprbx.ccp_rscode == 0)
1015 rc = 1;
1016 else
1017 rc = 0;
1018out_free:
1019 free_page((unsigned long) ap_msg.message);
1020 return rc;
1021}
1022
1023/**
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001024 * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device
1025 * since the bus_match already checked the hardware type. The PCIXCC
1026 * cards come in two flavours: micro code level 2 and micro code level 3.
1027 * This is checked by sending a test message to the device.
1028 * @ap_dev: pointer to the AP device.
1029 */
1030static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
1031{
1032 struct zcrypt_device *zdev;
Felix Beck8e89b6b2009-12-07 12:51:57 +01001033 int rc = 0;
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001034
Holger Dengler7fe6f092011-12-27 11:27:19 +01001035 zdev = zcrypt_device_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE);
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001036 if (!zdev)
1037 return -ENOMEM;
1038 zdev->ap_dev = ap_dev;
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001039 zdev->online = 1;
Felix Beck8e89b6b2009-12-07 12:51:57 +01001040 switch (ap_dev->device_type) {
1041 case AP_DEVICE_TYPE_PCIXCC:
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001042 rc = zcrypt_pcixcc_mcl(ap_dev);
1043 if (rc < 0) {
1044 zcrypt_device_free(zdev);
1045 return rc;
1046 }
1047 zdev->user_space_type = rc;
1048 if (rc == ZCRYPT_PCIXCC_MCL2) {
1049 zdev->type_string = "PCIXCC_MCL2";
1050 zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING;
1051 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
1052 zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
Felix Beckc2567f82011-01-05 12:47:47 +01001053 zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001054 } else {
1055 zdev->type_string = "PCIXCC_MCL3";
1056 zdev->speed_rating = PCIXCC_MCL3_SPEED_RATING;
1057 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
1058 zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
Felix Beckc2567f82011-01-05 12:47:47 +01001059 zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001060 }
Felix Beck8e89b6b2009-12-07 12:51:57 +01001061 break;
1062 case AP_DEVICE_TYPE_CEX2C:
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001063 zdev->user_space_type = ZCRYPT_CEX2C;
1064 zdev->type_string = "CEX2C";
1065 zdev->speed_rating = CEX2C_SPEED_RATING;
1066 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
1067 zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
Felix Beckc2567f82011-01-05 12:47:47 +01001068 zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
Felix Beck8e89b6b2009-12-07 12:51:57 +01001069 break;
1070 case AP_DEVICE_TYPE_CEX3C:
1071 zdev->user_space_type = ZCRYPT_CEX3C;
1072 zdev->type_string = "CEX3C";
1073 zdev->speed_rating = CEX3C_SPEED_RATING;
1074 zdev->min_mod_size = CEX3C_MIN_MOD_SIZE;
1075 zdev->max_mod_size = CEX3C_MAX_MOD_SIZE;
Felix Beckc2567f82011-01-05 12:47:47 +01001076 zdev->max_exp_bit_length = CEX3C_MAX_MOD_SIZE;
Felix Beck8e89b6b2009-12-07 12:51:57 +01001077 break;
1078 default:
1079 goto out_free;
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001080 }
Felix Beck8e89b6b2009-12-07 12:51:57 +01001081
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +02001082 rc = zcrypt_pcixcc_rng_supported(ap_dev);
1083 if (rc < 0) {
1084 zcrypt_device_free(zdev);
1085 return rc;
1086 }
1087 if (rc)
1088 zdev->ops = &zcrypt_pcixcc_with_rng_ops;
1089 else
1090 zdev->ops = &zcrypt_pcixcc_ops;
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001091 ap_dev->reply = &zdev->reply;
1092 ap_dev->private = zdev;
1093 rc = zcrypt_device_register(zdev);
1094 if (rc)
1095 goto out_free;
1096 return 0;
1097
1098 out_free:
1099 ap_dev->private = NULL;
1100 zcrypt_device_free(zdev);
1101 return rc;
1102}
1103
1104/**
1105 * This is called to remove the extended PCIXCC/CEX2C driver information
1106 * if an AP device is removed.
1107 */
1108static void zcrypt_pcixcc_remove(struct ap_device *ap_dev)
1109{
1110 struct zcrypt_device *zdev = ap_dev->private;
1111
1112 zcrypt_device_unregister(zdev);
1113}
1114
1115int __init zcrypt_pcixcc_init(void)
1116{
1117 return ap_driver_register(&zcrypt_pcixcc_driver, THIS_MODULE, "pcixcc");
1118}
1119
1120void zcrypt_pcixcc_exit(void)
1121{
1122 ap_driver_unregister(&zcrypt_pcixcc_driver);
1123}
1124
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001125module_init(zcrypt_pcixcc_init);
1126module_exit(zcrypt_pcixcc_exit);