blob: 68f3e6204db87079d5c1f49e700a1309026d3624 [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>
33#include <asm/atomic.h>
34#include <asm/uaccess.h>
35
36#include "ap_bus.h"
37#include "zcrypt_api.h"
38#include "zcrypt_error.h"
39#include "zcrypt_pcicc.h"
40#include "zcrypt_pcixcc.h"
41#include "zcrypt_cca_key.h"
42
43#define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */
44#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
45#define PCIXCC_MAX_MOD_SIZE 256 /* 2048 bits */
Felix Beck8e89b6b2009-12-07 12:51:57 +010046#define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE
47#define CEX3C_MAX_MOD_SIZE PCIXCC_MAX_MOD_SIZE
Martin Schwidefsky6684af12006-09-20 15:58:32 +020048
Felix Beck18278df2009-12-07 12:51:58 +010049#define PCIXCC_MCL2_SPEED_RATING 7870
Martin Schwidefsky6684af12006-09-20 15:58:32 +020050#define PCIXCC_MCL3_SPEED_RATING 7870
Felix Beck18278df2009-12-07 12:51:58 +010051#define CEX2C_SPEED_RATING 7000
Felix Beck7a6f5cd2009-12-07 12:51:59 +010052#define CEX3C_SPEED_RATING 6500 /* FIXME: needs finetuning */
Martin Schwidefsky6684af12006-09-20 15:58:32 +020053
54#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
55#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
56
57#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024)
58#define PCIXCC_MAX_XCRB_RESPONSE_SIZE PCIXCC_MAX_XCRB_MESSAGE_SIZE
59#define PCIXCC_MAX_XCRB_DATA_SIZE (11*1024)
60#define PCIXCC_MAX_XCRB_REPLY_SIZE (5*1024)
61
62#define PCIXCC_MAX_RESPONSE_SIZE PCIXCC_MAX_XCRB_RESPONSE_SIZE
63
64#define PCIXCC_CLEANUP_TIME (15*HZ)
65
Ralph Wuerthner54321142006-09-20 15:58:36 +020066#define CEIL4(x) ((((x)+3)/4)*4)
67
68struct response_type {
69 struct completion work;
70 int type;
71};
72#define PCIXCC_RESPONSE_TYPE_ICA 0
73#define PCIXCC_RESPONSE_TYPE_XCRB 1
74
Martin Schwidefsky6684af12006-09-20 15:58:32 +020075static struct ap_device_id zcrypt_pcixcc_ids[] = {
76 { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
77 { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
Felix Beckffda4f72009-12-07 12:51:56 +010078 { AP_DEVICE(AP_DEVICE_TYPE_CEX3C) },
Martin Schwidefsky6684af12006-09-20 15:58:32 +020079 { /* end of list */ },
80};
81
82#ifndef CONFIG_ZCRYPT_MONOLITHIC
83MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids);
84MODULE_AUTHOR("IBM Corporation");
85MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, "
86 "Copyright 2001, 2006 IBM Corporation");
87MODULE_LICENSE("GPL");
88#endif
89
90static int zcrypt_pcixcc_probe(struct ap_device *ap_dev);
91static void zcrypt_pcixcc_remove(struct ap_device *ap_dev);
92static void zcrypt_pcixcc_receive(struct ap_device *, struct ap_message *,
93 struct ap_message *);
94
95static struct ap_driver zcrypt_pcixcc_driver = {
96 .probe = zcrypt_pcixcc_probe,
97 .remove = zcrypt_pcixcc_remove,
98 .receive = zcrypt_pcixcc_receive,
99 .ids = zcrypt_pcixcc_ids,
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200100 .request_timeout = PCIXCC_CLEANUP_TIME,
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200101};
102
103/**
104 * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
105 * card in a type6 message. The 3 fields that must be filled in at execution
106 * time are req_parml, rpl_parml and usage_domain.
107 * Everything about this interface is ascii/big-endian, since the
108 * device does *not* have 'Intel inside'.
109 *
110 * The CPRBX is followed immediately by the parm block.
111 * The parm block contains:
112 * - function code ('PD' 0x5044 or 'PK' 0x504B)
113 * - rule block (one of:)
114 * + 0x000A 'PKCS-1.2' (MCL2 'PD')
115 * + 0x000A 'ZERO-PAD' (MCL2 'PK')
116 * + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD')
117 * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK')
118 * - VUD block
119 */
120static struct CPRBX static_cprbx = {
121 .cprb_len = 0x00DC,
122 .cprb_ver_id = 0x02,
123 .func_id = {0x54,0x32},
124};
125
126/**
127 * Convert a ICAMEX message to a type6 MEX message.
128 *
129 * @zdev: crypto device pointer
130 * @ap_msg: pointer to AP message
131 * @mex: pointer to user input data
132 *
133 * Returns 0 on success or -EFAULT.
134 */
135static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
136 struct ap_message *ap_msg,
137 struct ica_rsa_modexpo *mex)
138{
139 static struct type6_hdr static_type6_hdrX = {
140 .type = 0x06,
141 .offset1 = 0x00000058,
142 .agent_id = {'C','A',},
143 .function_code = {'P','K'},
144 };
145 static struct function_and_rules_block static_pke_fnr = {
146 .function_code = {'P','K'},
147 .ulen = 10,
148 .only_rule = {'M','R','P',' ',' ',' ',' ',' '}
149 };
150 static struct function_and_rules_block static_pke_fnr_MCL2 = {
151 .function_code = {'P','K'},
152 .ulen = 10,
153 .only_rule = {'Z','E','R','O','-','P','A','D'}
154 };
155 struct {
156 struct type6_hdr hdr;
157 struct CPRBX cprbx;
158 struct function_and_rules_block fr;
159 unsigned short length;
160 char text[0];
161 } __attribute__((packed)) *msg = ap_msg->message;
162 int size;
163
164 /* VUD.ciphertext */
165 msg->length = mex->inputdatalength + 2;
166 if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
167 return -EFAULT;
168
169 /* Set up key which is located after the variable length text. */
170 size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1);
171 if (size < 0)
172 return size;
173 size += sizeof(*msg) + mex->inputdatalength;
174
175 /* message header, cprbx and f&r */
176 msg->hdr = static_type6_hdrX;
177 msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
178 msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
179
180 msg->cprbx = static_cprbx;
181 msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
182 msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1;
183
184 msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
185 static_pke_fnr_MCL2 : static_pke_fnr;
186
187 msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx);
188
189 ap_msg->length = size;
190 return 0;
191}
192
193/**
194 * Convert a ICACRT message to a type6 CRT message.
195 *
196 * @zdev: crypto device pointer
197 * @ap_msg: pointer to AP message
198 * @crt: pointer to user input data
199 *
200 * Returns 0 on success or -EFAULT.
201 */
202static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
203 struct ap_message *ap_msg,
204 struct ica_rsa_modexpo_crt *crt)
205{
206 static struct type6_hdr static_type6_hdrX = {
207 .type = 0x06,
208 .offset1 = 0x00000058,
209 .agent_id = {'C','A',},
210 .function_code = {'P','D'},
211 };
212 static struct function_and_rules_block static_pkd_fnr = {
213 .function_code = {'P','D'},
214 .ulen = 10,
215 .only_rule = {'Z','E','R','O','-','P','A','D'}
216 };
217
218 static struct function_and_rules_block static_pkd_fnr_MCL2 = {
219 .function_code = {'P','D'},
220 .ulen = 10,
221 .only_rule = {'P','K','C','S','-','1','.','2'}
222 };
223 struct {
224 struct type6_hdr hdr;
225 struct CPRBX cprbx;
226 struct function_and_rules_block fr;
227 unsigned short length;
228 char text[0];
229 } __attribute__((packed)) *msg = ap_msg->message;
230 int size;
231
232 /* VUD.ciphertext */
233 msg->length = crt->inputdatalength + 2;
234 if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
235 return -EFAULT;
236
237 /* Set up key which is located after the variable length text. */
238 size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1);
239 if (size < 0)
240 return size;
241 size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */
242
243 /* message header, cprbx and f&r */
244 msg->hdr = static_type6_hdrX;
245 msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
246 msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
247
248 msg->cprbx = static_cprbx;
249 msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
250 msg->cprbx.req_parml = msg->cprbx.rpl_msgbl =
251 size - sizeof(msg->hdr) - sizeof(msg->cprbx);
252
253 msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
254 static_pkd_fnr_MCL2 : static_pkd_fnr;
255
256 ap_msg->length = size;
257 return 0;
258}
259
260/**
Ralph Wuerthner54321142006-09-20 15:58:36 +0200261 * Convert a XCRB message to a type6 CPRB message.
262 *
263 * @zdev: crypto device pointer
264 * @ap_msg: pointer to AP message
265 * @xcRB: pointer to user input data
266 *
267 * Returns 0 on success or -EFAULT.
268 */
269struct type86_fmt2_msg {
270 struct type86_hdr hdr;
271 struct type86_fmt2_ext fmt2;
272} __attribute__((packed));
273
274static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
275 struct ap_message *ap_msg,
276 struct ica_xcRB *xcRB)
277{
278 static struct type6_hdr static_type6_hdrX = {
279 .type = 0x06,
280 .offset1 = 0x00000058,
281 };
282 struct {
283 struct type6_hdr hdr;
Ralph Wuerthner16db63f2007-10-12 16:11:28 +0200284 struct CPRBX cprbx;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200285 } __attribute__((packed)) *msg = ap_msg->message;
286
287 int rcblen = CEIL4(xcRB->request_control_blk_length);
288 int replylen;
289 char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
290 char *function_code;
291
292 /* length checks */
293 ap_msg->length = sizeof(struct type6_hdr) +
294 CEIL4(xcRB->request_control_blk_length) +
295 xcRB->request_data_length;
Felix Beck1a89dd82008-07-14 09:59:27 +0200296 if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE)
Ralph Wuerthner54321142006-09-20 15:58:36 +0200297 return -EFAULT;
Felix Beck1a89dd82008-07-14 09:59:27 +0200298 if (CEIL4(xcRB->reply_control_blk_length) > PCIXCC_MAX_XCRB_REPLY_SIZE)
Ralph Wuerthner54321142006-09-20 15:58:36 +0200299 return -EFAULT;
Felix Beck1a89dd82008-07-14 09:59:27 +0200300 if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE)
Ralph Wuerthner54321142006-09-20 15:58:36 +0200301 return -EFAULT;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200302 replylen = CEIL4(xcRB->reply_control_blk_length) +
303 CEIL4(xcRB->reply_data_length) +
304 sizeof(struct type86_fmt2_msg);
305 if (replylen > PCIXCC_MAX_XCRB_RESPONSE_SIZE) {
Ralph Wuerthner54321142006-09-20 15:58:36 +0200306 xcRB->reply_control_blk_length = PCIXCC_MAX_XCRB_RESPONSE_SIZE -
307 (sizeof(struct type86_fmt2_msg) +
308 CEIL4(xcRB->reply_data_length));
Ralph Wuerthner54321142006-09-20 15:58:36 +0200309 }
310
311 /* prepare type6 header */
312 msg->hdr = static_type6_hdrX;
313 memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
314 msg->hdr.ToCardLen1 = xcRB->request_control_blk_length;
315 if (xcRB->request_data_length) {
316 msg->hdr.offset2 = msg->hdr.offset1 + rcblen;
317 msg->hdr.ToCardLen2 = xcRB->request_data_length;
318 }
319 msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length;
320 msg->hdr.FromCardLen2 = xcRB->reply_data_length;
321
322 /* prepare CPRB */
323 if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr,
324 xcRB->request_control_blk_length))
325 return -EFAULT;
326 if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
Felix Beck1a89dd82008-07-14 09:59:27 +0200327 xcRB->request_control_blk_length)
Ralph Wuerthner54321142006-09-20 15:58:36 +0200328 return -EFAULT;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200329 function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
330 memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
331
Felix Becka6a5d732009-12-07 12:51:55 +0100332 if (memcmp(function_code, "US", 2) == 0)
333 ap_msg->special = 1;
334 else
335 ap_msg->special = 0;
336
Ralph Wuerthner54321142006-09-20 15:58:36 +0200337 /* copy data block */
338 if (xcRB->request_data_length &&
339 copy_from_user(req_data, xcRB->request_data_address,
340 xcRB->request_data_length))
341 return -EFAULT;
342 return 0;
343}
344
345/**
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200346 * Prepare a type6 CPRB message for random number generation
347 *
348 * @ap_dev: AP device pointer
349 * @ap_msg: pointer to AP message
350 */
351static void rng_type6CPRB_msgX(struct ap_device *ap_dev,
352 struct ap_message *ap_msg,
353 unsigned random_number_length)
354{
355 struct {
356 struct type6_hdr hdr;
357 struct CPRBX cprbx;
358 char function_code[2];
359 short int rule_length;
360 char rule[8];
361 short int verb_length;
362 short int key_length;
363 } __attribute__((packed)) *msg = ap_msg->message;
364 static struct type6_hdr static_type6_hdrX = {
365 .type = 0x06,
366 .offset1 = 0x00000058,
367 .agent_id = {'C', 'A'},
368 .function_code = {'R', 'L'},
369 .ToCardLen1 = sizeof *msg - sizeof(msg->hdr),
370 .FromCardLen1 = sizeof *msg - sizeof(msg->hdr),
371 };
Felix Beck6458abc2009-10-06 10:34:09 +0200372 static struct CPRBX local_cprbx = {
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200373 .cprb_len = 0x00dc,
374 .cprb_ver_id = 0x02,
375 .func_id = {0x54, 0x32},
376 .req_parml = sizeof *msg - sizeof(msg->hdr) -
377 sizeof(msg->cprbx),
378 .rpl_msgbl = sizeof *msg - sizeof(msg->hdr),
379 };
380
381 msg->hdr = static_type6_hdrX;
382 msg->hdr.FromCardLen2 = random_number_length,
Felix Beck6458abc2009-10-06 10:34:09 +0200383 msg->cprbx = local_cprbx;
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200384 msg->cprbx.rpl_datal = random_number_length,
385 msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid);
386 memcpy(msg->function_code, msg->hdr.function_code, 0x02);
387 msg->rule_length = 0x0a;
388 memcpy(msg->rule, "RANDOM ", 8);
389 msg->verb_length = 0x02;
390 msg->key_length = 0x02;
391 ap_msg->length = sizeof *msg;
392}
393
394/**
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200395 * Copy results from a type 86 ICA reply message back to user space.
396 *
397 * @zdev: crypto device pointer
398 * @reply: reply AP message.
399 * @data: pointer to user output data
400 * @length: size of user output data
401 *
402 * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
403 */
404struct type86x_reply {
405 struct type86_hdr hdr;
406 struct type86_fmt2_ext fmt2;
407 struct CPRBX cprbx;
408 unsigned char pad[4]; /* 4 byte function code/rules block ? */
409 unsigned short length;
410 char text[0];
411} __attribute__((packed));
412
413static int convert_type86_ica(struct zcrypt_device *zdev,
414 struct ap_message *reply,
415 char __user *outputdata,
416 unsigned int outputdatalength)
417{
418 static unsigned char static_pad[] = {
419 0x00,0x02,
420 0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,
421 0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
422 0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,
423 0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
424 0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,
425 0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
426 0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,
427 0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
428 0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,
429 0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
430 0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,
431 0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
432 0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,
433 0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
434 0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,
435 0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
436 0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,
437 0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
438 0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,
439 0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
440 0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,
441 0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
442 0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,
443 0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
444 0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,
445 0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
446 0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,
447 0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
448 0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,
449 0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
450 0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,
451 0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
452 };
453 struct type86x_reply *msg = reply->message;
454 unsigned short service_rc, service_rs;
455 unsigned int reply_len, pad_len;
456 char *data;
457
458 service_rc = msg->cprbx.ccp_rtcode;
459 if (unlikely(service_rc != 0)) {
460 service_rs = msg->cprbx.ccp_rscode;
Felix Beck1a89dd82008-07-14 09:59:27 +0200461 if (service_rc == 8 && service_rs == 66)
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200462 return -EINVAL;
Felix Beck1a89dd82008-07-14 09:59:27 +0200463 if (service_rc == 8 && service_rs == 65)
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200464 return -EINVAL;
Felix Beck1a89dd82008-07-14 09:59:27 +0200465 if (service_rc == 8 && service_rs == 770)
Ralph Wuerthner2af48082007-10-12 16:11:30 +0200466 return -EINVAL;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200467 if (service_rc == 8 && service_rs == 783) {
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200468 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
469 return -EAGAIN;
470 }
Felix Beck1a89dd82008-07-14 09:59:27 +0200471 if (service_rc == 12 && service_rs == 769)
Ralph Wuerthner2af48082007-10-12 16:11:30 +0200472 return -EINVAL;
Felix Beck19b123e2010-01-27 10:12:39 +0100473 if (service_rc == 8 && service_rs == 72)
474 return -EINVAL;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200475 zdev->online = 0;
476 return -EAGAIN; /* repeat the request on a different device. */
477 }
478 data = msg->text;
479 reply_len = msg->length - 2;
480 if (reply_len > outputdatalength)
481 return -EINVAL;
Felix Beck1749a812008-04-17 07:46:28 +0200482 /*
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200483 * For all encipher requests, the length of the ciphertext (reply_len)
484 * will always equal the modulus length. For MEX decipher requests
485 * the output needs to get padded. Minimum pad size is 10.
486 *
487 * Currently, the cases where padding will be added is for:
488 * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
489 * ZERO-PAD and CRT is only supported for PKD requests)
490 * - PCICC, always
491 */
492 pad_len = outputdatalength - reply_len;
493 if (pad_len > 0) {
494 if (pad_len < 10)
495 return -EINVAL;
496 /* 'restore' padding left in the PCICC/PCIXCC card. */
497 if (copy_to_user(outputdata, static_pad, pad_len - 1))
498 return -EFAULT;
499 if (put_user(0, outputdata + pad_len - 1))
500 return -EFAULT;
501 }
502 /* Copy the crypto response to user space. */
503 if (copy_to_user(outputdata + pad_len, data, reply_len))
504 return -EFAULT;
505 return 0;
506}
507
Ralph Wuerthner54321142006-09-20 15:58:36 +0200508/**
509 * Copy results from a type 86 XCRB reply message back to user space.
510 *
511 * @zdev: crypto device pointer
512 * @reply: reply AP message.
513 * @xcRB: pointer to XCRB
514 *
515 * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
516 */
517static int convert_type86_xcrb(struct zcrypt_device *zdev,
518 struct ap_message *reply,
519 struct ica_xcRB *xcRB)
520{
521 struct type86_fmt2_msg *msg = reply->message;
522 char *data = reply->message;
523
524 /* Copy CPRB to user */
525 if (copy_to_user(xcRB->reply_control_blk_addr,
526 data + msg->fmt2.offset1, msg->fmt2.count1))
527 return -EFAULT;
528 xcRB->reply_control_blk_length = msg->fmt2.count1;
529
530 /* Copy data buffer to user */
531 if (msg->fmt2.count2)
532 if (copy_to_user(xcRB->reply_data_addr,
533 data + msg->fmt2.offset2, msg->fmt2.count2))
534 return -EFAULT;
535 xcRB->reply_data_length = msg->fmt2.count2;
536 return 0;
537}
538
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200539static int convert_type86_rng(struct zcrypt_device *zdev,
540 struct ap_message *reply,
541 char *buffer)
542{
543 struct {
544 struct type86_hdr hdr;
545 struct type86_fmt2_ext fmt2;
546 struct CPRBX cprbx;
547 } __attribute__((packed)) *msg = reply->message;
548 char *data = reply->message;
549
Felix Beck1a89dd82008-07-14 09:59:27 +0200550 if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0)
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200551 return -EINVAL;
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200552 memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2);
553 return msg->fmt2.count2;
554}
555
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200556static int convert_response_ica(struct zcrypt_device *zdev,
557 struct ap_message *reply,
558 char __user *outputdata,
559 unsigned int outputdatalength)
560{
561 struct type86x_reply *msg = reply->message;
562
563 /* Response type byte is the second byte in the response. */
564 switch (((unsigned char *) reply->message)[1]) {
565 case TYPE82_RSP_CODE:
566 case TYPE88_RSP_CODE:
567 return convert_error(zdev, reply);
568 case TYPE86_RSP_CODE:
569 if (msg->hdr.reply_code)
570 return convert_error(zdev, reply);
571 if (msg->cprbx.cprb_ver_id == 0x02)
572 return convert_type86_ica(zdev, reply,
573 outputdata, outputdatalength);
Felix Beck942b7e62009-10-06 10:34:10 +0200574 /* Fall through, no break, incorrect cprb version is an unknown
575 * response */
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200576 default: /* Unknown response type, this should NEVER EVER happen */
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200577 zdev->online = 0;
578 return -EAGAIN; /* repeat the request on a different device. */
579 }
580}
581
Ralph Wuerthner54321142006-09-20 15:58:36 +0200582static int convert_response_xcrb(struct zcrypt_device *zdev,
583 struct ap_message *reply,
584 struct ica_xcRB *xcRB)
585{
586 struct type86x_reply *msg = reply->message;
587
588 /* Response type byte is the second byte in the response. */
589 switch (((unsigned char *) reply->message)[1]) {
590 case TYPE82_RSP_CODE:
591 case TYPE88_RSP_CODE:
592 xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
593 return convert_error(zdev, reply);
594 case TYPE86_RSP_CODE:
595 if (msg->hdr.reply_code) {
596 memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32));
597 return convert_error(zdev, reply);
598 }
599 if (msg->cprbx.cprb_ver_id == 0x02)
600 return convert_type86_xcrb(zdev, reply, xcRB);
Felix Beck942b7e62009-10-06 10:34:10 +0200601 /* Fall through, no break, incorrect cprb version is an unknown
602 * response */
Ralph Wuerthner54321142006-09-20 15:58:36 +0200603 default: /* Unknown response type, this should NEVER EVER happen */
Ralph Wuerthner54321142006-09-20 15:58:36 +0200604 xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
605 zdev->online = 0;
606 return -EAGAIN; /* repeat the request on a different device. */
607 }
608}
609
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200610static int convert_response_rng(struct zcrypt_device *zdev,
611 struct ap_message *reply,
612 char *data)
613{
614 struct type86x_reply *msg = reply->message;
615
616 switch (msg->hdr.type) {
617 case TYPE82_RSP_CODE:
618 case TYPE88_RSP_CODE:
619 return -EINVAL;
620 case TYPE86_RSP_CODE:
621 if (msg->hdr.reply_code)
622 return -EINVAL;
623 if (msg->cprbx.cprb_ver_id == 0x02)
624 return convert_type86_rng(zdev, reply, data);
Felix Beck942b7e62009-10-06 10:34:10 +0200625 /* Fall through, no break, incorrect cprb version is an unknown
626 * response */
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200627 default: /* Unknown response type, this should NEVER EVER happen */
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200628 zdev->online = 0;
629 return -EAGAIN; /* repeat the request on a different device. */
630 }
631}
632
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200633/**
634 * This function is called from the AP bus code after a crypto request
635 * "msg" has finished with the reply message "reply".
636 * It is called from tasklet context.
637 * @ap_dev: pointer to the AP device
638 * @msg: pointer to the AP message
639 * @reply: pointer to the AP reply message
640 */
641static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,
642 struct ap_message *msg,
643 struct ap_message *reply)
644{
645 static struct error_hdr error_reply = {
646 .type = TYPE82_RSP_CODE,
647 .reply_code = REP82_ERROR_MACHINE_FAILURE,
648 };
Ralph Wuerthner54321142006-09-20 15:58:36 +0200649 struct response_type *resp_type =
650 (struct response_type *) msg->private;
Julia Lawall21e7b2c2008-12-25 13:39:28 +0100651 struct type86x_reply *t86r;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200652 int length;
653
654 /* Copy the reply message to the request message buffer. */
Julia Lawall21e7b2c2008-12-25 13:39:28 +0100655 if (IS_ERR(reply)) {
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200656 memcpy(msg->message, &error_reply, sizeof(error_reply));
Julia Lawall21e7b2c2008-12-25 13:39:28 +0100657 goto out;
658 }
659 t86r = reply->message;
660 if (t86r->hdr.type == TYPE86_RSP_CODE &&
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200661 t86r->cprbx.cprb_ver_id == 0x02) {
Ralph Wuerthner54321142006-09-20 15:58:36 +0200662 switch (resp_type->type) {
663 case PCIXCC_RESPONSE_TYPE_ICA:
664 length = sizeof(struct type86x_reply)
665 + t86r->length - 2;
666 length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
667 memcpy(msg->message, reply->message, length);
668 break;
669 case PCIXCC_RESPONSE_TYPE_XCRB:
670 length = t86r->fmt2.offset2 + t86r->fmt2.count2;
671 length = min(PCIXCC_MAX_XCRB_RESPONSE_SIZE, length);
672 memcpy(msg->message, reply->message, length);
673 break;
674 default:
Felix Beck1a89dd82008-07-14 09:59:27 +0200675 memcpy(msg->message, &error_reply, sizeof error_reply);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200676 }
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200677 } else
678 memcpy(msg->message, reply->message, sizeof error_reply);
Julia Lawall21e7b2c2008-12-25 13:39:28 +0100679out:
Ralph Wuerthner54321142006-09-20 15:58:36 +0200680 complete(&(resp_type->work));
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200681}
682
683static atomic_t zcrypt_step = ATOMIC_INIT(0);
684
685/**
686 * The request distributor calls this function if it picked the PCIXCC/CEX2C
687 * device to handle a modexpo request.
688 * @zdev: pointer to zcrypt_device structure that identifies the
689 * PCIXCC/CEX2C device to the request distributor
690 * @mex: pointer to the modexpo request buffer
691 */
692static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,
693 struct ica_rsa_modexpo *mex)
694{
695 struct ap_message ap_msg;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200696 struct response_type resp_type = {
697 .type = PCIXCC_RESPONSE_TYPE_ICA,
698 };
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200699 int rc;
700
Felix Beck468ffdd2009-12-07 12:51:54 +0100701 ap_init_message(&ap_msg);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200702 ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
703 if (!ap_msg.message)
704 return -ENOMEM;
705 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
706 atomic_inc_return(&zcrypt_step);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200707 ap_msg.private = &resp_type;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200708 rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
709 if (rc)
710 goto out_free;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200711 init_completion(&resp_type.work);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200712 ap_queue_message(zdev->ap_dev, &ap_msg);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200713 rc = wait_for_completion_interruptible(&resp_type.work);
714 if (rc == 0)
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200715 rc = convert_response_ica(zdev, &ap_msg, mex->outputdata,
716 mex->outputdatalength);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200717 else
718 /* Signal pending. */
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200719 ap_cancel_message(zdev->ap_dev, &ap_msg);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200720out_free:
721 free_page((unsigned long) ap_msg.message);
722 return rc;
723}
724
725/**
726 * The request distributor calls this function if it picked the PCIXCC/CEX2C
727 * device to handle a modexpo_crt request.
728 * @zdev: pointer to zcrypt_device structure that identifies the
729 * PCIXCC/CEX2C device to the request distributor
730 * @crt: pointer to the modexpoc_crt request buffer
731 */
732static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,
733 struct ica_rsa_modexpo_crt *crt)
734{
735 struct ap_message ap_msg;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200736 struct response_type resp_type = {
737 .type = PCIXCC_RESPONSE_TYPE_ICA,
738 };
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200739 int rc;
740
Felix Beck468ffdd2009-12-07 12:51:54 +0100741 ap_init_message(&ap_msg);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200742 ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
743 if (!ap_msg.message)
744 return -ENOMEM;
745 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
746 atomic_inc_return(&zcrypt_step);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200747 ap_msg.private = &resp_type;
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200748 rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
749 if (rc)
750 goto out_free;
Ralph Wuerthner54321142006-09-20 15:58:36 +0200751 init_completion(&resp_type.work);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200752 ap_queue_message(zdev->ap_dev, &ap_msg);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200753 rc = wait_for_completion_interruptible(&resp_type.work);
754 if (rc == 0)
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200755 rc = convert_response_ica(zdev, &ap_msg, crt->outputdata,
756 crt->outputdatalength);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200757 else
758 /* Signal pending. */
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200759 ap_cancel_message(zdev->ap_dev, &ap_msg);
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200760out_free:
761 free_page((unsigned long) ap_msg.message);
762 return rc;
763}
764
765/**
Ralph Wuerthner54321142006-09-20 15:58:36 +0200766 * The request distributor calls this function if it picked the PCIXCC/CEX2C
767 * device to handle a send_cprb request.
768 * @zdev: pointer to zcrypt_device structure that identifies the
769 * PCIXCC/CEX2C device to the request distributor
770 * @xcRB: pointer to the send_cprb request buffer
771 */
Heiko Carstens2b67fc42007-02-05 21:16:47 +0100772static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,
773 struct ica_xcRB *xcRB)
Ralph Wuerthner54321142006-09-20 15:58:36 +0200774{
775 struct ap_message ap_msg;
776 struct response_type resp_type = {
777 .type = PCIXCC_RESPONSE_TYPE_XCRB,
778 };
779 int rc;
780
Felix Beck468ffdd2009-12-07 12:51:54 +0100781 ap_init_message(&ap_msg);
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800782 ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200783 if (!ap_msg.message)
784 return -ENOMEM;
785 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
786 atomic_inc_return(&zcrypt_step);
787 ap_msg.private = &resp_type;
788 rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB);
789 if (rc)
790 goto out_free;
791 init_completion(&resp_type.work);
792 ap_queue_message(zdev->ap_dev, &ap_msg);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200793 rc = wait_for_completion_interruptible(&resp_type.work);
794 if (rc == 0)
Ralph Wuerthner54321142006-09-20 15:58:36 +0200795 rc = convert_response_xcrb(zdev, &ap_msg, xcRB);
Ralph Wuerthneraf512ed02007-07-10 11:24:19 +0200796 else
797 /* Signal pending. */
Ralph Wuerthner54321142006-09-20 15:58:36 +0200798 ap_cancel_message(zdev->ap_dev, &ap_msg);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200799out_free:
Johannes Weiner3e75a902009-03-26 15:24:48 +0100800 kzfree(ap_msg.message);
Ralph Wuerthner54321142006-09-20 15:58:36 +0200801 return rc;
802}
803
804/**
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200805 * The request distributor calls this function if it picked the PCIXCC/CEX2C
806 * device to generate random data.
807 * @zdev: pointer to zcrypt_device structure that identifies the
808 * PCIXCC/CEX2C device to the request distributor
809 * @buffer: pointer to a memory page to return random data
810 */
811
812static long zcrypt_pcixcc_rng(struct zcrypt_device *zdev,
813 char *buffer)
814{
815 struct ap_message ap_msg;
816 struct response_type resp_type = {
817 .type = PCIXCC_RESPONSE_TYPE_XCRB,
818 };
819 int rc;
820
Felix Beck468ffdd2009-12-07 12:51:54 +0100821 ap_init_message(&ap_msg);
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200822 ap_msg.message = kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
823 if (!ap_msg.message)
824 return -ENOMEM;
825 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
826 atomic_inc_return(&zcrypt_step);
827 ap_msg.private = &resp_type;
828 rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE);
829 init_completion(&resp_type.work);
830 ap_queue_message(zdev->ap_dev, &ap_msg);
831 rc = wait_for_completion_interruptible(&resp_type.work);
832 if (rc == 0)
833 rc = convert_response_rng(zdev, &ap_msg, buffer);
834 else
835 /* Signal pending. */
836 ap_cancel_message(zdev->ap_dev, &ap_msg);
837 kfree(ap_msg.message);
838 return rc;
839}
840
841/**
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200842 * The crypto operations for a PCIXCC/CEX2C card.
843 */
844static struct zcrypt_ops zcrypt_pcixcc_ops = {
845 .rsa_modexpo = zcrypt_pcixcc_modexpo,
846 .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt,
Ralph Wuerthner54321142006-09-20 15:58:36 +0200847 .send_cprb = zcrypt_pcixcc_send_cprb,
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200848};
849
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200850static struct zcrypt_ops zcrypt_pcixcc_with_rng_ops = {
851 .rsa_modexpo = zcrypt_pcixcc_modexpo,
852 .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt,
853 .send_cprb = zcrypt_pcixcc_send_cprb,
854 .rng = zcrypt_pcixcc_rng,
855};
856
Martin Schwidefsky6684af12006-09-20 15:58:32 +0200857/**
858 * Micro-code detection function. Its sends a message to a pcixcc card
859 * to find out the microcode level.
860 * @ap_dev: pointer to the AP device.
861 */
862static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev)
863{
864 static unsigned char msg[] = {
865 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
866 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
867 0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
868 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
869 0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
870 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
871 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,
872 0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
873 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
874 0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
875 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
876 0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
877 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,
878 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
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,0x00,0x00,0x00,0x00,0x00,
897 0x00,0x00,0x00,0x04,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,0x00,0x00,0x00,0x00,
903 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,
904 0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
905 0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,
906 0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
907 0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,
908 0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
909 0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,
910 0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
911 0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,
912 0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
913 0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,
914 0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
915 0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,
916 0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
917 0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,
918 0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
919 0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,
920 0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
921 0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,
922 0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
923 0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,
924 0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
925 0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,
926 0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
927 0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,
928 0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
929 0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,
930 0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
931 0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,
932 0xF1,0x3D,0x93,0x53
933 };
934 unsigned long long psmid;
935 struct CPRBX *cprbx;
936 char *reply;
937 int rc, i;
938
939 reply = (void *) get_zeroed_page(GFP_KERNEL);
940 if (!reply)
941 return -ENOMEM;
942
943 rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, msg, sizeof(msg));
944 if (rc)
945 goto out_free;
946
947 /* Wait for the test message to complete. */
948 for (i = 0; i < 6; i++) {
949 mdelay(300);
950 rc = ap_recv(ap_dev->qid, &psmid, reply, 4096);
951 if (rc == 0 && psmid == 0x0102030405060708ULL)
952 break;
953 }
954
955 if (i >= 6) {
956 /* Got no answer. */
957 rc = -ENODEV;
958 goto out_free;
959 }
960
961 cprbx = (struct CPRBX *) (reply + 48);
962 if (cprbx->ccp_rtcode == 8 && cprbx->ccp_rscode == 33)
963 rc = ZCRYPT_PCIXCC_MCL2;
964 else
965 rc = ZCRYPT_PCIXCC_MCL3;
966out_free:
967 free_page((unsigned long) reply);
968 return rc;
969}
970
971/**
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200972 * Large random number detection function. Its sends a message to a pcixcc
973 * card to find out if large random numbers are supported.
974 * @ap_dev: pointer to the AP device.
975 *
976 * Returns 1 if large random numbers are supported, 0 if not and < 0 on error.
977 */
978static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev)
979{
980 struct ap_message ap_msg;
981 unsigned long long psmid;
982 struct {
983 struct type86_hdr hdr;
984 struct type86_fmt2_ext fmt2;
985 struct CPRBX cprbx;
986 } __attribute__((packed)) *reply;
987 int rc, i;
988
Felix Beck468ffdd2009-12-07 12:51:54 +0100989 ap_init_message(&ap_msg);
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +0200990 ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
991 if (!ap_msg.message)
992 return -ENOMEM;
993
994 rng_type6CPRB_msgX(ap_dev, &ap_msg, 4);
995 rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message,
996 ap_msg.length);
997 if (rc)
998 goto out_free;
999
1000 /* Wait for the test message to complete. */
1001 for (i = 0; i < 2 * HZ; i++) {
1002 msleep(1000 / HZ);
1003 rc = ap_recv(ap_dev->qid, &psmid, ap_msg.message, 4096);
1004 if (rc == 0 && psmid == 0x0102030405060708ULL)
1005 break;
1006 }
1007
1008 if (i >= 2 * HZ) {
1009 /* Got no answer. */
1010 rc = -ENODEV;
1011 goto out_free;
1012 }
1013
1014 reply = ap_msg.message;
1015 if (reply->cprbx.ccp_rtcode == 0 && reply->cprbx.ccp_rscode == 0)
1016 rc = 1;
1017 else
1018 rc = 0;
1019out_free:
1020 free_page((unsigned long) ap_msg.message);
1021 return rc;
1022}
1023
1024/**
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001025 * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device
1026 * since the bus_match already checked the hardware type. The PCIXCC
1027 * cards come in two flavours: micro code level 2 and micro code level 3.
1028 * This is checked by sending a test message to the device.
1029 * @ap_dev: pointer to the AP device.
1030 */
1031static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
1032{
1033 struct zcrypt_device *zdev;
Felix Beck8e89b6b2009-12-07 12:51:57 +01001034 int rc = 0;
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001035
1036 zdev = zcrypt_device_alloc(PCIXCC_MAX_RESPONSE_SIZE);
1037 if (!zdev)
1038 return -ENOMEM;
1039 zdev->ap_dev = ap_dev;
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001040 zdev->online = 1;
Felix Beck8e89b6b2009-12-07 12:51:57 +01001041 switch (ap_dev->device_type) {
1042 case AP_DEVICE_TYPE_PCIXCC:
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001043 rc = zcrypt_pcixcc_mcl(ap_dev);
1044 if (rc < 0) {
1045 zcrypt_device_free(zdev);
1046 return rc;
1047 }
1048 zdev->user_space_type = rc;
1049 if (rc == ZCRYPT_PCIXCC_MCL2) {
1050 zdev->type_string = "PCIXCC_MCL2";
1051 zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING;
1052 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
1053 zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
1054 } 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;
1059 }
Felix Beck8e89b6b2009-12-07 12:51:57 +01001060 break;
1061 case AP_DEVICE_TYPE_CEX2C:
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001062 zdev->user_space_type = ZCRYPT_CEX2C;
1063 zdev->type_string = "CEX2C";
1064 zdev->speed_rating = CEX2C_SPEED_RATING;
1065 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
1066 zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
Felix Beck8e89b6b2009-12-07 12:51:57 +01001067 break;
1068 case AP_DEVICE_TYPE_CEX3C:
1069 zdev->user_space_type = ZCRYPT_CEX3C;
1070 zdev->type_string = "CEX3C";
1071 zdev->speed_rating = CEX3C_SPEED_RATING;
1072 zdev->min_mod_size = CEX3C_MIN_MOD_SIZE;
1073 zdev->max_mod_size = CEX3C_MAX_MOD_SIZE;
1074 break;
1075 default:
1076 goto out_free;
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001077 }
Felix Beck8e89b6b2009-12-07 12:51:57 +01001078
Ralph Wuerthner2f7c8bd2008-04-17 07:46:15 +02001079 rc = zcrypt_pcixcc_rng_supported(ap_dev);
1080 if (rc < 0) {
1081 zcrypt_device_free(zdev);
1082 return rc;
1083 }
1084 if (rc)
1085 zdev->ops = &zcrypt_pcixcc_with_rng_ops;
1086 else
1087 zdev->ops = &zcrypt_pcixcc_ops;
Martin Schwidefsky6684af12006-09-20 15:58:32 +02001088 ap_dev->reply = &zdev->reply;
1089 ap_dev->private = zdev;
1090 rc = zcrypt_device_register(zdev);
1091 if (rc)
1092 goto out_free;
1093 return 0;
1094
1095 out_free:
1096 ap_dev->private = NULL;
1097 zcrypt_device_free(zdev);
1098 return rc;
1099}
1100
1101/**
1102 * This is called to remove the extended PCIXCC/CEX2C driver information
1103 * if an AP device is removed.
1104 */
1105static void zcrypt_pcixcc_remove(struct ap_device *ap_dev)
1106{
1107 struct zcrypt_device *zdev = ap_dev->private;
1108
1109 zcrypt_device_unregister(zdev);
1110}
1111
1112int __init zcrypt_pcixcc_init(void)
1113{
1114 return ap_driver_register(&zcrypt_pcixcc_driver, THIS_MODULE, "pcixcc");
1115}
1116
1117void zcrypt_pcixcc_exit(void)
1118{
1119 ap_driver_unregister(&zcrypt_pcixcc_driver);
1120}
1121
1122#ifndef CONFIG_ZCRYPT_MONOLITHIC
1123module_init(zcrypt_pcixcc_init);
1124module_exit(zcrypt_pcixcc_exit);
1125#endif