s390 updates for the 4.20 merge window

- Improved access control for the zcrypt driver, multiple device nodes
    can now be created with different access control lists
 
  - Extend the pkey API to provide random protected keys, this is useful
    for encrypted swap device with ephemeral protected keys
 
  - Add support for virtually mapped kernel stacks
 
  - Rework the early boot code, this moves the memory detection into the
    boot code that runs prior to decompression.
 
  - Add KASAN support
 
  - Bug fixes and cleanups
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQEcBAABCAAGBQJbzXKpAAoJEDjwexyKj9rg98YH/jZ5/kEYV44JsACroTNBC782
 6QLCvoCvSgXUAqRwnIfnxrcjrUVNW2aK6rOSsI/I8rQDsSA3boJ7FimoEI2BsUZG
 dcMy0hC47AYB7yKREQX3gdDEj8f0bn8v2ize5F6gwLkIx0A+aBUSivRQeYMaF8sn
 N/5OkSJwjCb+ZkNmDa3SHif+hC5+iL+q1hfuBdQkeCBok9pAqhyosRkgLe8CQgUV
 HGrvaWJ4FudIpg4tu2jL2OsNoZFX2pK5d+Up886+KGKQEUfiXKYtdmzX17Vd7PIk
 Vkf7EWUipzIA7UtrJ6pljoFsrNa+83jm4j5Dgy0ohadCVUBYLORte3yEl4P1EoM=
 =MMf0
 -----END PGP SIGNATURE-----

Merge tag 's390-4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux

Pull s390 updates from Martin Schwidefsky:

 - Improved access control for the zcrypt driver, multiple device nodes
   can now be created with different access control lists

 - Extend the pkey API to provide random protected keys, this is useful
   for encrypted swap device with ephemeral protected keys

 - Add support for virtually mapped kernel stacks

 - Rework the early boot code, this moves the memory detection into the
   boot code that runs prior to decompression.

 - Add KASAN support

 - Bug fixes and cleanups

* tag 's390-4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (83 commits)
  s390/pkey: move pckmo subfunction available checks away from module init
  s390/kasan: support preemptible kernel build
  s390/pkey: Load pkey kernel module automatically
  s390/perf: Return error when debug_register fails
  s390/sthyi: Fix machine name validity indication
  s390/zcrypt: fix broken zcrypt_send_cprb in-kernel api function
  s390/vmalloc: fix VMALLOC_START calculation
  s390/mem_detect: add missing include
  s390/dumpstack: print psw mask and address again
  s390/crypto: Enhance paes cipher to accept variable length key material
  s390/pkey: Introduce new API for transforming key blobs
  s390/pkey: Introduce new API for random protected key verification
  s390/pkey: Add sysfs attributes to emit secure key blobs
  s390/pkey: Add sysfs attributes to emit protected key blobs
  s390/pkey: Define protected key blob format
  s390/pkey: Introduce new API for random protected key generation
  s390/zcrypt: add ap_adapter_mask sysfs attribute
  s390/zcrypt: provide apfs failure code on type 86 error reply
  s390/zcrypt: zcrypt device driver cleanup
  s390/kasan: add support for mem= kernel parameter
  ...
This commit is contained in:
Linus Torvalds 2018-10-23 11:14:47 +01:00
commit e2b623fbe6
121 changed files with 3712 additions and 1183 deletions

View file

@ -3309,10 +3309,8 @@ dasd_exit(void)
dasd_proc_exit();
#endif
dasd_eer_exit();
if (dasd_page_cache != NULL) {
kmem_cache_destroy(dasd_page_cache);
dasd_page_cache = NULL;
}
kmem_cache_destroy(dasd_page_cache);
dasd_page_cache = NULL;
dasd_gendisk_exit();
dasd_devmap_exit();
if (dasd_debug_area != NULL) {

View file

@ -11,6 +11,7 @@ endif
GCOV_PROFILE_sclp_early_core.o := n
KCOV_INSTRUMENT_sclp_early_core.o := n
UBSAN_SANITIZE_sclp_early_core.o := n
KASAN_SANITIZE_sclp_early_core.o := n
CFLAGS_sclp_early_core.o += -D__NO_FORTIFY

View file

@ -58,22 +58,31 @@ struct mon_private {
static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
{
struct appldata_product_id id;
struct appldata_parameter_list *parm_list;
struct appldata_product_id *id;
int rc;
memcpy(id.prod_nr, "LNXAPPL", 7);
id.prod_fn = myhdr->applid;
id.record_nr = myhdr->record_num;
id.version_nr = myhdr->version;
id.release_nr = myhdr->release;
id.mod_lvl = myhdr->mod_level;
rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen);
id = kmalloc(sizeof(*id), GFP_KERNEL);
parm_list = kmalloc(sizeof(*parm_list), GFP_KERNEL);
rc = -ENOMEM;
if (!id || !parm_list)
goto out;
memcpy(id->prod_nr, "LNXAPPL", 7);
id->prod_fn = myhdr->applid;
id->record_nr = myhdr->record_num;
id->version_nr = myhdr->version;
id->release_nr = myhdr->release;
id->mod_lvl = myhdr->mod_level;
rc = appldata_asm(parm_list, id, fcn,
(void *) buffer, myhdr->datalen);
if (rc <= 0)
return rc;
goto out;
pr_err("Writing monitor data failed with rc=%i\n", rc);
if (rc == 5)
return -EPERM;
return -EINVAL;
rc = (rc == 5) ? -EPERM : -EINVAL;
out:
kfree(id);
kfree(parm_list);
return rc;
}
static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,

View file

@ -63,6 +63,9 @@
typedef unsigned int sclp_cmdw_t;
#define SCLP_CMDW_READ_CPU_INFO 0x00010001
#define SCLP_CMDW_READ_SCP_INFO 0x00020001
#define SCLP_CMDW_READ_STORAGE_INFO 0x00040001
#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
#define SCLP_CMDW_READ_EVENT_DATA 0x00770005
#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005
#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005
@ -156,6 +159,54 @@ struct read_cpu_info_sccb {
u8 reserved[4096 - 16];
} __attribute__((packed, aligned(PAGE_SIZE)));
struct read_info_sccb {
struct sccb_header header; /* 0-7 */
u16 rnmax; /* 8-9 */
u8 rnsize; /* 10 */
u8 _pad_11[16 - 11]; /* 11-15 */
u16 ncpurl; /* 16-17 */
u16 cpuoff; /* 18-19 */
u8 _pad_20[24 - 20]; /* 20-23 */
u8 loadparm[8]; /* 24-31 */
u8 _pad_32[42 - 32]; /* 32-41 */
u8 fac42; /* 42 */
u8 fac43; /* 43 */
u8 _pad_44[48 - 44]; /* 44-47 */
u64 facilities; /* 48-55 */
u8 _pad_56[66 - 56]; /* 56-65 */
u8 fac66; /* 66 */
u8 _pad_67[76 - 67]; /* 67-83 */
u32 ibc; /* 76-79 */
u8 _pad80[84 - 80]; /* 80-83 */
u8 fac84; /* 84 */
u8 fac85; /* 85 */
u8 _pad_86[91 - 86]; /* 86-90 */
u8 fac91; /* 91 */
u8 _pad_92[98 - 92]; /* 92-97 */
u8 fac98; /* 98 */
u8 hamaxpow; /* 99 */
u32 rnsize2; /* 100-103 */
u64 rnmax2; /* 104-111 */
u32 hsa_size; /* 112-115 */
u8 fac116; /* 116 */
u8 fac117; /* 117 */
u8 fac118; /* 118 */
u8 fac119; /* 119 */
u16 hcpua; /* 120-121 */
u8 _pad_122[124 - 122]; /* 122-123 */
u32 hmfai; /* 124-127 */
u8 _pad_128[4096 - 128]; /* 128-4095 */
} __packed __aligned(PAGE_SIZE);
struct read_storage_sccb {
struct sccb_header header;
u16 max_id;
u16 assigned;
u16 standby;
u16 :16;
u32 entries[0];
} __packed;
static inline void sclp_fill_core_info(struct sclp_core_info *info,
struct read_cpu_info_sccb *sccb)
{
@ -275,6 +326,7 @@ unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb);
int sclp_early_set_event_mask(struct init_sccb *sccb,
sccb_mask_t receive_mask,
sccb_mask_t send_mask);
int sclp_early_get_info(struct read_info_sccb *info);
/* useful inlines */

View file

@ -460,15 +460,6 @@ static int sclp_mem_freeze(struct device *dev)
return -EPERM;
}
struct read_storage_sccb {
struct sccb_header header;
u16 max_id;
u16 assigned;
u16 standby;
u16 :16;
u32 entries[0];
} __packed;
static const struct dev_pm_ops sclp_mem_pm_ops = {
.freeze = sclp_mem_freeze,
};
@ -498,7 +489,7 @@ static int __init sclp_detect_standby_memory(void)
for (id = 0; id <= sclp_max_storage_id; id++) {
memset(sccb, 0, PAGE_SIZE);
sccb->header.length = PAGE_SIZE;
rc = sclp_sync_request(0x00040001 | id << 8, sccb);
rc = sclp_sync_request(SCLP_CMDW_READ_STORAGE_INFO | id << 8, sccb);
if (rc)
goto out;
switch (sccb->header.response_code) {

View file

@ -15,80 +15,17 @@
#include "sclp_sdias.h"
#include "sclp.h"
#define SCLP_CMDW_READ_SCP_INFO 0x00020001
#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
struct read_info_sccb {
struct sccb_header header; /* 0-7 */
u16 rnmax; /* 8-9 */
u8 rnsize; /* 10 */
u8 _pad_11[16 - 11]; /* 11-15 */
u16 ncpurl; /* 16-17 */
u16 cpuoff; /* 18-19 */
u8 _pad_20[24 - 20]; /* 20-23 */
u8 loadparm[8]; /* 24-31 */
u8 _pad_32[42 - 32]; /* 32-41 */
u8 fac42; /* 42 */
u8 fac43; /* 43 */
u8 _pad_44[48 - 44]; /* 44-47 */
u64 facilities; /* 48-55 */
u8 _pad_56[66 - 56]; /* 56-65 */
u8 fac66; /* 66 */
u8 _pad_67[76 - 67]; /* 67-83 */
u32 ibc; /* 76-79 */
u8 _pad80[84 - 80]; /* 80-83 */
u8 fac84; /* 84 */
u8 fac85; /* 85 */
u8 _pad_86[91 - 86]; /* 86-90 */
u8 fac91; /* 91 */
u8 _pad_92[98 - 92]; /* 92-97 */
u8 fac98; /* 98 */
u8 hamaxpow; /* 99 */
u32 rnsize2; /* 100-103 */
u64 rnmax2; /* 104-111 */
u8 _pad_112[116 - 112]; /* 112-115 */
u8 fac116; /* 116 */
u8 fac117; /* 117 */
u8 fac118; /* 118 */
u8 fac119; /* 119 */
u16 hcpua; /* 120-121 */
u8 _pad_122[124 - 122]; /* 122-123 */
u32 hmfai; /* 124-127 */
u8 _pad_128[4096 - 128]; /* 128-4095 */
} __packed __aligned(PAGE_SIZE);
static struct sclp_ipl_info sclp_ipl_info;
struct sclp_info sclp;
EXPORT_SYMBOL(sclp);
static int __init sclp_early_read_info(struct read_info_sccb *sccb)
{
int i;
sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
SCLP_CMDW_READ_SCP_INFO};
for (i = 0; i < ARRAY_SIZE(commands); i++) {
memset(sccb, 0, sizeof(*sccb));
sccb->header.length = sizeof(*sccb);
sccb->header.function_code = 0x80;
sccb->header.control_mask[2] = 0x80;
if (sclp_early_cmd(commands[i], sccb))
break;
if (sccb->header.response_code == 0x10)
return 0;
if (sccb->header.response_code != 0x1f0)
break;
}
return -EIO;
}
static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
{
struct sclp_core_entry *cpue;
u16 boot_cpu_address, cpu;
if (sclp_early_read_info(sccb))
if (sclp_early_get_info(sccb))
return;
sclp.facilities = sccb->facilities;
@ -147,6 +84,8 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
sclp_ipl_info.has_dump = 1;
memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
if (sccb->hsa_size)
sclp.hsa_size = (sccb->hsa_size - 1) * PAGE_SIZE;
sclp.mtid = (sccb->fac42 & 0x80) ? (sccb->fac42 & 31) : 0;
sclp.mtid_cp = (sccb->fac42 & 0x80) ? (sccb->fac43 & 31) : 0;
sclp.mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0;
@ -189,61 +128,6 @@ int __init sclp_early_get_core_info(struct sclp_core_info *info)
return 0;
}
static long __init sclp_early_hsa_size_init(struct sdias_sccb *sccb)
{
memset(sccb, 0, sizeof(*sccb));
sccb->hdr.length = sizeof(*sccb);
sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
sccb->evbuf.hdr.type = EVTYP_SDIAS;
sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
sccb->evbuf.event_id = 4712;
sccb->evbuf.dbs = 1;
if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
return -EIO;
if (sccb->hdr.response_code != 0x20)
return -EIO;
if (sccb->evbuf.blk_cnt == 0)
return 0;
return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
}
static long __init sclp_early_hsa_copy_wait(struct sdias_sccb *sccb)
{
memset(sccb, 0, PAGE_SIZE);
sccb->hdr.length = PAGE_SIZE;
if (sclp_early_cmd(SCLP_CMDW_READ_EVENT_DATA, sccb))
return -EIO;
if ((sccb->hdr.response_code != 0x20) && (sccb->hdr.response_code != 0x220))
return -EIO;
if (sccb->evbuf.blk_cnt == 0)
return 0;
return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
}
static void __init sclp_early_hsa_size_detect(void *sccb)
{
unsigned long flags;
long size = -EIO;
raw_local_irq_save(flags);
if (sclp_early_set_event_mask(sccb, EVTYP_SDIAS_MASK, EVTYP_SDIAS_MASK))
goto out;
size = sclp_early_hsa_size_init(sccb);
/* First check for synchronous response (LPAR) */
if (size)
goto out_mask;
if (!(S390_lowcore.ext_params & 1))
sclp_early_wait_irq();
size = sclp_early_hsa_copy_wait(sccb);
out_mask:
sclp_early_set_event_mask(sccb, 0, 0);
out:
raw_local_irq_restore(flags);
if (size > 0)
sclp.hsa_size = size;
}
static void __init sclp_early_console_detect(struct init_sccb *sccb)
{
if (sccb->header.response_code != 0x20)
@ -262,7 +146,6 @@ void __init sclp_early_detect(void)
sclp_early_facilities_detect(sccb);
sclp_early_init_core_info(sccb);
sclp_early_hsa_size_detect(sccb);
/*
* Turn off SCLP event notifications. Also save remote masks in the

View file

@ -9,9 +9,13 @@
#include <asm/lowcore.h>
#include <asm/ebcdic.h>
#include <asm/irq.h>
#include <asm/sections.h>
#include <asm/mem_detect.h>
#include "sclp.h"
#include "sclp_rw.h"
static struct read_info_sccb __bootdata(sclp_info_sccb);
static int __bootdata(sclp_info_sccb_valid);
char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data);
int sclp_init_state __section(.data) = sclp_init_state_uninitialized;
/*
@ -234,3 +238,115 @@ void sclp_early_printk_force(const char *str)
{
__sclp_early_printk(str, strlen(str), 1);
}
int __init sclp_early_read_info(void)
{
int i;
struct read_info_sccb *sccb = &sclp_info_sccb;
sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
SCLP_CMDW_READ_SCP_INFO};
for (i = 0; i < ARRAY_SIZE(commands); i++) {
memset(sccb, 0, sizeof(*sccb));
sccb->header.length = sizeof(*sccb);
sccb->header.function_code = 0x80;
sccb->header.control_mask[2] = 0x80;
if (sclp_early_cmd(commands[i], sccb))
break;
if (sccb->header.response_code == 0x10) {
sclp_info_sccb_valid = 1;
return 0;
}
if (sccb->header.response_code != 0x1f0)
break;
}
return -EIO;
}
int __init sclp_early_get_info(struct read_info_sccb *info)
{
if (!sclp_info_sccb_valid)
return -EIO;
*info = sclp_info_sccb;
return 0;
}
int __init sclp_early_get_memsize(unsigned long *mem)
{
unsigned long rnmax;
unsigned long rnsize;
struct read_info_sccb *sccb = &sclp_info_sccb;
if (!sclp_info_sccb_valid)
return -EIO;
rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
rnsize = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
rnsize <<= 20;
*mem = rnsize * rnmax;
return 0;
}
int __init sclp_early_get_hsa_size(unsigned long *hsa_size)
{
if (!sclp_info_sccb_valid)
return -EIO;
*hsa_size = 0;
if (sclp_info_sccb.hsa_size)
*hsa_size = (sclp_info_sccb.hsa_size - 1) * PAGE_SIZE;
return 0;
}
#define SCLP_STORAGE_INFO_FACILITY 0x0000400000000000UL
void __weak __init add_mem_detect_block(u64 start, u64 end) {}
int __init sclp_early_read_storage_info(void)
{
struct read_storage_sccb *sccb = (struct read_storage_sccb *)&sclp_early_sccb;
int rc, id, max_id = 0;
unsigned long rn, rzm;
sclp_cmdw_t command;
u16 sn;
if (!sclp_info_sccb_valid)
return -EIO;
if (!(sclp_info_sccb.facilities & SCLP_STORAGE_INFO_FACILITY))
return -EOPNOTSUPP;
rzm = sclp_info_sccb.rnsize ?: sclp_info_sccb.rnsize2;
rzm <<= 20;
for (id = 0; id <= max_id; id++) {
memset(sclp_early_sccb, 0, sizeof(sclp_early_sccb));
sccb->header.length = sizeof(sclp_early_sccb);
command = SCLP_CMDW_READ_STORAGE_INFO | (id << 8);
rc = sclp_early_cmd(command, sccb);
if (rc)
goto fail;
max_id = sccb->max_id;
switch (sccb->header.response_code) {
case 0x0010:
for (sn = 0; sn < sccb->assigned; sn++) {
if (!sccb->entries[sn])
continue;
rn = sccb->entries[sn] >> 16;
add_mem_detect_block((rn - 1) * rzm, rn * rzm);
}
break;
case 0x0310:
case 0x0410:
break;
default:
goto fail;
}
}
return 0;
fail:
mem_detect.count = 0;
return -EIO;
}

View file

@ -24,6 +24,7 @@
#define SCLP_ATYPE_PCI 2
#define SCLP_ERRNOTIFY_AQ_RESET 0
#define SCLP_ERRNOTIFY_AQ_REPAIR 1
#define SCLP_ERRNOTIFY_AQ_INFO_LOG 2
@ -111,9 +112,14 @@ static int sclp_pci_check_report(struct zpci_report_error_header *report)
if (report->version != 1)
return -EINVAL;
if (report->action != SCLP_ERRNOTIFY_AQ_REPAIR &&
report->action != SCLP_ERRNOTIFY_AQ_INFO_LOG)
switch (report->action) {
case SCLP_ERRNOTIFY_AQ_RESET:
case SCLP_ERRNOTIFY_AQ_REPAIR:
case SCLP_ERRNOTIFY_AQ_INFO_LOG:
break;
default:
return -EINVAL;
}
if (report->length > (PAGE_SIZE - sizeof(struct err_notify_sccb)))
return -EINVAL;

View file

@ -971,7 +971,7 @@ tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb)
snprintf(exception, BUFSIZE, "Data degraded");
break;
case 0x03:
snprintf(exception, BUFSIZE, "Data degraded in partion %i",
snprintf(exception, BUFSIZE, "Data degraded in partition %i",
sense->fmt.f70.mp);
break;
case 0x04:

View file

@ -153,7 +153,7 @@ static struct vmlogrdr_priv_t sys_ser[] = {
}
};
#define MAXMINOR (sizeof(sys_ser)/sizeof(struct vmlogrdr_priv_t))
#define MAXMINOR ARRAY_SIZE(sys_ser)
static char FENCE[] = {"EOR"};
static int vmlogrdr_major = 0;

View file

@ -608,6 +608,36 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
}
EXPORT_SYMBOL(ccwgroup_driver_unregister);
static int __ccwgroupdev_check_busid(struct device *dev, void *id)
{
char *bus_id = id;
return (strcmp(bus_id, dev_name(dev)) == 0);
}
/**
* get_ccwgroupdev_by_busid() - obtain device from a bus id
* @gdrv: driver the device is owned by
* @bus_id: bus id of the device to be searched
*
* This function searches all devices owned by @gdrv for a device with a bus
* id matching @bus_id.
* Returns:
* If a match is found, its reference count of the found device is increased
* and it is returned; else %NULL is returned.
*/
struct ccwgroup_device *get_ccwgroupdev_by_busid(struct ccwgroup_driver *gdrv,
char *bus_id)
{
struct device *dev;
dev = driver_find_device(&gdrv->driver, NULL, bus_id,
__ccwgroupdev_check_busid);
return dev ? to_ccwgroupdev(dev) : NULL;
}
EXPORT_SYMBOL_GPL(get_ccwgroupdev_by_busid);
/**
* ccwgroup_probe_ccwdev() - probe function for slave devices
* @cdev: ccw device to be probed

View file

@ -595,19 +595,11 @@ static inline int qdio_inbound_q_done(struct qdio_q *q)
return 0;
}
static inline int contains_aobs(struct qdio_q *q)
{
return !q->is_input_q && q->u.out.use_cq;
}
static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count)
{
unsigned char state = 0;
int j, b = start;
if (!contains_aobs(q))
return;
for (j = 0; j < count; ++j) {
get_buf_state(q, b, &state, 0);
if (state == SLSB_P_OUTPUT_PENDING) {
@ -618,8 +610,6 @@ static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count)
q->u.out.sbal_state[b].flags |=
QDIO_OUTBUF_STATE_FLAG_PENDING;
q->u.out.aobs[b] = NULL;
} else if (state == SLSB_P_OUTPUT_EMPTY) {
q->u.out.sbal_state[b].aob = NULL;
}
b = next_buf(b);
}
@ -638,7 +628,6 @@ static inline unsigned long qdio_aob_for_buffer(struct qdio_output_q *q,
q->aobs[bufnr] = aob;
}
if (q->aobs[bufnr]) {
q->sbal_state[bufnr].aob = q->aobs[bufnr];
q->aobs[bufnr]->user1 = (u64) q->sbal_state[bufnr].user;
phys_aob = virt_to_phys(q->aobs[bufnr]);
WARN_ON_ONCE(phys_aob & 0xFF);
@ -666,10 +655,10 @@ static void qdio_kick_handler(struct qdio_q *q)
qperf_inc(q, outbound_handler);
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x",
start, count);
if (q->u.out.use_cq)
qdio_handle_aobs(q, start, count);
}
qdio_handle_aobs(q, start, count);
q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count,
q->irq_ptr->int_parm);

View file

@ -27,7 +27,6 @@ struct qaob *qdio_allocate_aob(void)
{
return kmem_cache_zalloc(qdio_aob_cache, GFP_ATOMIC);
}
EXPORT_SYMBOL_GPL(qdio_allocate_aob);
void qdio_release_aob(struct qaob *aob)
{

View file

@ -10,7 +10,7 @@ zcrypt-objs := zcrypt_api.o zcrypt_card.o zcrypt_queue.o
zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o
obj-$(CONFIG_ZCRYPT) += zcrypt.o
# adapter drivers depend on ap.o and zcrypt.o
obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o
obj-$(CONFIG_ZCRYPT) += zcrypt_cex2c.o zcrypt_cex2a.o zcrypt_cex4.o
# pkey kernel module
pkey-objs := pkey_api.o

View file

@ -65,12 +65,11 @@ static struct device *ap_root_device;
DEFINE_SPINLOCK(ap_list_lock);
LIST_HEAD(ap_card_list);
/* Default permissions (card and domain masking) */
static struct ap_perms {
DECLARE_BITMAP(apm, AP_DEVICES);
DECLARE_BITMAP(aqm, AP_DOMAINS);
} ap_perms;
static DEFINE_MUTEX(ap_perms_mutex);
/* Default permissions (ioctl, card and domain masking) */
struct ap_perms ap_perms;
EXPORT_SYMBOL(ap_perms);
DEFINE_MUTEX(ap_perms_mutex);
EXPORT_SYMBOL(ap_perms_mutex);
static struct ap_config_info *ap_configuration;
static bool initialised;
@ -944,21 +943,9 @@ static int modify_bitmap(const char *str, unsigned long *bitmap, int bits)
return 0;
}
/*
* process_mask_arg() - parse a bitmap string and clear/set the
* bits in the bitmap accordingly. The string may be given as
* absolute value, a hex string like 0x1F2E3D4C5B6A" simple over-
* writing the current content of the bitmap. Or as relative string
* like "+1-16,-32,-0x40,+128" where only single bits or ranges of
* bits are cleared or set. Distinction is done based on the very
* first character which may be '+' or '-' for the relative string
* and othewise assume to be an absolute value string. If parsing fails
* a negative errno value is returned. All arguments and bitmaps are
* big endian order.
*/
static int process_mask_arg(const char *str,
unsigned long *bitmap, int bits,
struct mutex *lock)
int ap_parse_mask_str(const char *str,
unsigned long *bitmap, int bits,
struct mutex *lock)
{
unsigned long *newmap, size;
int rc;
@ -989,6 +976,7 @@ static int process_mask_arg(const char *str,
kfree(newmap);
return rc;
}
EXPORT_SYMBOL(ap_parse_mask_str);
/*
* AP bus attributes.
@ -1049,6 +1037,21 @@ static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf)
static BUS_ATTR_RO(ap_usage_domain_mask);
static ssize_t ap_adapter_mask_show(struct bus_type *bus, char *buf)
{
if (!ap_configuration) /* QCI not supported */
return snprintf(buf, PAGE_SIZE, "not supported\n");
return snprintf(buf, PAGE_SIZE,
"0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
ap_configuration->apm[0], ap_configuration->apm[1],
ap_configuration->apm[2], ap_configuration->apm[3],
ap_configuration->apm[4], ap_configuration->apm[5],
ap_configuration->apm[6], ap_configuration->apm[7]);
}
static BUS_ATTR_RO(ap_adapter_mask);
static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n",
@ -1161,7 +1164,7 @@ static ssize_t apmask_store(struct bus_type *bus, const char *buf,
{
int rc;
rc = process_mask_arg(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex);
rc = ap_parse_mask_str(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex);
if (rc)
return rc;
@ -1192,7 +1195,7 @@ static ssize_t aqmask_store(struct bus_type *bus, const char *buf,
{
int rc;
rc = process_mask_arg(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex);
rc = ap_parse_mask_str(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex);
if (rc)
return rc;
@ -1207,6 +1210,7 @@ static struct bus_attribute *const ap_bus_attrs[] = {
&bus_attr_ap_domain,
&bus_attr_ap_control_domain_mask,
&bus_attr_ap_usage_domain_mask,
&bus_attr_ap_adapter_mask,
&bus_attr_config_time,
&bus_attr_poll_thread,
&bus_attr_ap_interrupts,
@ -1218,11 +1222,10 @@ static struct bus_attribute *const ap_bus_attrs[] = {
};
/**
* ap_select_domain(): Select an AP domain.
*
* Pick one of the 16 AP domains.
* ap_select_domain(): Select an AP domain if possible and we haven't
* already done so before.
*/
static int ap_select_domain(void)
static void ap_select_domain(void)
{
int count, max_count, best_domain;
struct ap_queue_status status;
@ -1237,7 +1240,7 @@ static int ap_select_domain(void)
if (ap_domain_index >= 0) {
/* Domain has already been selected. */
spin_unlock_bh(&ap_domain_lock);
return 0;
return;
}
best_domain = -1;
max_count = 0;
@ -1264,11 +1267,8 @@ static int ap_select_domain(void)
if (best_domain >= 0) {
ap_domain_index = best_domain;
AP_DBF(DBF_DEBUG, "new ap_domain_index=%d\n", ap_domain_index);
spin_unlock_bh(&ap_domain_lock);
return 0;
}
spin_unlock_bh(&ap_domain_lock);
return -ENODEV;
}
/*
@ -1346,8 +1346,7 @@ static void ap_scan_bus(struct work_struct *unused)
AP_DBF(DBF_DEBUG, "%s running\n", __func__);
ap_query_configuration(ap_configuration);
if (ap_select_domain() != 0)
goto out;
ap_select_domain();
for (id = 0; id < AP_DEVICES; id++) {
/* check if device is registered */
@ -1467,12 +1466,11 @@ static void ap_scan_bus(struct work_struct *unused)
}
} /* end device loop */
if (defdomdevs < 1)
if (ap_domain_index >= 0 && defdomdevs < 1)
AP_DBF(DBF_INFO,
"no queue device with default domain %d available\n",
ap_domain_index);
out:
mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ);
}
@ -1496,21 +1494,22 @@ static int __init ap_debug_init(void)
static void __init ap_perms_init(void)
{
/* all resources useable if no kernel parameter string given */
memset(&ap_perms.ioctlm, 0xFF, sizeof(ap_perms.ioctlm));
memset(&ap_perms.apm, 0xFF, sizeof(ap_perms.apm));
memset(&ap_perms.aqm, 0xFF, sizeof(ap_perms.aqm));
/* apm kernel parameter string */
if (apm_str) {
memset(&ap_perms.apm, 0, sizeof(ap_perms.apm));
process_mask_arg(apm_str, ap_perms.apm, AP_DEVICES,
&ap_perms_mutex);
ap_parse_mask_str(apm_str, ap_perms.apm, AP_DEVICES,
&ap_perms_mutex);
}
/* aqm kernel parameter string */
if (aqm_str) {
memset(&ap_perms.aqm, 0, sizeof(ap_perms.aqm));
process_mask_arg(aqm_str, ap_perms.aqm, AP_DOMAINS,
&ap_perms_mutex);
ap_parse_mask_str(aqm_str, ap_perms.aqm, AP_DOMAINS,
&ap_perms_mutex);
}
}
@ -1533,7 +1532,7 @@ static int __init ap_module_init(void)
return -ENODEV;
}
/* set up the AP permissions (ap and aq masks) */
/* set up the AP permissions (ioctls, ap and aq masks) */
ap_perms_init();
/* Get AP configuration data if available */

View file

@ -20,6 +20,7 @@
#define AP_DEVICES 256 /* Number of AP devices. */
#define AP_DOMAINS 256 /* Number of AP domains. */
#define AP_IOCTLS 256 /* Number of ioctls. */
#define AP_RESET_TIMEOUT (HZ*0.7) /* Time in ticks for reset timeouts. */
#define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */
#define AP_POLL_TIME 1 /* Time in ticks between receive polls. */
@ -257,6 +258,14 @@ void ap_queue_resume(struct ap_device *ap_dev);
struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type,
int comp_device_type, unsigned int functions);
struct ap_perms {
unsigned long ioctlm[BITS_TO_LONGS(AP_IOCTLS)];
unsigned long apm[BITS_TO_LONGS(AP_DEVICES)];
unsigned long aqm[BITS_TO_LONGS(AP_DOMAINS)];
};
extern struct ap_perms ap_perms;
extern struct mutex ap_perms_mutex;
/*
* check APQN for owned/reserved by ap bus and default driver(s).
* Checks if this APQN is or will be in use by the ap bus
@ -280,4 +289,20 @@ int ap_owned_by_def_drv(int card, int queue);
int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm,
unsigned long *aqm);
/*
* ap_parse_mask_str() - helper function to parse a bitmap string
* and clear/set the bits in the bitmap accordingly. The string may be
* given as absolute value, a hex string like 0x1F2E3D4C5B6A" simple
* overwriting the current content of the bitmap. Or as relative string
* like "+1-16,-32,-0x40,+128" where only single bits or ranges of
* bits are cleared or set. Distinction is done based on the very
* first character which may be '+' or '-' for the relative string
* and othewise assume to be an absolute value string. If parsing fails
* a negative errno value is returned. All arguments and bitmaps are
* big endian order.
*/
int ap_parse_mask_str(const char *str,
unsigned long *bitmap, int bits,
struct mutex *lock);
#endif /* _AP_BUS_H_ */

