/*
- * linux/drivers/s390/misc/z90main.c
+ * linux/drivers/s390/crypto/z90main.c
*
- * z90crypt 1.3.1
+ * z90crypt 1.3.3
*
- * Copyright (C) 2001, 2004 IBM Corporation
+ * Copyright (C) 2001, 2005 IBM Corporation
* Author(s): Robert Burroughs (burrough@us.ibm.com)
- * Eric Rossman (edrossma@us.ibm.com)
+ * Eric Rossman (edrossma@us.ibm.com)
*
* Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
#include <linux/delay.h> // mdelay
#include <linux/init.h>
#include <linux/interrupt.h> // for tasklets
-#include <linux/ioctl32.h>
+#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/proc_fs.h>
#include <linux/syscalls.h>
-#include <linux/version.h>
#include "z90crypt.h"
#include "z90common.h"
-#ifndef Z90CRYPT_USE_HOTPLUG
-#include <linux/miscdevice.h>
-#endif
-
-#define VERSION_CODE(vers, rel, seq) (((vers)<<16) | ((rel)<<8) | (seq))
-#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0) /* version < 2.4 */
-# error "This kernel is too old: not supported"
-#endif
-#if LINUX_VERSION_CODE > VERSION_CODE(2,7,0) /* version > 2.6 */
-# error "This kernel is too recent: not supported by this file"
-#endif
-
-#define VERSION_Z90MAIN_C "$Revision: 1.31 $"
-
-static char z90cmain_version[] __initdata =
- "z90main.o (" VERSION_Z90MAIN_C "/"
- VERSION_Z90COMMON_H "/" VERSION_Z90CRYPT_H ")";
-
-extern char z90chardware_version[];
/**
* Defaults that may be modified.
*/
-#ifndef Z90CRYPT_USE_HOTPLUG
/**
* You can specify a different minor at compile time.
*/
#ifndef Z90CRYPT_MINOR
#define Z90CRYPT_MINOR MISC_DYNAMIC_MINOR
#endif
-#else
-/**
- * You can specify a different major at compile time.
- */
-#ifndef Z90CRYPT_MAJOR
-#define Z90CRYPT_MAJOR 0
-#endif
-#endif
/**
* You can specify a different domain at compile time or on the insmod
/**
* Reader should run every READERTIME milliseconds
+ * With the 100Hz patch for s390, z90crypt can lock the system solid while
+ * under heavy load. We'll try to avoid that.
*/
#ifndef READERTIME
+#if HZ > 1000
#define READERTIME 2
+#else
+#define READERTIME 10
+#endif
#endif
/**
#ifndef Z90CRYPT_NUM_DEVS
#define Z90CRYPT_NUM_DEVS Z90CRYPT_NUM_APS
#endif
-#ifndef Z90CRYPT_NUM_TYPES
-#define Z90CRYPT_NUM_TYPES 3
-#endif
/**
* Buffer size for receiving responses. The maximum Response Size
* is actually the maximum request size, since in an error condition
* the request itself may be returned unchanged.
*/
-#ifndef MAX_RESPONSE_SIZE
#define MAX_RESPONSE_SIZE 0x0000077C
-#endif
/**
* A count and status-byte mask
* All devices are arranged in a single array: 64 APs
*/
struct device {
- int dev_type; // PCICA, PCICC, or PCIXCC
+ int dev_type; // PCICA, PCICC, PCIXCC_MCL2,
+ // PCIXCC_MCL3, CEX2C, CEX2A
enum devstat dev_stat; // current device status
int dev_self_x; // Index in array
int disabled; // Set when device is in error
* it contains the request; at READ, the response. The function
* send_to_crypto_device converts the request to device-dependent
* form and use the caller's OPEN-allocated buffer for the response.
+ *
+ * For the contents of caller_dev_dep_req and caller_dev_dep_req_p
+ * because that points to it, see the discussion in z90hardware.c.
+ * Search for "extended request message block".
*/
struct caller {
int caller_buf_l; // length of original request
/**
* Function prototypes from z90hardware.c
*/
-enum hdstat query_online(int, int, int, int *, int *);
-enum devstat reset_device(int, int, int);
-enum devstat send_to_AP(int, int, int, unsigned char *);
-enum devstat receive_from_AP(int, int, int, unsigned char *, unsigned char *);
-int convert_request(unsigned char *, int, short, int, int, int *,
- unsigned char *);
-int convert_response(unsigned char *, unsigned char *, int *, unsigned char *);
+enum hdstat query_online(int deviceNr, int cdx, int resetNr, int *q_depth,
+ int *dev_type);
+enum devstat reset_device(int deviceNr, int cdx, int resetNr);
+enum devstat send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext);
+enum devstat receive_from_AP(int dev_nr, int cdx, int resplen,
+ unsigned char *resp, unsigned char *psmid);
+int convert_request(unsigned char *buffer, int func, unsigned short function,
+ int cdx, int dev_type, int *msg_l_p, unsigned char *msg_p);
+int convert_response(unsigned char *response, unsigned char *buffer,
+ int *respbufflen_p, unsigned char *resp_buff);
/**
* Low level function prototypes
*/
-static int create_z90crypt(int *);
-static int refresh_z90crypt(int *);
-static int find_crypto_devices(struct status *);
-static int create_crypto_device(int);
-static int destroy_crypto_device(int);
+static int create_z90crypt(int *cdx_p);
+static int refresh_z90crypt(int *cdx_p);
+static int find_crypto_devices(struct status *deviceMask);
+static int create_crypto_device(int index);
+static int destroy_crypto_device(int index);
static void destroy_z90crypt(void);
-static int refresh_index_array(struct status *, struct device_x *);
-static int probe_device_type(struct device *);
+static int refresh_index_array(struct status *status_str,
+ struct device_x *index_array);
+static int probe_device_type(struct device *devPtr);
+static int probe_PCIXCC_type(struct device *devPtr);
/**
* proc fs definitions
static ssize_t z90crypt_read(struct file *, char __user *, size_t, loff_t *);
static ssize_t z90crypt_write(struct file *, const char __user *,
size_t, loff_t *);
-static int z90crypt_ioctl(struct inode *, struct file *,
- unsigned int, unsigned long);
+static long z90crypt_unlocked_ioctl(struct file *, unsigned int, unsigned long);
+static long z90crypt_compat_ioctl(struct file *, unsigned int, unsigned long);
static void z90crypt_reader_task(unsigned long);
static void z90crypt_schedule_reader_task(unsigned long);
static int z90crypt_status_write(struct file *, const char __user *,
unsigned long, void *);
-/**
- * Hotplug support
- */
-
-#ifdef Z90CRYPT_USE_HOTPLUG
-#define Z90CRYPT_HOTPLUG_ADD 1
-#define Z90CRYPT_HOTPLUG_REMOVE 2
-
-static void z90crypt_hotplug_event(int, int, int);
-#endif
-
/**
* Storage allocated at initialization and used throughout the life of
* this insmod
*/
-#ifdef Z90CRYPT_USE_HOTPLUG
-static int z90crypt_major = Z90CRYPT_MAJOR;
-#endif
-
static int domain = DOMAIN_INDEX;
static struct z90crypt z90crypt;
static int quiesce_z90crypt;
static atomic_t z90crypt_step;
static struct file_operations z90crypt_fops = {
- .owner = THIS_MODULE,
- .read = z90crypt_read,
- .write = z90crypt_write,
- .ioctl = z90crypt_ioctl,
- .open = z90crypt_open,
- .release = z90crypt_release
+ .owner = THIS_MODULE,
+ .read = z90crypt_read,
+ .write = z90crypt_write,
+ .unlocked_ioctl = z90crypt_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = z90crypt_compat_ioctl,
+#endif
+ .open = z90crypt_open,
+ .release = z90crypt_release
};
-#ifndef Z90CRYPT_USE_HOTPLUG
static struct miscdevice z90crypt_misc_device = {
.minor = Z90CRYPT_MINOR,
.name = DEV_NAME,
.fops = &z90crypt_fops,
.devfs_name = DEV_NAME
};
-#endif
/**
* Documentation values.
*/
-MODULE_AUTHOR("zLinux Crypto Team: Robert H. Burroughs, Eric D. Rossman"
+MODULE_AUTHOR("zSeries Linux Crypto Team: Robert H. Burroughs, Eric D. Rossman"
"and Jochen Roehrig");
-MODULE_DESCRIPTION("zLinux Cryptographic Coprocessor device driver, "
- "Copyright 2001, 2004 IBM Corporation");
+MODULE_DESCRIPTION("zSeries Linux Cryptographic Coprocessor device driver, "
+ "Copyright 2001, 2005 IBM Corporation");
MODULE_LICENSE("GPL");
module_param(domain, int, 0);
MODULE_PARM_DESC(domain, "domain index for device");
compat_uptr_t n_modulus;
};
-static int
-trans_modexpo32(unsigned int fd, unsigned int cmd, unsigned long arg,
- struct file *file)
+static long
+trans_modexpo32(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct ica_rsa_modexpo_32 __user *mex32u = compat_ptr(arg);
struct ica_rsa_modexpo_32 mex32k;
struct ica_rsa_modexpo __user *mex64;
- int ret = 0;
+ long ret = 0;
unsigned int i;
if (!access_ok(VERIFY_WRITE, mex32u, sizeof(struct ica_rsa_modexpo_32)))
__put_user(compat_ptr(mex32k.b_key), &mex64->b_key) ||
__put_user(compat_ptr(mex32k.n_modulus), &mex64->n_modulus))
return -EFAULT;
- ret = sys_ioctl(fd, cmd, (unsigned long)mex64);
+ ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)mex64);
if (!ret)
if (__get_user(i, &mex64->outputdatalength) ||
__put_user(i, &mex32u->outputdatalength))
compat_uptr_t u_mult_inv;
};
-static int
-trans_modexpo_crt32(unsigned int fd, unsigned int cmd, unsigned long arg,
- struct file *file)
+static long
+trans_modexpo_crt32(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct ica_rsa_modexpo_crt_32 __user *crt32u = compat_ptr(arg);
struct ica_rsa_modexpo_crt_32 crt32k;
struct ica_rsa_modexpo_crt __user *crt64;
- int ret = 0;
+ long ret = 0;
unsigned int i;
if (!access_ok(VERIFY_WRITE, crt32u,
__put_user(compat_ptr(crt32k.np_prime), &crt64->np_prime) ||
__put_user(compat_ptr(crt32k.nq_prime), &crt64->nq_prime) ||
__put_user(compat_ptr(crt32k.u_mult_inv), &crt64->u_mult_inv))
- ret = -EFAULT;
- if (!ret)
- ret = sys_ioctl(fd, cmd, (unsigned long)crt64);
+ return -EFAULT;
+ ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)crt64);
if (!ret)
if (__get_user(i, &crt64->outputdatalength) ||
__put_user(i, &crt32u->outputdatalength))
return ret;
}
-static int compatible_ioctls[] = {
- ICAZ90STATUS, Z90QUIESCE, Z90STAT_TOTALCOUNT, Z90STAT_PCICACOUNT,
- Z90STAT_PCICCCOUNT, Z90STAT_PCIXCCCOUNT, Z90STAT_REQUESTQ_COUNT,
- Z90STAT_PENDINGQ_COUNT, Z90STAT_TOTALOPEN_COUNT, Z90STAT_DOMAIN_INDEX,
- Z90STAT_STATUS_MASK, Z90STAT_QDEPTH_MASK, Z90STAT_PERDEV_REQCNT,
-};
-
-static void z90_unregister_ioctl32s(void)
-{
- int i;
-
- unregister_ioctl32_conversion(ICARSAMODEXPO);
- unregister_ioctl32_conversion(ICARSACRT);
-
- for(i = 0; i < ARRAY_SIZE(compatible_ioctls); i++)
- unregister_ioctl32_conversion(compatible_ioctls[i]);
-}
-
-static int z90_register_ioctl32s(void)
-{
- int result, i;
-
- result = register_ioctl32_conversion(ICARSAMODEXPO, trans_modexpo32);
- if (result)
- return result;
- result = register_ioctl32_conversion(ICARSACRT, trans_modexpo_crt32);
- if (result)
- return result;
-
- for(i = 0; i < ARRAY_SIZE(compatible_ioctls); i++) {
- result = register_ioctl32_conversion(compatible_ioctls[i],NULL);
- if (result) {
- z90_unregister_ioctl32s();
- return result;
- }
- }
- return result;
-}
-#else // !CONFIG_COMPAT
-static inline void z90_unregister_ioctl32s(void)
-{
-}
-
-static inline int z90_register_ioctl32s(void)
+static long
+z90crypt_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
- return 0;
+ switch (cmd) {
+ case ICAZ90STATUS:
+ case Z90QUIESCE:
+ case Z90STAT_TOTALCOUNT:
+ case Z90STAT_PCICACOUNT:
+ case Z90STAT_PCICCCOUNT:
+ case Z90STAT_PCIXCCCOUNT:
+ case Z90STAT_PCIXCCMCL2COUNT:
+ case Z90STAT_PCIXCCMCL3COUNT:
+ case Z90STAT_CEX2CCOUNT:
+ case Z90STAT_REQUESTQ_COUNT:
+ case Z90STAT_PENDINGQ_COUNT:
+ case Z90STAT_TOTALOPEN_COUNT:
+ case Z90STAT_DOMAIN_INDEX:
+ case Z90STAT_STATUS_MASK:
+ case Z90STAT_QDEPTH_MASK:
+ case Z90STAT_PERDEV_REQCNT:
+ return z90crypt_unlocked_ioctl(filp, cmd, arg);
+ case ICARSAMODEXPO:
+ return trans_modexpo32(filp, cmd, arg);
+ case ICARSACRT:
+ return trans_modexpo_crt32(filp, cmd, arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
}
#endif
PDEBUG("PID %d\n", PID());
-#ifndef Z90CRYPT_USE_HOTPLUG
+ if ((domain < -1) || (domain > 15)) {
+ PRINTKW("Invalid param: domain = %d. Not loading.\n", domain);
+ return -EINVAL;
+ }
+
/* Register as misc device with given minor (or get a dynamic one). */
result = misc_register(&z90crypt_misc_device);
- if (result <0) {
+ if (result < 0) {
PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n",
z90crypt_misc_device.minor, result);
return result;
}
-#else
- /* Register the major (or get a dynamic one). */
- result = register_chrdev(z90crypt_major, REG_NAME, &z90crypt_fops);
- if (result < 0) {
- PRINTKW("register_chrdev (major %d) failed with %d.\n",
- z90crypt_major, result);
- return result;
- }
-
- if (z90crypt_major == 0)
- z90crypt_major = result;
-#endif
PDEBUG("Registered " DEV_NAME " with result %d\n", result);
PRINTKN("Version %d.%d.%d loaded, built on %s %s\n",
z90crypt_VERSION, z90crypt_RELEASE, z90crypt_VARIANT,
__DATE__, __TIME__);
- PRINTKN("%s\n", z90cmain_version);
- PRINTKN("%s\n", z90chardware_version);
PDEBUG("create_z90crypt (domain index %d) successful.\n",
domain);
} else
PRINTK("No devices at startup\n");
-#ifdef Z90CRYPT_USE_HOTPLUG
- /* generate hotplug event for device node generation */
- z90crypt_hotplug_event(z90crypt_major, 0, Z90CRYPT_HOTPLUG_ADD);
-#endif
-
/* Initialize globals. */
spin_lock_init(&queuespinlock);
reader_timer.expires = jiffies + (READERTIME * HZ / 1000);
add_timer(&reader_timer);
- if ((result = z90_register_ioctl32s()))
- goto init_module_cleanup;
-
return 0; // success
init_module_cleanup:
- z90_unregister_ioctl32s();
-
-#ifndef Z90CRYPT_USE_HOTPLUG
if ((nresult = misc_deregister(&z90crypt_misc_device)))
PRINTK("misc_deregister failed with %d.\n", nresult);
else
PDEBUG("misc_deregister successful.\n");
-#else
- if ((nresult = unregister_chrdev(z90crypt_major, REG_NAME)))
- PRINTK("unregister_chrdev failed with %d.\n", nresult);
- else
- PDEBUG("unregister_chrdev successful.\n");
-#endif
return result; // failure
}
PDEBUG("PID %d\n", PID());
- z90_unregister_ioctl32s();
-
remove_proc_entry("driver/z90crypt", 0);
-#ifndef Z90CRYPT_USE_HOTPLUG
if ((nresult = misc_deregister(&z90crypt_misc_device)))
PRINTK("misc_deregister failed with %d.\n", nresult);
else
PDEBUG("misc_deregister successful.\n");
-#else
- z90crypt_hotplug_event(z90crypt_major, 0, Z90CRYPT_HOTPLUG_REMOVE);
-
- if ((nresult = unregister_chrdev(z90crypt_major, REG_NAME)))
- PRINTK("unregister_chrdev failed with %d.\n", nresult);
- else
- PDEBUG("unregister_chrdev successful.\n");
-#endif
/* Remove the tasks */
tasklet_kill(&reader_tasklet);
* z90crypt_release
* z90crypt_read
* z90crypt_write
- * z90crypt_ioctl
+ * z90crypt_unlocked_ioctl
* z90crypt_status
* z90crypt_status_write
* disable_card
* enable_card
- * scan_char
- * scan_string
*
* Helper functions:
* z90crypt_rsa
if (quiesce_z90crypt)
return -EQUIESCE;
- private_data_p = kmalloc(sizeof(struct priv_data), GFP_KERNEL);
+ private_data_p = kzalloc(sizeof(struct priv_data), GFP_KERNEL);
if (!private_data_p) {
PRINTK("Memory allocate failed\n");
return -ENOMEM;
}
- memset((void *)private_data_p, 0, sizeof(struct priv_data));
private_data_p->status = STAT_OPEN;
private_data_p->opener_pid = PID();
filp->private_data = private_data_p;
static inline int
get_status_PCIXCCcount(void)
{
- return z90crypt.hdware_info->type_mask[PCIXCC].st_count;
+ return z90crypt.hdware_info->type_mask[PCIXCC_MCL2].st_count +
+ z90crypt.hdware_info->type_mask[PCIXCC_MCL3].st_count;
+}
+
+static inline int
+get_status_PCIXCCMCL2count(void)
+{
+ return z90crypt.hdware_info->type_mask[PCIXCC_MCL2].st_count;
+}
+
+static inline int
+get_status_PCIXCCMCL3count(void)
+{
+ return z90crypt.hdware_info->type_mask[PCIXCC_MCL3].st_count;
+}
+
+static inline int
+get_status_CEX2Ccount(void)
+{
+ return z90crypt.hdware_info->type_mask[CEX2C].st_count;
+}
+
+static inline int
+get_status_CEX2Acount(void)
+{
+ return z90crypt.hdware_info->type_mask[CEX2A].st_count;
}
static inline int
we_p->audit[2] = 0x00;
we_p->resp_buff_size = 0;
we_p->retcode = 0;
- we_p->devindex = -1; // send_to_crypto selects the device
- we_p->devtype = -1; // getCryptoBuffer selects the type
+ we_p->devindex = -1;
+ we_p->devtype = -1;
atomic_set(&we_p->alarmrung, 0);
init_waitqueue_head(&we_p->waitq);
INIT_LIST_HEAD(&(we_p->liste));
static inline void
remove_device(struct device *device_p)
{
- if (!device_p || device_p->disabled != 0)
+ if (!device_p || (device_p->disabled != 0))
return;
device_p->disabled = 1;
z90crypt.hdware_info->type_mask[device_p->dev_type].disabled_count++;
z90crypt.hdware_info->hdware_mask.disabled_count++;
}
+/**
+ * Bitlength limits for each card
+ *
+ * There are new MCLs which allow more bitlengths. See the table for details.
+ * The MCL must be applied and the newer bitlengths enabled for these to work.
+ *
+ * Card Type Old limit New limit
+ * PCICA ??-2048 same (the lower limit is less than 128 bit...)
+ * PCICC 512-1024 512-2048
+ * PCIXCC_MCL2 512-2048 ----- (applying any GA LIC will make an MCL3 card)
+ * PCIXCC_MCL3 ----- 128-2048
+ * CEX2C 512-2048 128-2048
+ * CEX2A ??-2048 same (the lower limit is less than 128 bit...)
+ *
+ * ext_bitlens (extended bitlengths) is a global, since you should not apply an
+ * MCL to just one card in a machine. We assume, at first, that all cards have
+ * these capabilities.
+ */
+int ext_bitlens = 1; // This is global
+#define PCIXCC_MIN_MOD_SIZE 16 // 128 bits
+#define OLD_PCIXCC_MIN_MOD_SIZE 64 // 512 bits
+#define PCICC_MIN_MOD_SIZE 64 // 512 bits
+#define OLD_PCICC_MAX_MOD_SIZE 128 // 1024 bits
+#define MAX_MOD_SIZE 256 // 2048 bits
+
static inline int
-select_device_type(int *dev_type_p)
+select_device_type(int *dev_type_p, int bytelength)
{
+ static int count = 0;
+ int PCICA_avail, PCIXCC_MCL3_avail, CEX2C_avail, CEX2A_avail,
+ index_to_use;
struct status *stat;
if ((*dev_type_p != PCICC) && (*dev_type_p != PCICA) &&
- (*dev_type_p != PCIXCC) && (*dev_type_p != ANYDEV))
+ (*dev_type_p != PCIXCC_MCL2) && (*dev_type_p != PCIXCC_MCL3) &&
+ (*dev_type_p != CEX2C) && (*dev_type_p != CEX2A) &&
+ (*dev_type_p != ANYDEV))
return -1;
if (*dev_type_p != ANYDEV) {
stat = &z90crypt.hdware_info->type_mask[*dev_type_p];
if (stat->st_count >
- stat->disabled_count + stat->user_disabled_count)
+ (stat->disabled_count + stat->user_disabled_count))
return 0;
return -1;
}
+ /**
+ * Assumption: PCICA, PCIXCC_MCL3, CEX2C, and CEX2A are all similar in
+ * speed.
+ *
+ * PCICA and CEX2A do NOT co-exist, so it would be either one or the
+ * other present.
+ */
stat = &z90crypt.hdware_info->type_mask[PCICA];
- if (stat->st_count > stat->disabled_count + stat->user_disabled_count) {
- *dev_type_p = PCICA;
+ PCICA_avail = stat->st_count -
+ (stat->disabled_count + stat->user_disabled_count);
+ stat = &z90crypt.hdware_info->type_mask[PCIXCC_MCL3];
+ PCIXCC_MCL3_avail = stat->st_count -
+ (stat->disabled_count + stat->user_disabled_count);
+ stat = &z90crypt.hdware_info->type_mask[CEX2C];
+ CEX2C_avail = stat->st_count -
+ (stat->disabled_count + stat->user_disabled_count);
+ stat = &z90crypt.hdware_info->type_mask[CEX2A];
+ CEX2A_avail = stat->st_count -
+ (stat->disabled_count + stat->user_disabled_count);
+ if (PCICA_avail || PCIXCC_MCL3_avail || CEX2C_avail || CEX2A_avail) {
+ /**
+ * bitlength is a factor, PCICA or CEX2A are the most capable,
+ * even with the new MCL for PCIXCC.
+ */
+ if ((bytelength < PCIXCC_MIN_MOD_SIZE) ||
+ (!ext_bitlens && (bytelength < OLD_PCIXCC_MIN_MOD_SIZE))) {
+ if (PCICA_avail) {
+ *dev_type_p = PCICA;
+ return 0;
+ }
+ if (CEX2A_avail) {
+ *dev_type_p = CEX2A;
+ return 0;
+ }
+ return -1;
+ }
+
+ index_to_use = count % (PCICA_avail + PCIXCC_MCL3_avail +
+ CEX2C_avail + CEX2A_avail);
+ if (index_to_use < PCICA_avail)
+ *dev_type_p = PCICA;
+ else if (index_to_use < (PCICA_avail + PCIXCC_MCL3_avail))
+ *dev_type_p = PCIXCC_MCL3;
+ else if (index_to_use < (PCICA_avail + PCIXCC_MCL3_avail +
+ CEX2C_avail))
+ *dev_type_p = CEX2C;
+ else
+ *dev_type_p = CEX2A;
+ count++;
return 0;
}
- stat = &z90crypt.hdware_info->type_mask[PCIXCC];
- if (stat->st_count > stat->disabled_count + stat->user_disabled_count) {
- *dev_type_p = PCIXCC;
+ /* Less than OLD_PCIXCC_MIN_MOD_SIZE cannot go to a PCIXCC_MCL2 */
+ if (bytelength < OLD_PCIXCC_MIN_MOD_SIZE)
+ return -1;
+ stat = &z90crypt.hdware_info->type_mask[PCIXCC_MCL2];
+ if (stat->st_count >
+ (stat->disabled_count + stat->user_disabled_count)) {
+ *dev_type_p = PCIXCC_MCL2;
return 0;
}
+ /**
+ * Less than PCICC_MIN_MOD_SIZE or more than OLD_PCICC_MAX_MOD_SIZE
+ * (if we don't have the MCL applied and the newer bitlengths enabled)
+ * cannot go to a PCICC
+ */
+ if ((bytelength < PCICC_MIN_MOD_SIZE) ||
+ (!ext_bitlens && (bytelength > OLD_PCICC_MAX_MOD_SIZE))) {
+ return -1;
+ }
stat = &z90crypt.hdware_info->type_mask[PCICC];
- if (stat->st_count > stat->disabled_count + stat->user_disabled_count) {
+ if (stat->st_count >
+ (stat->disabled_count + stat->user_disabled_count)) {
*dev_type_p = PCICC;
return 0;
}
* Try the selected number, then the selected type (can be ANYDEV)
*/
static inline int
-select_device(int *dev_type_p, int *device_nr_p)
+select_device(int *dev_type_p, int *device_nr_p, int bytelength)
{
int i, indx, devTp, low_count, low_indx;
struct device_x *index_p;
dev_ptr = z90crypt.device_p[*device_nr_p];
if (dev_ptr &&
- dev_ptr->dev_stat != DEV_GONE &&
- dev_ptr->disabled == 0 &&
- dev_ptr->user_disabled == 0) {
+ (dev_ptr->dev_stat != DEV_GONE) &&
+ (dev_ptr->disabled == 0) &&
+ (dev_ptr->user_disabled == 0)) {
PDEBUG("selected by number, index = %d\n",
*device_nr_p);
*dev_type_p = dev_ptr->dev_type;
*device_nr_p = -1;
PDEBUG("trying type = %d\n", *dev_type_p);
devTp = *dev_type_p;
- if (select_device_type(&devTp) == -1) {
+ if (select_device_type(&devTp, bytelength) == -1) {
PDEBUG("failed to select by type\n");
return -1;
}
indx = index_p->device_index[i];
dev_ptr = z90crypt.device_p[indx];
if (dev_ptr &&
- dev_ptr->dev_stat != DEV_GONE &&
- dev_ptr->disabled == 0 &&
- dev_ptr->user_disabled == 0 &&
- devTp == dev_ptr->dev_type &&
- low_count > dev_ptr->dev_caller_count) {
+ (dev_ptr->dev_stat != DEV_GONE) &&
+ (dev_ptr->disabled == 0) &&
+ (dev_ptr->user_disabled == 0) &&
+ (devTp == dev_ptr->dev_type) &&
+ (low_count > dev_ptr->dev_caller_count)) {
low_count = dev_ptr->dev_caller_count;
low_indx = indx;
}
struct caller *caller_p;
struct device *device_p;
int dev_nr;
+ int bytelen = ((struct ica_rsa_modexpo *)we_p->buffer)->inputdatalength;
if (!we_p->requestptr)
return SEN_FATAL_ERROR;
caller_p = (struct caller *)we_p->requestptr;
dev_nr = we_p->devindex;
- if (select_device(&we_p->devtype, &dev_nr) == -1) {
+ if (select_device(&we_p->devtype, &dev_nr, bytelen) == -1) {
if (z90crypt.hdware_info->hdware_mask.st_count != 0)
return SEN_RETRY;
else
static unsigned char NULL_psmid[8] =
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-/**
- * MIN_MOD_SIZE is a PCICC and PCIXCC limit.
- * MAX_PCICC_MOD_SIZE is a hard limit for the PCICC.
- * MAX_MOD_SIZE is a hard limit for the PCIXCC and PCICA.
- */
-#define MIN_MOD_SIZE 64
-#define MAX_PCICC_MOD_SIZE 128
-#define MAX_MOD_SIZE 256
-
/**
* Used in device configuration functions
*/
struct caller *caller_p = (struct caller *)we_p->requestptr;
if ((we_p->devtype != PCICC) && (we_p->devtype != PCICA) &&
- (we_p->devtype != PCIXCC))
+ (we_p->devtype != PCIXCC_MCL2) && (we_p->devtype != PCIXCC_MCL3) &&
+ (we_p->devtype != CEX2C) && (we_p->devtype != CEX2A))
return SEN_NOT_AVAIL;
memcpy(caller_p->caller_id, we_p->caller_id,
return;
if (caller_p->caller_liste.next && caller_p->caller_liste.prev)
if (!list_empty(&caller_p->caller_liste)) {
- list_del(&caller_p->caller_liste);
+ list_del_init(&caller_p->caller_liste);
device_p->dev_caller_count--;
- INIT_LIST_HEAD(&caller_p->caller_liste);
}
memset(caller_p->caller_id, 0, sizeof(caller_p->caller_id));
}
}
if ((we_p->devtype != PCICA) && (we_p->devtype != PCICC) &&
- (we_p->devtype != PCIXCC) && (we_p->devtype != ANYDEV)) {
+ (we_p->devtype != PCIXCC_MCL2) && (we_p->devtype != PCIXCC_MCL3) &&
+ (we_p->devtype != CEX2C) && (we_p->devtype != CEX2A) &&
+ (we_p->devtype != ANYDEV)) {
PRINTK("invalid device type\n");
return SEN_USER_ERROR;
}
if (rv != 0)
return rv;
- if (select_device_type(&we_p->devtype) < 0)
+ if (select_device_type(&we_p->devtype, mex_p->inputdatalength) < 0)
return SEN_NOT_AVAIL;
temp_buffer = (unsigned char *)we_p + sizeof(struct work_element) +
function = PCI_FUNC_KEY_ENCRYPT;
switch (we_p->devtype) {
- /* PCICA does everything with a simple RSA mod-expo operation */
+ /* PCICA and CEX2A do everything with a simple RSA mod-expo operation */
case PCICA:
+ case CEX2A:
function = PCI_FUNC_KEY_ENCRYPT;
break;
/**
- * PCIXCC does all Mod-Expo form with a simple RSA mod-expo
+ * PCIXCC_MCL2 does all Mod-Expo form with a simple RSA mod-expo
* operation, and all CRT forms with a PKCS-1.2 format decrypt.
+ * PCIXCC_MCL3 and CEX2C do all Mod-Expo and CRT forms with a simple RSA
+ * mod-expo operation
*/
- case PCIXCC:
- /* Anything less than MIN_MOD_SIZE MUST go to a PCICA */
- if (mex_p->inputdatalength < MIN_MOD_SIZE)
- return SEN_NOT_AVAIL;
+ case PCIXCC_MCL2:
+ if (we_p->funccode == ICARSAMODEXPO)
+ function = PCI_FUNC_KEY_ENCRYPT;
+ else
+ function = PCI_FUNC_KEY_DECRYPT;
+ break;
+ case PCIXCC_MCL3:
+ case CEX2C:
if (we_p->funccode == ICARSAMODEXPO)
function = PCI_FUNC_KEY_ENCRYPT;
else
* PCICC does everything as a PKCS-1.2 format request
*/
case PCICC:
- /* Anything less than MIN_MOD_SIZE MUST go to a PCICA */
- if (mex_p->inputdatalength < MIN_MOD_SIZE) {
- return SEN_NOT_AVAIL;
- }
- /* Anythings over MAX_PCICC_MOD_SIZE MUST go to a PCICA */
- if (mex_p->inputdatalength > MAX_PCICC_MOD_SIZE) {
- return SEN_NOT_AVAIL;
- }
/* PCICC cannot handle input that is is PKCS#1.1 padded */
if (is_PKCS11_padded(temp_buffer, mex_p->inputdatalength)) {
return SEN_NOT_AVAIL;
rv = -ENODEV;
break;
case SEN_NOT_AVAIL:
+ case EGETBUFF:
rv = -EGETBUFF;
break;
default:
spin_lock_irq(&queuespinlock);
list_for_each(lptr, &request_list) {
if (lptr == &we_p->liste) {
- list_del(lptr);
+ list_del_init(lptr);
requestq_count--;
break;
}
}
list_for_each(lptr, &pending_list) {
if (lptr == &we_p->liste) {
- list_del(lptr);
+ list_del_init(lptr);
pendingq_count--;
break;
}
if ((we_p->status[0] & STAT_FAILED)) {
switch (rv) {
/**
- * EINVAL *after* receive is almost always padding
- * error issued by a PCICC or PCIXCC. We convert this
- * return value to -EGETBUFF which should trigger a
- * fallback to software.
+ * EINVAL *after* receive is almost always a padding error or
+ * length error issued by a coprocessor (not an accelerator).
+ * We convert this return value to -EGETBUFF which should
+ * trigger a fallback to software.
*/
case -EINVAL:
- if ((we_p->devtype == PCICC) ||
- (we_p->devtype == PCIXCC))
+ if ((we_p->devtype != PCICA) &&
+ (we_p->devtype != CEX2A))
rv = -EGETBUFF;
break;
case -ETIMEOUT:
* This function is a little long, but it's really just one large switch
* statement.
*/
-static int
-z90crypt_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static long
+z90crypt_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct priv_data *private_data_p = filp->private_data;
unsigned char *status;
unsigned int *reqcnt;
struct ica_z90_status *pstat;
int ret, i, loopLim, tempstat;
- static int deprecated_msg_count = 0;
+ static int deprecated_msg_count1 = 0;
+ static int deprecated_msg_count2 = 0;
PDEBUG("filp %p (PID %d), cmd 0x%08X\n", filp, PID(), cmd);
PDEBUG("cmd 0x%08X: dir %s, size 0x%04X, type 0x%02X, nr 0x%02X\n",
ret = -EFAULT;
break;
- case Z90STAT_PCIXCCCOUNT:
- tempstat = get_status_PCIXCCcount();
+ case Z90STAT_PCIXCCMCL2COUNT:
+ tempstat = get_status_PCIXCCMCL2count();
+ if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+ ret = -EFAULT;
+ break;
+
+ case Z90STAT_PCIXCCMCL3COUNT:
+ tempstat = get_status_PCIXCCMCL3count();
+ if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+ ret = -EFAULT;
+ break;
+
+ case Z90STAT_CEX2CCOUNT:
+ tempstat = get_status_CEX2Ccount();
+ if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
+ ret = -EFAULT;
+ break;
+
+ case Z90STAT_CEX2ACOUNT:
+ tempstat = get_status_CEX2Acount();
if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
ret = -EFAULT;
break;
/* THIS IS DEPRECATED. USE THE NEW STATUS CALLS */
case ICAZ90STATUS:
- if (deprecated_msg_count < 100) {
+ if (deprecated_msg_count1 < 20) {
PRINTK("deprecated call to ioctl (ICAZ90STATUS)!\n");
- deprecated_msg_count++;
- if (deprecated_msg_count == 100)
+ deprecated_msg_count1++;
+ if (deprecated_msg_count1 == 20)
PRINTK("No longer issuing messages related to "
"deprecated call to ICAZ90STATUS.\n");
}
kfree(pstat);
break;
+ /* THIS IS DEPRECATED. USE THE NEW STATUS CALLS */
+ case Z90STAT_PCIXCCCOUNT:
+ if (deprecated_msg_count2 < 20) {
+ PRINTK("deprecated ioctl (Z90STAT_PCIXCCCOUNT)!\n");
+ deprecated_msg_count2++;
+ if (deprecated_msg_count2 == 20)
+ PRINTK("No longer issuing messages about depre"
+ "cated ioctl Z90STAT_PCIXCCCOUNT.\n");
+ }
+
+ tempstat = get_status_PCIXCCcount();
+ if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
+ ret = -EFAULT;
+ break;
+
case Z90QUIESCE:
if (current->euid != 0) {
PRINTK("QUIESCE fails: euid %d\n",
get_status_PCICAcount());
len += sprintf(resp_buff+len, "PCICC count: %d\n",
get_status_PCICCcount());
- len += sprintf(resp_buff+len, "PCIXCC count: %d\n",
- get_status_PCIXCCcount());
+ len += sprintf(resp_buff+len, "PCIXCC MCL2 count: %d\n",
+ get_status_PCIXCCMCL2count());
+ len += sprintf(resp_buff+len, "PCIXCC MCL3 count: %d\n",
+ get_status_PCIXCCMCL3count());
+ len += sprintf(resp_buff+len, "CEX2C count: %d\n",
+ get_status_CEX2Ccount());
+ len += sprintf(resp_buff+len, "CEX2A count: %d\n",
+ get_status_CEX2Acount());
len += sprintf(resp_buff+len, "requestq count: %d\n",
get_status_requestq_count());
len += sprintf(resp_buff+len, "pendingq count: %d\n",
len += sprintf(resp_buff+len, "Total open handles: %d\n\n",
get_status_totalopen_count());
len += sprinthx(
- "Online devices: 1 means PCICA, 2 means PCICC, 3 means PCIXCC",
+ "Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) "
+ "4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A",
resp_buff+len,
get_status_status_mask(workarea),
Z90CRYPT_NUM_APS);
z90crypt.hdware_info->type_mask[devp->dev_type].user_disabled_count--;
}
-static inline int
-scan_char(unsigned char *bf, unsigned int len,
- unsigned int *offs, unsigned int *p_eof, unsigned char c)
-{
- unsigned int i, found;
-
- found = 0;
- for (i = 0; i < len; i++) {
- if (bf[i] == c) {
- found = 1;
- break;
- }
- if (bf[i] == '\0') {
- *p_eof = 1;
- break;
- }
- if (bf[i] == '\n') {
- break;
- }
- }
- *offs = i+1;
- return found;
-}
-
-static inline int
-scan_string(unsigned char *bf, unsigned int len,
- unsigned int *offs, unsigned int *p_eof, unsigned char *s)
-{
- unsigned int temp_len, temp_offs, found, eof;
-
- temp_len = temp_offs = found = eof = 0;
- while (!eof && !found) {
- found = scan_char(bf+temp_len, len-temp_len,
- &temp_offs, &eof, *s);
-
- temp_len += temp_offs;
- if (eof) {
- found = 0;
- break;
- }
-
- if (found) {
- if (len >= temp_offs+strlen(s)) {
- found = !strncmp(bf+temp_len-1, s, strlen(s));
- if (found) {
- *offs = temp_len+strlen(s)-1;
- break;
- }
- } else {
- found = 0;
- *p_eof = 1;
- break;
- }
- }
- }
- return found;
-}
-
static int
z90crypt_status_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
- int i, j, len, offs, found, eof;
- unsigned char *lbuf;
+ int j, eol;
+ unsigned char *lbuf, *ptr;
unsigned int local_count;
-#define LBUFSIZE 600
+#define LBUFSIZE 1200
lbuf = kmalloc(LBUFSIZE, GFP_KERNEL);
if (!lbuf) {
PRINTK("kmalloc failed!\n");
return -EFAULT;
}
- lbuf[local_count-1] = '\0';
+ lbuf[local_count] = '\0';
- len = 0;
- eof = 0;
- found = 0;
- while (!eof) {
- found = scan_string(lbuf+len, local_count-len, &offs, &eof,
- "Online devices");
- len += offs;
- if (found == 1)
- break;
+ ptr = strstr(lbuf, "Online devices");
+ if (ptr == 0) {
+ PRINTK("Unable to parse data (missing \"Online devices\")\n");
+ kfree(lbuf);
+ return count;
}
- if (eof) {
+ ptr = strstr(ptr, "\n");
+ if (ptr == 0) {
+ PRINTK("Unable to parse data (missing newline after \"Online devices\")\n");
kfree(lbuf);
return count;
}
+ ptr++;
- if (found)
- found = scan_char(lbuf+len, local_count-len, &offs, &eof, '\n');
-
- if (!found || eof) {
+ if (strstr(ptr, "Waiting work element counts") == NULL) {
+ PRINTK("Unable to parse data (missing \"Waiting work element counts\")\n");
kfree(lbuf);
return count;
}
- len += offs;
j = 0;
- for (i = 0; i < 80; i++) {
- switch (*(lbuf+len+i)) {
+ eol = 0;
+ while ((j < 64) && (*ptr != '\0')) {
+ switch (*ptr) {
case '\t':
case ' ':
break;
case '\n':
default:
- eof = 1;
+ eol = 1;
break;
- case '0':
- case '1':
- case '2':
- case '3':
+ case '0': // no device
+ case '1': // PCICA
+ case '2': // PCICC
+ case '3': // PCIXCC_MCL2
+ case '4': // PCIXCC_MCL3
+ case '5': // CEX2C
+ case '6': // CEX2A
j++;
break;
case 'd':
j++;
break;
}
- if (eof)
+ if (eol)
break;
+ ptr++;
}
kfree(lbuf);
dev_ptr = z90crypt.device_p[index];
rv = 0;
do {
- PDEBUG("Dequeue called for device %d\n", index);
if (!dev_ptr || dev_ptr->disabled) {
- rv = REC_NO_RESPONSE;
+ rv = REC_NO_WORK; // a disabled device can't return work
break;
}
if (dev_ptr->dev_self_x != index) {
- PRINTK("Corrupt dev ptr in receive_from_AP\n");
+ PRINTKC("Corrupt dev ptr\n");
z90crypt.terminating = 1;
rv = REC_FATAL_ERROR;
break;
PRINTK("dev_resp_l = %d, dev_resp_p = %p\n",
dev_ptr->dev_resp_l, dev_ptr->dev_resp_p);
} else {
+ PDEBUG("Dequeue called for device %d\n", index);
dv = receive_from_AP(index, z90crypt.cdx,
dev_ptr->dev_resp_l,
dev_ptr->dev_resp_p, psmid);
if (!memcmp(caller_p->caller_id, psmid,
sizeof(caller_p->caller_id))) {
if (!list_empty(&caller_p->caller_liste)) {
- list_del(ptr);
+ list_del_init(ptr);
dev_ptr->dev_caller_count--;
- INIT_LIST_HEAD(&caller_p->caller_liste);
break;
}
}
caller_p = 0;
}
if (!caller_p) {
+ PRINTKW("Unable to locate PSMID %02X%02X%02X%02X%02X"
+ "%02X%02X%02X in device list\n",
+ psmid[0], psmid[1], psmid[2], psmid[3],
+ psmid[4], psmid[5], psmid[6], psmid[7]);
rv = REC_USER_GONE;
break;
}
rv = convert_response(dev_ptr->dev_resp_p,
caller_p->caller_buf_p, buff_len_p, buff);
switch (rv) {
+ case REC_USE_PCICA:
+ break;
case REC_OPERAND_INV:
- PDEBUG("dev %d: user error %d\n", index, rv);
+ case REC_OPERAND_SIZE:
+ case REC_EVEN_MOD:
+ case REC_INVALID_PAD:
+ PDEBUG("device %d: 'user error' %d\n", index, rv);
break;
case WRONG_DEVICE_TYPE:
case REC_HARDWAR_ERR:
case REC_BAD_MESSAGE:
- PRINTK("dev %d: hardware error %d\n",
- index, rv);
+ PRINTKW("device %d: hardware error %d\n", index, rv);
rv = REC_NO_RESPONSE;
break;
- case REC_RELEASED:
- PDEBUG("dev %d: REC_RELEASED = %d\n",
- index, rv);
- break;
default:
- PDEBUG("dev %d: rv = %d\n", index, rv);
+ PDEBUG("device %d: rv = %d\n", index, rv);
break;
}
} while (0);
PRINTK("Zero *buff_len_p\n");
break;
case REC_NO_RESPONSE:
+ PRINTKW("Removing device %d from availability\n", index);
remove_device(dev_ptr);
break;
}
return;
requestq_count--;
rq_p = list_entry(request_list.next, struct work_element, liste);
- list_del(&rq_p->liste);
+ list_del_init(&rq_p->liste);
rq_p->audit[1] |= FP_REMREQUEST;
if (rq_p->devtype == SHRT2DEVPTR(index)->dev_type) {
rq_p->devindex = SHRT2LONG(index);
list_for_each_safe(lptr, tptr, &pending_list) {
pq_p = list_entry(lptr, struct work_element, liste);
if (!memcmp(pq_p->caller_id, psmid, sizeof(pq_p->caller_id))) {
- list_del(lptr);
+ list_del_init(lptr);
pendingq_count--;
pq_p->audit[1] |= FP_NOTPENDING;
break;
pq_p->retcode = -EINVAL;
pq_p->status[0] |= STAT_FAILED;
break;
+ case REC_USE_PCICA:
+ pq_p->retcode = -ERESTARTSYS;
+ pq_p->status[0] |= STAT_FAILED;
+ break;
case REC_NO_RESPONSE:
default:
if (z90crypt.mask.st_count > 1)
* return TRUE if the work element should be removed from the queue
*/
static inline int
-helper_receive_rc(int index, int *rc_p, int *workavail_p)
+helper_receive_rc(int index, int *rc_p)
{
switch (*rc_p) {
case 0:
case REC_OPERAND_SIZE:
case REC_EVEN_MOD:
case REC_INVALID_PAD:
- return 1;
+ case REC_USE_PCICA:
+ break;
case REC_BUSY:
case REC_NO_WORK:
case REC_EMPTY:
case REC_RETRY_DEV:
case REC_FATAL_ERROR:
- break;
+ return 0;
case REC_NO_RESPONSE:
- *workavail_p = 0;
break;
default:
- PRINTK("rc %d, device %d\n", *rc_p, SHRT2LONG(index));
+ PRINTK("rc %d, device %d converted to REC_NO_RESPONSE\n",
+ *rc_p, SHRT2LONG(index));
*rc_p = REC_NO_RESPONSE;
- *workavail_p = 0;
break;
}
- return 0;
+ return 1;
}
static inline void
static void
z90crypt_reader_task(unsigned long ptr)
{
- int workavail, remaining, index, rc, buff_len;
+ int workavail, index, rc, buff_len;
unsigned char psmid[8];
unsigned char __user *resp_addr;
static unsigned char buff[1024];
- PDEBUG("jiffies %ld\n", jiffies);
-
/**
* we use workavail = 2 to ensure 2 passes with nothing dequeued before
- * exiting the loop. If remaining == 0 after the loop, there is no work
- * remaining on the queues.
+ * exiting the loop. If (pendingq_count+requestq_count) == 0 after the
+ * loop, there is no work remaining on the queues.
*/
resp_addr = 0;
workavail = 2;
- remaining = 0;
buff_len = 0;
while (workavail) {
workavail--;
&resp_addr);
PDEBUG("Dequeued: rc = %d.\n", rc);
- if (helper_receive_rc(index, &rc, &workavail)) {
+ if (helper_receive_rc(index, &rc)) {
if (rc != REC_NO_RESPONSE) {
helper_send_work(index);
workavail = 2;
}
if (rc == REC_FATAL_ERROR)
- remaining = 0;
- else if (rc != REC_NO_RESPONSE)
- remaining +=
- SHRT2DEVPTR(index)->dev_caller_count;
+ PRINTKW("REC_FATAL_ERROR from device %d!\n",
+ SHRT2LONG(index));
}
spin_unlock_irq(&queuespinlock);
}
- if (remaining) {
- spin_lock_irq(&queuespinlock);
+ if (pendingq_count + requestq_count)
z90crypt_schedule_reader_timer();
- spin_unlock_irq(&queuespinlock);
- }
}
static inline void
pq_p->status[0] |= STAT_FAILED;
unbuild_caller(LONG2DEVPTR(pq_p->devindex),
(struct caller *)pq_p->requestptr);
- list_del(lptr);
+ list_del_init(lptr);
pendingq_count--;
pq_p->audit[1] |= FP_NOTPENDING;
pq_p->audit[1] |= FP_AWAKENING;
pq_p = list_entry(lptr, struct work_element, liste);
pq_p->retcode = -ENODEV;
pq_p->status[0] |= STAT_FAILED;
- list_del(lptr);
+ list_del_init(lptr);
requestq_count--;
pq_p->audit[1] |= FP_REMREQUEST;
pq_p->audit[1] |= FP_AWAKENING;
pq_p = list_entry(lptr, struct work_element, liste);
if (pq_p->requestsent >= timelimit)
break;
+ PRINTKW("Purging(PQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
+ ((struct caller *)pq_p->requestptr)->caller_id[0],
+ ((struct caller *)pq_p->requestptr)->caller_id[1],
+ ((struct caller *)pq_p->requestptr)->caller_id[2],
+ ((struct caller *)pq_p->requestptr)->caller_id[3],
+ ((struct caller *)pq_p->requestptr)->caller_id[4],
+ ((struct caller *)pq_p->requestptr)->caller_id[5],
+ ((struct caller *)pq_p->requestptr)->caller_id[6],
+ ((struct caller *)pq_p->requestptr)->caller_id[7]);
pq_p->retcode = -ETIMEOUT;
pq_p->status[0] |= STAT_FAILED;
/* get this off any caller queue it may be on */
unbuild_caller(LONG2DEVPTR(pq_p->devindex),
(struct caller *) pq_p->requestptr);
- list_del(lptr);
+ list_del_init(lptr);
pendingq_count--;
pq_p->audit[1] |= FP_TIMEDOUT;
pq_p->audit[1] |= FP_NOTPENDING;
pq_p = list_entry(lptr, struct work_element, liste);
if (pq_p->requestsent >= timelimit)
break;
+ PRINTKW("Purging(RQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
+ ((struct caller *)pq_p->requestptr)->caller_id[0],
+ ((struct caller *)pq_p->requestptr)->caller_id[1],
+ ((struct caller *)pq_p->requestptr)->caller_id[2],
+ ((struct caller *)pq_p->requestptr)->caller_id[3],
+ ((struct caller *)pq_p->requestptr)->caller_id[4],
+ ((struct caller *)pq_p->requestptr)->caller_id[5],
+ ((struct caller *)pq_p->requestptr)->caller_id[6],
+ ((struct caller *)pq_p->requestptr)->caller_id[7]);
pq_p->retcode = -ETIMEOUT;
pq_p->status[0] |= STAT_FAILED;
- list_del(lptr);
+ list_del_init(lptr);
requestq_count--;
pq_p->audit[1] |= FP_TIMEDOUT;
pq_p->audit[1] |= FP_REMREQUEST;
z90crypt.max_count = Z90CRYPT_NUM_DEVS;
z90crypt.cdx = *cdx_p;
- hdware_blk_p = (struct hdware_block *)
- kmalloc(sizeof(struct hdware_block), GFP_ATOMIC);
+ hdware_blk_p = kzalloc(sizeof(struct hdware_block), GFP_ATOMIC);
if (!hdware_blk_p) {
PDEBUG("kmalloc for hardware block failed\n");
return ENOMEM;
}
- memset(hdware_blk_p, 0x00, sizeof(struct hdware_block));
z90crypt.hdware_info = hdware_blk_p;
return 0;
{
enum hdstat hd_stat;
int q_depth, dev_type;
- int i, j, k;
+ int indx, chkdom, numdomains;
- q_depth = dev_type = k = 0;
- for (i = 0; i < z90crypt.max_count; i++) {
+ q_depth = dev_type = numdomains = 0;
+ for (chkdom = 0; chkdom <= 15; cdx_array[chkdom++] = -1);
+ for (indx = 0; indx < z90crypt.max_count; indx++) {
hd_stat = HD_NOT_THERE;
- for (j = 0; j <= 15; cdx_array[j++] = -1);
- k = 0;
- for (j = 0; j <= 15; j++) {
- hd_stat = query_online(i, j, MAX_RESET,
+ numdomains = 0;
+ for (chkdom = 0; chkdom <= 15; chkdom++) {
+ hd_stat = query_online(indx, chkdom, MAX_RESET,
&q_depth, &dev_type);
if (hd_stat == HD_TSQ_EXCEPTION) {
z90crypt.terminating = 1;
break;
}
if (hd_stat == HD_ONLINE) {
- cdx_array[k++] = j;
- if (*cdx_p == j) {
+ cdx_array[numdomains++] = chkdom;
+ if (*cdx_p == chkdom) {
*correct_cdx_found = 1;
break;
}
}
}
- if ((*correct_cdx_found == 1) || (k != 0))
+ if ((*correct_cdx_found == 1) || (numdomains != 0))
break;
if (z90crypt.terminating)
break;
}
- return k;
+ return numdomains;
}
static inline int
probe_crypto_domain(int *cdx_p)
{
int cdx_array[16];
- int correct_cdx_found, k;
+ char cdx_array_text[53], temp[5];
+ int correct_cdx_found, numdomains;
correct_cdx_found = 0;
- k = helper_scan_devices(cdx_array, cdx_p, &correct_cdx_found);
+ numdomains = helper_scan_devices(cdx_array, cdx_p, &correct_cdx_found);
if (z90crypt.terminating)
return TSQ_FATAL_ERROR;
if (correct_cdx_found)
return 0;
- if (k == 0) {
- *cdx_p = 0;
- return 0;
+ if (numdomains == 0) {
+ PRINTKW("Unable to find crypto domain: No devices found\n");
+ return Z90C_NO_DEVICES;
}
- if (k == 1) {
- if ((*cdx_p == -1) || !z90crypt.domain_established) {
+ if (numdomains == 1) {
+ if (*cdx_p == -1) {
*cdx_p = cdx_array[0];
return 0;
}
- if (*cdx_p != cdx_array[0]) {
- PRINTK("incorrect domain: specified = %d, found = %d\n",
- *cdx_p, cdx_array[0]);
- return Z90C_INCORRECT_DOMAIN;
- }
+ PRINTKW("incorrect domain: specified = %d, found = %d\n",
+ *cdx_p, cdx_array[0]);
+ return Z90C_INCORRECT_DOMAIN;
+ }
+
+ numdomains--;
+ sprintf(cdx_array_text, "%d", cdx_array[numdomains]);
+ while (numdomains) {
+ numdomains--;
+ sprintf(temp, ", %d", cdx_array[numdomains]);
+ strcat(cdx_array_text, temp);
}
+ PRINTKW("ambiguous domain detected: specified = %d, found array = %s\n",
+ *cdx_p, cdx_array_text);
return Z90C_AMBIGUOUS_DOMAIN;
}
refresh_z90crypt(int *cdx_p)
{
int i, j, indx, rv;
- struct status local_mask;
+ static struct status local_mask;
struct device *devPtr;
unsigned char oldStat, newStat;
int return_unchanged;
return TSQ_FATAL_ERROR;
rv = 0;
if (!z90crypt.hdware_info->hdware_mask.st_count &&
- !z90crypt.domain_established)
+ !z90crypt.domain_established) {
rv = probe_crypto_domain(cdx_p);
- if (z90crypt.terminating)
- return TSQ_FATAL_ERROR;
- if (rv) {
- switch (rv) {
- case Z90C_AMBIGUOUS_DOMAIN:
- PRINTK("ambiguous domain detected\n");
- break;
- case Z90C_INCORRECT_DOMAIN:
- PRINTK("incorrect domain specified\n");
- break;
- default:
- PRINTK("probe domain returned %d\n", rv);
- break;
- }
- return rv;
- }
- if (*cdx_p) {
+ if (z90crypt.terminating)
+ return TSQ_FATAL_ERROR;
+ if (rv == Z90C_NO_DEVICES)
+ return 0; // try later
+ if (rv)
+ return rv;
z90crypt.cdx = *cdx_p;
z90crypt.domain_established = 1;
}
total_size = sizeof(struct device) +
z90crypt.q_depth_array[index] * sizeof(int);
- dev_ptr = (struct device *) kmalloc(total_size, GFP_ATOMIC);
+ dev_ptr = kzalloc(total_size, GFP_ATOMIC);
if (!dev_ptr) {
PRINTK("kmalloc device %d failed\n", index);
return ENOMEM;
}
- memset(dev_ptr, 0, total_size);
dev_ptr->dev_resp_p = kmalloc(MAX_RESPONSE_SIZE, GFP_ATOMIC);
if (!dev_ptr->dev_resp_p) {
kfree(dev_ptr);
return rv;
}
}
+ if (dev_ptr->dev_type == PCIXCC_UNK) {
+ rv = probe_PCIXCC_type(dev_ptr);
+ if (rv) {
+ PRINTK("rv = %d from probe_PCIXCC_type %d\n",
+ rv, index);
+ kfree(dev_ptr->dev_resp_p);
+ kfree(dev_ptr);
+ return rv;
+ }
+ }
deviceType = dev_ptr->dev_type;
z90crypt.dev_type_array[index] = deviceType;
if (deviceType == PCICA)
z90crypt.hdware_info->device_type_array[index] = 1;
else if (deviceType == PCICC)
z90crypt.hdware_info->device_type_array[index] = 2;
- else if (deviceType == PCIXCC)
+ else if (deviceType == PCIXCC_MCL2)
z90crypt.hdware_info->device_type_array[index] = 3;
- else
+ else if (deviceType == PCIXCC_MCL3)
+ z90crypt.hdware_info->device_type_array[index] = 4;
+ else if (deviceType == CEX2C)
+ z90crypt.hdware_info->device_type_array[index] = 5;
+ else if (deviceType == CEX2A)
+ z90crypt.hdware_info->device_type_array[index] = 6;
+ else // No idea how this would happen.
z90crypt.hdware_info->device_type_array[index] = -1;
}
if (dev_ptr) {
disabledFlag = dev_ptr->disabled;
t = dev_ptr->dev_type;
- if (dev_ptr->dev_resp_p)
- kfree(dev_ptr->dev_resp_p);
+ kfree(dev_ptr->dev_resp_p);
kfree(dev_ptr);
} else {
disabledFlag = 0;
destroy_z90crypt(void)
{
int i;
+
for (i = 0; i < z90crypt.max_count; i++)
if (z90crypt.device_p[i])
destroy_crypto_device(i);
- if (z90crypt.hdware_info)
- kfree((void *)z90crypt.hdware_info);
+ kfree(z90crypt.hdware_info);
memset((void *)&z90crypt, 0, sizeof(z90crypt));
}
-static unsigned char static_testmsg[] = {
+static unsigned char static_testmsg[384] = {
0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x00,0x06,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x43,0x43,
{
int rv, dv, i, index, length;
unsigned char psmid[8];
- static unsigned char loc_testmsg[384];
+ static unsigned char loc_testmsg[sizeof(static_testmsg)];
index = devPtr->dev_self_x;
rv = 0;
return rv;
}
-#ifdef Z90CRYPT_USE_HOTPLUG
-void
-z90crypt_hotplug_event(int dev_major, int dev_minor, int action)
-{
-#ifdef CONFIG_HOTPLUG
- char *argv[3];
- char *envp[6];
- char major[20];
- char minor[20];
-
- sprintf(major, "MAJOR=%d", dev_major);
- sprintf(minor, "MINOR=%d", dev_minor);
+static unsigned char MCL3_testmsg[] = {
+0x00,0x00,0x00,0x00,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
+0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
+0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
+0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
+0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
+0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
+0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
+0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
+0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
+0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
+0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
+0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
+0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
+0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
+0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
+0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,0xF1,0x3D,0x93,0x53
+};
- argv[0] = hotplug_path;
- argv[1] = "z90crypt";
- argv[2] = 0;
+static int
+probe_PCIXCC_type(struct device *devPtr)
+{
+ int rv, dv, i, index, length;
+ unsigned char psmid[8];
+ static unsigned char loc_testmsg[548];
+ struct CPRBX *cprbx_p;
- envp[0] = "HOME=/";
- envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+ index = devPtr->dev_self_x;
+ rv = 0;
+ do {
+ memcpy(loc_testmsg, MCL3_testmsg, sizeof(MCL3_testmsg));
+ length = sizeof(MCL3_testmsg) - 0x0C;
+ dv = send_to_AP(index, z90crypt.cdx, length, loc_testmsg);
+ if (dv) {
+ PDEBUG("dv returned = %d\n", dv);
+ if (dv == DEV_SEN_EXCEPTION) {
+ rv = SEN_FATAL_ERROR;
+ PRINTKC("exception in send to AP %d\n", index);
+ break;
+ }
+ PDEBUG("return value from send_to_AP: %d\n", rv);
+ switch (dv) {
+ case DEV_GONE:
+ PDEBUG("dev %d not available\n", index);
+ rv = SEN_NOT_AVAIL;
+ break;
+ case DEV_ONLINE:
+ rv = 0;
+ break;
+ case DEV_EMPTY:
+ rv = SEN_NOT_AVAIL;
+ break;
+ case DEV_NO_WORK:
+ rv = SEN_FATAL_ERROR;
+ break;
+ case DEV_BAD_MESSAGE:
+ rv = SEN_USER_ERROR;
+ break;
+ case DEV_QUEUE_FULL:
+ rv = SEN_QUEUE_FULL;
+ break;
+ default:
+ PRINTK("unknown dv=%d for dev %d\n", dv, index);
+ rv = SEN_NOT_AVAIL;
+ break;
+ }
+ }
- switch (action) {
- case Z90CRYPT_HOTPLUG_ADD:
- envp[2] = "ACTION=add";
- break;
- case Z90CRYPT_HOTPLUG_REMOVE:
- envp[2] = "ACTION=remove";
- break;
- default:
- BUG();
- }
- envp[3] = major;
- envp[4] = minor;
- envp[5] = 0;
+ if (rv)
+ break;
- call_usermodehelper(argv[0], argv, envp, 0);
-#endif
+ for (i = 0; i < 6; i++) {
+ mdelay(300);
+ dv = receive_from_AP(index, z90crypt.cdx,
+ devPtr->dev_resp_l,
+ devPtr->dev_resp_p, psmid);
+ PDEBUG("dv returned by DQ = %d\n", dv);
+ if (dv == DEV_REC_EXCEPTION) {
+ rv = REC_FATAL_ERROR;
+ PRINTKC("exception in dequeue %d\n",
+ index);
+ break;
+ }
+ switch (dv) {
+ case DEV_ONLINE:
+ rv = 0;
+ break;
+ case DEV_EMPTY:
+ rv = REC_EMPTY;
+ break;
+ case DEV_NO_WORK:
+ rv = REC_NO_WORK;
+ break;
+ case DEV_BAD_MESSAGE:
+ case DEV_GONE:
+ default:
+ rv = REC_NO_RESPONSE;
+ break;
+ }
+ if ((rv != 0) && (rv != REC_NO_WORK))
+ break;
+ if (rv == 0)
+ break;
+ }
+ if (rv)
+ break;
+ cprbx_p = (struct CPRBX *) (devPtr->dev_resp_p + 48);
+ if ((cprbx_p->ccp_rtcode == 8) && (cprbx_p->ccp_rscode == 33)) {
+ devPtr->dev_type = PCIXCC_MCL2;
+ PDEBUG("device %d is MCL2\n", index);
+ } else {
+ devPtr->dev_type = PCIXCC_MCL3;
+ PDEBUG("device %d is MCL3\n", index);
+ }
+ } while (0);
+ /* In a general error case, the card is not marked online */
+ return rv;
}
-#endif
module_init(z90crypt_init_module);
module_exit(z90crypt_cleanup_module);