diff options
Diffstat (limited to 'drivers/s390/crypto/zcrypt_api.c')
-rw-r--r-- | drivers/s390/crypto/zcrypt_api.c | 1091 |
1 files changed, 1091 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..1edc10a7a6f2 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_api.c | |||
@@ -0,0 +1,1091 @@ | |||
1 | /* | ||
2 | * linux/drivers/s390/crypto/zcrypt_api.c | ||
3 | * | ||
4 | * zcrypt 2.1.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 long zcrypt_send_cprb(struct ica_xcRB *xcRB) | ||
396 | { | ||
397 | struct zcrypt_device *zdev; | ||
398 | int rc; | ||
399 | |||
400 | spin_lock_bh(&zcrypt_device_lock); | ||
401 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
402 | if (!zdev->online || !zdev->ops->send_cprb || | ||
403 | (xcRB->user_defined != AUTOSELECT && | ||
404 | AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined) | ||
405 | ) | ||
406 | continue; | ||
407 | zcrypt_device_get(zdev); | ||
408 | get_device(&zdev->ap_dev->device); | ||
409 | zdev->request_count++; | ||
410 | __zcrypt_decrease_preference(zdev); | ||
411 | spin_unlock_bh(&zcrypt_device_lock); | ||
412 | if (try_module_get(zdev->ap_dev->drv->driver.owner)) { | ||
413 | rc = zdev->ops->send_cprb(zdev, xcRB); | ||
414 | module_put(zdev->ap_dev->drv->driver.owner); | ||
415 | } | ||
416 | else | ||
417 | rc = -EAGAIN; | ||
418 | spin_lock_bh(&zcrypt_device_lock); | ||
419 | zdev->request_count--; | ||
420 | __zcrypt_increase_preference(zdev); | ||
421 | put_device(&zdev->ap_dev->device); | ||
422 | zcrypt_device_put(zdev); | ||
423 | spin_unlock_bh(&zcrypt_device_lock); | ||
424 | return rc; | ||
425 | } | ||
426 | spin_unlock_bh(&zcrypt_device_lock); | ||
427 | return -ENODEV; | ||
428 | } | ||
429 | |||
430 | static void zcrypt_status_mask(char status[AP_DEVICES]) | ||
431 | { | ||
432 | struct zcrypt_device *zdev; | ||
433 | |||
434 | memset(status, 0, sizeof(char) * AP_DEVICES); | ||
435 | spin_lock_bh(&zcrypt_device_lock); | ||
436 | list_for_each_entry(zdev, &zcrypt_device_list, list) | ||
437 | status[AP_QID_DEVICE(zdev->ap_dev->qid)] = | ||
438 | zdev->online ? zdev->user_space_type : 0x0d; | ||
439 | spin_unlock_bh(&zcrypt_device_lock); | ||
440 | } | ||
441 | |||
442 | static void zcrypt_qdepth_mask(char qdepth[AP_DEVICES]) | ||
443 | { | ||
444 | struct zcrypt_device *zdev; | ||
445 | |||
446 | memset(qdepth, 0, sizeof(char) * AP_DEVICES); | ||
447 | spin_lock_bh(&zcrypt_device_lock); | ||
448 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
449 | spin_lock(&zdev->ap_dev->lock); | ||
450 | qdepth[AP_QID_DEVICE(zdev->ap_dev->qid)] = | ||
451 | zdev->ap_dev->pendingq_count + | ||
452 | zdev->ap_dev->requestq_count; | ||
453 | spin_unlock(&zdev->ap_dev->lock); | ||
454 | } | ||
455 | spin_unlock_bh(&zcrypt_device_lock); | ||
456 | } | ||
457 | |||
458 | static void zcrypt_perdev_reqcnt(int reqcnt[AP_DEVICES]) | ||
459 | { | ||
460 | struct zcrypt_device *zdev; | ||
461 | |||
462 | memset(reqcnt, 0, sizeof(int) * AP_DEVICES); | ||
463 | spin_lock_bh(&zcrypt_device_lock); | ||
464 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
465 | spin_lock(&zdev->ap_dev->lock); | ||
466 | reqcnt[AP_QID_DEVICE(zdev->ap_dev->qid)] = | ||
467 | zdev->ap_dev->total_request_count; | ||
468 | spin_unlock(&zdev->ap_dev->lock); | ||
469 | } | ||
470 | spin_unlock_bh(&zcrypt_device_lock); | ||
471 | } | ||
472 | |||
473 | static int zcrypt_pendingq_count(void) | ||
474 | { | ||
475 | struct zcrypt_device *zdev; | ||
476 | int pendingq_count = 0; | ||
477 | |||
478 | spin_lock_bh(&zcrypt_device_lock); | ||
479 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
480 | spin_lock(&zdev->ap_dev->lock); | ||
481 | pendingq_count += zdev->ap_dev->pendingq_count; | ||
482 | spin_unlock(&zdev->ap_dev->lock); | ||
483 | } | ||
484 | spin_unlock_bh(&zcrypt_device_lock); | ||
485 | return pendingq_count; | ||
486 | } | ||
487 | |||
488 | static int zcrypt_requestq_count(void) | ||
489 | { | ||
490 | struct zcrypt_device *zdev; | ||
491 | int requestq_count = 0; | ||
492 | |||
493 | spin_lock_bh(&zcrypt_device_lock); | ||
494 | list_for_each_entry(zdev, &zcrypt_device_list, list) { | ||
495 | spin_lock(&zdev->ap_dev->lock); | ||
496 | requestq_count += zdev->ap_dev->requestq_count; | ||
497 | spin_unlock(&zdev->ap_dev->lock); | ||
498 | } | ||
499 | spin_unlock_bh(&zcrypt_device_lock); | ||
500 | return requestq_count; | ||
501 | } | ||
502 | |||
503 | static int zcrypt_count_type(int type) | ||
504 | { | ||
505 | struct zcrypt_device *zdev; | ||
506 | int device_count = 0; | ||
507 | |||
508 | spin_lock_bh(&zcrypt_device_lock); | ||
509 | list_for_each_entry(zdev, &zcrypt_device_list, list) | ||
510 | if (zdev->user_space_type == type) | ||
511 | device_count++; | ||
512 | spin_unlock_bh(&zcrypt_device_lock); | ||
513 | return device_count; | ||
514 | } | ||
515 | |||
516 | /** | ||
517 | * Old, deprecated combi status call. | ||
518 | */ | ||
519 | static long zcrypt_ica_status(struct file *filp, unsigned long arg) | ||
520 | { | ||
521 | struct ica_z90_status *pstat; | ||
522 | int ret; | ||
523 | |||
524 | pstat = kzalloc(sizeof(*pstat), GFP_KERNEL); | ||
525 | if (!pstat) | ||
526 | return -ENOMEM; | ||
527 | pstat->totalcount = zcrypt_device_count; | ||
528 | pstat->leedslitecount = zcrypt_count_type(ZCRYPT_PCICA); | ||
529 | pstat->leeds2count = zcrypt_count_type(ZCRYPT_PCICC); | ||
530 | pstat->requestqWaitCount = zcrypt_requestq_count(); | ||
531 | pstat->pendingqWaitCount = zcrypt_pendingq_count(); | ||
532 | pstat->totalOpenCount = atomic_read(&zcrypt_open_count); | ||
533 | pstat->cryptoDomain = ap_domain_index; | ||
534 | zcrypt_status_mask(pstat->status); | ||
535 | zcrypt_qdepth_mask(pstat->qdepth); | ||
536 | ret = 0; | ||
537 | if (copy_to_user((void __user *) arg, pstat, sizeof(*pstat))) | ||
538 | ret = -EFAULT; | ||
539 | kfree(pstat); | ||
540 | return ret; | ||
541 | } | ||
542 | |||
543 | static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, | ||
544 | unsigned long arg) | ||
545 | { | ||
546 | int rc; | ||
547 | |||
548 | switch (cmd) { | ||
549 | case ICARSAMODEXPO: { | ||
550 | struct ica_rsa_modexpo __user *umex = (void __user *) arg; | ||
551 | struct ica_rsa_modexpo mex; | ||
552 | if (copy_from_user(&mex, umex, sizeof(mex))) | ||
553 | return -EFAULT; | ||
554 | do { | ||
555 | rc = zcrypt_rsa_modexpo(&mex); | ||
556 | } while (rc == -EAGAIN); | ||
557 | if (rc) | ||
558 | return rc; | ||
559 | return put_user(mex.outputdatalength, &umex->outputdatalength); | ||
560 | } | ||
561 | case ICARSACRT: { | ||
562 | struct ica_rsa_modexpo_crt __user *ucrt = (void __user *) arg; | ||
563 | struct ica_rsa_modexpo_crt crt; | ||
564 | if (copy_from_user(&crt, ucrt, sizeof(crt))) | ||
565 | return -EFAULT; | ||
566 | do { | ||
567 | rc = zcrypt_rsa_crt(&crt); | ||
568 | } while (rc == -EAGAIN); | ||
569 | if (rc) | ||
570 | return rc; | ||
571 | return put_user(crt.outputdatalength, &ucrt->outputdatalength); | ||
572 | } | ||
573 | case ZSECSENDCPRB: { | ||
574 | struct ica_xcRB __user *uxcRB = (void __user *) arg; | ||
575 | struct ica_xcRB xcRB; | ||
576 | if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB))) | ||
577 | return -EFAULT; | ||
578 | do { | ||
579 | rc = zcrypt_send_cprb(&xcRB); | ||
580 | } while (rc == -EAGAIN); | ||
581 | if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB))) | ||
582 | return -EFAULT; | ||
583 | return rc; | ||
584 | } | ||
585 | case Z90STAT_STATUS_MASK: { | ||
586 | char status[AP_DEVICES]; | ||
587 | zcrypt_status_mask(status); | ||
588 | if (copy_to_user((char __user *) arg, status, | ||
589 | sizeof(char) * AP_DEVICES)) | ||
590 | return -EFAULT; | ||
591 | return 0; | ||
592 | } | ||
593 | case Z90STAT_QDEPTH_MASK: { | ||
594 | char qdepth[AP_DEVICES]; | ||
595 | zcrypt_qdepth_mask(qdepth); | ||
596 | if (copy_to_user((char __user *) arg, qdepth, | ||
597 | sizeof(char) * AP_DEVICES)) | ||
598 | return -EFAULT; | ||
599 | return 0; | ||
600 | } | ||
601 | case Z90STAT_PERDEV_REQCNT: { | ||
602 | int reqcnt[AP_DEVICES]; | ||
603 | zcrypt_perdev_reqcnt(reqcnt); | ||
604 | if (copy_to_user((int __user *) arg, reqcnt, | ||
605 | sizeof(int) * AP_DEVICES)) | ||
606 | return -EFAULT; | ||
607 | return 0; | ||
608 | } | ||
609 | case Z90STAT_REQUESTQ_COUNT: | ||
610 | return put_user(zcrypt_requestq_count(), (int __user *) arg); | ||
611 | case Z90STAT_PENDINGQ_COUNT: | ||
612 | return put_user(zcrypt_pendingq_count(), (int __user *) arg); | ||
613 | case Z90STAT_TOTALOPEN_COUNT: | ||
614 | return put_user(atomic_read(&zcrypt_open_count), | ||
615 | (int __user *) arg); | ||
616 | case Z90STAT_DOMAIN_INDEX: | ||
617 | return put_user(ap_domain_index, (int __user *) arg); | ||
618 | /** | ||
619 | * Deprecated ioctls. Don't add another device count ioctl, | ||
620 | * you can count them yourself in the user space with the | ||
621 | * output of the Z90STAT_STATUS_MASK ioctl. | ||
622 | */ | ||
623 | case ICAZ90STATUS: | ||
624 | return zcrypt_ica_status(filp, arg); | ||
625 | case Z90STAT_TOTALCOUNT: | ||
626 | return put_user(zcrypt_device_count, (int __user *) arg); | ||
627 | case Z90STAT_PCICACOUNT: | ||
628 | return put_user(zcrypt_count_type(ZCRYPT_PCICA), | ||
629 | (int __user *) arg); | ||
630 | case Z90STAT_PCICCCOUNT: | ||
631 | return put_user(zcrypt_count_type(ZCRYPT_PCICC), | ||
632 | (int __user *) arg); | ||
633 | case Z90STAT_PCIXCCMCL2COUNT: | ||
634 | return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL2), | ||
635 | (int __user *) arg); | ||
636 | case Z90STAT_PCIXCCMCL3COUNT: | ||
637 | return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL3), | ||
638 | (int __user *) arg); | ||
639 | case Z90STAT_PCIXCCCOUNT: | ||
640 | return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL2) + | ||
641 | zcrypt_count_type(ZCRYPT_PCIXCC_MCL3), | ||
642 | (int __user *) arg); | ||
643 | case Z90STAT_CEX2CCOUNT: | ||
644 | return put_user(zcrypt_count_type(ZCRYPT_CEX2C), | ||
645 | (int __user *) arg); | ||
646 | case Z90STAT_CEX2ACOUNT: | ||
647 | return put_user(zcrypt_count_type(ZCRYPT_CEX2A), | ||
648 | (int __user *) arg); | ||
649 | default: | ||
650 | /* unknown ioctl number */ | ||
651 | return -ENOIOCTLCMD; | ||
652 | } | ||
653 | } | ||
654 | |||
655 | #ifdef CONFIG_COMPAT | ||
656 | /** | ||
657 | * ioctl32 conversion routines | ||
658 | */ | ||
659 | struct compat_ica_rsa_modexpo { | ||
660 | compat_uptr_t inputdata; | ||
661 | unsigned int inputdatalength; | ||
662 | compat_uptr_t outputdata; | ||
663 | unsigned int outputdatalength; | ||
664 | compat_uptr_t b_key; | ||
665 | compat_uptr_t n_modulus; | ||
666 | }; | ||
667 | |||
668 | static long trans_modexpo32(struct file *filp, unsigned int cmd, | ||
669 | unsigned long arg) | ||
670 | { | ||
671 | struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg); | ||
672 | struct compat_ica_rsa_modexpo mex32; | ||
673 | struct ica_rsa_modexpo mex64; | ||
674 | long rc; | ||
675 | |||
676 | if (copy_from_user(&mex32, umex32, sizeof(mex32))) | ||
677 | return -EFAULT; | ||
678 | mex64.inputdata = compat_ptr(mex32.inputdata); | ||
679 | mex64.inputdatalength = mex32.inputdatalength; | ||
680 | mex64.outputdata = compat_ptr(mex32.outputdata); | ||
681 | mex64.outputdatalength = mex32.outputdatalength; | ||
682 | mex64.b_key = compat_ptr(mex32.b_key); | ||
683 | mex64.n_modulus = compat_ptr(mex32.n_modulus); | ||
684 | do { | ||
685 | rc = zcrypt_rsa_modexpo(&mex64); | ||
686 | } while (rc == -EAGAIN); | ||
687 | if (!rc) | ||
688 | rc = put_user(mex64.outputdatalength, | ||
689 | &umex32->outputdatalength); | ||
690 | return rc; | ||
691 | } | ||
692 | |||
693 | struct compat_ica_rsa_modexpo_crt { | ||
694 | compat_uptr_t inputdata; | ||
695 | unsigned int inputdatalength; | ||
696 | compat_uptr_t outputdata; | ||
697 | unsigned int outputdatalength; | ||
698 | compat_uptr_t bp_key; | ||
699 | compat_uptr_t bq_key; | ||
700 | compat_uptr_t np_prime; | ||
701 | compat_uptr_t nq_prime; | ||
702 | compat_uptr_t u_mult_inv; | ||
703 | }; | ||
704 | |||
705 | static long trans_modexpo_crt32(struct file *filp, unsigned int cmd, | ||
706 | unsigned long arg) | ||
707 | { | ||
708 | struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg); | ||
709 | struct compat_ica_rsa_modexpo_crt crt32; | ||
710 | struct ica_rsa_modexpo_crt crt64; | ||
711 | long rc; | ||
712 | |||
713 | if (copy_from_user(&crt32, ucrt32, sizeof(crt32))) | ||
714 | return -EFAULT; | ||
715 | crt64.inputdata = compat_ptr(crt32.inputdata); | ||
716 | crt64.inputdatalength = crt32.inputdatalength; | ||
717 | crt64.outputdata= compat_ptr(crt32.outputdata); | ||
718 | crt64.outputdatalength = crt32.outputdatalength; | ||
719 | crt64.bp_key = compat_ptr(crt32.bp_key); | ||
720 | crt64.bq_key = compat_ptr(crt32.bq_key); | ||
721 | crt64.np_prime = compat_ptr(crt32.np_prime); | ||
722 | crt64.nq_prime = compat_ptr(crt32.nq_prime); | ||
723 | crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv); | ||
724 | do { | ||
725 | rc = zcrypt_rsa_crt(&crt64); | ||
726 | } while (rc == -EAGAIN); | ||
727 | if (!rc) | ||
728 | rc = put_user(crt64.outputdatalength, | ||
729 | &ucrt32->outputdatalength); | ||
730 | return rc; | ||
731 | } | ||
732 | |||
733 | struct compat_ica_xcRB { | ||
734 | unsigned short agent_ID; | ||
735 | unsigned int user_defined; | ||
736 | unsigned short request_ID; | ||
737 | unsigned int request_control_blk_length; | ||
738 | unsigned char padding1[16 - sizeof (compat_uptr_t)]; | ||
739 | compat_uptr_t request_control_blk_addr; | ||
740 | unsigned int request_data_length; | ||
741 | char padding2[16 - sizeof (compat_uptr_t)]; | ||
742 | compat_uptr_t request_data_address; | ||
743 | unsigned int reply_control_blk_length; | ||
744 | char padding3[16 - sizeof (compat_uptr_t)]; | ||
745 | compat_uptr_t reply_control_blk_addr; | ||
746 | unsigned int reply_data_length; | ||
747 | char padding4[16 - sizeof (compat_uptr_t)]; | ||
748 | compat_uptr_t reply_data_addr; | ||
749 | unsigned short priority_window; | ||
750 | unsigned int status; | ||
751 | } __attribute__((packed)); | ||
752 | |||
753 | static long trans_xcRB32(struct file *filp, unsigned int cmd, | ||
754 | unsigned long arg) | ||
755 | { | ||
756 | struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg); | ||
757 | struct compat_ica_xcRB xcRB32; | ||
758 | struct ica_xcRB xcRB64; | ||
759 | long rc; | ||
760 | |||
761 | if (copy_from_user(&xcRB32, uxcRB32, sizeof(xcRB32))) | ||
762 | return -EFAULT; | ||
763 | xcRB64.agent_ID = xcRB32.agent_ID; | ||
764 | xcRB64.user_defined = xcRB32.user_defined; | ||
765 | xcRB64.request_ID = xcRB32.request_ID; | ||
766 | xcRB64.request_control_blk_length = | ||
767 | xcRB32.request_control_blk_length; | ||
768 | xcRB64.request_control_blk_addr = | ||
769 | compat_ptr(xcRB32.request_control_blk_addr); | ||
770 | xcRB64.request_data_length = | ||
771 | xcRB32.request_data_length; | ||
772 | xcRB64.request_data_address = | ||
773 | compat_ptr(xcRB32.request_data_address); | ||
774 | xcRB64.reply_control_blk_length = | ||
775 | xcRB32.reply_control_blk_length; | ||
776 | xcRB64.reply_control_blk_addr = | ||
777 | compat_ptr(xcRB32.reply_control_blk_addr); | ||
778 | xcRB64.reply_data_length = xcRB32.reply_data_length; | ||
779 | xcRB64.reply_data_addr = | ||
780 | compat_ptr(xcRB32.reply_data_addr); | ||
781 | xcRB64.priority_window = xcRB32.priority_window; | ||
782 | xcRB64.status = xcRB32.status; | ||
783 | do { | ||
784 | rc = zcrypt_send_cprb(&xcRB64); | ||
785 | } while (rc == -EAGAIN); | ||
786 | xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length; | ||
787 | xcRB32.reply_data_length = xcRB64.reply_data_length; | ||
788 | xcRB32.status = xcRB64.status; | ||
789 | if (copy_to_user(uxcRB32, &xcRB32, sizeof(xcRB32))) | ||
790 | return -EFAULT; | ||
791 | return rc; | ||
792 | } | ||
793 | |||
794 | long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, | ||
795 | unsigned long arg) | ||
796 | { | ||
797 | if (cmd == ICARSAMODEXPO) | ||
798 | return trans_modexpo32(filp, cmd, arg); | ||
799 | if (cmd == ICARSACRT) | ||
800 | return trans_modexpo_crt32(filp, cmd, arg); | ||
801 | if (cmd == ZSECSENDCPRB) | ||
802 | return trans_xcRB32(filp, cmd, arg); | ||
803 | return zcrypt_unlocked_ioctl(filp, cmd, arg); | ||
804 | } | ||
805 | #endif | ||
806 | |||
807 | /** | ||
808 | * Misc device file operations. | ||
809 | */ | ||
810 | static struct file_operations zcrypt_fops = { | ||
811 | .owner = THIS_MODULE, | ||
812 | .read = zcrypt_read, | ||
813 | .write = zcrypt_write, | ||
814 | .unlocked_ioctl = zcrypt_unlocked_ioctl, | ||
815 | #ifdef CONFIG_COMPAT | ||
816 | .compat_ioctl = zcrypt_compat_ioctl, | ||
817 | #endif | ||
818 | .open = zcrypt_open, | ||
819 | .release = zcrypt_release | ||
820 | }; | ||
821 | |||
822 | /** | ||
823 | * Misc device. | ||
824 | */ | ||
825 | static struct miscdevice zcrypt_misc_device = { | ||
826 | .minor = MISC_DYNAMIC_MINOR, | ||
827 | .name = "z90crypt", | ||
828 | .fops = &zcrypt_fops, | ||
829 | }; | ||
830 | |||
831 | /** | ||
832 | * Deprecated /proc entry support. | ||
833 | */ | ||
834 | static struct proc_dir_entry *zcrypt_entry; | ||
835 | |||
836 | static inline int sprintcl(unsigned char *outaddr, unsigned char *addr, | ||
837 | unsigned int len) | ||
838 | { | ||
839 | int hl, i; | ||
840 | |||
841 | hl = 0; | ||
842 | for (i = 0; i < len; i++) | ||
843 | hl += sprintf(outaddr+hl, "%01x", (unsigned int) addr[i]); | ||
844 | hl += sprintf(outaddr+hl, " "); | ||
845 | return hl; | ||
846 | } | ||
847 | |||
848 | static inline int sprintrw(unsigned char *outaddr, unsigned char *addr, | ||
849 | unsigned int len) | ||
850 | { | ||
851 | int hl, inl, c, cx; | ||
852 | |||
853 | hl = sprintf(outaddr, " "); | ||
854 | inl = 0; | ||
855 | for (c = 0; c < (len / 16); c++) { | ||
856 | hl += sprintcl(outaddr+hl, addr+inl, 16); | ||
857 | inl += 16; | ||
858 | } | ||
859 | cx = len%16; | ||
860 | if (cx) { | ||
861 | hl += sprintcl(outaddr+hl, addr+inl, cx); | ||
862 | inl += cx; | ||
863 | } | ||
864 | hl += sprintf(outaddr+hl, "\n"); | ||
865 | return hl; | ||
866 | } | ||
867 | |||
868 | static inline int sprinthx(unsigned char *title, unsigned char *outaddr, | ||
869 | unsigned char *addr, unsigned int len) | ||
870 | { | ||
871 | int hl, inl, r, rx; | ||
872 | |||
873 | hl = sprintf(outaddr, "\n%s\n", title); | ||
874 | inl = 0; | ||
875 | for (r = 0; r < (len / 64); r++) { | ||
876 | hl += sprintrw(outaddr+hl, addr+inl, 64); | ||
877 | inl += 64; | ||
878 | } | ||
879 | rx = len % 64; | ||
880 | if (rx) { | ||
881 | hl += sprintrw(outaddr+hl, addr+inl, rx); | ||
882 | inl += rx; | ||
883 | } | ||
884 | hl += sprintf(outaddr+hl, "\n"); | ||
885 | return hl; | ||
886 | } | ||
887 | |||
888 | static inline int sprinthx4(unsigned char *title, unsigned char *outaddr, | ||
889 | unsigned int *array, unsigned int len) | ||
890 | { | ||
891 | int hl, r; | ||
892 | |||
893 | hl = sprintf(outaddr, "\n%s\n", title); | ||
894 | for (r = 0; r < len; r++) { | ||
895 | if ((r % 8) == 0) | ||
896 | hl += sprintf(outaddr+hl, " "); | ||
897 | hl += sprintf(outaddr+hl, "%08X ", array[r]); | ||
898 | if ((r % 8) == 7) | ||
899 | hl += sprintf(outaddr+hl, "\n"); | ||
900 | } | ||
901 | hl += sprintf(outaddr+hl, "\n"); | ||
902 | return hl; | ||
903 | } | ||
904 | |||
905 | static int zcrypt_status_read(char *resp_buff, char **start, off_t offset, | ||
906 | int count, int *eof, void *data) | ||
907 | { | ||
908 | unsigned char *workarea; | ||
909 | int len; | ||
910 | |||
911 | len = 0; | ||
912 | |||
913 | /* resp_buff is a page. Use the right half for a work area */ | ||
914 | workarea = resp_buff + 2000; | ||
915 | len += sprintf(resp_buff + len, "\nzcrypt version: %d.%d.%d\n", | ||
916 | ZCRYPT_VERSION, ZCRYPT_RELEASE, ZCRYPT_VARIANT); | ||
917 | len += sprintf(resp_buff + len, "Cryptographic domain: %d\n", | ||
918 | ap_domain_index); | ||
919 | len += sprintf(resp_buff + len, "Total device count: %d\n", | ||
920 | zcrypt_device_count); | ||
921 | len += sprintf(resp_buff + len, "PCICA count: %d\n", | ||
922 | zcrypt_count_type(ZCRYPT_PCICA)); | ||
923 | len += sprintf(resp_buff + len, "PCICC count: %d\n", | ||
924 | zcrypt_count_type(ZCRYPT_PCICC)); | ||
925 | len += sprintf(resp_buff + len, "PCIXCC MCL2 count: %d\n", | ||
926 | zcrypt_count_type(ZCRYPT_PCIXCC_MCL2)); | ||
927 | len += sprintf(resp_buff + len, "PCIXCC MCL3 count: %d\n", | ||
928 | zcrypt_count_type(ZCRYPT_PCIXCC_MCL3)); | ||
929 | len += sprintf(resp_buff + len, "CEX2C count: %d\n", | ||
930 | zcrypt_count_type(ZCRYPT_CEX2C)); | ||
931 | len += sprintf(resp_buff + len, "CEX2A count: %d\n", | ||
932 | zcrypt_count_type(ZCRYPT_CEX2A)); | ||
933 | len += sprintf(resp_buff + len, "requestq count: %d\n", | ||
934 | zcrypt_requestq_count()); | ||
935 | len += sprintf(resp_buff + len, "pendingq count: %d\n", | ||
936 | zcrypt_pendingq_count()); | ||
937 | len += sprintf(resp_buff + len, "Total open handles: %d\n\n", | ||
938 | atomic_read(&zcrypt_open_count)); | ||
939 | zcrypt_status_mask(workarea); | ||
940 | len += sprinthx("Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) " | ||
941 | "4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A", | ||
942 | resp_buff+len, workarea, AP_DEVICES); | ||
943 | zcrypt_qdepth_mask(workarea); | ||
944 | len += sprinthx("Waiting work element counts", | ||
945 | resp_buff+len, workarea, AP_DEVICES); | ||
946 | zcrypt_perdev_reqcnt((unsigned int *) workarea); | ||
947 | len += sprinthx4("Per-device successfully completed request counts", | ||
948 | resp_buff+len,(unsigned int *) workarea, AP_DEVICES); | ||
949 | *eof = 1; | ||
950 | memset((void *) workarea, 0x00, AP_DEVICES * sizeof(unsigned int)); | ||
951 | return len; | ||
952 | } | ||
953 | |||
954 | static void zcrypt_disable_card(int index) | ||
955 | { | ||
956 | struct zcrypt_device *zdev; | ||
957 | |||
958 | spin_lock_bh(&zcrypt_device_lock); | ||
959 | list_for_each_entry(zdev, &zcrypt_device_list, list) | ||
960 | if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) { | ||
961 | zdev->online = 0; | ||
962 | ap_flush_queue(zdev->ap_dev); | ||
963 | break; | ||
964 | } | ||
965 | spin_unlock_bh(&zcrypt_device_lock); | ||
966 | } | ||
967 | |||
968 | static void zcrypt_enable_card(int index) | ||
969 | { | ||
970 | struct zcrypt_device *zdev; | ||
971 | |||
972 | spin_lock_bh(&zcrypt_device_lock); | ||
973 | list_for_each_entry(zdev, &zcrypt_device_list, list) | ||
974 | if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) { | ||
975 | zdev->online = 1; | ||
976 | break; | ||
977 | } | ||
978 | spin_unlock_bh(&zcrypt_device_lock); | ||
979 | } | ||
980 | |||
981 | static int zcrypt_status_write(struct file *file, const char __user *buffer, | ||
982 | unsigned long count, void *data) | ||
983 | { | ||
984 | unsigned char *lbuf, *ptr; | ||
985 | unsigned long local_count; | ||
986 | int j; | ||
987 | |||
988 | if (count <= 0) | ||
989 | return 0; | ||
990 | |||
991 | #define LBUFSIZE 1200UL | ||
992 | lbuf = kmalloc(LBUFSIZE, GFP_KERNEL); | ||
993 | if (!lbuf) { | ||
994 | PRINTK("kmalloc failed!\n"); | ||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | local_count = min(LBUFSIZE - 1, count); | ||
999 | if (copy_from_user(lbuf, buffer, local_count) != 0) { | ||
1000 | kfree(lbuf); | ||
1001 | return -EFAULT; | ||
1002 | } | ||
1003 | lbuf[local_count] = '\0'; | ||
1004 | |||
1005 | ptr = strstr(lbuf, "Online devices"); | ||
1006 | if (!ptr) { | ||
1007 | PRINTK("Unable to parse data (missing \"Online devices\")\n"); | ||
1008 | goto out; | ||
1009 | } | ||
1010 | ptr = strstr(ptr, "\n"); | ||
1011 | if (!ptr) { | ||
1012 | PRINTK("Unable to parse data (missing newline " | ||
1013 | "after \"Online devices\")\n"); | ||
1014 | goto out; | ||
1015 | } | ||
1016 | ptr++; | ||
1017 | |||
1018 | if (strstr(ptr, "Waiting work element counts") == NULL) { | ||
1019 | PRINTK("Unable to parse data (missing " | ||
1020 | "\"Waiting work element counts\")\n"); | ||
1021 | goto out; | ||
1022 | } | ||
1023 | |||
1024 | for (j = 0; j < 64 && *ptr; ptr++) { | ||
1025 | /** | ||
1026 | * '0' for no device, '1' for PCICA, '2' for PCICC, | ||
1027 | * '3' for PCIXCC_MCL2, '4' for PCIXCC_MCL3, | ||
1028 | * '5' for CEX2C and '6' for CEX2A' | ||
1029 | */ | ||
1030 | if (*ptr >= '0' && *ptr <= '6') | ||
1031 | j++; | ||
1032 | else if (*ptr == 'd' || *ptr == 'D') | ||
1033 | zcrypt_disable_card(j++); | ||
1034 | else if (*ptr == 'e' || *ptr == 'E') | ||
1035 | zcrypt_enable_card(j++); | ||
1036 | else if (*ptr != ' ' && *ptr != '\t') | ||
1037 | break; | ||
1038 | } | ||
1039 | out: | ||
1040 | kfree(lbuf); | ||
1041 | return count; | ||
1042 | } | ||
1043 | |||
1044 | /** | ||
1045 | * The module initialization code. | ||
1046 | */ | ||
1047 | int __init zcrypt_api_init(void) | ||
1048 | { | ||
1049 | int rc; | ||
1050 | |||
1051 | /* Register the request sprayer. */ | ||
1052 | rc = misc_register(&zcrypt_misc_device); | ||
1053 | if (rc < 0) { | ||
1054 | PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n", | ||
1055 | zcrypt_misc_device.minor, rc); | ||
1056 | goto out; | ||
1057 | } | ||
1058 | |||
1059 | /* Set up the proc file system */ | ||
1060 | zcrypt_entry = create_proc_entry("driver/z90crypt", 0644, NULL); | ||
1061 | if (!zcrypt_entry) { | ||
1062 | PRINTK("Couldn't create z90crypt proc entry\n"); | ||
1063 | rc = -ENOMEM; | ||
1064 | goto out_misc; | ||
1065 | } | ||
1066 | zcrypt_entry->nlink = 1; | ||
1067 | zcrypt_entry->data = NULL; | ||
1068 | zcrypt_entry->read_proc = zcrypt_status_read; | ||
1069 | zcrypt_entry->write_proc = zcrypt_status_write; | ||
1070 | |||
1071 | return 0; | ||
1072 | |||
1073 | out_misc: | ||
1074 | misc_deregister(&zcrypt_misc_device); | ||
1075 | out: | ||
1076 | return rc; | ||
1077 | } | ||
1078 | |||
1079 | /** | ||
1080 | * The module termination code. | ||
1081 | */ | ||
1082 | void zcrypt_api_exit(void) | ||
1083 | { | ||
1084 | remove_proc_entry("driver/z90crypt", NULL); | ||
1085 | misc_deregister(&zcrypt_misc_device); | ||
1086 | } | ||
1087 | |||
1088 | #ifndef CONFIG_ZCRYPT_MONOLITHIC | ||
1089 | module_init(zcrypt_api_init); | ||
1090 | module_exit(zcrypt_api_exit); | ||
1091 | #endif | ||