View file

@ -16,9 +16,12 @@
#include <linux/slab.h>
#include <linux/kallsyms.h>
#include <linux/debugfs.h>
#include <linux/random.h>
#include <linux/cpufeature.h>
#include <asm/zcrypt.h>
#include <asm/cpacf.h>
#include <asm/pkey.h>
#include <crypto/aes.h>
#include "zcrypt_api.h"
@ -32,6 +35,9 @@ MODULE_DESCRIPTION("s390 protected key interface");
/* Size of vardata block used for some of the cca requests/replies */
#define VARDATASIZE 4096
/* mask of available pckmo subfunctions, fetched once at module init */
static cpacf_mask_t pckmo_functions;
/*
* debug feature data and functions
*/
@ -55,6 +61,24 @@ static void __exit pkey_debug_exit(void)
debug_unregister(debug_info);
}
/* Key token types */
#define TOKTYPE_NON_CCA 0x00 /* Non-CCA key token */
#define TOKTYPE_CCA_INTERNAL 0x01 /* CCA internal key token */
/* For TOKTYPE_NON_CCA: */
#define TOKVER_PROTECTED_KEY 0x01 /* Protected key token */
/* For TOKTYPE_CCA_INTERNAL: */
#define TOKVER_CCA_AES 0x04 /* CCA AES key token */
/* header part of a key token */
struct keytoken_header {
u8 type; /* one of the TOKTYPE values */
u8 res0[3];
u8 version; /* one of the TOKVER values */
u8 res1[3];
} __packed;
/* inside view of a secure key token (only type 0x01 version 0x04) */
struct secaeskeytoken {
u8 type; /* 0x01 for internal key token */
@ -71,6 +95,17 @@ struct secaeskeytoken {
u8 tvv[4]; /* token validation value */
} __packed;
/* inside view of a protected key token (only type 0x00 version 0x01) */
struct protaeskeytoken {
u8 type; /* 0x00 for PAES specific key tokens */
u8 res0[3];
u8 version; /* should be 0x01 for protected AES key token */
u8 res1[3];
u32 keytype; /* key type, one of the PKEY_KEYTYPE values */
u32 len; /* bytes actually stored in protkey[] */
u8 protkey[MAXPROTKEYSIZE]; /* the protected key blob */
} __packed;
/*
* Simple check if the token is a valid CCA secure AES key
* token. If keybitsize is given, the bitsize of the key is
@ -80,16 +115,16 @@ static int check_secaeskeytoken(const u8 *token, int keybitsize)
{
struct secaeskeytoken *t = (struct secaeskeytoken *) token;
if (t->type != 0x01) {
if (t->type != TOKTYPE_CCA_INTERNAL) {
DEBUG_ERR(
"%s secure token check failed, type mismatch 0x%02x != 0x01\n",
__func__, (int) t->type);
"%s secure token check failed, type mismatch 0x%02x != 0x%02x\n",
__func__, (int) t->type, TOKTYPE_CCA_INTERNAL);
return -EINVAL;
}
if (t->version != 0x04) {
if (t->version != TOKVER_CCA_AES) {
DEBUG_ERR(
"%s secure token check failed, version mismatch 0x%02x != 0x04\n",
__func__, (int) t->version);
"%s secure token check failed, version mismatch 0x%02x != 0x%02x\n",
__func__, (int) t->version, TOKVER_CCA_AES);
return -EINVAL;
}
if (keybitsize > 0 && t->bitsize != keybitsize) {
@ -647,6 +682,16 @@ int pkey_clr2protkey(u32 keytype,
return -EINVAL;
}
/*
* Check if the needed pckmo subfunction is available.
* These subfunctions can be enabled/disabled by customers
* in the LPAR profile or may even change on the fly.
*/
if (!cpacf_test_func(&pckmo_functions, fc)) {
DEBUG_ERR("%s pckmo functions not available\n", __func__);
return -EOPNOTSUPP;
}
/* prepare param block */
memset(paramblock, 0, sizeof(paramblock));
memcpy(paramblock, clrkey->clrkey, keysize);
@ -1051,6 +1096,166 @@ out:
}
EXPORT_SYMBOL(pkey_verifykey);
/*
* Generate a random protected key
*/
int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey)
{
struct pkey_clrkey clrkey;
int keysize;
int rc;
switch (keytype) {
case PKEY_KEYTYPE_AES_128:
keysize = 16;
break;
case PKEY_KEYTYPE_AES_192:
keysize = 24;
break;
case PKEY_KEYTYPE_AES_256:
keysize = 32;
break;
default:
DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__,
keytype);
return -EINVAL;
}
/* generate a dummy random clear key */
get_random_bytes(clrkey.clrkey, keysize);
/* convert it to a dummy protected key */
rc = pkey_clr2protkey(keytype, &clrkey, protkey);
if (rc)
return rc;
/* replace the key part of the protected key with random bytes */
get_random_bytes(protkey->protkey, keysize);
return 0;
}
EXPORT_SYMBOL(pkey_genprotkey);
/*
* Verify if a protected key is still valid
*/
int pkey_verifyprotkey(const struct pkey_protkey *protkey)
{
unsigned long fc;
struct {
u8 iv[AES_BLOCK_SIZE];
u8 key[MAXPROTKEYSIZE];
} param;
u8 null_msg[AES_BLOCK_SIZE];
u8 dest_buf[AES_BLOCK_SIZE];
unsigned int k;
switch (protkey->type) {
case PKEY_KEYTYPE_AES_128:
fc = CPACF_KMC_PAES_128;
break;
case PKEY_KEYTYPE_AES_192:
fc = CPACF_KMC_PAES_192;
break;
case PKEY_KEYTYPE_AES_256:
fc = CPACF_KMC_PAES_256;
break;
default:
DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__,
protkey->type);
return -EINVAL;
}
memset(null_msg, 0, sizeof(null_msg));
memset(param.iv, 0, sizeof(param.iv));
memcpy(param.key, protkey->protkey, sizeof(param.key));
k = cpacf_kmc(fc | CPACF_ENCRYPT, &param, null_msg, dest_buf,
sizeof(null_msg));
if (k != sizeof(null_msg)) {
DEBUG_ERR("%s protected key is not valid\n", __func__);
return -EKEYREJECTED;
}
return 0;
}
EXPORT_SYMBOL(pkey_verifyprotkey);
/*
* Transform a non-CCA key token into a protected key
*/
static int pkey_nonccatok2pkey(const __u8 *key, __u32 keylen,
struct pkey_protkey *protkey)
{
struct keytoken_header *hdr = (struct keytoken_header *)key;
struct protaeskeytoken *t;
switch (hdr->version) {
case TOKVER_PROTECTED_KEY:
if (keylen != sizeof(struct protaeskeytoken))
return -EINVAL;
t = (struct protaeskeytoken *)key;
protkey->len = t->len;
protkey->type = t->keytype;
memcpy(protkey->protkey, t->protkey,
sizeof(protkey->protkey));
return pkey_verifyprotkey(protkey);
default:
DEBUG_ERR("%s unknown/unsupported non-CCA token version %d\n",
__func__, hdr->version);
return -EINVAL;
}
}
/*
* Transform a CCA internal key token into a protected key
*/
static int pkey_ccainttok2pkey(const __u8 *key, __u32 keylen,
struct pkey_protkey *protkey)
{
struct keytoken_header *hdr = (struct keytoken_header *)key;
switch (hdr->version) {
case TOKVER_CCA_AES:
if (keylen != sizeof(struct secaeskeytoken))
return -EINVAL;
return pkey_skey2pkey((struct pkey_seckey *)key,
protkey);
default:
DEBUG_ERR("%s unknown/unsupported CCA internal token version %d\n",
__func__, hdr->version);
return -EINVAL;
}
}
/*
* Transform a key blob (of any type) into a protected key
*/
int pkey_keyblob2pkey(const __u8 *key, __u32 keylen,
struct pkey_protkey *protkey)
{
struct keytoken_header *hdr = (struct keytoken_header *)key;
if (keylen < sizeof(struct keytoken_header))
return -EINVAL;
switch (hdr->type) {
case TOKTYPE_NON_CCA:
return pkey_nonccatok2pkey(key, keylen, protkey);
case TOKTYPE_CCA_INTERNAL:
return pkey_ccainttok2pkey(key, keylen, protkey);
default:
DEBUG_ERR("%s unknown/unsupported blob type %d\n", __func__,
hdr->type);
return -EINVAL;
}
}
EXPORT_SYMBOL(pkey_keyblob2pkey);
/*
* File io functions
*/
@ -1167,6 +1372,58 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
return -EFAULT;
break;
}
case PKEY_GENPROTK: {
struct pkey_genprotk __user *ugp = (void __user *) arg;
struct pkey_genprotk kgp;
if (copy_from_user(&kgp, ugp, sizeof(kgp)))
return -EFAULT;
rc = pkey_genprotkey(kgp.keytype, &kgp.protkey);
DEBUG_DBG("%s pkey_genprotkey()=%d\n", __func__, rc);
if (rc)
break;
if (copy_to_user(ugp, &kgp, sizeof(kgp)))
return -EFAULT;
break;
}
case PKEY_VERIFYPROTK: {
struct pkey_verifyprotk __user *uvp = (void __user *) arg;
struct pkey_verifyprotk kvp;
if (copy_from_user(&kvp, uvp, sizeof(kvp)))
return -EFAULT;
rc = pkey_verifyprotkey(&kvp.protkey);
DEBUG_DBG("%s pkey_verifyprotkey()=%d\n", __func__, rc);
break;
}
case PKEY_KBLOB2PROTK: {
struct pkey_kblob2pkey __user *utp = (void __user *) arg;
struct pkey_kblob2pkey ktp;
__u8 __user *ukey;
__u8 *kkey;
if (copy_from_user(&ktp, utp, sizeof(ktp)))
return -EFAULT;
if (ktp.keylen < MINKEYBLOBSIZE ||
ktp.keylen > MAXKEYBLOBSIZE)
return -EINVAL;
ukey = ktp.key;
kkey = kmalloc(ktp.keylen, GFP_KERNEL);
if (kkey == NULL)
return -ENOMEM;
if (copy_from_user(kkey, ukey, ktp.keylen)) {
kfree(kkey);
return -EFAULT;
}
rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey);
DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc);
kfree(kkey);
if (rc)
break;
if (copy_to_user(utp, &ktp, sizeof(ktp)))
return -EFAULT;
break;
}
default:
/* unknown/unsupported ioctl cmd */
return -ENOTTY;
@ -1178,6 +1435,236 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
/*
* Sysfs and file io operations
*/
/*
* Sysfs attribute read function for all protected key binary attributes.
* The implementation can not deal with partial reads, because a new random
* protected key blob is generated with each read. In case of partial reads
* (i.e. off != 0 or count < key blob size) -EINVAL is returned.
*/
static ssize_t pkey_protkey_aes_attr_read(u32 keytype, bool is_xts, char *buf,
loff_t off, size_t count)
{
struct protaeskeytoken protkeytoken;
struct pkey_protkey protkey;
int rc;
if (off != 0 || count < sizeof(protkeytoken))
return -EINVAL;
if (is_xts)
if (count < 2 * sizeof(protkeytoken))
return -EINVAL;
memset(&protkeytoken, 0, sizeof(protkeytoken));
protkeytoken.type = TOKTYPE_NON_CCA;
protkeytoken.version = TOKVER_PROTECTED_KEY;
protkeytoken.keytype = keytype;
rc = pkey_genprotkey(protkeytoken.keytype, &protkey);
if (rc)
return rc;
protkeytoken.len = protkey.len;
memcpy(&protkeytoken.protkey, &protkey.protkey, protkey.len);
memcpy(buf, &protkeytoken, sizeof(protkeytoken));
if (is_xts) {
rc = pkey_genprotkey(protkeytoken.keytype, &protkey);
if (rc)
return rc;
protkeytoken.len = protkey.len;
memcpy(&protkeytoken.protkey, &protkey.protkey, protkey.len);
memcpy(buf + sizeof(protkeytoken), &protkeytoken,
sizeof(protkeytoken));
return 2 * sizeof(protkeytoken);
}
return sizeof(protkeytoken);
}
static ssize_t protkey_aes_128_read(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
{
return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_128, false, buf,
off, count);
}
static ssize_t protkey_aes_192_read(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
{
return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_192, false, buf,
off, count);
}
static ssize_t protkey_aes_256_read(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
{
return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_256, false, buf,
off, count);
}
static ssize_t protkey_aes_128_xts_read(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
{
return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_128, true, buf,
off, count);
}
static ssize_t protkey_aes_256_xts_read(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
{
return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_256, true, buf,
off, count);
}
static BIN_ATTR_RO(protkey_aes_128, sizeof(struct protaeskeytoken));
static BIN_ATTR_RO(protkey_aes_192, sizeof(struct protaeskeytoken));
static BIN_ATTR_RO(protkey_aes_256, sizeof(struct protaeskeytoken));
static BIN_ATTR_RO(protkey_aes_128_xts, 2 * sizeof(struct protaeskeytoken));
static BIN_ATTR_RO(protkey_aes_256_xts, 2 * sizeof(struct protaeskeytoken));
static struct bin_attribute *protkey_attrs[] = {
&bin_attr_protkey_aes_128,
&bin_attr_protkey_aes_192,
&bin_attr_protkey_aes_256,
&bin_attr_protkey_aes_128_xts,
&bin_attr_protkey_aes_256_xts,
NULL
};
static struct attribute_group protkey_attr_group = {
.name = "protkey",
.bin_attrs = protkey_attrs,
};
/*
* Sysfs attribute read function for all secure key ccadata binary attributes.
* The implementation can not deal with partial reads, because a new random
* protected key blob is generated with each read. In case of partial reads
* (i.e. off != 0 or count < key blob size) -EINVAL is returned.
*/
static ssize_t pkey_ccadata_aes_attr_read(u32 keytype, bool is_xts, char *buf,
loff_t off, size_t count)
{
int rc;
if (off != 0 || count < sizeof(struct secaeskeytoken))
return -EINVAL;
if (is_xts)
if (count < 2 * sizeof(struct secaeskeytoken))
return -EINVAL;
rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf);
if (rc)
return rc;
if (is_xts) {
buf += sizeof(struct pkey_seckey);
rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf);
if (rc)
return rc;
return 2 * sizeof(struct secaeskeytoken);
}
return sizeof(struct secaeskeytoken);
}
static ssize_t ccadata_aes_128_read(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
{
return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_128, false, buf,
off, count);
}
static ssize_t ccadata_aes_192_read(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
{
return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_192, false, buf,
off, count);
}
static ssize_t ccadata_aes_256_read(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
{
return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_256, false, buf,
off, count);
}
static ssize_t ccadata_aes_128_xts_read(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
{
return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_128, true, buf,
off, count);
}
static ssize_t ccadata_aes_256_xts_read(struct file *filp,
struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off,
size_t count)
{
return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_256, true, buf,
off, count);
}
static BIN_ATTR_RO(ccadata_aes_128, sizeof(struct secaeskeytoken));
static BIN_ATTR_RO(ccadata_aes_192, sizeof(struct secaeskeytoken));
static BIN_ATTR_RO(ccadata_aes_256, sizeof(struct secaeskeytoken));
static BIN_ATTR_RO(ccadata_aes_128_xts, 2 * sizeof(struct secaeskeytoken));
static BIN_ATTR_RO(ccadata_aes_256_xts, 2 * sizeof(struct secaeskeytoken));
static struct bin_attribute *ccadata_attrs[] = {
&bin_attr_ccadata_aes_128,
&bin_attr_ccadata_aes_192,
&bin_attr_ccadata_aes_256,
&bin_attr_ccadata_aes_128_xts,
&bin_attr_ccadata_aes_256_xts,
NULL
};
static struct attribute_group ccadata_attr_group = {
.name = "ccadata",
.bin_attrs = ccadata_attrs,
};
static const struct attribute_group *pkey_attr_groups[] = {
&protkey_attr_group,
&ccadata_attr_group,
NULL,
};
static const struct file_operations pkey_fops = {
.owner = THIS_MODULE,
.open = nonseekable_open,
@ -1190,6 +1677,7 @@ static struct miscdevice pkey_dev = {
.minor = MISC_DYNAMIC_MINOR,
.mode = 0666,
.fops = &pkey_fops,
.groups = pkey_attr_groups,
};
/*
@ -1197,14 +1685,23 @@ static struct miscdevice pkey_dev = {
*/
static int __init pkey_init(void)
{
cpacf_mask_t pckmo_functions;
cpacf_mask_t kmc_functions;
/* check for pckmo instructions available */
/*
* The pckmo instruction should be available - even if we don't
* actually invoke it. This instruction comes with MSA 3 which
* is also the minimum level for the kmc instructions which
* are able to work with protected keys.
*/
if (!cpacf_query(CPACF_PCKMO, &pckmo_functions))
return -EOPNOTSUPP;
if (!cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_128_KEY) ||
!cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_192_KEY) ||
!cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_256_KEY))
/* check for kmc instructions available */
if (!cpacf_query(CPACF_KMC, &kmc_functions))
return -EOPNOTSUPP;
if (!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) ||
!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) ||
!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256))
return -EOPNOTSUPP;
pkey_debug_init();
@ -1222,5 +1719,5 @@ static void __exit pkey_exit(void)
pkey_debug_exit();
}
module_init(pkey_init);
module_cpu_feature_match(MSA, pkey_init);
module_exit(pkey_exit);

