Commit dabecb29 authored by Holger Dengler's avatar Holger Dengler Committed by Martin Schwidefsky

s390/zcryt: Handle AP configuration changes

Detect external AP bus configuration changes and request
an AP device rescan.
Signed-off-by: default avatarHolger Dengler <hd@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 745e967a
...@@ -950,6 +950,20 @@ void ap_driver_unregister(struct ap_driver *ap_drv) ...@@ -950,6 +950,20 @@ void ap_driver_unregister(struct ap_driver *ap_drv)
} }
EXPORT_SYMBOL(ap_driver_unregister); EXPORT_SYMBOL(ap_driver_unregister);
void ap_bus_force_rescan(void)
{
/* Delete the AP bus rescan timer. */
del_timer(&ap_config_timer);
/* processing a synchonuous bus rescan */
ap_scan_bus(NULL);
/* Setup the AP bus rescan timer again. */
ap_config_timer.expires = jiffies + ap_config_time * HZ;
add_timer(&ap_config_timer);
}
EXPORT_SYMBOL(ap_bus_force_rescan);
/* /*
* AP bus attributes. * AP bus attributes.
*/ */
......
...@@ -231,6 +231,7 @@ int ap_recv(ap_qid_t, unsigned long long *, void *, size_t); ...@@ -231,6 +231,7 @@ int ap_recv(ap_qid_t, unsigned long long *, void *, size_t);
void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg); void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg); void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
void ap_flush_queue(struct ap_device *ap_dev); void ap_flush_queue(struct ap_device *ap_dev);
void ap_bus_force_rescan(void);
int ap_module_init(void); int ap_module_init(void);
void ap_module_exit(void); void ap_module_exit(void);
......
...@@ -38,7 +38,10 @@ ...@@ -38,7 +38,10 @@
#include <linux/atomic.h> #include <linux/atomic.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/hw_random.h> #include <linux/hw_random.h>
#include <linux/debugfs.h>
#include <asm/debug.h>
#include "zcrypt_debug.h"
#include "zcrypt_api.h" #include "zcrypt_api.h"
/* /*
...@@ -53,6 +56,10 @@ static DEFINE_SPINLOCK(zcrypt_device_lock); ...@@ -53,6 +56,10 @@ static DEFINE_SPINLOCK(zcrypt_device_lock);
static LIST_HEAD(zcrypt_device_list); static LIST_HEAD(zcrypt_device_list);
static int zcrypt_device_count = 0; static int zcrypt_device_count = 0;
static atomic_t zcrypt_open_count = ATOMIC_INIT(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 int zcrypt_rng_device_add(void);
static void zcrypt_rng_device_remove(void); static void zcrypt_rng_device_remove(void);
...@@ -60,6 +67,10 @@ static void zcrypt_rng_device_remove(void); ...@@ -60,6 +67,10 @@ static void zcrypt_rng_device_remove(void);
static DEFINE_SPINLOCK(zcrypt_ops_list_lock); static DEFINE_SPINLOCK(zcrypt_ops_list_lock);
static LIST_HEAD(zcrypt_ops_list); 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. * Device attributes common for all crypto devices.
*/ */
...@@ -89,6 +100,8 @@ static ssize_t zcrypt_online_store(struct device *dev, ...@@ -89,6 +100,8 @@ static ssize_t zcrypt_online_store(struct device *dev,
if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
return -EINVAL; return -EINVAL;
zdev->online = online; zdev->online = online;
ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dman", zdev->ap_dev->qid,
zdev->online);
if (!online) if (!online)
ap_flush_queue(zdev->ap_dev); ap_flush_queue(zdev->ap_dev);
return count; return count;
...@@ -106,6 +119,24 @@ static struct attribute_group zcrypt_device_attr_group = { ...@@ -106,6 +119,24 @@ static struct attribute_group zcrypt_device_attr_group = {
.attrs = zcrypt_device_attrs, .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. * __zcrypt_increase_preference(): Increase preference of a crypto device.
* @zdev: Pointer the crypto device * @zdev: Pointer the crypto device
...@@ -194,6 +225,7 @@ struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size) ...@@ -194,6 +225,7 @@ struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size)
zdev->reply.length = max_response_size; zdev->reply.length = max_response_size;
spin_lock_init(&zdev->lock); spin_lock_init(&zdev->lock);
INIT_LIST_HEAD(&zdev->list); INIT_LIST_HEAD(&zdev->list);
zdev->dbf_area = zcrypt_dbf_devices;
return zdev; return zdev;
out_free: out_free:
...@@ -229,6 +261,8 @@ int zcrypt_device_register(struct zcrypt_device *zdev) ...@@ -229,6 +261,8 @@ int zcrypt_device_register(struct zcrypt_device *zdev)
kref_init(&zdev->refcount); kref_init(&zdev->refcount);
spin_lock_bh(&zcrypt_device_lock); spin_lock_bh(&zcrypt_device_lock);
zdev->online = 1; /* New devices are online by default. */ 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); list_add_tail(&zdev->list, &zcrypt_device_list);
__zcrypt_increase_preference(zdev); __zcrypt_increase_preference(zdev);
zcrypt_device_count++; zcrypt_device_count++;
...@@ -707,6 +741,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, ...@@ -707,6 +741,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
do { do {
rc = zcrypt_rsa_modexpo(&mex); rc = zcrypt_rsa_modexpo(&mex);
} while (rc == -EAGAIN); } 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) if (rc)
return rc; return rc;
return put_user(mex.outputdatalength, &umex->outputdatalength); return put_user(mex.outputdatalength, &umex->outputdatalength);
...@@ -719,6 +758,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, ...@@ -719,6 +758,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
do { do {
rc = zcrypt_rsa_crt(&crt); rc = zcrypt_rsa_crt(&crt);
} while (rc == -EAGAIN); } 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) if (rc)
return rc; return rc;
return put_user(crt.outputdatalength, &ucrt->outputdatalength); return put_user(crt.outputdatalength, &ucrt->outputdatalength);
...@@ -731,6 +775,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, ...@@ -731,6 +775,11 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
do { do {
rc = zcrypt_send_cprb(&xcRB); rc = zcrypt_send_cprb(&xcRB);
} while (rc == -EAGAIN); } 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))) if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
return -EFAULT; return -EFAULT;
return rc; return rc;
...@@ -837,10 +886,15 @@ static long trans_modexpo32(struct file *filp, unsigned int cmd, ...@@ -837,10 +886,15 @@ static long trans_modexpo32(struct file *filp, unsigned int cmd,
do { do {
rc = zcrypt_rsa_modexpo(&mex64); rc = zcrypt_rsa_modexpo(&mex64);
} while (rc == -EAGAIN); } while (rc == -EAGAIN);
if (!rc) /* on failure: retry once again after a requested rescan */
rc = put_user(mex64.outputdatalength, if ((rc == -ENODEV) && (zcrypt_process_rescan()))
&umex32->outputdatalength); do {
rc = zcrypt_rsa_modexpo(&mex64);
} while (rc == -EAGAIN);
if (rc)
return rc; return rc;
return put_user(mex64.outputdatalength,
&umex32->outputdatalength);
} }
struct compat_ica_rsa_modexpo_crt { struct compat_ica_rsa_modexpo_crt {
...@@ -877,10 +931,15 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd, ...@@ -877,10 +931,15 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
do { do {
rc = zcrypt_rsa_crt(&crt64); rc = zcrypt_rsa_crt(&crt64);
} while (rc == -EAGAIN); } while (rc == -EAGAIN);
if (!rc) /* on failure: retry once again after a requested rescan */
rc = put_user(crt64.outputdatalength, if ((rc == -ENODEV) && (zcrypt_process_rescan()))
&ucrt32->outputdatalength); do {
rc = zcrypt_rsa_crt(&crt64);
} while (rc == -EAGAIN);
if (rc)
return rc; return rc;
return put_user(crt64.outputdatalength,
&ucrt32->outputdatalength);
} }
struct compat_ica_xcRB { struct compat_ica_xcRB {
...@@ -936,6 +995,11 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd, ...@@ -936,6 +995,11 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
do { do {
rc = zcrypt_send_cprb(&xcRB64); rc = zcrypt_send_cprb(&xcRB64);
} while (rc == -EAGAIN); } 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_control_blk_length = xcRB64.reply_control_blk_length;
xcRB32.reply_data_length = xcRB64.reply_data_length; xcRB32.reply_data_length = xcRB64.reply_data_length;
xcRB32.status = xcRB64.status; xcRB32.status = xcRB64.status;
...@@ -1193,6 +1257,9 @@ static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data) ...@@ -1193,6 +1257,9 @@ static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data)
*/ */
if (zcrypt_rng_buffer_index == 0) { if (zcrypt_rng_buffer_index == 0) {
rc = zcrypt_rng((char *) zcrypt_rng_buffer); 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) if (rc < 0)
return -EIO; return -EIO;
zcrypt_rng_buffer_index = rc / sizeof *data; zcrypt_rng_buffer_index = rc / sizeof *data;
...@@ -1245,6 +1312,30 @@ static void zcrypt_rng_device_remove(void) ...@@ -1245,6 +1312,30 @@ static void zcrypt_rng_device_remove(void)
mutex_unlock(&zcrypt_rng_mutex); 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. * zcrypt_api_init(): Module initialization.
* *
...@@ -1254,6 +1345,12 @@ int __init zcrypt_api_init(void) ...@@ -1254,6 +1345,12 @@ int __init zcrypt_api_init(void)
{ {
int rc; int rc;
rc = zcrypt_debug_init();
if (rc)
goto out;
atomic_set(&zcrypt_rescan_req, 0);
/* Register the request sprayer. */ /* Register the request sprayer. */
rc = misc_register(&zcrypt_misc_device); rc = misc_register(&zcrypt_misc_device);
if (rc < 0) if (rc < 0)
...@@ -1283,6 +1380,7 @@ void zcrypt_api_exit(void) ...@@ -1283,6 +1380,7 @@ void zcrypt_api_exit(void)
{ {
remove_proc_entry("driver/z90crypt", NULL); remove_proc_entry("driver/z90crypt", NULL);
misc_deregister(&zcrypt_misc_device); misc_deregister(&zcrypt_misc_device);
zcrypt_debug_exit();
} }
module_init(zcrypt_api_init); module_init(zcrypt_api_init);
......
...@@ -29,8 +29,10 @@ ...@@ -29,8 +29,10 @@
#ifndef _ZCRYPT_API_H_ #ifndef _ZCRYPT_API_H_
#define _ZCRYPT_API_H_ #define _ZCRYPT_API_H_
#include "ap_bus.h" #include <linux/atomic.h>
#include <asm/debug.h>
#include <asm/zcrypt.h> #include <asm/zcrypt.h>
#include "ap_bus.h"
/* deprecated status calls */ /* deprecated status calls */
#define ICAZ90STATUS _IOR(ZCRYPT_IOCTL_MAGIC, 0x10, struct ica_z90_status) #define ICAZ90STATUS _IOR(ZCRYPT_IOCTL_MAGIC, 0x10, struct ica_z90_status)
...@@ -112,8 +114,13 @@ struct zcrypt_device { ...@@ -112,8 +114,13 @@ struct zcrypt_device {
struct ap_message reply; /* Per-device reply structure. */ struct ap_message reply; /* Per-device reply structure. */
int max_exp_bit_length; int max_exp_bit_length;
debug_info_t *dbf_area; /* debugging */
}; };
/* transport layer rescanning */
extern atomic_t zcrypt_rescan_req;
struct zcrypt_device *zcrypt_device_alloc(size_t); struct zcrypt_device *zcrypt_device_alloc(size_t);
void zcrypt_device_free(struct zcrypt_device *); void zcrypt_device_free(struct zcrypt_device *);
void zcrypt_device_get(struct zcrypt_device *); void zcrypt_device_get(struct zcrypt_device *);
......
/*
* 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 */
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#ifndef _ZCRYPT_ERROR_H_ #ifndef _ZCRYPT_ERROR_H_
#define _ZCRYPT_ERROR_H_ #define _ZCRYPT_ERROR_H_
#include <linux/atomic.h>
#include "zcrypt_debug.h"
#include "zcrypt_api.h" #include "zcrypt_api.h"
/** /**
...@@ -108,16 +110,27 @@ static inline int convert_error(struct zcrypt_device *zdev, ...@@ -108,16 +110,27 @@ static inline int convert_error(struct zcrypt_device *zdev,
* and then repeat the request. * and then repeat the request.
*/ */
WARN_ON(1); WARN_ON(1);
atomic_set(&zcrypt_rescan_req, 1);
zdev->online = 0; zdev->online = 0;
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
zdev->ap_dev->qid,
zdev->online, ehdr->reply_code);
return -EAGAIN; return -EAGAIN;
case REP82_ERROR_TRANSPORT_FAIL: case REP82_ERROR_TRANSPORT_FAIL:
case REP82_ERROR_MACHINE_FAILURE: case REP82_ERROR_MACHINE_FAILURE:
// REP88_ERROR_MODULE_FAILURE // '10' CEX2A // REP88_ERROR_MODULE_FAILURE // '10' CEX2A
/* If a card fails disable it and repeat the request. */ /* If a card fails disable it and repeat the request. */
atomic_set(&zcrypt_rescan_req, 1);
zdev->online = 0; zdev->online = 0;
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
zdev->ap_dev->qid,
zdev->online, ehdr->reply_code);
return -EAGAIN; return -EAGAIN;
default: default:
zdev->online = 0; zdev->online = 0;
ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d",
zdev->ap_dev->qid,
zdev->online, ehdr->reply_code);
return -EAGAIN; /* repeat the request on a different device. */ return -EAGAIN; /* repeat the request on a different device. */
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment