diff options
Diffstat (limited to 'drivers/s390/crypto/zcrypt_api.c')
-rw-r--r-- | drivers/s390/crypto/zcrypt_api.c | 981 |
1 files changed, 981 insertions, 0 deletions
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c new file mode 100644 index 000000000000..b3fe003b3d2d --- /dev/null +++ b/drivers/s390/crypto/zcrypt_api.c | |||
@@ -0,0 +1,981 @@ | |||
1 | /* | ||
2 | * linux/drivers/s390/crypto/zcrypt_api.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 | * Cornelia Huck <cornelia.huck@de.ibm.com> | ||
10 | * | ||
11 | * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) | ||
12 | * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
13 | * Ralph Wuerthner <rwuerthn@de.ibm.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation; either version 2, or (at your option) | ||
18 | * any later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, | ||
21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
23 | * GNU General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
28 | */ | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/interrupt.h> | ||
33 | #include <linux/miscdevice.h> | ||
34 | #include <linux/fs.h> | ||
35 | #include <linux/proc_fs.h> | ||
36 | #include <linux/compat.h> | ||
37 | #include <asm/atomic.h> | ||
38 | #include <asm/uaccess.h> | ||
39 | |||
40 | #include "zcrypt_api.h" | ||
41 | |||
42 | /** | ||
43 | * Module description. | ||
44 | */ | ||
45 | MODULE_AUTHOR("IBM Corporation"); | ||
46 | MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " | ||
47 | "Copyright 2001, 2006 IBM Corporation"); | ||
48 | MODULE_LICENSE("GPL"); | ||
49 | |||
50 | static DEFINE_SPINLOCK(zcrypt_device_lock); | ||
51 | static LIST_HEAD(zcrypt_device_list); | ||
52 | static int zcrypt_device_count = 0; | ||
53 | static atomic_t zcrypt_open_count = ATOMIC_INIT(0); | ||
54 | |||
55 | /** | ||
56 | * Device attributes common for all crypto devices. | ||
57 | */ | ||
58 | static ssize_t zcrypt_type_show(struct device *dev, | ||
59 | struct device_attribute *attr, char *buf) | ||
60 | { | ||
61 | struct zcrypt_device *zdev = to_ap_dev(dev)->private; | ||
62 | return snprintf(buf, PAGE_SIZE, "%s\n", zdev->type_string); | ||
63 | } | ||
64 | |||
65 | static DEVICE_ATTR(type, 0444, zcrypt_type_show, NULL); | ||
66 | |||
67 | static ssize_t zcrypt_online_show(struct device *dev, | ||
68 | struct device_attribute *attr, char *buf) | ||
69 | { | ||
70 | struct zcrypt_device *zdev = to_ap_dev(dev)->private; | ||
71 | return snprintf(buf, PAGE_SIZE, "%d\n", zdev->online); | ||
72 | } | ||
73 | |||
74 | static ssize_t zcrypt_online_store(struct device *dev, | ||
75 | struct device_attribute *attr, | ||
76 | const char *buf, size_t count) | ||
77 | { | ||
78 | struct zcrypt_device *zdev = to_ap_dev(dev)->private; | ||
79 | int online; | ||
80 | |||
81 | if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) | ||
82 | return -EINVAL; | ||
83 | zdev->online = online; | ||
84 | if (!online) | ||
85 | ap_flush_queue(zdev->ap_dev); | ||
86 | return count; | ||
87 | } | ||
88 | |||
89 | static DEVICE_ATTR(online, 0644, zcrypt_online_show, zcrypt_online_store); | ||
90 | |||
91 | static struct attribute * zcrypt_device_attrs[] = { | ||
92 | &dev_attr_type.attr, | ||
93 | &dev_attr_online.attr, | ||
94 | NULL, | ||
95 | }; | ||
96 | |||
97 | static struct attribute_group zcrypt_device_attr_group = { | ||
98 | .attrs = zcrypt_device_attrs, | ||
99 | }; | ||
100 | |||
101 | /** | ||
102 | * Move the device towards the head of the device list. | ||
103 | * Need to be called while holding the zcrypt device list lock. | ||
104 | * Note: cards with speed_rating of 0 are kept at the end of the list. | ||
105 | */ | ||
106 | static void __zcrypt_increase_preference(struct zcrypt_device *zdev) | ||
107 | { | ||
108 | struct zcrypt_device *tmp; | ||
109 | struct list_head *l; | ||
110 | |||
111 | if (zdev->speed_rating == 0) | ||
112 | return; | ||
113 | for (l = zdev->list.prev; l != &zcrypt_device_list; l = l->prev) { | ||
114 | tmp = list_entry(l, struct zcrypt_device, list); | ||
115 | if ((tmp->request_count + 1) * tmp->speed_rating <= | ||
116 | (zdev->request_count + 1) * zdev->speed_rating && | ||
117 | tmp->speed_rating != 0) | ||
118 | break; | ||
119 | } | ||
120 | if (l == zdev->list.prev) | ||
121 | return; | ||
122 | /* Move zdev behind l */ | ||
123 | list_del(&zdev->list); | ||
124 | list_add(&zdev->list, l); | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * Move the device towards the tail of the device list. | ||
129 | * Need to be called while holding the zcrypt device list lock. | ||
130 | * Note: cards with speed_rating of 0 are kept at the end of the list. | ||
131 | */ | ||
132 | static void __zcrypt_decrease_preference(struct zcrypt_device *zdev) | ||
133 | { | ||
134 | struct zcrypt_device *tmp; | ||
135 | struct list_head *l; | ||
136 | |||
137 | if (zdev->speed_rating == 0) | ||
138 | return; | ||
139 | for (l = zdev->list.next; l != &zcrypt_device_list; l = l->next) { | ||
140 | tmp = list_entry(l, struct zcrypt_device, list); | ||
141 | if ((tmp->request_count + 1) * tmp->speed_rating > | ||
142 | (zdev->request_count + 1) * zdev->speed_rating || | ||
143 | tmp->speed_rating == 0) | ||
144 | break; | ||
145 | } | ||
146 | if (l == zdev->list.next) | ||
147 | return; | ||
148 | /* Move zdev before l */ | ||
149 | list_del(&zdev->list); | ||
150 | list_add_tail(&zdev->list, l); | ||
151 | } | ||
152 | |||
153 | static void zcrypt_device_release(struct kref *kref) | ||
154 | { | ||
155 | struct zcrypt_device *zdev = | ||
156 | container_of(kref, struct zcrypt_device, refcount); | ||
157 | zcrypt_device_free(zdev); | ||
158 | } | ||
159 | |||
160 | void zcrypt_device_get(struct zcrypt_device *zdev) | ||
161 | { | ||
162 | kref_get(&zdev->refcount); | ||
163 | } | ||
164 | EXPORT_SYMBOL(zcrypt_device_get); | ||
165 | |||
166 | int zcrypt_device_put(struct zcrypt_device *zdev) | ||
167 | { | ||
168 | return kref_put(&zdev->refcount, zcrypt_device_release); | ||
169 | } | ||
170 | EXPORT_SYMBOL(zcrypt_device_put); | ||
171 | |||
172 | struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size) | ||
173 | { | ||
174 | struct zcrypt_device *zdev; | ||
175 | |||
176 | zdev = kzalloc(sizeof(struct zcrypt_device), GFP_KERNEL); | ||
177 | if (!zdev) | ||
178 | return NULL; | ||
179 | zdev->reply.message = kmalloc(max_response_size, GFP_KERNEL); | ||
180 | if (!zdev->reply.message) | ||
181 | goto out_free; | ||
182 | zdev->reply.length = max_response_size; | ||
183 | spin_lock_init(&zdev->lock); | ||
184 | INIT_LIST_HEAD(&zdev->list); | ||
185 | return zdev; | ||
186 | |||
187 | out_free: | ||
188 | kfree(zdev); | ||
189 | return NULL; | ||
190 | } | ||
191 | EXPORT_SYMBOL(zcrypt_device_alloc); | ||
192 | |||
193 | void zcrypt_device_free(struct zcrypt_device *zdev) | ||
194 | { | ||
195 | kfree(zdev->reply.message); | ||
196 | kfree(zdev); | ||
197 | } | ||
198 | EXPORT_SYMBOL(zcrypt_device_free); | ||
199 | |||
200 | /** | ||
201 | * Register a crypto device. | ||
202 | */ | ||
203 | int zcrypt_device_register(struct zcrypt_device *zdev) | ||
204 | { | ||
205 | int rc; | ||
206 | |||
207 | rc = sysfs_create_group(&zdev->ap_dev->device.kobj, | ||
208 | &zcrypt_device_attr_group); | ||
209 | if (rc) | ||
210 | goto out; | ||
211 | get_device(&zdev->ap_dev->device); | ||
212 | kref_init(&zdev->refcount); | ||
213 | spin_lock_bh(&zcrypt_device_lock); | ||
214 | zdev->online = 1; /* New devices are online by default. */ | ||
215 | list_add_tail(&zdev->list, &zcrypt_device_list); | ||
216 | __zcrypt_increase_preference(zdev); | ||
217 | zcrypt_device_count++; | ||
218 | spin_unlock_bh(&zcrypt_device_lock); | ||
219 | out: | ||
220 | return rc; | ||
221 | } | ||
222 | EXPORT_SYMBOL(zcrypt_device_register); | ||
223 | |||
224 | /** | ||
225 | * Unregister a crypto device. | ||
226 | */ | ||
227 | void zcrypt_device_unregister(struct zcrypt_device *zdev) | ||
228 | { | ||
229 | spin_lock_bh(&zcrypt_device_lock); | ||
230 | zcrypt_device_count--; | ||
231 | list_del_init(&zdev->list); | ||
232 | spin_unlock_bh(&zcrypt_device_lock); | ||
233 | sysfs_remove_group(&zdev->ap_dev->device.kobj, | ||
234 | &zcrypt_device_attr_group); | ||
235 | put_device(&zdev->ap_dev->device); | ||
236 | zcrypt_device_put(zdev); | ||
237 | } | ||
238 | EXPORT_SYMBOL(zcrypt_device_unregister); | ||
239 | |||
240 | /** | ||
241 | * zcrypt_read is not be supported beyond zcrypt 1.3.1 | ||
242 | */ | ||
243 | static ssize_t zcrypt_read(struct file *filp, char __user *buf, | ||
244 | size_t count, loff_t *f_pos) | ||
245 | { | ||
246 | return -EPERM; | ||
247 | } | ||
248 | |||
249 | /** | ||
250 | * Write is is not allowed | ||
251 | */ | ||
252 | static ssize_t zcrypt_write(struct file *filp, const char __user *buf, | ||
253 | size_t count, loff_t *f_pos) | ||
254 | { | ||
255 | return -EPERM; | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * Device open/close functions to count number of users. | ||
260 | */ | ||
261 | static int zcrypt_open(struct inode *inode, struct file *filp) | ||
262 | { | ||
263 | atomic_inc(&zcrypt_open_count); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static int zcrypt_release(struct inode *inode, struct file *filp) | ||
268 | { | ||
269 | atomic_dec(&zcrypt_open_count); | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | /** | ||
274 | * zcrypt ioctls. | ||
275 | */ | ||
276 | static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) | ||
277 | { | ||
278 | struct zcrypt_device *zdev; | ||
279 | int rc; | ||
280 | |||
281 | if (mex->outputdatalength < mex->inputdatalength) | ||
282 | return -EINVAL; | ||
283 | /** | ||
284 | * As long as outputdatalength is big enough, we can set the | ||
285 | * outputdatalength equal to the inputdatalength, since that is the | ||
286 | * number of bytes we will copy in any case | ||
287 | */ | ||
288 | mex->outputdatalength = mex->inputdatalength; | ||
289 | |||
290 | spin_lock_bh(&zcrypt_device_lock); | ||
291 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
292 | if (!zdev->online || | ||
293 | !zdev->ops->rsa_modexpo || | ||
294 | zdev->min_mod_size > mex->inputdatalength || | ||
295 | zdev->max_mod_size < mex->inputdatalength) | ||
296 | continue; | ||
297 | zcrypt_device_get(zdev); | ||
298 | get_device(&zdev->ap_dev->device); | ||
299 | zdev->request_count++; | ||
300 | __zcrypt_decrease_preference(zdev); | ||
301 | spin_unlock_bh(&zcrypt_device_lock); | ||
302 | if (try_module_get(zdev->ap_dev->drv->driver.owner)) { | ||
303 | rc = zdev->ops->rsa_modexpo(zdev, mex); | ||
304 | module_put(zdev->ap_dev->drv->driver.owner); | ||
305 | } | ||
306 | else | ||
307 | rc = -EAGAIN; | ||
308 | spin_lock_bh(&zcrypt_device_lock); | ||
309 | zdev->request_count--; | ||
310 | __zcrypt_increase_preference(zdev); | ||
311 | put_device(&zdev->ap_dev->device); | ||
312 | zcrypt_device_put(zdev); | ||
313 | spin_unlock_bh(&zcrypt_device_lock); | ||
314 | return rc; | ||
315 | } | ||
316 | spin_unlock_bh(&zcrypt_device_lock); | ||
317 | return -ENODEV; | ||
318 | } | ||
319 | |||
320 | static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) | ||
321 | { | ||
322 | struct zcrypt_device *zdev; | ||
323 | unsigned long long z1, z2, z3; | ||
324 | int rc, copied; | ||
325 | |||
326 | if (crt->outputdatalength < crt->inputdatalength || | ||
327 | (crt->inputdatalength & 1)) | ||
328 | return -EINVAL; | ||
329 | /** | ||
330 | * As long as outputdatalength is big enough, we can set the | ||
331 | * outputdatalength equal to the inputdatalength, since that is the | ||
332 | * number of bytes we will copy in any case | ||
333 | */ | ||
334 | crt->outputdatalength = crt->inputdatalength; | ||
335 | |||
336 | copied = 0; | ||
337 | restart: | ||
338 | spin_lock_bh(&zcrypt_device_lock); | ||
339 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
340 | if (!zdev->online || | ||
341 | !zdev->ops->rsa_modexpo_crt || | ||
342 | zdev->min_mod_size > crt->inputdatalength || | ||
343 | zdev->max_mod_size < crt->inputdatalength) | ||
344 | continue; | ||
345 | if (zdev->short_crt && crt->inputdatalength > 240) { | ||
346 | /** | ||
347 | * Check inputdata for leading zeros for cards | ||
348 | * that can't handle np_prime, bp_key, or | ||
349 | * u_mult_inv > 128 bytes. | ||
350 | */ | ||
351 | if (copied == 0) { | ||
352 | int len; | ||
353 | spin_unlock_bh(&zcrypt_device_lock); | ||
354 | /* len is max 256 / 2 - 120 = 8 */ | ||
355 | len = crt->inputdatalength / 2 - 120; | ||
356 | z1 = z2 = z3 = 0; | ||
357 | if (copy_from_user(&z1, crt->np_prime, len) || | ||
358 | copy_from_user(&z2, crt->bp_key, len) || | ||
359 | copy_from_user(&z3, crt->u_mult_inv, len)) | ||
360 | return -EFAULT; | ||
361 | copied = 1; | ||
362 | /** | ||
363 | * We have to restart device lookup - | ||
364 | * the device list may have changed by now. | ||
365 | */ | ||
366 | goto restart; | ||
367 | } | ||
368 | if (z1 != 0ULL || z2 != 0ULL || z3 != 0ULL) | ||
369 | /* The device can't handle this request. */ | ||
370 | continue; | ||
371 | } | ||
372 | zcrypt_device_get(zdev); | ||
373 | get_device(&zdev->ap_dev->device); | ||
374 | zdev->request_count++; | ||
375 | __zcrypt_decrease_preference(zdev); | ||
376 | spin_unlock_bh(&zcrypt_device_lock); | ||
377 | if (try_module_get(zdev->ap_dev->drv->driver.owner)) { | ||
378 | rc = zdev->ops->rsa_modexpo_crt(zdev, crt); | ||
379 | module_put(zdev->ap_dev->drv->driver.owner); | ||
380 | } | ||
381 | else | ||
382 | rc = -EAGAIN; | ||
383 | spin_lock_bh(&zcrypt_device_lock); | ||
384 | zdev->request_count--; | ||
385 | __zcrypt_increase_preference(zdev); | ||
386 | put_device(&zdev->ap_dev->device); | ||
387 | zcrypt_device_put(zdev); | ||
388 | spin_unlock_bh(&zcrypt_device_lock); | ||
389 | return rc; | ||
390 | } | ||
391 | spin_unlock_bh(&zcrypt_device_lock); | ||
392 | return -ENODEV; | ||
393 | } | ||
394 | |||
395 | static void zcrypt_status_mask(char status[AP_DEVICES]) | ||
396 | { | ||
397 | struct zcrypt_device *zdev; | ||
398 | |||
399 | memset(status, 0, sizeof(char) * AP_DEVICES); | ||
400 | spin_lock_bh(&zcrypt_device_lock); | ||
401 | list_for_each_entry(zdev, &zcrypt_device_list, list) | ||
402 | status[AP_QID_DEVICE(zdev->ap_dev->qid)] = | ||
403 | zdev->online ? zdev->user_space_type : 0x0d; | ||
404 | spin_unlock_bh(&zcrypt_device_lock); | ||
405 | } | ||
406 | |||
407 | static void zcrypt_qdepth_mask(char qdepth[AP_DEVICES]) | ||
408 | { | ||
409 | struct zcrypt_device *zdev; | ||
410 | |||
411 | memset(qdepth, 0, sizeof(char) * AP_DEVICES); | ||
412 | spin_lock_bh(&zcrypt_device_lock); | ||
413 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
414 | spin_lock(&zdev->ap_dev->lock); | ||
415 | qdepth[AP_QID_DEVICE(zdev->ap_dev->qid)] = | ||
416 | zdev->ap_dev->pendingq_count + | ||
417 | zdev->ap_dev->requestq_count; | ||
418 | spin_unlock(&zdev->ap_dev->lock); | ||
419 | } | ||
420 | spin_unlock_bh(&zcrypt_device_lock); | ||
421 | } | ||
422 | |||
423 | static void zcrypt_perdev_reqcnt(int reqcnt[AP_DEVICES]) | ||
424 | { | ||
425 | struct zcrypt_device *zdev; | ||
426 | |||
427 | memset(reqcnt, 0, sizeof(int) * AP_DEVICES); | ||
428 | spin_lock_bh(&zcrypt_device_lock); | ||
429 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
430 | spin_lock(&zdev->ap_dev->lock); | ||
431 | reqcnt[AP_QID_DEVICE(zdev->ap_dev->qid)] = | ||
432 | zdev->ap_dev->total_request_count; | ||
433 | spin_unlock(&zdev->ap_dev->lock); | ||
434 | } | ||
435 | spin_unlock_bh(&zcrypt_device_lock); | ||
436 | } | ||
437 | |||
438 | static int zcrypt_pendingq_count(void) | ||
439 | { | ||
440 | struct zcrypt_device *zdev; | ||
441 | int pendingq_count = 0; | ||
442 | |||
443 | spin_lock_bh(&zcrypt_device_lock); | ||
444 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
445 | spin_lock(&zdev->ap_dev->lock); | ||
446 | pendingq_count += zdev->ap_dev->pendingq_count; | ||
447 | spin_unlock(&zdev->ap_dev->lock); | ||
448 | } | ||
449 | spin_unlock_bh(&zcrypt_device_lock); | ||
450 | return pendingq_count; | ||
451 | } | ||
452 | |||
453 | static int zcrypt_requestq_count(void) | ||
454 | { | ||
455 | struct zcrypt_device *zdev; | ||
456 | int requestq_count = 0; | ||
457 | |||
458 | spin_lock_bh(&zcrypt_device_lock); | ||
459 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
460 | spin_lock(&zdev->ap_dev->lock); | ||
461 | requestq_count += zdev->ap_dev->requestq_count; | ||
462 | spin_unlock(&zdev->ap_dev->lock); | ||
463 | } | ||
464 | spin_unlock_bh(&zcrypt_device_lock); | ||
465 | return requestq_count; | ||
466 | } | ||
467 | |||
468 | static int zcrypt_count_type(int type) | ||
469 | { | ||
470 | struct zcrypt_device *zdev; | ||
471 | int device_count = 0; | ||
472 | |||
473 | spin_lock_bh(&zcrypt_device_lock); | ||
474 | list_for_each_entry(zdev, &zcrypt_device_list, list) | ||
475 | if (zdev->user_space_type == type) | ||
476 | device_count++; | ||
477 | spin_unlock_bh(&zcrypt_device_lock); | ||
478 | return device_count; | ||
479 | } | ||
480 | |||
481 | /** | ||
482 | * Old, deprecated combi status call. | ||
483 | */ | ||
484 | static long zcrypt_ica_status(struct file *filp, unsigned long arg) | ||
485 | { | ||
486 | struct ica_z90_status *pstat; | ||
487 | int ret; | ||
488 | |||
489 | pstat = kzalloc(sizeof(*pstat), GFP_KERNEL); | ||
490 | if (!pstat) | ||
491 | return -ENOMEM; | ||
492 | pstat->totalcount = zcrypt_device_count; | ||
493 | pstat->leedslitecount = zcrypt_count_type(ZCRYPT_PCICA); | ||
494 | pstat->leeds2count = zcrypt_count_type(ZCRYPT_PCICC); | ||
495 | pstat->requestqWaitCount = zcrypt_requestq_count(); | ||
496 | pstat->pendingqWaitCount = zcrypt_pendingq_count(); | ||
497 | pstat->totalOpenCount = atomic_read(&zcrypt_open_count); | ||
498 | pstat->cryptoDomain = ap_domain_index; | ||
499 | zcrypt_status_mask(pstat->status); | ||
500 | zcrypt_qdepth_mask(pstat->qdepth); | ||
501 | ret = 0; | ||
502 | if (copy_to_user((void __user *) arg, pstat, sizeof(*pstat))) | ||
503 | ret = -EFAULT; | ||
504 | kfree(pstat); | ||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, | ||
509 | unsigned long arg) | ||
510 | { | ||
511 | int rc; | ||
512 | |||
513 | switch (cmd) { | ||
514 | case ICARSAMODEXPO: { | ||
515 | struct ica_rsa_modexpo __user *umex = (void __user *) arg; | ||
516 | struct ica_rsa_modexpo mex; | ||
517 | if (copy_from_user(&mex, umex, sizeof(mex))) | ||
518 | return -EFAULT; | ||
519 | do { | ||
520 | rc = zcrypt_rsa_modexpo(&mex); | ||
521 | } while (rc == -EAGAIN); | ||
522 | if (rc) | ||
523 | return rc; | ||
524 | return put_user(mex.outputdatalength, &umex->outputdatalength); | ||
525 | } | ||
526 | case ICARSACRT: { | ||
527 | struct ica_rsa_modexpo_crt __user *ucrt = (void __user *) arg; | ||
528 | struct ica_rsa_modexpo_crt crt; | ||
529 | if (copy_from_user(&crt, ucrt, sizeof(crt))) | ||
530 | return -EFAULT; | ||
531 | do { | ||
532 | rc = zcrypt_rsa_crt(&crt); | ||
533 | } while (rc == -EAGAIN); | ||
534 | if (rc) | ||
535 | return rc; | ||
536 | return put_user(crt.outputdatalength, &ucrt->outputdatalength); | ||
537 | } | ||
538 | case Z90STAT_STATUS_MASK: { | ||
539 | char status[AP_DEVICES]; | ||
540 | zcrypt_status_mask(status); | ||
541 | if (copy_to_user((char __user *) arg, status, | ||
542 | sizeof(char) * AP_DEVICES)) | ||
543 | return -EFAULT; | ||
544 | return 0; | ||
545 | } | ||
546 | case Z90STAT_QDEPTH_MASK: { | ||
547 | char qdepth[AP_DEVICES]; | ||
548 | zcrypt_qdepth_mask(qdepth); | ||
549 | if (copy_to_user((char __user *) arg, qdepth, | ||
550 | sizeof(char) * AP_DEVICES)) | ||
551 | return -EFAULT; | ||
552 | return 0; | ||
553 | } | ||
554 | case Z90STAT_PERDEV_REQCNT: { | ||
555 | int reqcnt[AP_DEVICES]; | ||
556 | zcrypt_perdev_reqcnt(reqcnt); | ||
557 | if (copy_to_user((int __user *) arg, reqcnt, | ||
558 | sizeof(int) * AP_DEVICES)) | ||
559 | return -EFAULT; | ||
560 | return 0; | ||
561 | } | ||
562 | case Z90STAT_REQUESTQ_COUNT: | ||
563 | return put_user(zcrypt_requestq_count(), (int __user *) arg); | ||
564 | case Z90STAT_PENDINGQ_COUNT: | ||
565 | return put_user(zcrypt_pendingq_count(), (int __user *) arg); | ||
566 | case Z90STAT_TOTALOPEN_COUNT: | ||
567 | return put_user(atomic_read(&zcrypt_open_count), | ||
568 | (int __user *) arg); | ||
569 | case Z90STAT_DOMAIN_INDEX: | ||
570 | return put_user(ap_domain_index, (int __user *) arg); | ||
571 | /** | ||
572 | * Deprecated ioctls. Don't add another device count ioctl, | ||
573 | * you can count them yourself in the user space with the | ||
574 | * output of the Z90STAT_STATUS_MASK ioctl. | ||
575 | */ | ||
576 | case ICAZ90STATUS: | ||
577 | return zcrypt_ica_status(filp, arg); | ||
578 | case Z90STAT_TOTALCOUNT: | ||
579 | return put_user(zcrypt_device_count, (int __user *) arg); | ||
580 | case Z90STAT_PCICACOUNT: | ||
581 | return put_user(zcrypt_count_type(ZCRYPT_PCICA), | ||
582 | (int __user *) arg); | ||
583 | case Z90STAT_PCICCCOUNT: | ||
584 | return put_user(zcrypt_count_type(ZCRYPT_PCICC), | ||
585 | (int __user *) arg); | ||
586 | case Z90STAT_PCIXCCMCL2COUNT: | ||
587 | return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL2), | ||
588 | (int __user *) arg); | ||
589 | case Z90STAT_PCIXCCMCL3COUNT: | ||
590 | return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL3), | ||
591 | (int __user *) arg); | ||
592 | case Z90STAT_PCIXCCCOUNT: | ||
593 | return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL2) + | ||
594 | zcrypt_count_type(ZCRYPT_PCIXCC_MCL3), | ||
595 | (int __user *) arg); | ||
596 | case Z90STAT_CEX2CCOUNT: | ||
597 | return put_user(zcrypt_count_type(ZCRYPT_CEX2C), | ||
598 | (int __user *) arg); | ||
599 | case Z90STAT_CEX2ACOUNT: | ||
600 | return put_user(zcrypt_count_type(ZCRYPT_CEX2A), | ||
601 | (int __user *) arg); | ||
602 | default: | ||
603 | /* unknown ioctl number */ | ||
604 | return -ENOIOCTLCMD; | ||
605 | } | ||
606 | } | ||
607 | |||
608 | #ifdef CONFIG_COMPAT | ||
609 | /** | ||
610 | * ioctl32 conversion routines | ||
611 | */ | ||
612 | struct compat_ica_rsa_modexpo { | ||
613 | compat_uptr_t inputdata; | ||
614 | unsigned int inputdatalength; | ||
615 | compat_uptr_t outputdata; | ||
616 | unsigned int outputdatalength; | ||
617 | compat_uptr_t b_key; | ||
618 | compat_uptr_t n_modulus; | ||
619 | }; | ||
620 | |||
621 | static long trans_modexpo32(struct file *filp, unsigned int cmd, | ||
622 | unsigned long arg) | ||
623 | { | ||
624 | struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg); | ||
625 | struct compat_ica_rsa_modexpo mex32; | ||
626 | struct ica_rsa_modexpo mex64; | ||
627 | long rc; | ||
628 | |||
629 | if (copy_from_user(&mex32, umex32, sizeof(mex32))) | ||
630 | return -EFAULT; | ||
631 | mex64.inputdata = compat_ptr(mex32.inputdata); | ||
632 | mex64.inputdatalength = mex32.inputdatalength; | ||
633 | mex64.outputdata = compat_ptr(mex32.outputdata); | ||
634 | mex64.outputdatalength = mex32.outputdatalength; | ||
635 | mex64.b_key = compat_ptr(mex32.b_key); | ||
636 | mex64.n_modulus = compat_ptr(mex32.n_modulus); | ||
637 | do { | ||
638 | rc = zcrypt_rsa_modexpo(&mex64); | ||
639 | } while (rc == -EAGAIN); | ||
640 | if (!rc) | ||
641 | rc = put_user(mex64.outputdatalength, | ||
642 | &umex32->outputdatalength); | ||
643 | return rc; | ||
644 | } | ||
645 | |||
646 | struct compat_ica_rsa_modexpo_crt { | ||
647 | compat_uptr_t inputdata; | ||
648 | unsigned int inputdatalength; | ||
649 | compat_uptr_t outputdata; | ||
650 | unsigned int outputdatalength; | ||
651 | compat_uptr_t bp_key; | ||
652 | compat_uptr_t bq_key; | ||
653 | compat_uptr_t np_prime; | ||
654 | compat_uptr_t nq_prime; | ||
655 | compat_uptr_t u_mult_inv; | ||
656 | }; | ||
657 | |||
658 | static long trans_modexpo_crt32(struct file *filp, unsigned int cmd, | ||
659 | unsigned long arg) | ||
660 | { | ||
661 | struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg); | ||
662 | struct compat_ica_rsa_modexpo_crt crt32; | ||
663 | struct ica_rsa_modexpo_crt crt64; | ||
664 | long rc; | ||
665 | |||
666 | if (copy_from_user(&crt32, ucrt32, sizeof(crt32))) | ||
667 | return -EFAULT; | ||
668 | crt64.inputdata = compat_ptr(crt32.inputdata); | ||
669 | crt64.inputdatalength = crt32.inputdatalength; | ||
670 | crt64.outputdata= compat_ptr(crt32.outputdata); | ||
671 | crt64.outputdatalength = crt32.outputdatalength; | ||
672 | crt64.bp_key = compat_ptr(crt32.bp_key); | ||
673 | crt64.bq_key = compat_ptr(crt32.bq_key); | ||
674 | crt64.np_prime = compat_ptr(crt32.np_prime); | ||
675 | crt64.nq_prime = compat_ptr(crt32.nq_prime); | ||
676 | crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv); | ||
677 | do { | ||
678 | rc = zcrypt_rsa_crt(&crt64); | ||
679 | } while (rc == -EAGAIN); | ||
680 | if (!rc) | ||
681 | rc = put_user(crt64.outputdatalength, | ||
682 | &ucrt32->outputdatalength); | ||
683 | return rc; | ||
684 | } | ||
685 | |||
686 | long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, | ||
687 | unsigned long arg) | ||
688 | { | ||
689 | if (cmd == ICARSAMODEXPO) | ||
690 | return trans_modexpo32(filp, cmd, arg); | ||
691 | if (cmd == ICARSACRT) | ||
692 | return trans_modexpo_crt32(filp, cmd, arg); | ||
693 | return zcrypt_unlocked_ioctl(filp, cmd, arg); | ||
694 | } | ||
695 | #endif | ||
696 | |||
697 | /** | ||
698 | * Misc device file operations. | ||
699 | */ | ||
700 | static struct file_operations zcrypt_fops = { | ||
701 | .owner = THIS_MODULE, | ||
702 | .read = zcrypt_read, | ||
703 | .write = zcrypt_write, | ||
704 | .unlocked_ioctl = zcrypt_unlocked_ioctl, | ||
705 | #ifdef CONFIG_COMPAT | ||
706 | .compat_ioctl = zcrypt_compat_ioctl, | ||
707 | #endif | ||
708 | .open = zcrypt_open, | ||
709 | .release = zcrypt_release | ||
710 | }; | ||
711 | |||
712 | /** | ||
713 | * Misc device. | ||
714 | */ | ||
715 | static struct miscdevice zcrypt_misc_device = { | ||
716 | .minor = MISC_DYNAMIC_MINOR, | ||
717 | .name = "z90crypt", | ||
718 | .fops = &zcrypt_fops, | ||
719 | }; | ||
720 | |||
721 | /** | ||
722 | * Deprecated /proc entry support. | ||
723 | */ | ||
724 | static struct proc_dir_entry *zcrypt_entry; | ||
725 | |||
726 | static inline int sprintcl(unsigned char *outaddr, unsigned char *addr, | ||
727 | unsigned int len) | ||
728 | { | ||
729 | int hl, i; | ||
730 | |||
731 | hl = 0; | ||
732 | for (i = 0; i < len; i++) | ||
733 | hl += sprintf(outaddr+hl, "%01x", (unsigned int) addr[i]); | ||
734 | hl += sprintf(outaddr+hl, " "); | ||
735 | return hl; | ||
736 | } | ||
737 | |||
738 | static inline int sprintrw(unsigned char *outaddr, unsigned char *addr, | ||
739 | unsigned int len) | ||
740 | { | ||
741 | int hl, inl, c, cx; | ||
742 | |||
743 | hl = sprintf(outaddr, " "); | ||
744 | inl = 0; | ||
745 | for (c = 0; c < (len / 16); c++) { | ||
746 | hl += sprintcl(outaddr+hl, addr+inl, 16); | ||
747 | inl += 16; | ||
748 | } | ||
749 | cx = len%16; | ||
750 | if (cx) { | ||
751 | hl += sprintcl(outaddr+hl, addr+inl, cx); | ||
752 | inl += cx; | ||
753 | } | ||
754 | hl += sprintf(outaddr+hl, "\n"); | ||
755 | return hl; | ||
756 | } | ||
757 | |||
758 | static inline int sprinthx(unsigned char *title, unsigned char *outaddr, | ||
759 | unsigned char *addr, unsigned int len) | ||
760 | { | ||
761 | int hl, inl, r, rx; | ||
762 | |||
763 | hl = sprintf(outaddr, "\n%s\n", title); | ||
764 | inl = 0; | ||
765 | for (r = 0; r < (len / 64); r++) { | ||
766 | hl += sprintrw(outaddr+hl, addr+inl, 64); | ||
767 | inl += 64; | ||
768 | } | ||
769 | rx = len % 64; | ||
770 | if (rx) { | ||
771 | hl += sprintrw(outaddr+hl, addr+inl, rx); | ||
772 | inl += rx; | ||
773 | } | ||
774 | hl += sprintf(outaddr+hl, "\n"); | ||
775 | return hl; | ||
776 | } | ||
777 | |||
778 | static inline int sprinthx4(unsigned char *title, unsigned char *outaddr, | ||
779 | unsigned int *array, unsigned int len) | ||
780 | { | ||
781 | int hl, r; | ||
782 | |||
783 | hl = sprintf(outaddr, "\n%s\n", title); | ||
784 | for (r = 0; r < len; r++) { | ||
785 | if ((r % 8) == 0) | ||
786 | hl += sprintf(outaddr+hl, " "); | ||
787 | hl += sprintf(outaddr+hl, "%08X ", array[r]); | ||
788 | if ((r % 8) == 7) | ||
789 | hl += sprintf(outaddr+hl, "\n"); | ||
790 | } | ||
791 | hl += sprintf(outaddr+hl, "\n"); | ||
792 | return hl; | ||
793 | } | ||
794 | |||
795 | static int zcrypt_status_read(char *resp_buff, char **start, off_t offset, | ||
796 | int count, int *eof, void *data) | ||
797 | { | ||
798 | unsigned char *workarea; | ||
799 | int len; | ||
800 | |||
801 | len = 0; | ||
802 | |||
803 | /* resp_buff is a page. Use the right half for a work area */ | ||
804 | workarea = resp_buff + 2000; | ||
805 | len += sprintf(resp_buff + len, "\nzcrypt version: %d.%d.%d\n", | ||
806 | ZCRYPT_VERSION, ZCRYPT_RELEASE, ZCRYPT_VARIANT); | ||
807 | len += sprintf(resp_buff + len, "Cryptographic domain: %d\n", | ||
808 | ap_domain_index); | ||
809 | len += sprintf(resp_buff + len, "Total device count: %d\n", | ||
810 | zcrypt_device_count); | ||
811 | len += sprintf(resp_buff + len, "PCICA count: %d\n", | ||
812 | zcrypt_count_type(ZCRYPT_PCICA)); | ||
813 | len += sprintf(resp_buff + len, "PCICC count: %d\n", | ||
814 | zcrypt_count_type(ZCRYPT_PCICC)); | ||
815 | len += sprintf(resp_buff + len, "PCIXCC MCL2 count: %d\n", | ||
816 | zcrypt_count_type(ZCRYPT_PCIXCC_MCL2)); | ||
817 | len += sprintf(resp_buff + len, "PCIXCC MCL3 count: %d\n", | ||
818 | zcrypt_count_type(ZCRYPT_PCIXCC_MCL3)); | ||
819 | len += sprintf(resp_buff + len, "CEX2C count: %d\n", | ||
820 | zcrypt_count_type(ZCRYPT_CEX2C)); | ||
821 | len += sprintf(resp_buff + len, "CEX2A count: %d\n", | ||
822 | zcrypt_count_type(ZCRYPT_CEX2A)); | ||
823 | len += sprintf(resp_buff + len, "requestq count: %d\n", | ||
824 | zcrypt_requestq_count()); | ||
825 | len += sprintf(resp_buff + len, "pendingq count: %d\n", | ||
826 | zcrypt_pendingq_count()); | ||
827 | len += sprintf(resp_buff + len, "Total open handles: %d\n\n", | ||
828 | atomic_read(&zcrypt_open_count)); | ||
829 | zcrypt_status_mask(workarea); | ||
830 | len += sprinthx("Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) " | ||
831 | "4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A", | ||
832 | resp_buff+len, workarea, AP_DEVICES); | ||
833 | zcrypt_qdepth_mask(workarea); | ||
834 | len += sprinthx("Waiting work element counts", | ||
835 | resp_buff+len, workarea, AP_DEVICES); | ||
836 | zcrypt_perdev_reqcnt((unsigned int *) workarea); | ||
837 | len += sprinthx4("Per-device successfully completed request counts", | ||
838 | resp_buff+len,(unsigned int *) workarea, AP_DEVICES); | ||
839 | *eof = 1; | ||
840 | memset((void *) workarea, 0x00, AP_DEVICES * sizeof(unsigned int)); | ||
841 | return len; | ||
842 | } | ||
843 | |||
844 | static void zcrypt_disable_card(int index) | ||
845 | { | ||
846 | struct zcrypt_device *zdev; | ||
847 | |||
848 | spin_lock_bh(&zcrypt_device_lock); | ||
849 | list_for_each_entry(zdev, &zcrypt_device_list, list) | ||
850 | if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) { | ||
851 | zdev->online = 0; | ||
852 | ap_flush_queue(zdev->ap_dev); | ||
853 | break; | ||
854 | } | ||
855 | spin_unlock_bh(&zcrypt_device_lock); | ||
856 | } | ||
857 | |||
858 | static void zcrypt_enable_card(int index) | ||
859 | { | ||
860 | struct zcrypt_device *zdev; | ||
861 | |||
862 | spin_lock_bh(&zcrypt_device_lock); | ||
863 | list_for_each_entry(zdev, &zcrypt_device_list, list) | ||
864 | if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) { | ||
865 | zdev->online = 1; | ||
866 | break; | ||
867 | } | ||
868 | spin_unlock_bh(&zcrypt_device_lock); | ||
869 | } | ||
870 | |||
871 | static int zcrypt_status_write(struct file *file, const char __user *buffer, | ||
872 | unsigned long count, void *data) | ||
873 | { | ||
874 | unsigned char *lbuf, *ptr; | ||
875 | unsigned long local_count; | ||
876 | int j; | ||
877 | |||
878 | if (count <= 0) | ||
879 | return 0; | ||
880 | |||
881 | #define LBUFSIZE 1200UL | ||
882 | lbuf = kmalloc(LBUFSIZE, GFP_KERNEL); | ||
883 | if (!lbuf) { | ||
884 | PRINTK("kmalloc failed!\n"); | ||
885 | return 0; | ||
886 | } | ||
887 | |||
888 | local_count = min(LBUFSIZE - 1, count); | ||
889 | if (copy_from_user(lbuf, buffer, local_count) != 0) { | ||
890 | kfree(lbuf); | ||
891 | return -EFAULT; | ||
892 | } | ||
893 | lbuf[local_count] = '\0'; | ||
894 | |||
895 | ptr = strstr(lbuf, "Online devices"); | ||
896 | if (!ptr) { | ||
897 | PRINTK("Unable to parse data (missing \"Online devices\")\n"); | ||
898 | goto out; | ||
899 | } | ||
900 | ptr = strstr(ptr, "\n"); | ||
901 | if (!ptr) { | ||
902 | PRINTK("Unable to parse data (missing newline " | ||
903 | "after \"Online devices\")\n"); | ||
904 | goto out; | ||
905 | } | ||
906 | ptr++; | ||
907 | |||
908 | if (strstr(ptr, "Waiting work element counts") == NULL) { | ||
909 | PRINTK("Unable to parse data (missing " | ||
910 | "\"Waiting work element counts\")\n"); | ||
911 | goto out; | ||
912 | } | ||
913 | |||
914 | for (j = 0; j < 64 && *ptr; ptr++) { | ||
915 | /** | ||
916 | * '0' for no device, '1' for PCICA, '2' for PCICC, | ||
917 | * '3' for PCIXCC_MCL2, '4' for PCIXCC_MCL3, | ||
918 | * '5' for CEX2C and '6' for CEX2A' | ||
919 | */ | ||
920 | if (*ptr >= '0' && *ptr <= '6') | ||
921 | j++; | ||
922 | else if (*ptr == 'd' || *ptr == 'D') | ||
923 | zcrypt_disable_card(j++); | ||
924 | else if (*ptr == 'e' || *ptr == 'E') | ||
925 | zcrypt_enable_card(j++); | ||
926 | else if (*ptr != ' ' && *ptr != '\t') | ||
927 | break; | ||
928 | } | ||
929 | out: | ||
930 | kfree(lbuf); | ||
931 | return count; | ||
932 | } | ||
933 | |||
934 | /** | ||
935 | * The module initialization code. | ||
936 | */ | ||
937 | int __init zcrypt_api_init(void) | ||
938 | { | ||
939 | int rc; | ||
940 | |||
941 | /* Register the request sprayer. */ | ||
942 | rc = misc_register(&zcrypt_misc_device); | ||
943 | if (rc < 0) { | ||
944 | PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n", | ||
945 | zcrypt_misc_device.minor, rc); | ||
946 | goto out; | ||
947 | } | ||
948 | |||
949 | /* Set up the proc file system */ | ||
950 | zcrypt_entry = create_proc_entry("driver/z90crypt", 0644, NULL); | ||
951 | if (!zcrypt_entry) { | ||
952 | PRINTK("Couldn't create z90crypt proc entry\n"); | ||
953 | rc = -ENOMEM; | ||
954 | goto out_misc; | ||
955 | } | ||
956 | zcrypt_entry->nlink = 1; | ||
957 | zcrypt_entry->data = NULL; | ||
958 | zcrypt_entry->read_proc = zcrypt_status_read; | ||
959 | zcrypt_entry->write_proc = zcrypt_status_write; | ||
960 | |||
961 | return 0; | ||
962 | |||
963 | out_misc: | ||
964 | misc_deregister(&zcrypt_misc_device); | ||
965 | out: | ||
966 | return rc; | ||
967 | } | ||
968 | |||
969 | /** | ||
970 | * The module termination code. | ||
971 | */ | ||
972 | void zcrypt_api_exit(void) | ||
973 | { | ||
974 | remove_proc_entry("driver/z90crypt", NULL); | ||
975 | misc_deregister(&zcrypt_misc_device); | ||
976 | } | ||
977 | |||
978 | #ifndef CONFIG_ZCRYPT_MONOLITHIC | ||
979 | module_init(zcrypt_api_init); | ||
980 | module_exit(zcrypt_api_exit); | ||
981 | #endif | ||