View file

@ -1,8 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Copyright IBM Corp. 2001, 2018
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
* Cornelia Huck <cornelia.huck@de.ibm.com>
@ -11,6 +9,7 @@
* Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
* Ralph Wuerthner <rwuerthn@de.ibm.com>
* MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
* Multiple device nodes: Harald Freudenberger <freude@linux.ibm.com>
*/
#include <linux/module.h>
@ -24,6 +23,8 @@
#include <linux/uaccess.h>
#include <linux/hw_random.h>
#include <linux/debugfs.h>
#include <linux/cdev.h>
#include <linux/ctype.h>
#include <asm/debug.h>
#define CREATE_TRACE_POINTS
@ -108,6 +109,375 @@ struct zcrypt_ops *zcrypt_msgtype(unsigned char *name, int variant)
}
EXPORT_SYMBOL(zcrypt_msgtype);
/*
* Multi device nodes extension functions.
*/
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
struct zcdn_device;
static struct class *zcrypt_class;
static dev_t zcrypt_devt;
static struct cdev zcrypt_cdev;
struct zcdn_device {
struct device device;
struct ap_perms perms;
};
#define to_zcdn_dev(x) container_of((x), struct zcdn_device, device)
#define ZCDN_MAX_NAME 32
static int zcdn_create(const char *name);
static int zcdn_destroy(const char *name);
/* helper function, matches the name for find_zcdndev_by_name() */
static int __match_zcdn_name(struct device *dev, const void *data)
{
return strcmp(dev_name(dev), (const char *)data) == 0;
}
/* helper function, matches the devt value for find_zcdndev_by_devt() */
static int __match_zcdn_devt(struct device *dev, const void *data)
{
return dev->devt == *((dev_t *) data);
}
/*
* Find zcdn device by name.
* Returns reference to the zcdn device which needs to be released
* with put_device() after use.
*/
static inline struct zcdn_device *find_zcdndev_by_name(const char *name)
{
struct device *dev =
class_find_device(zcrypt_class, NULL,
(void *) name,
__match_zcdn_name);
return dev ? to_zcdn_dev(dev) : NULL;
}
/*
* Find zcdn device by devt value.
* Returns reference to the zcdn device which needs to be released
* with put_device() after use.
*/
static inline struct zcdn_device *find_zcdndev_by_devt(dev_t devt)
{
struct device *dev =
class_find_device(zcrypt_class, NULL,
(void *) &devt,
__match_zcdn_devt);
return dev ? to_zcdn_dev(dev) : NULL;
}
static ssize_t ioctlmask_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int i, rc;
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
if (mutex_lock_interruptible(&ap_perms_mutex))
return -ERESTARTSYS;
buf[0] = '0';
buf[1] = 'x';
for (i = 0; i < sizeof(zcdndev->perms.ioctlm) / sizeof(long); i++)
snprintf(buf + 2 + 2 * i * sizeof(long),
PAGE_SIZE - 2 - 2 * i * sizeof(long),
"%016lx", zcdndev->perms.ioctlm[i]);
buf[2 + 2 * i * sizeof(long)] = '\n';
buf[2 + 2 * i * sizeof(long) + 1] = '\0';
rc = 2 + 2 * i * sizeof(long) + 1;
mutex_unlock(&ap_perms_mutex);
return rc;
}
static ssize_t ioctlmask_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int rc;
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
rc = ap_parse_mask_str(buf, zcdndev->perms.ioctlm,
AP_IOCTLS, &ap_perms_mutex);
if (rc)
return rc;
return count;
}
static DEVICE_ATTR_RW(ioctlmask);
static ssize_t apmask_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int i, rc;
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
if (mutex_lock_interruptible(&ap_perms_mutex))
return -ERESTARTSYS;
buf[0] = '0';
buf[1] = 'x';
for (i = 0; i < sizeof(zcdndev->perms.apm) / sizeof(long); i++)
snprintf(buf + 2 + 2 * i * sizeof(long),
PAGE_SIZE - 2 - 2 * i * sizeof(long),
"%016lx", zcdndev->perms.apm[i]);
buf[2 + 2 * i * sizeof(long)] = '\n';
buf[2 + 2 * i * sizeof(long) + 1] = '\0';
rc = 2 + 2 * i * sizeof(long) + 1;
mutex_unlock(&ap_perms_mutex);
return rc;
}
static ssize_t apmask_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int rc;
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
rc = ap_parse_mask_str(buf, zcdndev->perms.apm,
AP_DEVICES, &ap_perms_mutex);
if (rc)
return rc;
return count;
}
static DEVICE_ATTR_RW(apmask);
static ssize_t aqmask_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int i, rc;
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
if (mutex_lock_interruptible(&ap_perms_mutex))
return -ERESTARTSYS;
buf[0] = '0';
buf[1] = 'x';
for (i = 0; i < sizeof(zcdndev->perms.aqm) / sizeof(long); i++)
snprintf(buf + 2 + 2 * i * sizeof(long),
PAGE_SIZE - 2 - 2 * i * sizeof(long),
"%016lx", zcdndev->perms.aqm[i]);
buf[2 + 2 * i * sizeof(long)] = '\n';
buf[2 + 2 * i * sizeof(long) + 1] = '\0';
rc = 2 + 2 * i * sizeof(long) + 1;
mutex_unlock(&ap_perms_mutex);
return rc;
}
static ssize_t aqmask_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int rc;
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
rc = ap_parse_mask_str(buf, zcdndev->perms.aqm,
AP_DOMAINS, &ap_perms_mutex);
if (rc)
return rc;
return count;
}
static DEVICE_ATTR_RW(aqmask);
static struct attribute *zcdn_dev_attrs[] = {
&dev_attr_ioctlmask.attr,
&dev_attr_apmask.attr,
&dev_attr_aqmask.attr,
NULL
};
static struct attribute_group zcdn_dev_attr_group = {
.attrs = zcdn_dev_attrs
};
static const struct attribute_group *zcdn_dev_attr_groups[] = {
&zcdn_dev_attr_group,
NULL
};
static ssize_t zcdn_create_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int rc;
char name[ZCDN_MAX_NAME];
strncpy(name, skip_spaces(buf), sizeof(name));
name[sizeof(name) - 1] = '\0';
rc = zcdn_create(strim(name));
return rc ? rc : count;
}
static const struct class_attribute class_attr_zcdn_create =
__ATTR(create, 0600, NULL, zcdn_create_store);
static ssize_t zcdn_destroy_store(struct class *class,
struct class_attribute *attr,
const char *buf, size_t count)
{
int rc;
char name[ZCDN_MAX_NAME];
strncpy(name, skip_spaces(buf), sizeof(name));
name[sizeof(name) - 1] = '\0';
rc = zcdn_destroy(strim(name));
return rc ? rc : count;
}
static const struct class_attribute class_attr_zcdn_destroy =
__ATTR(destroy, 0600, NULL, zcdn_destroy_store);
static void zcdn_device_release(struct device *dev)
{
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
ZCRYPT_DBF(DBF_INFO, "releasing zcdn device %d:%d\n",
MAJOR(dev->devt), MINOR(dev->devt));
kfree(zcdndev);
}
static int zcdn_create(const char *name)
{
dev_t devt;
int i, rc = 0;
char nodename[ZCDN_MAX_NAME];
struct zcdn_device *zcdndev;
if (mutex_lock_interruptible(&ap_perms_mutex))
return -ERESTARTSYS;
/* check if device node with this name already exists */
if (name[0]) {
zcdndev = find_zcdndev_by_name(name);
if (zcdndev) {
put_device(&zcdndev->device);
rc = -EEXIST;
goto unlockout;
}
}
/* find an unused minor number */
for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) {
devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i);
zcdndev = find_zcdndev_by_devt(devt);
if (zcdndev)
put_device(&zcdndev->device);
else
break;
}
if (i == ZCRYPT_MAX_MINOR_NODES) {
rc = -ENOSPC;
goto unlockout;
}
/* alloc and prepare a new zcdn device */
zcdndev = kzalloc(sizeof(*zcdndev), GFP_KERNEL);
if (!zcdndev) {
rc = -ENOMEM;
goto unlockout;
}
zcdndev->device.release = zcdn_device_release;
zcdndev->device.class = zcrypt_class;
zcdndev->device.devt = devt;
zcdndev->device.groups = zcdn_dev_attr_groups;
if (name[0])
strncpy(nodename, name, sizeof(nodename));
else
snprintf(nodename, sizeof(nodename),
ZCRYPT_NAME "_%d", (int) MINOR(devt));
nodename[sizeof(nodename)-1] = '\0';
if (dev_set_name(&zcdndev->device, nodename)) {
rc = -EINVAL;
goto unlockout;
}
rc = device_register(&zcdndev->device);
if (rc) {
put_device(&zcdndev->device);
goto unlockout;
}
ZCRYPT_DBF(DBF_INFO, "created zcdn device %d:%d\n",
MAJOR(devt), MINOR(devt));
unlockout:
mutex_unlock(&ap_perms_mutex);
return rc;
}
static int zcdn_destroy(const char *name)
{
int rc = 0;
struct zcdn_device *zcdndev;
if (mutex_lock_interruptible(&ap_perms_mutex))
return -ERESTARTSYS;
/* try to find this zcdn device */
zcdndev = find_zcdndev_by_name(name);
if (!zcdndev) {
rc = -ENOENT;
goto unlockout;
}
/*
* The zcdn device is not hard destroyed. It is subject to
* reference counting and thus just needs to be unregistered.
*/
put_device(&zcdndev->device);
device_unregister(&zcdndev->device);
unlockout:
mutex_unlock(&ap_perms_mutex);
return rc;
}
static void zcdn_destroy_all(void)
{
int i;
dev_t devt;
struct zcdn_device *zcdndev;
mutex_lock(&ap_perms_mutex);
for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) {
devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i);
zcdndev = find_zcdndev_by_devt(devt);
if (zcdndev) {
put_device(&zcdndev->device);
device_unregister(&zcdndev->device);
}
}
mutex_unlock(&ap_perms_mutex);
}
#endif
/**
* zcrypt_read (): Not supported beyond zcrypt 1.3.1.
*
@ -137,6 +507,23 @@ static ssize_t zcrypt_write(struct file *filp, const char __user *buf,
*/
static int zcrypt_open(struct inode *inode, struct file *filp)
{
struct ap_perms *perms = &ap_perms;
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
if (filp->f_inode->i_cdev == &zcrypt_cdev) {
struct zcdn_device *zcdndev;
if (mutex_lock_interruptible(&ap_perms_mutex))
return -ERESTARTSYS;
zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev);
/* find returns a reference, no get_device() needed */
mutex_unlock(&ap_perms_mutex);
if (zcdndev)
perms = &zcdndev->perms;
}
#endif
filp->private_data = (void *) perms;
atomic_inc(&zcrypt_open_count);
return nonseekable_open(inode, filp);
}
@ -148,10 +535,55 @@ static int zcrypt_open(struct inode *inode, struct file *filp)
*/
static int zcrypt_release(struct inode *inode, struct file *filp)
{
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
if (filp->f_inode->i_cdev == &zcrypt_cdev) {
struct zcdn_device *zcdndev;
if (mutex_lock_interruptible(&ap_perms_mutex))
return -ERESTARTSYS;
zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev);
mutex_unlock(&ap_perms_mutex);
if (zcdndev) {
/* 2 puts here: one for find, one for open */
put_device(&zcdndev->device);
put_device(&zcdndev->device);
}
}
#endif
atomic_dec(&zcrypt_open_count);
return 0;
}
static inline int zcrypt_check_ioctl(struct ap_perms *perms,
unsigned int cmd)
{
int rc = -EPERM;
int ioctlnr = (cmd & _IOC_NRMASK) >> _IOC_NRSHIFT;
if (ioctlnr > 0 && ioctlnr < AP_IOCTLS) {
if (test_bit_inv(ioctlnr, perms->ioctlm))
rc = 0;
}
if (rc)
ZCRYPT_DBF(DBF_WARN,
"ioctl check failed: ioctlnr=0x%04x rc=%d\n",
ioctlnr, rc);
return rc;
}
static inline bool zcrypt_check_card(struct ap_perms *perms, int card)
{
return test_bit_inv(card, perms->apm) ? true : false;
}
static inline bool zcrypt_check_queue(struct ap_perms *perms, int queue)
{
return test_bit_inv(queue, perms->aqm) ? true : false;
}
static inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc,
struct zcrypt_queue *zq,
unsigned int weight)
@ -213,7 +645,8 @@ static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq,
/*
* zcrypt ioctls.
*/
static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
static long zcrypt_rsa_modexpo(struct ap_perms *perms,
struct ica_rsa_modexpo *mex)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
@ -250,6 +683,9 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
if (zc->min_mod_size > mex->inputdatalength ||
zc->max_mod_size < mex->inputdatalength)
continue;
/* check if device node has admission for this card */
if (!zcrypt_check_card(perms, zc->card->id))
continue;
/* get weight index of the card device */
weight = zc->speed_rating[func_code];
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
@ -258,6 +694,10 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
/* check if device is online and eligible */
if (!zq->online || !zq->ops->rsa_modexpo)
continue;
/* check if device node has admission for this queue */
if (!zcrypt_check_queue(perms,
AP_QID_QUEUE(zq->queue->qid)))
continue;
if (zcrypt_queue_compare(zq, pref_zq,
weight, pref_weight))
continue;
@ -287,7 +727,8 @@ out:
return rc;
}
static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
static long zcrypt_rsa_crt(struct ap_perms *perms,
struct ica_rsa_modexpo_crt *crt)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
@ -324,6 +765,9 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
if (zc->min_mod_size > crt->inputdatalength ||
zc->max_mod_size < crt->inputdatalength)
continue;
/* check if device node has admission for this card */
if (!zcrypt_check_card(perms, zc->card->id))
continue;
/* get weight index of the card device */
weight = zc->speed_rating[func_code];
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
@ -332,6 +776,10 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
/* check if device is online and eligible */
if (!zq->online || !zq->ops->rsa_modexpo_crt)
continue;
/* check if device node has admission for this queue */
if (!zcrypt_check_queue(perms,
AP_QID_QUEUE(zq->queue->qid)))
continue;
if (zcrypt_queue_compare(zq, pref_zq,
weight, pref_weight))
continue;
@ -361,7 +809,8 @@ out:
return rc;
}
long zcrypt_send_cprb(struct ica_xcRB *xcRB)
static long _zcrypt_send_cprb(struct ap_perms *perms,
struct ica_xcRB *xcRB)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
@ -373,6 +822,7 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB)
trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB);
xcRB->status = 0;
ap_init_message(&ap_msg);
rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain);
if (rc)
@ -389,6 +839,9 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB)
if (xcRB->user_defined != AUTOSELECT &&
xcRB->user_defined != zc->card->id)
continue;
/* check if device node has admission for this card */
if (!zcrypt_check_card(perms, zc->card->id))
continue;
/* get weight index of the card device */
weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY];
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
@ -400,6 +853,10 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB)
((*domain != (unsigned short) AUTOSELECT) &&
(*domain != AP_QID_QUEUE(zq->queue->qid))))
continue;
/* check if device node has admission for this queue */
if (!zcrypt_check_queue(perms,
AP_QID_QUEUE(zq->queue->qid)))
continue;
if (zcrypt_queue_compare(zq, pref_zq,
weight, pref_weight))
continue;
@ -433,6 +890,11 @@ out:
AP_QID_CARD(qid), AP_QID_QUEUE(qid));
return rc;
}
long zcrypt_send_cprb(struct ica_xcRB *xcRB)
{
return _zcrypt_send_cprb(&ap_perms, xcRB);
}
EXPORT_SYMBOL(zcrypt_send_cprb);
static bool is_desired_ep11_card(unsigned int dev_id,
@ -459,7 +921,8 @@ static bool is_desired_ep11_queue(unsigned int dev_qid,
return false;
}
static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
static long zcrypt_send_ep11_cprb(struct ap_perms *perms,
struct ep11_urb *xcrb)
{
struct zcrypt_card *zc, *pref_zc;
struct zcrypt_queue *zq, *pref_zq;
@ -510,6 +973,9 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
if (targets &&
!is_desired_ep11_card(zc->card->id, target_num, targets))
continue;
/* check if device node has admission for this card */
if (!zcrypt_check_card(perms, zc->card->id))
continue;
/* get weight index of the card device */
weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY];
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
@ -522,6 +988,10 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
!is_desired_ep11_queue(zq->queue->qid,
target_num, targets)))
continue;
/* check if device node has admission for this queue */
if (!zcrypt_check_queue(perms,
AP_QID_QUEUE(zq->queue->qid)))
continue;
if (zcrypt_queue_compare(zq, pref_zq,
weight, pref_weight))
continue;
@ -788,7 +1258,13 @@ static int zcrypt_requestq_count(void)
static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int rc = 0;
int rc;
struct ap_perms *perms =
(struct ap_perms *) filp->private_data;
rc = zcrypt_check_ioctl(perms, cmd);
if (rc)
return rc;
switch (cmd) {
case ICARSAMODEXPO: {
@ -798,12 +1274,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
if (copy_from_user(&mex, umex, sizeof(mex)))
return -EFAULT;
do {
rc = zcrypt_rsa_modexpo(&mex);
rc = zcrypt_rsa_modexpo(perms, &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);
rc = zcrypt_rsa_modexpo(perms, &mex);
} while (rc == -EAGAIN);
if (rc) {
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSAMODEXPO rc=%d\n", rc);
@ -818,12 +1294,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
if (copy_from_user(&crt, ucrt, sizeof(crt)))
return -EFAULT;
do {
rc = zcrypt_rsa_crt(&crt);
rc = zcrypt_rsa_crt(perms, &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);
rc = zcrypt_rsa_crt(perms, &crt);
} while (rc == -EAGAIN);
if (rc) {
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSACRT rc=%d\n", rc);
@ -838,15 +1314,16 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB)))
return -EFAULT;
do {
rc = zcrypt_send_cprb(&xcRB);
rc = _zcrypt_send_cprb(perms, &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);
rc = _zcrypt_send_cprb(perms, &xcRB);
} while (rc == -EAGAIN);
if (rc)
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d\n", rc);
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d status=0x%x\n",
rc, xcRB.status);
if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
return -EFAULT;
return rc;
@ -858,12 +1335,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb)))
return -EFAULT;
do {
rc = zcrypt_send_ep11_cprb(&xcrb);
rc = zcrypt_send_ep11_cprb(perms, &xcrb);
} while (rc == -EAGAIN);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
rc = zcrypt_send_ep11_cprb(&xcrb);
rc = zcrypt_send_ep11_cprb(perms, &xcrb);
} while (rc == -EAGAIN);
if (rc)
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d\n", rc);
@ -989,8 +1466,8 @@ struct compat_ica_rsa_modexpo {
compat_uptr_t n_modulus;
};
static long trans_modexpo32(struct file *filp, unsigned int cmd,
unsigned long arg)
static long trans_modexpo32(struct ap_perms *perms, struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg);
struct compat_ica_rsa_modexpo mex32;
@ -1006,12 +1483,12 @@ static long trans_modexpo32(struct file *filp, unsigned int cmd,
mex64.b_key = compat_ptr(mex32.b_key);
mex64.n_modulus = compat_ptr(mex32.n_modulus);
do {
rc = zcrypt_rsa_modexpo(&mex64);
rc = zcrypt_rsa_modexpo(perms, &mex64);
} while (rc == -EAGAIN);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
rc = zcrypt_rsa_modexpo(&mex64);
rc = zcrypt_rsa_modexpo(perms, &mex64);
} while (rc == -EAGAIN);
if (rc)
return rc;
@ -1031,8 +1508,8 @@ struct compat_ica_rsa_modexpo_crt {
compat_uptr_t u_mult_inv;
};
static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
unsigned long arg)
static long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg);
struct compat_ica_rsa_modexpo_crt crt32;
@ -1051,12 +1528,12 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
crt64.nq_prime = compat_ptr(crt32.nq_prime);
crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv);
do {
rc = zcrypt_rsa_crt(&crt64);
rc = zcrypt_rsa_crt(perms, &crt64);
} while (rc == -EAGAIN);
/* on failure: retry once again after a requested rescan */
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
do {
rc = zcrypt_rsa_crt(&crt64);
rc = zcrypt_rsa_crt(perms, &crt64);
} while (rc == -EAGAIN);
if (rc)
return rc;
@ -1084,8 +1561,8 @@ struct compat_ica_xcRB {
unsigned int status;
} __packed;
static long trans_xcRB32(struct file *filp, unsigned int cmd,
unsigned long arg)
static long trans_xcRB32(struct ap_perms *perms, struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg);
struct compat_ica_xcRB xcRB32;
@ -1115,12 +1592,12 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
xcRB64.priority_window = xcRB32.priority_window;
xcRB64.status = xcRB32.status;
do {
rc = zcrypt_send_cprb(&xcRB64);
rc = _zcrypt_send_cprb(perms, &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);
rc = _zcrypt_send_cprb(perms, &xcRB64);
} while (rc == -EAGAIN);
xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
xcRB32.reply_data_length = xcRB64.reply_data_length;
@ -1133,12 +1610,20 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int rc;
struct ap_perms *perms =
(struct ap_perms *) filp->private_data;
rc = zcrypt_check_ioctl(perms, cmd);
if (rc)
return rc;
if (cmd == ICARSAMODEXPO)
return trans_modexpo32(filp, cmd, arg);
return trans_modexpo32(perms, filp, cmd, arg);
if (cmd == ICARSACRT)
return trans_modexpo_crt32(filp, cmd, arg);
return trans_modexpo_crt32(perms, filp, cmd, arg);
if (cmd == ZSECSENDCPRB)
return trans_xcRB32(filp, cmd, arg);
return trans_xcRB32(perms, filp, cmd, arg);
return zcrypt_unlocked_ioctl(filp, cmd, arg);
}
#endif
@ -1256,6 +1741,67 @@ void zcrypt_debug_exit(void)
debug_unregister(zcrypt_dbf_info);
}
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
static int __init zcdn_init(void)
{
int rc;
/* create a new class 'zcrypt' */
zcrypt_class = class_create(THIS_MODULE, ZCRYPT_NAME);
if (IS_ERR(zcrypt_class)) {
rc = PTR_ERR(zcrypt_class);
goto out_class_create_failed;
}
zcrypt_class->dev_release = zcdn_device_release;
/* alloc device minor range */
rc = alloc_chrdev_region(&zcrypt_devt,
0, ZCRYPT_MAX_MINOR_NODES,
ZCRYPT_NAME);
if (rc)
goto out_alloc_chrdev_failed;
cdev_init(&zcrypt_cdev, &zcrypt_fops);
zcrypt_cdev.owner = THIS_MODULE;
rc = cdev_add(&zcrypt_cdev, zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
if (rc)
goto out_cdev_add_failed;
/* need some class specific sysfs attributes */
rc = class_create_file(zcrypt_class, &class_attr_zcdn_create);
if (rc)
goto out_class_create_file_1_failed;
rc = class_create_file(zcrypt_class, &class_attr_zcdn_destroy);
if (rc)
goto out_class_create_file_2_failed;
return 0;
out_class_create_file_2_failed:
class_remove_file(zcrypt_class, &class_attr_zcdn_create);
out_class_create_file_1_failed:
cdev_del(&zcrypt_cdev);
out_cdev_add_failed:
unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
out_alloc_chrdev_failed:
class_destroy(zcrypt_class);
out_class_create_failed:
return rc;
}
static void zcdn_exit(void)
{
class_remove_file(zcrypt_class, &class_attr_zcdn_create);
class_remove_file(zcrypt_class, &class_attr_zcdn_destroy);
zcdn_destroy_all();
cdev_del(&zcrypt_cdev);
unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
class_destroy(zcrypt_class);
}
#endif
/**
* zcrypt_api_init(): Module initialization.
*
@ -1269,15 +1815,27 @@ int __init zcrypt_api_init(void)
if (rc)
goto out;
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
rc = zcdn_init();
if (rc)
goto out;
#endif
/* Register the request sprayer. */
rc = misc_register(&zcrypt_misc_device);
if (rc < 0)
goto out;
goto out_misc_register_failed;
zcrypt_msgtype6_init();
zcrypt_msgtype50_init();
return 0;
out_misc_register_failed:
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
zcdn_exit();
#endif
zcrypt_debug_exit();
out:
return rc;
}
@ -1289,6 +1847,9 @@ out:
*/
void __exit zcrypt_api_exit(void)
{
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
zcdn_exit();
#endif
misc_deregister(&zcrypt_misc_device);
zcrypt_msgtype6_exit();
zcrypt_msgtype50_exit();

View file

@ -1,8 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Copyright IBM Corp. 2001, 2018
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
* Cornelia Huck <cornelia.huck@de.ibm.com>
@ -22,17 +20,8 @@
#include "ap_bus.h"
/**
* device type for an actual device is either PCICA, PCICC, PCIXCC_MCL2,
* PCIXCC_MCL3, CEX2C, or CEX2A
*
* NOTE: PCIXCC_MCL3 refers to a PCIXCC with May 2004 version of Licensed
* Internal Code (LIC) (EC J12220 level 29).
* PCIXCC_MCL2 refers to any LIC before this level.
* Supported device types
*/
#define ZCRYPT_PCICA 1
#define ZCRYPT_PCICC 2
#define ZCRYPT_PCIXCC_MCL2 3
#define ZCRYPT_PCIXCC_MCL3 4
#define ZCRYPT_CEX2C 5
#define ZCRYPT_CEX2A 6
#define ZCRYPT_CEX3C 7

View file

@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)

