aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/crypto/zcrypt_pcixcc.c
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2006-09-20 09:58:32 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2006-09-20 09:58:32 -0400
commit6684af1a07a1f88f3970bc90e5aed173d39168db (patch)
treede3056173598cced75379f04427702497466b515 /drivers/s390/crypto/zcrypt_pcixcc.c
parent963ed931c3fd18082bfde0e8704a28955663abf4 (diff)
[S390] zcrypt PCICC, PCIXCC coprocessor card ap bus drivers.
Signed-off-by: Ralph Wuerthner <rwuerthn@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/crypto/zcrypt_pcixcc.c')
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c714
1 files changed, 714 insertions, 0 deletions
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
new file mode 100644
index 000000000000..6064cf58be43
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -0,0 +1,714 @@
1/*
2 * linux/drivers/s390/crypto/zcrypt_pcixcc.c
3 *
4 * zcrypt 2.0.0
5 *
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 */
46
47#define PCIXCC_MCL2_SPEED_RATING 7870 /* FIXME: needs finetuning */
48#define PCIXCC_MCL3_SPEED_RATING 7870
49#define CEX2C_SPEED_RATING 8540
50
51#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
52#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
53
54#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024)
55#define PCIXCC_MAX_XCRB_RESPONSE_SIZE PCIXCC_MAX_XCRB_MESSAGE_SIZE
56#define PCIXCC_MAX_XCRB_DATA_SIZE (11*1024)
57#define PCIXCC_MAX_XCRB_REPLY_SIZE (5*1024)
58
59#define PCIXCC_MAX_RESPONSE_SIZE PCIXCC_MAX_XCRB_RESPONSE_SIZE
60
61#define PCIXCC_CLEANUP_TIME (15*HZ)
62
63static struct ap_device_id zcrypt_pcixcc_ids[] = {
64 { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
65 { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
66 { /* end of list */ },
67};
68
69#ifndef CONFIG_ZCRYPT_MONOLITHIC
70MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids);
71MODULE_AUTHOR("IBM Corporation");
72MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, "
73 "Copyright 2001, 2006 IBM Corporation");
74MODULE_LICENSE("GPL");
75#endif
76
77static int zcrypt_pcixcc_probe(struct ap_device *ap_dev);
78static void zcrypt_pcixcc_remove(struct ap_device *ap_dev);
79static void zcrypt_pcixcc_receive(struct ap_device *, struct ap_message *,
80 struct ap_message *);
81
82static struct ap_driver zcrypt_pcixcc_driver = {
83 .probe = zcrypt_pcixcc_probe,
84 .remove = zcrypt_pcixcc_remove,
85 .receive = zcrypt_pcixcc_receive,
86 .ids = zcrypt_pcixcc_ids,
87};
88
89/**
90 * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
91 * card in a type6 message. The 3 fields that must be filled in at execution
92 * time are req_parml, rpl_parml and usage_domain.
93 * Everything about this interface is ascii/big-endian, since the
94 * device does *not* have 'Intel inside'.
95 *
96 * The CPRBX is followed immediately by the parm block.
97 * The parm block contains:
98 * - function code ('PD' 0x5044 or 'PK' 0x504B)
99 * - rule block (one of:)
100 * + 0x000A 'PKCS-1.2' (MCL2 'PD')
101 * + 0x000A 'ZERO-PAD' (MCL2 'PK')
102 * + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD')
103 * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK')
104 * - VUD block
105 */
106static struct CPRBX static_cprbx = {
107 .cprb_len = 0x00DC,
108 .cprb_ver_id = 0x02,
109 .func_id = {0x54,0x32},
110};
111
112/**
113 * Convert a ICAMEX message to a type6 MEX message.
114 *
115 * @zdev: crypto device pointer
116 * @ap_msg: pointer to AP message
117 * @mex: pointer to user input data
118 *
119 * Returns 0 on success or -EFAULT.
120 */
121static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
122 struct ap_message *ap_msg,
123 struct ica_rsa_modexpo *mex)
124{
125 static struct type6_hdr static_type6_hdrX = {
126 .type = 0x06,
127 .offset1 = 0x00000058,
128 .agent_id = {'C','A',},
129 .function_code = {'P','K'},
130 };
131 static struct function_and_rules_block static_pke_fnr = {
132 .function_code = {'P','K'},
133 .ulen = 10,
134 .only_rule = {'M','R','P',' ',' ',' ',' ',' '}
135 };
136 static struct function_and_rules_block static_pke_fnr_MCL2 = {
137 .function_code = {'P','K'},
138 .ulen = 10,
139 .only_rule = {'Z','E','R','O','-','P','A','D'}
140 };
141 struct {
142 struct type6_hdr hdr;
143 struct CPRBX cprbx;
144 struct function_and_rules_block fr;
145 unsigned short length;
146 char text[0];
147 } __attribute__((packed)) *msg = ap_msg->message;
148 int size;
149
150 /* VUD.ciphertext */
151 msg->length = mex->inputdatalength + 2;
152 if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
153 return -EFAULT;
154
155 /* Set up key which is located after the variable length text. */
156 size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1);
157 if (size < 0)
158 return size;
159 size += sizeof(*msg) + mex->inputdatalength;
160
161 /* message header, cprbx and f&r */
162 msg->hdr = static_type6_hdrX;
163 msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
164 msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
165
166 msg->cprbx = static_cprbx;
167 msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
168 msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1;
169
170 msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
171 static_pke_fnr_MCL2 : static_pke_fnr;
172
173 msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx);
174
175 ap_msg->length = size;
176 return 0;
177}
178
179/**
180 * Convert a ICACRT message to a type6 CRT message.
181 *
182 * @zdev: crypto device pointer
183 * @ap_msg: pointer to AP message
184 * @crt: pointer to user input data
185 *
186 * Returns 0 on success or -EFAULT.
187 */
188static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
189 struct ap_message *ap_msg,
190 struct ica_rsa_modexpo_crt *crt)
191{
192 static struct type6_hdr static_type6_hdrX = {
193 .type = 0x06,
194 .offset1 = 0x00000058,
195 .agent_id = {'C','A',},
196 .function_code = {'P','D'},
197 };
198 static struct function_and_rules_block static_pkd_fnr = {
199 .function_code = {'P','D'},
200 .ulen = 10,
201 .only_rule = {'Z','E','R','O','-','P','A','D'}
202 };
203
204 static struct function_and_rules_block static_pkd_fnr_MCL2 = {
205 .function_code = {'P','D'},
206 .ulen = 10,
207 .only_rule = {'P','K','C','S','-','1','.','2'}
208 };
209 struct {
210 struct type6_hdr hdr;
211 struct CPRBX cprbx;
212 struct function_and_rules_block fr;
213 unsigned short length;
214 char text[0];
215 } __attribute__((packed)) *msg = ap_msg->message;
216 int size;
217
218 /* VUD.ciphertext */
219 msg->length = crt->inputdatalength + 2;
220 if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
221 return -EFAULT;
222
223 /* Set up key which is located after the variable length text. */
224 size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1);
225 if (size < 0)
226 return size;
227 size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */
228
229 /* message header, cprbx and f&r */
230 msg->hdr = static_type6_hdrX;
231 msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
232 msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
233
234 msg->cprbx = static_cprbx;
235 msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
236 msg->cprbx.req_parml = msg->cprbx.rpl_msgbl =
237 size - sizeof(msg->hdr) - sizeof(msg->cprbx);
238
239 msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
240 static_pkd_fnr_MCL2 : static_pkd_fnr;
241
242 ap_msg->length = size;
243 return 0;
244}
245
246/**
247 * Copy results from a type 86 ICA reply message back to user space.
248 *
249 * @zdev: crypto device pointer
250 * @reply: reply AP message.
251 * @data: pointer to user output data
252 * @length: size of user output data
253 *
254 * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
255 */
256struct type86x_reply {
257 struct type86_hdr hdr;
258 struct type86_fmt2_ext fmt2;
259 struct CPRBX cprbx;
260 unsigned char pad[4]; /* 4 byte function code/rules block ? */
261 unsigned short length;
262 char text[0];
263} __attribute__((packed));
264
265static int convert_type86_ica(struct zcrypt_device *zdev,
266 struct ap_message *reply,
267 char __user *outputdata,
268 unsigned int outputdatalength)
269{
270 static unsigned char static_pad[] = {
271 0x00,0x02,
272 0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,
273 0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
274 0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,
275 0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
276 0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,
277 0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
278 0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,
279 0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
280 0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,
281 0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
282 0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,
283 0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
284 0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,
285 0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
286 0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,
287 0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
288 0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,
289 0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
290 0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,
291 0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
292 0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,
293 0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
294 0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,
295 0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
296 0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,
297 0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
298 0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,
299 0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
300 0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,
301 0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
302 0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,
303 0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
304 };
305 struct type86x_reply *msg = reply->message;
306 unsigned short service_rc, service_rs;
307 unsigned int reply_len, pad_len;
308 char *data;
309
310 service_rc = msg->cprbx.ccp_rtcode;
311 if (unlikely(service_rc != 0)) {
312 service_rs = msg->cprbx.ccp_rscode;
313 if (service_rc == 8 && service_rs == 66) {
314 PDEBUG("Bad block format on PCIXCC/CEX2C\n");
315 return -EINVAL;
316 }
317 if (service_rc == 8 && service_rs == 65) {
318 PDEBUG("Probably an even modulus on PCIXCC/CEX2C\n");
319 return -EINVAL;
320 }
321 if (service_rc == 8 && service_rs == 770) {
322 PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
323 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
324 return -EAGAIN;
325 }
326 if (service_rc == 8 && service_rs == 783) {
327 PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
328 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
329 return -EAGAIN;
330 }
331 PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
332 service_rc, service_rs);
333 zdev->online = 0;
334 return -EAGAIN; /* repeat the request on a different device. */
335 }
336 data = msg->text;
337 reply_len = msg->length - 2;
338 if (reply_len > outputdatalength)
339 return -EINVAL;
340 /**
341 * For all encipher requests, the length of the ciphertext (reply_len)
342 * will always equal the modulus length. For MEX decipher requests
343 * the output needs to get padded. Minimum pad size is 10.
344 *
345 * Currently, the cases where padding will be added is for:
346 * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
347 * ZERO-PAD and CRT is only supported for PKD requests)
348 * - PCICC, always
349 */
350 pad_len = outputdatalength - reply_len;
351 if (pad_len > 0) {
352 if (pad_len < 10)
353 return -EINVAL;
354 /* 'restore' padding left in the PCICC/PCIXCC card. */
355 if (copy_to_user(outputdata, static_pad, pad_len - 1))
356 return -EFAULT;
357 if (put_user(0, outputdata + pad_len - 1))
358 return -EFAULT;
359 }
360 /* Copy the crypto response to user space. */
361 if (copy_to_user(outputdata + pad_len, data, reply_len))
362 return -EFAULT;
363 return 0;
364}
365
366static int convert_response_ica(struct zcrypt_device *zdev,
367 struct ap_message *reply,
368 char __user *outputdata,
369 unsigned int outputdatalength)
370{
371 struct type86x_reply *msg = reply->message;
372
373 /* Response type byte is the second byte in the response. */
374 switch (((unsigned char *) reply->message)[1]) {
375 case TYPE82_RSP_CODE:
376 case TYPE88_RSP_CODE:
377 return convert_error(zdev, reply);
378 case TYPE86_RSP_CODE:
379 if (msg->hdr.reply_code)
380 return convert_error(zdev, reply);
381 if (msg->cprbx.cprb_ver_id == 0x02)
382 return convert_type86_ica(zdev, reply,
383 outputdata, outputdatalength);
384 /* no break, incorrect cprb version is an unknown response */
385 default: /* Unknown response type, this should NEVER EVER happen */
386 PRINTK("Unrecognized Message Header: %08x%08x\n",
387 *(unsigned int *) reply->message,
388 *(unsigned int *) (reply->message+4));
389 zdev->online = 0;
390 return -EAGAIN; /* repeat the request on a different device. */
391 }
392}
393
394/**
395 * This function is called from the AP bus code after a crypto request
396 * "msg" has finished with the reply message "reply".
397 * It is called from tasklet context.
398 * @ap_dev: pointer to the AP device
399 * @msg: pointer to the AP message
400 * @reply: pointer to the AP reply message
401 */
402static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,
403 struct ap_message *msg,
404 struct ap_message *reply)
405{
406 static struct error_hdr error_reply = {
407 .type = TYPE82_RSP_CODE,
408 .reply_code = REP82_ERROR_MACHINE_FAILURE,
409 };
410 struct type86x_reply *t86r = reply->message;
411 int length;
412
413 /* Copy the reply message to the request message buffer. */
414 if (IS_ERR(reply))
415 memcpy(msg->message, &error_reply, sizeof(error_reply));
416 else if (t86r->hdr.type == TYPE86_RSP_CODE &&
417 t86r->cprbx.cprb_ver_id == 0x02) {
418 length = sizeof(struct type86x_reply) + t86r->length - 2;
419 length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
420 memcpy(msg->message, reply->message, length);
421 } else
422 memcpy(msg->message, reply->message, sizeof error_reply);
423 complete((struct completion *) msg->private);
424}
425
426static atomic_t zcrypt_step = ATOMIC_INIT(0);
427
428/**
429 * The request distributor calls this function if it picked the PCIXCC/CEX2C
430 * device to handle a modexpo request.
431 * @zdev: pointer to zcrypt_device structure that identifies the
432 * PCIXCC/CEX2C device to the request distributor
433 * @mex: pointer to the modexpo request buffer
434 */
435static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,
436 struct ica_rsa_modexpo *mex)
437{
438 struct ap_message ap_msg;
439 struct completion work;
440 int rc;
441
442 ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
443 if (!ap_msg.message)
444 return -ENOMEM;
445 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
446 atomic_inc_return(&zcrypt_step);
447 ap_msg.private = &work;
448 rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
449 if (rc)
450 goto out_free;
451 init_completion(&work);
452 ap_queue_message(zdev->ap_dev, &ap_msg);
453 rc = wait_for_completion_interruptible_timeout(
454 &work, PCIXCC_CLEANUP_TIME);
455 if (rc > 0)
456 rc = convert_response_ica(zdev, &ap_msg, mex->outputdata,
457 mex->outputdatalength);
458 else {
459 /* Signal pending or message timed out. */
460 ap_cancel_message(zdev->ap_dev, &ap_msg);
461 if (rc == 0)
462 /* Message timed out. */
463 rc = -ETIME;
464 }
465out_free:
466 free_page((unsigned long) ap_msg.message);
467 return rc;
468}
469
470/**
471 * The request distributor calls this function if it picked the PCIXCC/CEX2C
472 * device to handle a modexpo_crt request.
473 * @zdev: pointer to zcrypt_device structure that identifies the
474 * PCIXCC/CEX2C device to the request distributor
475 * @crt: pointer to the modexpoc_crt request buffer
476 */
477static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,
478 struct ica_rsa_modexpo_crt *crt)
479{
480 struct ap_message ap_msg;
481 struct completion work;
482 int rc;
483
484 ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
485 if (!ap_msg.message)
486 return -ENOMEM;
487 ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
488 atomic_inc_return(&zcrypt_step);
489 ap_msg.private = &work;
490 rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
491 if (rc)
492 goto out_free;
493 init_completion(&work);
494 ap_queue_message(zdev->ap_dev, &ap_msg);
495 rc = wait_for_completion_interruptible_timeout(
496 &work, PCIXCC_CLEANUP_TIME);
497 if (rc > 0)
498 rc = convert_response_ica(zdev, &ap_msg, crt->outputdata,
499 crt->outputdatalength);
500 else {
501 /* Signal pending or message timed out. */
502 ap_cancel_message(zdev->ap_dev, &ap_msg);
503 if (rc == 0)
504 /* Message timed out. */
505 rc = -ETIME;
506 }
507out_free:
508 free_page((unsigned long) ap_msg.message);
509 return rc;
510}
511
512/**
513 * The crypto operations for a PCIXCC/CEX2C card.
514 */
515static struct zcrypt_ops zcrypt_pcixcc_ops = {
516 .rsa_modexpo = zcrypt_pcixcc_modexpo,
517 .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt,
518};
519
520/**
521 * Micro-code detection function. Its sends a message to a pcixcc card
522 * to find out the microcode level.
523 * @ap_dev: pointer to the AP device.
524 */
525static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev)
526{
527 static unsigned char msg[] = {
528 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
529 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
530 0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
531 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
532 0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
533 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
534 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,
535 0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
536 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
537 0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
538 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
539 0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
540 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,
541 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
542 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
543 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
544 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
545 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
546 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
547 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
548 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
549 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
550 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
551 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
552 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
553 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
554 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
555 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
556 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
557 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
558 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
559 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
560 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
561 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
562 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
563 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
564 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
565 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
566 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,
567 0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
568 0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,
569 0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
570 0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,
571 0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
572 0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,
573 0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
574 0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,
575 0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
576 0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,
577 0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
578 0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,
579 0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
580 0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,
581 0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
582 0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,
583 0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
584 0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,
585 0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
586 0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,
587 0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
588 0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,
589 0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
590 0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,
591 0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
592 0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,
593 0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
594 0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,
595 0xF1,0x3D,0x93,0x53
596 };
597 unsigned long long psmid;
598 struct CPRBX *cprbx;
599 char *reply;
600 int rc, i;
601
602 reply = (void *) get_zeroed_page(GFP_KERNEL);
603 if (!reply)
604 return -ENOMEM;
605
606 rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, msg, sizeof(msg));
607 if (rc)
608 goto out_free;
609
610 /* Wait for the test message to complete. */
611 for (i = 0; i < 6; i++) {
612 mdelay(300);
613 rc = ap_recv(ap_dev->qid, &psmid, reply, 4096);
614 if (rc == 0 && psmid == 0x0102030405060708ULL)
615 break;
616 }
617
618 if (i >= 6) {
619 /* Got no answer. */
620 rc = -ENODEV;
621 goto out_free;
622 }
623
624 cprbx = (struct CPRBX *) (reply + 48);
625 if (cprbx->ccp_rtcode == 8 && cprbx->ccp_rscode == 33)
626 rc = ZCRYPT_PCIXCC_MCL2;
627 else
628 rc = ZCRYPT_PCIXCC_MCL3;
629out_free:
630 free_page((unsigned long) reply);
631 return rc;
632}
633
634/**
635 * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device
636 * since the bus_match already checked the hardware type. The PCIXCC
637 * cards come in two flavours: micro code level 2 and micro code level 3.
638 * This is checked by sending a test message to the device.
639 * @ap_dev: pointer to the AP device.
640 */
641static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
642{
643 struct zcrypt_device *zdev;
644 int rc;
645
646 zdev = zcrypt_device_alloc(PCIXCC_MAX_RESPONSE_SIZE);
647 if (!zdev)
648 return -ENOMEM;
649 zdev->ap_dev = ap_dev;
650 zdev->ops = &zcrypt_pcixcc_ops;
651 zdev->online = 1;
652 if (ap_dev->device_type == AP_DEVICE_TYPE_PCIXCC) {
653 rc = zcrypt_pcixcc_mcl(ap_dev);
654 if (rc < 0) {
655 zcrypt_device_free(zdev);
656 return rc;
657 }
658 zdev->user_space_type = rc;
659 if (rc == ZCRYPT_PCIXCC_MCL2) {
660 zdev->type_string = "PCIXCC_MCL2";
661 zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING;
662 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
663 zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
664 } else {
665 zdev->type_string = "PCIXCC_MCL3";
666 zdev->speed_rating = PCIXCC_MCL3_SPEED_RATING;
667 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
668 zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
669 }
670 } else {
671 zdev->user_space_type = ZCRYPT_CEX2C;
672 zdev->type_string = "CEX2C";
673 zdev->speed_rating = CEX2C_SPEED_RATING;
674 zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
675 zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
676 }
677 ap_dev->reply = &zdev->reply;
678 ap_dev->private = zdev;
679 rc = zcrypt_device_register(zdev);
680 if (rc)
681 goto out_free;
682 return 0;
683
684 out_free:
685 ap_dev->private = NULL;
686 zcrypt_device_free(zdev);
687 return rc;
688}
689
690/**
691 * This is called to remove the extended PCIXCC/CEX2C driver information
692 * if an AP device is removed.
693 */
694static void zcrypt_pcixcc_remove(struct ap_device *ap_dev)
695{
696 struct zcrypt_device *zdev = ap_dev->private;
697
698 zcrypt_device_unregister(zdev);
699}
700
701int __init zcrypt_pcixcc_init(void)
702{
703 return ap_driver_register(&zcrypt_pcixcc_driver, THIS_MODULE, "pcixcc");
704}
705
706void zcrypt_pcixcc_exit(void)
707{
708 ap_driver_unregister(&zcrypt_pcixcc_driver);
709}
710
711#ifndef CONFIG_ZCRYPT_MONOLITHIC
712module_init(zcrypt_pcixcc_init);
713module_exit(zcrypt_pcixcc_exit);
714#endif