#include <linux/atomic.h>
#include <asm/uaccess.h>
#include <linux/hw_random.h>
+#include <linux/debugfs.h>
+#include <asm/debug.h>
+#include "zcrypt_debug.h"
#include "zcrypt_api.h"
/*
static LIST_HEAD(zcrypt_device_list);
static int zcrypt_device_count = 0;
static atomic_t zcrypt_open_count = ATOMIC_INIT(0);
+static atomic_t zcrypt_rescan_count = ATOMIC_INIT(0);
+
+atomic_t zcrypt_rescan_req = ATOMIC_INIT(0);
+EXPORT_SYMBOL(zcrypt_rescan_req);
static int zcrypt_rng_device_add(void);
static void zcrypt_rng_device_remove(void);
static DEFINE_SPINLOCK(zcrypt_ops_list_lock);
static LIST_HEAD(zcrypt_ops_list);
+static debug_info_t *zcrypt_dbf_common;
+static debug_info_t *zcrypt_dbf_devices;
+static struct dentry *debugfs_root;
+
/*
* Device attributes common for all crypto devices.
*/
if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
return -EINVAL;
zdev->online = online;
+ ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dman", zdev->ap_dev->qid,
+ zdev->online);
if (!online)
ap_flush_queue(zdev->ap_dev);
return count;
.attrs = zcrypt_device_attrs,
};
+/**
+ * Process a rescan of the transport layer.
+ *
+ * Returns 1, if the rescan has been processed, otherwise 0.
+ */
+static inline int zcrypt_process_rescan(void)
+{
+ if (atomic_read(&zcrypt_rescan_req)) {
+ atomic_set(&zcrypt_rescan_req, 0);
+ atomic_inc(&zcrypt_rescan_count);
+ ap_bus_force_rescan();
+ ZCRYPT_DBF_COMMON(DBF_INFO, "rescan%07d",
+ atomic_inc_return(&zcrypt_rescan_count));
+ return 1;
+ }
+ return 0;
+}
+
/**
* __zcrypt_increase_preference(): Increase preference of a crypto device.
* @zdev: Pointer the crypto device
zdev->reply.length = max_response_size;
spin_lock_init(&zdev->lock);
INIT_LIST_HEAD(&zdev->list);
+ zdev->dbf_area = zcrypt_dbf_devices;
return zdev;
out_free:
kref_init(&zdev->refcount);
spin_lock_bh(&zcrypt_device_lock);
zdev->online = 1; /* New devices are online by default. */
+ ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dreg", zdev->ap_dev->qid,
+ zdev->online);
list_add_tail(&zdev->list, &zcrypt_device_list);
__zcrypt_increase_preference(zdev);
zcrypt_device_count++;
do {
rc = zcrypt_rsa_modexpo(&mex);
} while (rc == -EAGAIN);
+ /* on failure: retry once again after a requested rescan */
+ if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+ do {
+ rc = zcrypt_rsa_modexpo(&mex);
+ } while (rc == -EAGAIN);
if (rc)
return rc;
return put_user(mex.outputdatalength, &umex->outputdatalength);
do {
rc = zcrypt_rsa_crt(&crt);
} while (rc == -EAGAIN);
+ /* on failure: retry once again after a requested rescan */
+ if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+ do {
+ rc = zcrypt_rsa_crt(&crt);
+ } while (rc == -EAGAIN);
if (rc)
return rc;
return put_user(crt.outputdatalength, &ucrt->outputdatalength);
do {
rc = zcrypt_send_cprb(&xcRB);
} while (rc == -EAGAIN);
+ /* on failure: retry once again after a requested rescan */
+ if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+ do {
+ rc = zcrypt_send_cprb(&xcRB);
+ } while (rc == -EAGAIN);
if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
return -EFAULT;
return rc;
do {
rc = zcrypt_rsa_modexpo(&mex64);
} while (rc == -EAGAIN);
- if (!rc)
- rc = put_user(mex64.outputdatalength,
- &umex32->outputdatalength);
- return rc;
+ /* on failure: retry once again after a requested rescan */
+ if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+ do {
+ rc = zcrypt_rsa_modexpo(&mex64);
+ } while (rc == -EAGAIN);
+ if (rc)
+ return rc;
+ return put_user(mex64.outputdatalength,
+ &umex32->outputdatalength);
}
struct compat_ica_rsa_modexpo_crt {
do {
rc = zcrypt_rsa_crt(&crt64);
} while (rc == -EAGAIN);
- if (!rc)
- rc = put_user(crt64.outputdatalength,
- &ucrt32->outputdatalength);
- return rc;
+ /* on failure: retry once again after a requested rescan */
+ if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+ do {
+ rc = zcrypt_rsa_crt(&crt64);
+ } while (rc == -EAGAIN);
+ if (rc)
+ return rc;
+ return put_user(crt64.outputdatalength,
+ &ucrt32->outputdatalength);
}
struct compat_ica_xcRB {
do {
rc = zcrypt_send_cprb(&xcRB64);
} while (rc == -EAGAIN);
+ /* on failure: retry once again after a requested rescan */
+ if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+ do {
+ rc = zcrypt_send_cprb(&xcRB64);
+ } while (rc == -EAGAIN);
xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
xcRB32.reply_data_length = xcRB64.reply_data_length;
xcRB32.status = xcRB64.status;
*/
if (zcrypt_rng_buffer_index == 0) {
rc = zcrypt_rng((char *) zcrypt_rng_buffer);
+ /* on failure: retry once again after a requested rescan */
+ if ((rc == -ENODEV) && (zcrypt_process_rescan()))
+ rc = zcrypt_rng((char *) zcrypt_rng_buffer);
if (rc < 0)
return -EIO;
zcrypt_rng_buffer_index = rc / sizeof *data;
mutex_unlock(&zcrypt_rng_mutex);
}
+int __init zcrypt_debug_init(void)
+{
+ debugfs_root = debugfs_create_dir("zcrypt", NULL);
+
+ zcrypt_dbf_common = debug_register("zcrypt_common", 1, 1, 16);
+ debug_register_view(zcrypt_dbf_common, &debug_hex_ascii_view);
+ debug_set_level(zcrypt_dbf_common, DBF_ERR);
+
+ zcrypt_dbf_devices = debug_register("zcrypt_devices", 1, 1, 16);
+ debug_register_view(zcrypt_dbf_devices, &debug_hex_ascii_view);
+ debug_set_level(zcrypt_dbf_devices, DBF_ERR);
+
+ return 0;
+}
+
+void zcrypt_debug_exit(void)
+{
+ debugfs_remove(debugfs_root);
+ if (zcrypt_dbf_common)
+ debug_unregister(zcrypt_dbf_common);
+ if (zcrypt_dbf_devices)
+ debug_unregister(zcrypt_dbf_devices);
+}
+
/**
* zcrypt_api_init(): Module initialization.
*
{
int rc;
+ rc = zcrypt_debug_init();
+ if (rc)
+ goto out;
+
+ atomic_set(&zcrypt_rescan_req, 0);
+
/* Register the request sprayer. */
rc = misc_register(&zcrypt_misc_device);
if (rc < 0)
{
remove_proc_entry("driver/z90crypt", NULL);
misc_deregister(&zcrypt_misc_device);
+ zcrypt_debug_exit();
}
module_init(zcrypt_api_init);
--- /dev/null
+/*
+ * Copyright IBM Corp. 2012
+ * Author(s): Holger Dengler (hd@linux.vnet.ibm.com)
+ */
+#ifndef ZCRYPT_DEBUG_H
+#define ZCRYPT_DEBUG_H
+
+#include <asm/debug.h>
+#include "zcrypt_api.h"
+
+/* that gives us 15 characters in the text event views */
+#define ZCRYPT_DBF_LEN 16
+
+/* sort out low debug levels early to avoid wasted sprints */
+static inline int zcrypt_dbf_passes(debug_info_t *dbf_grp, int level)
+{
+ return (level <= dbf_grp->level);
+}
+
+#define DBF_ERR 3 /* error conditions */
+#define DBF_WARN 4 /* warning conditions */
+#define DBF_INFO 6 /* informational */
+
+#define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO)
+
+#define ZCRYPT_DBF_COMMON(level, text...) \
+ do { \
+ if (zcrypt_dbf_passes(zcrypt_dbf_common, level)) { \
+ char debug_buffer[ZCRYPT_DBF_LEN]; \
+ snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \
+ debug_text_event(zcrypt_dbf_common, level, \
+ debug_buffer); \
+ } \
+ } while (0)
+
+#define ZCRYPT_DBF_DEVICES(level, text...) \
+ do { \
+ if (zcrypt_dbf_passes(zcrypt_dbf_devices, level)) { \
+ char debug_buffer[ZCRYPT_DBF_LEN]; \
+ snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \
+ debug_text_event(zcrypt_dbf_devices, level, \
+ debug_buffer); \
+ } \
+ } while (0)
+
+#define ZCRYPT_DBF_DEV(level, device, text...) \
+ do { \
+ if (zcrypt_dbf_passes(device->dbf_area, level)) { \
+ char debug_buffer[ZCRYPT_DBF_LEN]; \
+ snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \
+ debug_text_event(device->dbf_area, level, \
+ debug_buffer); \
+ } \
+ } while (0)
+
+int zcrypt_debug_init(void);
+void zcrypt_debug_exit(void);
+
+#endif /* ZCRYPT_DEBUG_H */