View file

@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2006
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)

View file

@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@ -43,8 +41,8 @@
#define CEX3A_CLEANUP_TIME CEX2A_CLEANUP_TIME
MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " \
"Copyright IBM Corp. 2001, 2012");
MODULE_DESCRIPTION("CEX2A/CEX3A Cryptographic Coprocessor device driver, " \
"Copyright IBM Corp. 2001, 2018");
MODULE_LICENSE("GPL");
static struct ap_device_id zcrypt_cex2a_card_ids[] = {

View file

@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2006
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@ -14,7 +12,7 @@
#define _ZCRYPT_CEX2A_H_
/**
* The type 50 message family is associated with a CEX2A card.
* The type 50 message family is associated with CEXxA cards.
*
* The four members of the family are described below.
*
@ -111,7 +109,7 @@ struct type50_crb3_msg {
} __packed;
/**
* The type 80 response family is associated with a CEX2A card.
* The type 80 response family is associated with a CEXxA cards.
*
* Note that all unsigned char arrays are right-justified and left-padded
* with zeroes.

View file

@ -1,8 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Copyright IBM Corp. 2001, 2018
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
*
@ -25,39 +23,22 @@
#include "zcrypt_api.h"
#include "zcrypt_error.h"
#include "zcrypt_msgtype6.h"
#include "zcrypt_pcixcc.h"
#include "zcrypt_cex2c.h"
#include "zcrypt_cca_key.h"
#define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */
#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
#define PCIXCC_MAX_MOD_SIZE 256 /* 2048 bits */
#define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE
#define CEX2C_MIN_MOD_SIZE 16 /* 128 bits */
#define CEX2C_MAX_MOD_SIZE 256 /* 2048 bits */
#define CEX3C_MIN_MOD_SIZE 16 /* 128 bits */
#define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */
#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024)
#define PCIXCC_CLEANUP_TIME (15*HZ)
#define CEIL4(x) ((((x)+3)/4)*4)
struct response_type {
struct completion work;
int type;
};
#define PCIXCC_RESPONSE_TYPE_ICA 0
#define PCIXCC_RESPONSE_TYPE_XCRB 1
#define CEX2C_MAX_XCRB_MESSAGE_SIZE (12*1024)
#define CEX2C_CLEANUP_TIME (15*HZ)
MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \
"Copyright IBM Corp. 2001, 2012");
MODULE_DESCRIPTION("CEX2C/CEX3C Cryptographic Coprocessor device driver, " \
"Copyright IBM Corp. 2001, 2018");
MODULE_LICENSE("GPL");
static struct ap_device_id zcrypt_pcixcc_card_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_PCIXCC,
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
static struct ap_device_id zcrypt_cex2c_card_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_CEX2C,
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX3C,
@ -65,11 +46,9 @@ static struct ap_device_id zcrypt_pcixcc_card_ids[] = {
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_card_ids);
MODULE_DEVICE_TABLE(ap, zcrypt_cex2c_card_ids);
static struct ap_device_id zcrypt_pcixcc_queue_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_PCIXCC,
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
static struct ap_device_id zcrypt_cex2c_queue_ids[] = {
{ .dev_type = AP_DEVICE_TYPE_CEX2C,
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
{ .dev_type = AP_DEVICE_TYPE_CEX3C,
@ -77,16 +56,16 @@ static struct ap_device_id zcrypt_pcixcc_queue_ids[] = {
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_queue_ids);
MODULE_DEVICE_TABLE(ap, zcrypt_cex2c_queue_ids);
/**
* Large random number detection function. Its sends a message to a pcixcc
* Large random number detection function. Its sends a message to a CEX2C/CEX3C
* card to find out if large random numbers are supported.
* @ap_dev: pointer to the AP device.
*
* Returns 1 if large random numbers are supported, 0 if not and < 0 on error.
*/
static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq)
static int zcrypt_cex2c_rng_supported(struct ap_queue *aq)
{
struct ap_message ap_msg;
unsigned long long psmid;
@ -147,13 +126,11 @@ out_free:
}
/**
* Probe function for PCIXCC/CEX2C card devices. It always accepts the
* AP device since the bus_match already checked the hardware type. The
* PCIXCC cards come in two flavours: micro code level 2 and micro code
* level 3. This is checked by sending a test message to the device.
* Probe function for CEX2C/CEX3C card devices. It always accepts the
* AP device since the bus_match already checked the hardware type.
* @ap_dev: pointer to the AP card device.
*/
static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev)
{
/*
* Normalized speed ratings per crypto adapter
@ -179,9 +156,9 @@ static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
zc->type_string = "CEX2C";
memcpy(zc->speed_rating, CEX2C_SPEED_IDX,
sizeof(CEX2C_SPEED_IDX));
zc->min_mod_size = PCIXCC_MIN_MOD_SIZE;
zc->max_mod_size = PCIXCC_MAX_MOD_SIZE;
zc->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
zc->min_mod_size = CEX2C_MIN_MOD_SIZE;
zc->max_mod_size = CEX2C_MAX_MOD_SIZE;
zc->max_exp_bit_length = CEX2C_MAX_MOD_SIZE;
break;
case AP_DEVICE_TYPE_CEX3C:
zc->user_space_type = ZCRYPT_CEX3C;
@ -208,10 +185,10 @@ static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
}
/**
* This is called to remove the PCIXCC/CEX2C card driver information
* This is called to remove the CEX2C/CEX3C card driver information
* if an AP card device is removed.
*/
static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev)
static void zcrypt_cex2c_card_remove(struct ap_device *ap_dev)
{
struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private;
@ -219,33 +196,31 @@ static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev)
zcrypt_card_unregister(zc);
}
static struct ap_driver zcrypt_pcixcc_card_driver = {
.probe = zcrypt_pcixcc_card_probe,
.remove = zcrypt_pcixcc_card_remove,
.ids = zcrypt_pcixcc_card_ids,
static struct ap_driver zcrypt_cex2c_card_driver = {
.probe = zcrypt_cex2c_card_probe,
.remove = zcrypt_cex2c_card_remove,
.ids = zcrypt_cex2c_card_ids,
.flags = AP_DRIVER_FLAG_DEFAULT,
};
/**
* Probe function for PCIXCC/CEX2C queue devices. It always accepts the
* AP device since the bus_match already checked the hardware type. The
* PCIXCC cards come in two flavours: micro code level 2 and micro code
* level 3. This is checked by sending a test message to the device.
* Probe function for CEX2C/CEX3C queue devices. It always accepts the
* AP device since the bus_match already checked the hardware type.
* @ap_dev: pointer to the AP card device.
*/
static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev)
static int zcrypt_cex2c_queue_probe(struct ap_device *ap_dev)
{
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
struct zcrypt_queue *zq;
int rc;
zq = zcrypt_queue_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE);
zq = zcrypt_queue_alloc(CEX2C_MAX_XCRB_MESSAGE_SIZE);
if (!zq)
return -ENOMEM;
zq->queue = aq;
zq->online = 1;
atomic_set(&zq->load, 0);
rc = zcrypt_pcixcc_rng_supported(aq);
rc = zcrypt_cex2c_rng_supported(aq);
if (rc < 0) {
zcrypt_queue_free(zq);
return rc;
@ -257,7 +232,7 @@ static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev)
zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_NORNG);
ap_queue_init_reply(aq, &zq->reply);
aq->request_timeout = PCIXCC_CLEANUP_TIME,
aq->request_timeout = CEX2C_CLEANUP_TIME;
aq->private = zq;
rc = zcrypt_queue_register(zq);
if (rc) {
@ -268,10 +243,10 @@ static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev)
}
/**
* This is called to remove the PCIXCC/CEX2C queue driver information
* This is called to remove the CEX2C/CEX3C queue driver information
* if an AP queue device is removed.
*/
static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev)
static void zcrypt_cex2c_queue_remove(struct ap_device *ap_dev)
{
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
struct zcrypt_queue *zq = aq->private;
@ -281,37 +256,37 @@ static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev)
zcrypt_queue_unregister(zq);
}
static struct ap_driver zcrypt_pcixcc_queue_driver = {
.probe = zcrypt_pcixcc_queue_probe,
.remove = zcrypt_pcixcc_queue_remove,
static struct ap_driver zcrypt_cex2c_queue_driver = {
.probe = zcrypt_cex2c_queue_probe,
.remove = zcrypt_cex2c_queue_remove,
.suspend = ap_queue_suspend,
.resume = ap_queue_resume,
.ids = zcrypt_pcixcc_queue_ids,
.ids = zcrypt_cex2c_queue_ids,
.flags = AP_DRIVER_FLAG_DEFAULT,
};
int __init zcrypt_pcixcc_init(void)
int __init zcrypt_cex2c_init(void)
{
int rc;
rc = ap_driver_register(&zcrypt_pcixcc_card_driver,
THIS_MODULE, "pcixcccard");
rc = ap_driver_register(&zcrypt_cex2c_card_driver,
THIS_MODULE, "cex2card");
if (rc)
return rc;
rc = ap_driver_register(&zcrypt_pcixcc_queue_driver,
THIS_MODULE, "pcixccqueue");
rc = ap_driver_register(&zcrypt_cex2c_queue_driver,
THIS_MODULE, "cex2cqueue");
if (rc)
ap_driver_unregister(&zcrypt_pcixcc_card_driver);
ap_driver_unregister(&zcrypt_cex2c_card_driver);
return rc;
}
void zcrypt_pcixcc_exit(void)
void zcrypt_cex2c_exit(void)
{
ap_driver_unregister(&zcrypt_pcixcc_queue_driver);
ap_driver_unregister(&zcrypt_pcixcc_card_driver);
ap_driver_unregister(&zcrypt_cex2c_queue_driver);
ap_driver_unregister(&zcrypt_cex2c_card_driver);
}
module_init(zcrypt_pcixcc_init);
module_exit(zcrypt_pcixcc_exit);
module_init(zcrypt_cex2c_init);
module_exit(zcrypt_cex2c_exit);

View file

@ -1,8 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Copyright IBM Corp. 2001, 2018
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
*
@ -11,10 +9,10 @@
* MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
*/
#ifndef _ZCRYPT_PCIXCC_H_
#define _ZCRYPT_PCIXCC_H_
#ifndef _ZCRYPT_CEX2C_H_
#define _ZCRYPT_CEX2C_H_
int zcrypt_pcixcc_init(void);
void zcrypt_pcixcc_exit(void);
int zcrypt_cex2c_init(void);
void zcrypt_cex2c_exit(void);
#endif /* _ZCRYPT_PCIXCC_H_ */
#endif /* _ZCRYPT_CEX2C_H_ */

View file

@ -37,8 +37,8 @@
#define CEX4_CLEANUP_TIME (900*HZ)
MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("CEX4 Cryptographic Card device driver, " \
"Copyright IBM Corp. 2012");
MODULE_DESCRIPTION("CEX4/CEX5/CEX6 Cryptographic Card device driver, " \
"Copyright IBM Corp. 2018");
MODULE_LICENSE("GPL");
static struct ap_device_id zcrypt_cex4_card_ids[] = {
@ -66,8 +66,9 @@ static struct ap_device_id zcrypt_cex4_queue_ids[] = {
MODULE_DEVICE_TABLE(ap, zcrypt_cex4_queue_ids);
/**
* Probe function for CEX4 card device. It always accepts the AP device
* since the bus_match already checked the hardware type.
* Probe function for CEX4/CEX5/CEX6 card device. It always
* accepts the AP device since the bus_match already checked
* the hardware type.
* @ap_dev: pointer to the AP device.
*/
static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
@ -199,7 +200,7 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
}
/**
* This is called to remove the CEX4 card driver information
* This is called to remove the CEX4/CEX5/CEX6 card driver information
* if an AP card device is removed.
*/
static void zcrypt_cex4_card_remove(struct ap_device *ap_dev)
@ -218,8 +219,9 @@ static struct ap_driver zcrypt_cex4_card_driver = {
};
/**
* Probe function for CEX4 queue device. It always accepts the AP device
* since the bus_match already checked the hardware type.
* Probe function for CEX4/CEX5/CEX6 queue device. It always
* accepts the AP device since the bus_match already checked
* the hardware type.
* @ap_dev: pointer to the AP device.
*/
static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev)
@ -265,8 +267,8 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev)
}
/**
* This is called to remove the CEX4 queue driver information
* if an AP queue device is removed.
* This is called to remove the CEX4/CEX5/CEX6 queue driver
* information if an AP queue device is removed.
*/
static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev)
{

View file

@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2006
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@ -16,6 +14,7 @@
#include <linux/atomic.h>
#include "zcrypt_debug.h"
#include "zcrypt_api.h"
#include "zcrypt_msgtype6.h"
/**
* Reply Messages
@ -114,6 +113,27 @@ static inline int convert_error(struct zcrypt_queue *zq,
card, queue, ehdr->reply_code);
return -EAGAIN;
case REP82_ERROR_TRANSPORT_FAIL:
/* Card or infrastructure failure, disable card */
atomic_set(&zcrypt_rescan_req, 1);
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
card, queue);
/* For type 86 response show the apfs value (failure reason) */
if (ehdr->type == TYPE86_RSP_CODE) {
struct {
struct type86_hdr hdr;
struct type86_fmt2_ext fmt2;
} __packed * head = reply->message;
unsigned int apfs = *((u32 *)head->fmt2.apfs);
ZCRYPT_DBF(DBF_ERR,
"device=%02x.%04x reply=0x%02x apfs=0x%x => online=0 rc=EAGAIN\n",
card, queue, apfs, ehdr->reply_code);
} else
ZCRYPT_DBF(DBF_ERR,
"device=%02x.%04x reply=0x%02x => online=0 rc=EAGAIN\n",
card, queue, ehdr->reply_code);
return -EAGAIN;
case REP82_ERROR_MACHINE_FAILURE:
// REP88_ERROR_MODULE_FAILURE // '10' CEX2A
/* If a card fails disable it and repeat the request. */

View file

@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@ -27,13 +25,13 @@
#include "zcrypt_error.h"
#include "zcrypt_msgtype50.h"
/* 4096 bits */
/* >= CEX3A: 4096 bits */
#define CEX3A_MAX_MOD_SIZE 512
/* max outputdatalength + type80_hdr */
/* CEX2A: max outputdatalength + type80_hdr */
#define CEX2A_MAX_RESPONSE_SIZE 0x110
/* 512 bit modulus, (max outputdatalength) + type80_hdr */
/* >= CEX3A: 512 bit modulus, (max outputdatalength) + type80_hdr */
#define CEX3A_MAX_RESPONSE_SIZE 0x210
MODULE_AUTHOR("IBM Corporation");
@ -42,7 +40,7 @@ MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \
MODULE_LICENSE("GPL");
/**
* The type 50 message family is associated with a CEX2A card.
* The type 50 message family is associated with a CEXxA cards.
*
* The four members of the family are described below.
*
@ -139,7 +137,7 @@ struct type50_crb3_msg {
} __packed;
/**
* The type 80 response family is associated with a CEX2A card.
* The type 80 response family is associated with a CEXxA cards.
*
* Note that all unsigned char arrays are right-justified and left-padded
* with zeroes.
@ -273,7 +271,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq,
/*
* CEX2A and CEX3A w/o FW update can handle requests up to
* 256 byte modulus (2k keys).
* CEX3A with FW update and CEX4A cards are able to handle
* CEX3A with FW update and newer CEXxA cards are able to handle
* 512 byte modulus (4k keys).
*/
if (mod_len <= 128) { /* up to 1024 bit key size */
@ -356,7 +354,7 @@ static int convert_type80(struct zcrypt_queue *zq,
unsigned char *data;
if (t80h->len < sizeof(*t80h) + outputdatalength) {
/* The result is too short, the CEX2A card may not do that.. */
/* The result is too short, the CEXxA card may not do that.. */
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
@ -447,10 +445,10 @@ out:
static atomic_t zcrypt_step = ATOMIC_INIT(0);
/**
* The request distributor calls this function if it picked the CEX2A
* The request distributor calls this function if it picked the CEXxA
* device to handle a modexpo request.
* @zq: pointer to zcrypt_queue structure that identifies the
* CEX2A device to the request distributor
* CEXxA device to the request distributor
* @mex: pointer to the modexpo request buffer
*/
static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq,
@ -493,10 +491,10 @@ out_free:
}
/**
* The request distributor calls this function if it picked the CEX2A
* The request distributor calls this function if it picked the CEXxA
* device to handle a modexpo_crt request.
* @zq: pointer to zcrypt_queue structure that identifies the
* CEX2A device to the request distributor
* CEXxA device to the request distributor
* @crt: pointer to the modexpoc_crt request buffer
*/
static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq,

View file

@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)

View file

@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@ -29,8 +27,7 @@
#include "zcrypt_msgtype6.h"
#include "zcrypt_cca_key.h"
#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
#define CEXXC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
#define CEIL4(x) ((((x)+3)/4)*4)
@ -38,9 +35,9 @@ struct response_type {
struct completion work;
int type;
};
#define PCIXCC_RESPONSE_TYPE_ICA 0
#define PCIXCC_RESPONSE_TYPE_XCRB 1
#define PCIXCC_RESPONSE_TYPE_EP11 2
#define CEXXC_RESPONSE_TYPE_ICA 0
#define CEXXC_RESPONSE_TYPE_XCRB 1
#define CEXXC_RESPONSE_TYPE_EP11 2
MODULE_AUTHOR("IBM Corporation");
MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \
@ -111,7 +108,7 @@ struct function_and_rules_block {
} __packed;
/**
* The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
* The following is used to initialize the CPRBX passed to the CEXxC/CEXxP
* card in a type6 message. The 3 fields that must be filled in at execution
* time are req_parml, rpl_parml and usage_domain.
* Everything about this interface is ascii/big-endian, since the
@ -294,7 +291,7 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_queue *zq,
/* message header, cprbx and f&r */
msg->hdr = static_type6_hdrX;
msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
msg->hdr.FromCardLen1 = CEXXC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
msg->cprbx = static_cprbx;
msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
@ -364,7 +361,7 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_queue *zq,
/* message header, cprbx and f&r */
msg->hdr = static_type6_hdrX;
msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
msg->hdr.FromCardLen1 = CEXXC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
msg->cprbx = static_cprbx;
msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
@ -658,16 +655,6 @@ static int convert_type86_ica(struct zcrypt_queue *zq,
(int) service_rc, (int) service_rs);
return -EINVAL;
}
if (service_rc == 8 && service_rs == 783) {
zq->zcard->min_mod_size =
PCIXCC_MIN_MOD_SIZE_OLD;
ZCRYPT_DBF(DBF_DEBUG,
"device=%02x.%04x rc/rs=%d/%d => rc=EAGAIN\n",
AP_QID_CARD(zq->queue->qid),
AP_QID_QUEUE(zq->queue->qid),
(int) service_rc, (int) service_rs);
return -EAGAIN;
}
zq->online = 0;
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
AP_QID_CARD(zq->queue->qid),
@ -697,7 +684,7 @@ static int convert_type86_ica(struct zcrypt_queue *zq,
if (pad_len > 0) {
if (pad_len < 10)
return -EINVAL;
/* 'restore' padding left in the PCICC/PCIXCC card. */
/* 'restore' padding left in the CEXXC card. */
if (copy_to_user(outputdata, static_pad, pad_len - 1))
return -EFAULT;
if (put_user(0, outputdata + pad_len - 1))
@ -955,13 +942,13 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq,
if (t86r->hdr.type == TYPE86_RSP_CODE &&
t86r->cprbx.cprb_ver_id == 0x02) {
switch (resp_type->type) {
case PCIXCC_RESPONSE_TYPE_ICA:
case CEXXC_RESPONSE_TYPE_ICA:
length = sizeof(struct type86x_reply)
+ t86r->length - 2;
length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
length = min(CEXXC_MAX_ICA_RESPONSE_SIZE, length);
memcpy(msg->message, reply->message, length);
break;
case PCIXCC_RESPONSE_TYPE_XCRB:
case CEXXC_RESPONSE_TYPE_XCRB:
length = t86r->fmt2.offset2 + t86r->fmt2.count2;
length = min(MSGTYPE06_MAX_MSG_SIZE, length);
memcpy(msg->message, reply->message, length);
@ -1004,7 +991,7 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq,
if (t86r->hdr.type == TYPE86_RSP_CODE &&
t86r->cprbx.cprb_ver_id == 0x04) {
switch (resp_type->type) {
case PCIXCC_RESPONSE_TYPE_EP11:
case CEXXC_RESPONSE_TYPE_EP11:
length = t86r->fmt2.offset1 + t86r->fmt2.count1;
length = min(MSGTYPE06_MAX_MSG_SIZE, length);
memcpy(msg->message, reply->message, length);
@ -1022,10 +1009,10 @@ out:
static atomic_t zcrypt_step = ATOMIC_INIT(0);
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* The request distributor calls this function if it picked the CEXxC
* device to handle a modexpo request.
* @zq: pointer to zcrypt_queue structure that identifies the
* PCIXCC/CEX2C device to the request distributor
* CEXxC device to the request distributor
* @mex: pointer to the modexpo request buffer
*/
static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
@ -1033,7 +1020,7 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
{
struct ap_message ap_msg;
struct response_type resp_type = {
.type = PCIXCC_RESPONSE_TYPE_ICA,
.type = CEXXC_RESPONSE_TYPE_ICA,
};
int rc;
@ -1066,10 +1053,10 @@ out_free:
}
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* The request distributor calls this function if it picked the CEXxC
* device to handle a modexpo_crt request.
* @zq: pointer to zcrypt_queue structure that identifies the
* PCIXCC/CEX2C device to the request distributor
* CEXxC device to the request distributor
* @crt: pointer to the modexpoc_crt request buffer
*/
static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
@ -1077,7 +1064,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
{
struct ap_message ap_msg;
struct response_type resp_type = {
.type = PCIXCC_RESPONSE_TYPE_ICA,
.type = CEXXC_RESPONSE_TYPE_ICA,
};
int rc;
@ -1122,7 +1109,7 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
unsigned int *func_code, unsigned short **dom)
{
struct response_type resp_type = {
.type = PCIXCC_RESPONSE_TYPE_XCRB,
.type = CEXXC_RESPONSE_TYPE_XCRB,
};
ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
@ -1131,18 +1118,17 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL);
ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
if (!ap_msg->private)
return -ENOMEM;
memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
return XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code, dom);
}
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* The request distributor calls this function if it picked the CEXxC
* device to handle a send_cprb request.
* @zq: pointer to zcrypt_queue structure that identifies the
* PCIXCC/CEX2C device to the request distributor
* CEXxC device to the request distributor
* @xcRB: pointer to the send_cprb request buffer
*/
static long zcrypt_msgtype6_send_cprb(struct zcrypt_queue *zq,
@ -1178,7 +1164,7 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
unsigned int *func_code)
{
struct response_type resp_type = {
.type = PCIXCC_RESPONSE_TYPE_EP11,
.type = CEXXC_RESPONSE_TYPE_EP11,
};
ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
@ -1187,10 +1173,9 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
ap_msg->receive = zcrypt_msgtype6_receive_ep11;
ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL);
ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
if (!ap_msg->private)
return -ENOMEM;
memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
return xcrb_msg_to_type6_ep11cprb_msgx(ap_msg, xcrb, func_code);
}
@ -1273,7 +1258,7 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
unsigned int *domain)
{
struct response_type resp_type = {
.type = PCIXCC_RESPONSE_TYPE_XCRB,
.type = CEXXC_RESPONSE_TYPE_XCRB,
};
ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
@ -1282,10 +1267,9 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
ap_msg->receive = zcrypt_msgtype6_receive;
ap_msg->psmid = (((unsigned long long) current->pid) << 32) +
atomic_inc_return(&zcrypt_step);
ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL);
ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
if (!ap_msg->private)
return -ENOMEM;
memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain);
@ -1294,10 +1278,10 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
}
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* The request distributor calls this function if it picked the CEXxC
* device to generate random data.
* @zq: pointer to zcrypt_queue structure that identifies the
* PCIXCC/CEX2C device to the request distributor
* CEXxC device to the request distributor
* @buffer: pointer to a memory page to return random data
*/
static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq,
@ -1332,7 +1316,7 @@ static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq,
}
/**
* The crypto operations for a PCIXCC/CEX2C card.
* The crypto operations for a CEXxC card.
*/
static struct zcrypt_ops zcrypt_msgtype6_norng_ops = {
.owner = THIS_MODULE,

View file

@ -1,7 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)
@ -24,7 +22,7 @@
#define MSGTYPE06_MAX_MSG_SIZE (12*1024)
/**
* The type 6 message family is associated with PCICC or PCIXCC cards.
* The type 6 message family is associated with CEXxC/CEXxP cards.
*
* It contains a message header followed by a CPRB, both of which
* are described below.
@ -43,13 +41,8 @@ struct type6_hdr {
unsigned int offset2; /* 0x00000000 */
unsigned int offset3; /* 0x00000000 */
unsigned int offset4; /* 0x00000000 */
unsigned char agent_id[16]; /* PCICC: */
/* 0x0100 */
/* 0x4343412d4150504c202020 */
/* 0x010101 */
/* PCIXCC: */
/* 0x4341000000000000 */
/* 0x0000000000000000 */
unsigned char agent_id[16]; /* 0x4341000000000000 */
/* 0x0000000000000000 */
unsigned char rqid[2]; /* rqid. internal to 603 */
unsigned char reserved5[2]; /* 0x0000 */
unsigned char function_code[2]; /* for PKD, 0x5044 (ascii 'PD') */
@ -65,7 +58,7 @@ struct type6_hdr {
} __packed;
/**
* The type 86 message family is associated with PCICC and PCIXCC cards.
* The type 86 message family is associated with CEXxC/CEXxP cards.
*
* It contains a message header followed by a CPRB. The CPRB is
* the same as the request CPRB, which is described above.

View file

@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* zcrypt 2.1.0
*
* Copyright IBM Corp. 2001, 2012
* Author(s): Robert Burroughs
* Eric Rossman (edrossma@us.ibm.com)