diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/block/dasd.c | 17 | ||||
-rw-r--r-- | drivers/s390/block/dasd_eckd.c | 33 | ||||
-rw-r--r-- | drivers/s390/block/dasd_genhd.c | 5 | ||||
-rw-r--r-- | drivers/s390/block/dasd_int.h | 3 | ||||
-rw-r--r-- | drivers/s390/block/dasd_ioctl.c | 6 | ||||
-rw-r--r-- | drivers/s390/block/dcssblk.c | 11 | ||||
-rw-r--r-- | drivers/s390/char/zcore.c | 41 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 7 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_drv.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/vfio_ccw_private.h | 2 | ||||
-rw-r--r-- | drivers/s390/crypto/pkey_api.c | 512 | ||||
-rw-r--r-- | drivers/s390/crypto/vfio_ap_ops.c | 134 | ||||
-rw-r--r-- | drivers/s390/crypto/vfio_ap_private.h | 3 | ||||
-rw-r--r-- | drivers/s390/net/ctcm_dbug.c | 2 | ||||
-rw-r--r-- | drivers/s390/net/ctcm_main.c | 6 | ||||
-rw-r--r-- | drivers/s390/net/ctcm_main.h | 1 | ||||
-rw-r--r-- | drivers/s390/net/ctcm_mpc.c | 18 | ||||
-rw-r--r-- | drivers/s390/net/ctcm_sysfs.c | 46 | ||||
-rw-r--r-- | drivers/s390/net/ism_drv.c | 10 | ||||
-rw-r--r-- | drivers/s390/net/lcs.c | 13 | ||||
-rw-r--r-- | drivers/s390/net/lcs.h | 2 |
22 files changed, 624 insertions, 252 deletions
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 9fbfce735d56..edcbf77852c3 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2737,7 +2737,12 @@ static void __dasd_cleanup_cqr(struct dasd_ccw_req *cqr) else if (status == 0) { switch (cqr->intrc) { case -EPERM: - error = BLK_STS_NEXUS; + /* + * DASD doesn't implement SCSI/NVMe reservations, but it + * implements a locking scheme similar to them. We + * return this error when we no longer have the lock. + */ + error = BLK_STS_RESV_CONFLICT; break; case -ENOLINK: error = BLK_STS_TRANSPORT; @@ -3234,12 +3239,12 @@ struct blk_mq_ops dasd_mq_ops = { .exit_hctx = dasd_exit_hctx, }; -static int dasd_open(struct block_device *bdev, fmode_t mode) +static int dasd_open(struct gendisk *disk, blk_mode_t mode) { struct dasd_device *base; int rc; - base = dasd_device_from_gendisk(bdev->bd_disk); + base = dasd_device_from_gendisk(disk); if (!base) return -ENODEV; @@ -3268,14 +3273,12 @@ static int dasd_open(struct block_device *bdev, fmode_t mode) rc = -ENODEV; goto out; } - - if ((mode & FMODE_WRITE) && + if ((mode & BLK_OPEN_WRITE) && (test_bit(DASD_FLAG_DEVICE_RO, &base->flags) || (base->features & DASD_FEATURE_READONLY))) { rc = -EROFS; goto out; } - dasd_put_device(base); return 0; @@ -3287,7 +3290,7 @@ unlock: return rc; } -static void dasd_release(struct gendisk *disk, fmode_t mode) +static void dasd_release(struct gendisk *disk) { struct dasd_device *base = dasd_device_from_gendisk(disk); if (base) { diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ade1369fe5ed..113c509bf6d0 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -127,6 +127,8 @@ static int prepare_itcw(struct itcw *, unsigned int, unsigned int, int, struct dasd_device *, struct dasd_device *, unsigned int, int, unsigned int, unsigned int, unsigned int, unsigned int); +static int dasd_eckd_query_pprc_status(struct dasd_device *, + struct dasd_pprc_data_sc4 *); /* initial attempt at a probe function. this can be simplified once * the other detection code is gone */ @@ -3733,6 +3735,26 @@ static int count_exts(unsigned int from, unsigned int to, int trks_per_ext) return count; } +static int dasd_in_copy_relation(struct dasd_device *device) +{ + struct dasd_pprc_data_sc4 *temp; + int rc; + + if (!dasd_eckd_pprc_enabled(device)) + return 0; + + temp = kzalloc(sizeof(*temp), GFP_KERNEL); + if (!temp) + return -ENOMEM; + + rc = dasd_eckd_query_pprc_status(device, temp); + if (!rc) + rc = temp->dev_info[0].state; + + kfree(temp); + return rc; +} + /* * Release allocated space for a given range or an entire volume. */ @@ -3749,6 +3771,7 @@ dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block, int cur_to_trk, cur_from_trk; struct dasd_ccw_req *cqr; u32 beg_cyl, end_cyl; + int copy_relation; struct ccw1 *ccw; int trks_per_ext; size_t ras_size; @@ -3760,6 +3783,10 @@ dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block, if (dasd_eckd_ras_sanity_checks(device, first_trk, last_trk)) return ERR_PTR(-EINVAL); + copy_relation = dasd_in_copy_relation(device); + if (copy_relation < 0) + return ERR_PTR(copy_relation); + rq = req ? blk_mq_rq_to_pdu(req) : NULL; features = &private->features; @@ -3788,9 +3815,11 @@ dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block, /* * This bit guarantees initialisation of tracks within an extent that is * not fully specified, but is only supported with a certain feature - * subset. + * subset and for devices not in a copy relation. */ - ras_data->op_flags.guarantee_init = !!(features->feature[56] & 0x01); + if (features->feature[56] & 0x01 && !copy_relation) + ras_data->op_flags.guarantee_init = 1; + ras_data->lss = private->conf.ned->ID; ras_data->dev_addr = private->conf.ned->unit_addr; ras_data->nr_exts = nr_exts; diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index 998a961e1704..fe5108a1b332 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -130,7 +130,8 @@ int dasd_scan_partitions(struct dasd_block *block) struct block_device *bdev; int rc; - bdev = blkdev_get_by_dev(disk_devt(block->gdp), FMODE_READ, NULL); + bdev = blkdev_get_by_dev(disk_devt(block->gdp), BLK_OPEN_READ, NULL, + NULL); if (IS_ERR(bdev)) { DBF_DEV_EVENT(DBF_ERR, block->base, "scan partitions error, blkdev_get returned %ld", @@ -179,7 +180,7 @@ void dasd_destroy_partitions(struct dasd_block *block) mutex_unlock(&bdev->bd_disk->open_mutex); /* Matching blkdev_put to the blkdev_get in dasd_scan_partitions. */ - blkdev_put(bdev, FMODE_READ); + blkdev_put(bdev, NULL); } int dasd_gendisk_init(void) diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 33f812f0e515..0aa56351da72 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -965,7 +965,8 @@ int dasd_scan_partitions(struct dasd_block *); void dasd_destroy_partitions(struct dasd_block *); /* externals in dasd_ioctl.c */ -int dasd_ioctl(struct block_device *, fmode_t, unsigned int, unsigned long); +int dasd_ioctl(struct block_device *bdev, blk_mode_t mode, unsigned int cmd, + unsigned long arg); int dasd_set_read_only(struct block_device *bdev, bool ro); /* externals in dasd_proc.c */ diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 9327dcdd6e5e..513a7e6eee63 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -552,10 +552,10 @@ static int __dasd_ioctl_information(struct dasd_block *block, memcpy(dasd_info->type, base->discipline->name, 4); - spin_lock_irqsave(&block->queue_lock, flags); + spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags); list_for_each(l, &base->ccw_queue) dasd_info->chanq_len++; - spin_unlock_irqrestore(&block->queue_lock, flags); + spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags); return 0; } @@ -612,7 +612,7 @@ static int dasd_ioctl_readall_cmb(struct dasd_block *block, unsigned int cmd, return ret; } -int dasd_ioctl(struct block_device *bdev, fmode_t mode, +int dasd_ioctl(struct block_device *bdev, blk_mode_t mode, unsigned int cmd, unsigned long arg) { struct dasd_block *block; diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index ee47ac520cd4..405d76df9427 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -28,8 +28,8 @@ #define DCSSBLK_PARM_LEN 400 #define DCSS_BUS_ID_SIZE 20 -static int dcssblk_open(struct block_device *bdev, fmode_t mode); -static void dcssblk_release(struct gendisk *disk, fmode_t mode); +static int dcssblk_open(struct gendisk *disk, blk_mode_t mode); +static void dcssblk_release(struct gendisk *disk); static void dcssblk_submit_bio(struct bio *bio); static long dcssblk_dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages, enum dax_access_mode mode, void **kaddr, @@ -810,12 +810,11 @@ out_buf: } static int -dcssblk_open(struct block_device *bdev, fmode_t mode) +dcssblk_open(struct gendisk *disk, blk_mode_t mode) { - struct dcssblk_dev_info *dev_info; + struct dcssblk_dev_info *dev_info = disk->private_data; int rc; - dev_info = bdev->bd_disk->private_data; if (NULL == dev_info) { rc = -ENODEV; goto out; @@ -827,7 +826,7 @@ out: } static void -dcssblk_release(struct gendisk *disk, fmode_t mode) +dcssblk_release(struct gendisk *disk) { struct dcssblk_dev_info *dev_info = disk->private_data; struct segment_info *entry; diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 599f547310f8..942c73a11ca3 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -51,6 +51,7 @@ static struct dentry *zcore_dir; static struct dentry *zcore_reipl_file; static struct dentry *zcore_hsa_file; static struct ipl_parameter_block *zcore_ipl_block; +static unsigned long os_info_flags; static DEFINE_MUTEX(hsa_buf_mutex); static char hsa_buf[PAGE_SIZE] __aligned(PAGE_SIZE); @@ -139,7 +140,13 @@ static ssize_t zcore_reipl_write(struct file *filp, const char __user *buf, { if (zcore_ipl_block) { diag308(DIAG308_SET, zcore_ipl_block); - diag308(DIAG308_LOAD_CLEAR, NULL); + if (os_info_flags & OS_INFO_FLAG_REIPL_CLEAR) + diag308(DIAG308_LOAD_CLEAR, NULL); + /* Use special diag308 subcode for CCW normal ipl */ + if (zcore_ipl_block->pb0_hdr.pbt == IPL_PBT_CCW) + diag308(DIAG308_LOAD_NORMAL_DUMP, NULL); + else + diag308(DIAG308_LOAD_NORMAL, NULL); } return count; } @@ -212,7 +219,10 @@ static int __init check_sdias(void) */ static int __init zcore_reipl_init(void) { + struct os_info_entry *entry; struct ipib_info ipib_info; + unsigned long os_info_addr; + struct os_info *os_info; int rc; rc = memcpy_hsa_kernel(&ipib_info, __LC_DUMP_REIPL, sizeof(ipib_info)); @@ -234,6 +244,35 @@ static int __init zcore_reipl_init(void) free_page((unsigned long) zcore_ipl_block); zcore_ipl_block = NULL; } + /* + * Read the bit-flags field from os_info flags entry. + * Return zero even for os_info read or entry checksum errors in order + * to continue dump processing, considering that os_info could be + * corrupted on the panicked system. + */ + os_info = (void *)__get_free_page(GFP_KERNEL); + if (!os_info) + return -ENOMEM; + rc = memcpy_hsa_kernel(&os_info_addr, __LC_OS_INFO, sizeof(os_info_addr)); + if (rc) + goto out; + if (os_info_addr < sclp.hsa_size) + rc = memcpy_hsa_kernel(os_info, os_info_addr, PAGE_SIZE); + else + rc = memcpy_real(os_info, os_info_addr, PAGE_SIZE); + if (rc || os_info_csum(os_info) != os_info->csum) + goto out; + entry = &os_info->entry[OS_INFO_FLAGS_ENTRY]; + if (entry->addr && entry->size) { + if (entry->addr < sclp.hsa_size) + rc = memcpy_hsa_kernel(&os_info_flags, entry->addr, sizeof(os_info_flags)); + else + rc = memcpy_real(&os_info_flags, entry->addr, sizeof(os_info_flags)); + if (rc || (__force u32)csum_partial(&os_info_flags, entry->size, 0) != entry->csum) + os_info_flags = 0; + } +out: + free_page((unsigned long)os_info); return 0; } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 8eb089b99cde..c0d620ffea61 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1111,6 +1111,8 @@ static void io_subchannel_verify(struct subchannel *sch) cdev = sch_get_cdev(sch); if (cdev) dev_fsm_event(cdev, DEV_EVENT_VERIFY); + else + css_schedule_eval(sch->schid); } static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask) @@ -1374,6 +1376,7 @@ void ccw_device_set_notoper(struct ccw_device *cdev) enum io_sch_action { IO_SCH_UNREG, IO_SCH_ORPH_UNREG, + IO_SCH_UNREG_CDEV, IO_SCH_ATTACH, IO_SCH_UNREG_ATTACH, IO_SCH_ORPH_ATTACH, @@ -1406,7 +1409,7 @@ static enum io_sch_action sch_get_action(struct subchannel *sch) } if ((sch->schib.pmcw.pam & sch->opm) == 0) { if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) - return IO_SCH_UNREG; + return IO_SCH_UNREG_CDEV; return IO_SCH_DISC; } if (device_is_disconnected(cdev)) @@ -1468,6 +1471,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) case IO_SCH_ORPH_ATTACH: ccw_device_set_disconnected(cdev); break; + case IO_SCH_UNREG_CDEV: case IO_SCH_UNREG_ATTACH: case IO_SCH_UNREG: if (!cdev) @@ -1501,6 +1505,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process) if (rc) goto out; break; + case IO_SCH_UNREG_CDEV: case IO_SCH_UNREG_ATTACH: spin_lock_irqsave(sch->lock, flags); sch_set_cdev(sch, NULL); diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 5ea6249d8180..641f0dbb65a9 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -95,7 +95,7 @@ static inline int do_sqbs(u64 token, unsigned char state, int queue, " lgr 1,%[token]\n" " .insn rsy,0xeb000000008a,%[qs],%[ccq],0(%[state])" : [ccq] "+&d" (_ccq), [qs] "+&d" (_queuestart) - : [state] "d" ((unsigned long)state), [token] "d" (token) + : [state] "a" ((unsigned long)state), [token] "d" (token) : "memory", "cc", "1"); *count = _ccq & 0xff; *start = _queuestart & 0xff; diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c index ff538a086fc7..43601816ea4e 100644 --- a/drivers/s390/cio/vfio_ccw_drv.c +++ b/drivers/s390/cio/vfio_ccw_drv.c @@ -171,7 +171,7 @@ static int vfio_ccw_sch_probe(struct subchannel *sch) return -ENODEV; } - parent = kzalloc(sizeof(*parent), GFP_KERNEL); + parent = kzalloc(struct_size(parent, mdev_types, 1), GFP_KERNEL); if (!parent) return -ENOMEM; diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h index b441ae6700fd..b62bbc5c6376 100644 --- a/drivers/s390/cio/vfio_ccw_private.h +++ b/drivers/s390/cio/vfio_ccw_private.h @@ -79,7 +79,7 @@ struct vfio_ccw_parent { struct mdev_parent parent; struct mdev_type mdev_type; - struct mdev_type *mdev_types[1]; + struct mdev_type *mdev_types[]; }; /** diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index 5a05d1cdfec2..e58bfd225323 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -2,7 +2,8 @@ /* * pkey device driver * - * Copyright IBM Corp. 2017,2019 + * Copyright IBM Corp. 2017, 2023 + * * Author(s): Harald Freudenberger */ @@ -32,8 +33,10 @@ MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("s390 protected key interface"); #define KEYBLOBBUFSIZE 8192 /* key buffer size used for internal processing */ +#define MINKEYBLOBBUFSIZE (sizeof(struct keytoken_header)) #define PROTKEYBLOBBUFSIZE 256 /* protected key buffer size used internal */ #define MAXAPQNSINLIST 64 /* max 64 apqns within a apqn list */ +#define AES_WK_VP_SIZE 32 /* Size of WK VP block appended to a prot key */ /* * debug feature data and functions @@ -71,49 +74,106 @@ struct protaeskeytoken { } __packed; /* inside view of a clear key token (type 0x00 version 0x02) */ -struct clearaeskeytoken { - u8 type; /* 0x00 for PAES specific key tokens */ +struct clearkeytoken { + u8 type; /* 0x00 for PAES specific key tokens */ u8 res0[3]; - u8 version; /* 0x02 for clear AES key token */ + u8 version; /* 0x02 for clear key token */ u8 res1[3]; - u32 keytype; /* key type, one of the PKEY_KEYTYPE values */ - u32 len; /* bytes actually stored in clearkey[] */ + u32 keytype; /* key type, one of the PKEY_KEYTYPE_* values */ + u32 len; /* bytes actually stored in clearkey[] */ u8 clearkey[]; /* clear key value */ } __packed; +/* helper function which translates the PKEY_KEYTYPE_AES_* to their keysize */ +static inline u32 pkey_keytype_aes_to_size(u32 keytype) +{ + switch (keytype) { + case PKEY_KEYTYPE_AES_128: + return 16; + case PKEY_KEYTYPE_AES_192: + return 24; + case PKEY_KEYTYPE_AES_256: + return 32; + default: + return 0; + } +} + /* - * Create a protected key from a clear key value. + * Create a protected key from a clear key value via PCKMO instruction. */ -static int pkey_clr2protkey(u32 keytype, - const struct pkey_clrkey *clrkey, - struct pkey_protkey *protkey) +static int pkey_clr2protkey(u32 keytype, const u8 *clrkey, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) { /* mask of available pckmo subfunctions */ static cpacf_mask_t pckmo_functions; - long fc; + u8 paramblock[112]; + u32 pkeytype; int keysize; - u8 paramblock[64]; + long fc; switch (keytype) { case PKEY_KEYTYPE_AES_128: + /* 16 byte key, 32 byte aes wkvp, total 48 bytes */ keysize = 16; + pkeytype = keytype; fc = CPACF_PCKMO_ENC_AES_128_KEY; break; case PKEY_KEYTYPE_AES_192: + /* 24 byte key, 32 byte aes wkvp, total 56 bytes */ keysize = 24; + pkeytype = keytype; fc = CPACF_PCKMO_ENC_AES_192_KEY; break; case PKEY_KEYTYPE_AES_256: + /* 32 byte key, 32 byte aes wkvp, total 64 bytes */ keysize = 32; + pkeytype = keytype; fc = CPACF_PCKMO_ENC_AES_256_KEY; break; + case PKEY_KEYTYPE_ECC_P256: + /* 32 byte key, 32 byte aes wkvp, total 64 bytes */ + keysize = 32; + pkeytype = PKEY_KEYTYPE_ECC; + fc = CPACF_PCKMO_ENC_ECC_P256_KEY; + break; + case PKEY_KEYTYPE_ECC_P384: + /* 48 byte key, 32 byte aes wkvp, total 80 bytes */ + keysize = 48; + pkeytype = PKEY_KEYTYPE_ECC; + fc = CPACF_PCKMO_ENC_ECC_P384_KEY; + break; + case PKEY_KEYTYPE_ECC_P521: + /* 80 byte key, 32 byte aes wkvp, total 112 bytes */ + keysize = 80; + pkeytype = PKEY_KEYTYPE_ECC; + fc = CPACF_PCKMO_ENC_ECC_P521_KEY; + break; + case PKEY_KEYTYPE_ECC_ED25519: + /* 32 byte key, 32 byte aes wkvp, total 64 bytes */ + keysize = 32; + pkeytype = PKEY_KEYTYPE_ECC; + fc = CPACF_PCKMO_ENC_ECC_ED25519_KEY; + break; + case PKEY_KEYTYPE_ECC_ED448: + /* 64 byte key, 32 byte aes wkvp, total 96 bytes */ + keysize = 64; + pkeytype = PKEY_KEYTYPE_ECC; + fc = CPACF_PCKMO_ENC_ECC_ED448_KEY; + break; default: - DEBUG_ERR("%s unknown/unsupported keytype %d\n", + DEBUG_ERR("%s unknown/unsupported keytype %u\n", __func__, keytype); return -EINVAL; } + if (*protkeylen < keysize + AES_WK_VP_SIZE) { + DEBUG_ERR("%s prot key buffer size too small: %u < %d\n", + __func__, *protkeylen, keysize + AES_WK_VP_SIZE); + return -EINVAL; + } + /* Did we already check for PCKMO ? */ if (!pckmo_functions.bytes[0]) { /* no, so check now */ @@ -128,15 +188,15 @@ static int pkey_clr2protkey(u32 keytype, /* prepare param block */ memset(paramblock, 0, sizeof(paramblock)); - memcpy(paramblock, clrkey->clrkey, keysize); + memcpy(paramblock, clrkey, keysize); /* call the pckmo instruction */ cpacf_pckmo(fc, paramblock); - /* copy created protected key */ - protkey->type = keytype; - protkey->len = keysize + 32; - memcpy(protkey->protkey, paramblock, keysize + 32); + /* copy created protected key to key buffer including the wkvp block */ + *protkeylen = keysize + AES_WK_VP_SIZE; + memcpy(protkey, paramblock, *protkeylen); + *protkeytype = pkeytype; return 0; } @@ -144,11 +204,12 @@ static int pkey_clr2protkey(u32 keytype, /* * Find card and transform secure key into protected key. */ -static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey) +static int pkey_skey2pkey(const u8 *key, u8 *protkey, + u32 *protkeylen, u32 *protkeytype) { - int rc, verify; - u16 cardnr, domain; struct keytoken_header *hdr = (struct keytoken_header *)key; + u16 cardnr, domain; + int rc, verify; zcrypt_wait_api_operational(); @@ -167,14 +228,13 @@ static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey) continue; switch (hdr->version) { case TOKVER_CCA_AES: - rc = cca_sec2protkey(cardnr, domain, - key, pkey->protkey, - &pkey->len, &pkey->type); + rc = cca_sec2protkey(cardnr, domain, key, + protkey, protkeylen, protkeytype); break; case TOKVER_CCA_VLSC: - rc = cca_cipher2protkey(cardnr, domain, - key, pkey->protkey, - &pkey->len, &pkey->type); + rc = cca_cipher2protkey(cardnr, domain, key, + protkey, protkeylen, + protkeytype); break; default: return -EINVAL; @@ -195,9 +255,9 @@ static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey) static int pkey_clr2ep11key(const u8 *clrkey, size_t clrkeylen, u8 *keybuf, size_t *keybuflen) { - int i, rc; - u16 card, dom; u32 nr_apqns, *apqns = NULL; + u16 card, dom; + int i, rc; zcrypt_wait_api_operational(); @@ -227,12 +287,13 @@ out: /* * Find card and transform EP11 secure key into protected key. */ -static int pkey_ep11key2pkey(const u8 *key, struct pkey_protkey *pkey) +static int pkey_ep11key2pkey(const u8 *key, u8 *protkey, + u32 *protkeylen, u32 *protkeytype) { - int i, rc; - u16 card, dom; - u32 nr_apqns, *apqns = NULL; struct ep11keyblob *kb = (struct ep11keyblob *)key; + u32 nr_apqns, *apqns = NULL; + u16 card, dom; + int i, rc; zcrypt_wait_api_operational(); @@ -246,9 +307,8 @@ static int pkey_ep11key2pkey(const u8 *key, struct pkey_protkey *pkey) for (rc = -ENODEV, i = 0; i < nr_apqns; i++) { card = apqns[i] >> 16; dom = apqns[i] & 0xFFFF; - pkey->len = sizeof(pkey->protkey); rc = ep11_kblob2protkey(card, dom, key, kb->head.len, - pkey->protkey, &pkey->len, &pkey->type); + protkey, protkeylen, protkeytype); if (rc == 0) break; } @@ -306,38 +366,31 @@ out: /* * Generate a random protected key */ -static int pkey_genprotkey(u32 keytype, struct pkey_protkey *protkey) +static int pkey_genprotkey(u32 keytype, u8 *protkey, + u32 *protkeylen, u32 *protkeytype) { - struct pkey_clrkey clrkey; + u8 clrkey[32]; 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: + keysize = pkey_keytype_aes_to_size(keytype); + if (!keysize) { DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__, keytype); return -EINVAL; } /* generate a dummy random clear key */ - get_random_bytes(clrkey.clrkey, keysize); + get_random_bytes(clrkey, keysize); /* convert it to a dummy protected key */ - rc = pkey_clr2protkey(keytype, &clrkey, protkey); + rc = pkey_clr2protkey(keytype, clrkey, + protkey, protkeylen, protkeytype); if (rc) return rc; /* replace the key part of the protected key with random bytes */ - get_random_bytes(protkey->protkey, keysize); + get_random_bytes(protkey, keysize); return 0; } @@ -345,37 +398,46 @@ static int pkey_genprotkey(u32 keytype, struct pkey_protkey *protkey) /* * Verify if a protected key is still valid */ -static int pkey_verifyprotkey(const struct pkey_protkey *protkey) +static int pkey_verifyprotkey(const u8 *protkey, u32 protkeylen, + u32 protkeytype) { - 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; + unsigned int k, pkeylen; + unsigned long fc; - switch (protkey->type) { + switch (protkeytype) { case PKEY_KEYTYPE_AES_128: + pkeylen = 16 + AES_WK_VP_SIZE; fc = CPACF_KMC_PAES_128; break; case PKEY_KEYTYPE_AES_192: + pkeylen = 24 + AES_WK_VP_SIZE; fc = CPACF_KMC_PAES_192; break; case PKEY_KEYTYPE_AES_256: + pkeylen = 32 + AES_WK_VP_SIZE; fc = CPACF_KMC_PAES_256; break; default: - DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__, - protkey->type); + DEBUG_ERR("%s unknown/unsupported keytype %u\n", __func__, + protkeytype); + return -EINVAL; + } + if (protkeylen != pkeylen) { + DEBUG_ERR("%s invalid protected key size %u for keytype %u\n", + __func__, protkeylen, protkeytype); return -EINVAL; } memset(null_msg, 0, sizeof(null_msg)); memset(param.iv, 0, sizeof(param.iv)); - memcpy(param.key, protkey->protkey, sizeof(param.key)); + memcpy(param.key, protkey, protkeylen); k = cpacf_kmc(fc | CPACF_ENCRYPT, ¶m, null_msg, dest_buf, sizeof(null_msg)); @@ -387,15 +449,119 @@ static int pkey_verifyprotkey(const struct pkey_protkey *protkey) return 0; } +/* Helper for pkey_nonccatok2pkey, handles aes clear key token */ +static int nonccatokaes2pkey(const struct clearkeytoken *t, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) +{ + size_t tmpbuflen = max_t(size_t, SECKEYBLOBSIZE, MAXEP11AESKEYBLOBSIZE); + u8 *tmpbuf = NULL; + u32 keysize; + int rc; + + keysize = pkey_keytype_aes_to_size(t->keytype); + if (!keysize) { + DEBUG_ERR("%s unknown/unsupported keytype %u\n", + __func__, t->keytype); + return -EINVAL; + } + if (t->len != keysize) { + DEBUG_ERR("%s non clear key aes token: invalid key len %u\n", + __func__, t->len); + return -EINVAL; + } + + /* try direct way with the PCKMO instruction */ + rc = pkey_clr2protkey(t->keytype, t->clearkey, + protkey, protkeylen, protkeytype); + if (!rc) + goto out; + + /* PCKMO failed, so try the CCA secure key way */ + tmpbuf = kmalloc(tmpbuflen, GFP_ATOMIC); + if (!tmpbuf) + return -ENOMEM; + zcrypt_wait_api_operational(); + rc = cca_clr2seckey(0xFFFF, 0xFFFF, t->keytype, t->clearkey, tmpbuf); + if (rc) + goto try_via_ep11; + rc = pkey_skey2pkey(tmpbuf, + protkey, protkeylen, protkeytype); + if (!rc) + goto out; + +try_via_ep11: + /* if the CCA way also failed, let's try via EP11 */ + rc = pkey_clr2ep11key(t->clearkey, t->len, + tmpbuf, &tmpbuflen); + if (rc) + goto failure; + rc = pkey_ep11key2pkey(tmpbuf, + protkey, protkeylen, protkeytype); + if (!rc) + goto out; + +failure: + DEBUG_ERR("%s unable to build protected key from clear", __func__); + +out: + kfree(tmpbuf); + return rc; +} + +/* Helper for pkey_nonccatok2pkey, handles ecc clear key token */ +static int nonccatokecc2pkey(const struct clearkeytoken *t, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) +{ + u32 keylen; + int rc; + + switch (t->keytype) { + case PKEY_KEYTYPE_ECC_P256: + keylen = 32; + break; + case PKEY_KEYTYPE_ECC_P384: + keylen = 48; + break; + case PKEY_KEYTYPE_ECC_P521: + keylen = 80; + break; + case PKEY_KEYTYPE_ECC_ED25519: + keylen = 32; + break; + case PKEY_KEYTYPE_ECC_ED448: + keylen = 64; + break; + default: + DEBUG_ERR("%s unknown/unsupported keytype %u\n", + __func__, t->keytype); + return -EINVAL; + } + + if (t->len != keylen) { + DEBUG_ERR("%s non clear key ecc token: invalid key len %u\n", + __func__, t->len); + return -EINVAL; + } + + /* only one path possible: via PCKMO instruction */ + rc = pkey_clr2protkey(t->keytype, t->clearkey, + protkey, protkeylen, protkeytype); + if (rc) { + DEBUG_ERR("%s unable to build protected key from clear", + __func__); + } + + return rc; +} + /* * Transform a non-CCA key token into a protected key */ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen, - struct pkey_protkey *protkey) + u8 *protkey, u32 *protkeylen, u32 *protkeytype) { - int rc = -EINVAL; - u8 *tmpbuf = NULL; struct keytoken_header *hdr = (struct keytoken_header *)key; + int rc = -EINVAL; switch (hdr->version) { case TOKVER_PROTECTED_KEY: { @@ -404,59 +570,40 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen, if (keylen != sizeof(struct protaeskeytoken)) goto out; t = (struct protaeskeytoken *)key; - protkey->len = t->len; - protkey->type = t->keytype; - memcpy(protkey->protkey, t->protkey, - sizeof(protkey->protkey)); - rc = pkey_verifyprotkey(protkey); + rc = pkey_verifyprotkey(t->protkey, t->len, t->keytype); + if (rc) + goto out; + memcpy(protkey, t->protkey, t->len); + *protkeylen = t->len; + *protkeytype = t->keytype; break; } case TOKVER_CLEAR_KEY: { - struct clearaeskeytoken *t; - struct pkey_clrkey ckey; - union u_tmpbuf { - u8 skey[SECKEYBLOBSIZE]; - u8 ep11key[MAXEP11AESKEYBLOBSIZE]; - }; - size_t tmpbuflen = sizeof(union u_tmpbuf); - - if (keylen < sizeof(struct clearaeskeytoken)) - goto out; - t = (struct clearaeskeytoken *)key; - if (keylen != sizeof(*t) + t->len) - goto out; - if ((t->keytype == PKEY_KEYTYPE_AES_128 && t->len == 16) || - (t->keytype == PKEY_KEYTYPE_AES_192 && t->len == 24) || - (t->keytype == PKEY_KEYTYPE_AES_256 && t->len == 32)) - memcpy(ckey.clrkey, t->clearkey, t->len); - else - goto out; - /* alloc temp key buffer space */ - tmpbuf = kmalloc(tmpbuflen, GFP_ATOMIC); - if (!tmpbuf) { - rc = -ENOMEM; + struct clearkeytoken *t = (struct clearkeytoken *)key; + + if (keylen < sizeof(struct clearkeytoken) || + keylen != sizeof(*t) + t->len) goto out; - } - /* try direct way with the PCKMO instruction */ - rc = pkey_clr2protkey(t->keytype, &ckey, protkey); - if (rc == 0) + switch (t->keytype) { + case PKEY_KEYTYPE_AES_128: + case PKEY_KEYTYPE_AES_192: + case PKEY_KEYTYPE_AES_256: + rc = nonccatokaes2pkey(t, protkey, + protkeylen, protkeytype); break; - /* PCKMO failed, so try the CCA secure key way */ - zcrypt_wait_api_operational(); - rc = cca_clr2seckey(0xFFFF, 0xFFFF, t->keytype, - ckey.clrkey, tmpbuf); - if (rc == 0) - rc = pkey_skey2pkey(tmpbuf, protkey); - if (rc == 0) + case PKEY_KEYTYPE_ECC_P256: + case PKEY_KEYTYPE_ECC_P384: + case PKEY_KEYTYPE_ECC_P521: + case PKEY_KEYTYPE_ECC_ED25519: + case PKEY_KEYTYPE_ECC_ED448: + rc = nonccatokecc2pkey(t, protkey, + protkeylen, protkeytype); break; - /* if the CCA way also failed, let's try via EP11 */ - rc = pkey_clr2ep11key(ckey.clrkey, t->len, - tmpbuf, &tmpbuflen); - if (rc == 0) - rc = pkey_ep11key2pkey(tmpbuf, protkey); - /* now we should really have an protected key */ - DEBUG_ERR("%s unable to build protected key from clear", - __func__); + default: + DEBUG_ERR("%s unknown/unsupported non cca clear key type %u\n", + __func__, t->keytype); + return -EINVAL; + } break; } case TOKVER_EP11_AES: { @@ -464,7 +611,8 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen, rc = ep11_check_aes_key(debug_info, 3, key, keylen, 1); if (rc) goto out; - rc = pkey_ep11key2pkey(key, protkey); + rc = pkey_ep11key2pkey(key, + protkey, protkeylen, protkeytype); break; } case TOKVER_EP11_AES_WITH_HEADER: @@ -473,16 +621,14 @@ static int pkey_nonccatok2pkey(const u8 *key, u32 keylen, if (rc) goto out; rc = pkey_ep11key2pkey(key + sizeof(struct ep11kblob_header), - protkey); + protkey, protkeylen, protkeytype); break; default: DEBUG_ERR("%s unknown/unsupported non-CCA token version %d\n", __func__, hdr->version); - rc = -EINVAL; } out: - kfree(tmpbuf); return rc; } @@ -490,7 +636,7 @@ out: * Transform a CCA internal key token into a protected key */ static int pkey_ccainttok2pkey(const u8 *key, u32 keylen, - struct pkey_protkey *protkey) + u8 *protkey, u32 *protkeylen, u32 *protkeytype) { struct keytoken_header *hdr = (struct keytoken_header *)key; @@ -509,17 +655,17 @@ static int pkey_ccainttok2pkey(const u8 *key, u32 keylen, return -EINVAL; } - return pkey_skey2pkey(key, protkey); + return pkey_skey2pkey(key, protkey, protkeylen, protkeytype); } /* * Transform a key blob (of any type) into a protected key */ int pkey_keyblob2pkey(const u8 *key, u32 keylen, - struct pkey_protkey *protkey) + u8 *protkey, u32 *protkeylen, u32 *protkeytype) { - int rc; struct keytoken_header *hdr = (struct keytoken_header *)key; + int rc; if (keylen < sizeof(struct keytoken_header)) { DEBUG_ERR("%s invalid keylen %d\n", __func__, keylen); @@ -528,10 +674,12 @@ int pkey_keyblob2pkey(const u8 *key, u32 keylen, switch (hdr->type) { case TOKTYPE_NON_CCA: - rc = pkey_nonccatok2pkey(key, keylen, protkey); + rc = pkey_nonccatok2pkey(key, keylen, + protkey, protkeylen, protkeytype); break; case TOKTYPE_CCA_INTERNAL: - rc = pkey_ccainttok2pkey(key, keylen, protkey); + rc = pkey_ccainttok2pkey(key, keylen, + protkey, protkeylen, protkeytype); break; default: DEBUG_ERR("%s unknown/unsupported blob type %d\n", @@ -663,9 +811,9 @@ static int pkey_verifykey2(const u8 *key, size_t keylen, enum pkey_key_type *ktype, enum pkey_key_size *ksize, u32 *flags) { - int rc; - u32 _nr_apqns, *_apqns = NULL; struct keytoken_header *hdr = (struct keytoken_header *)key; + u32 _nr_apqns, *_apqns = NULL; + int rc; if (keylen < sizeof(struct keytoken_header)) return -EINVAL; @@ -771,10 +919,10 @@ out: static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns, const u8 *key, size_t keylen, - struct pkey_protkey *pkey) + u8 *protkey, u32 *protkeylen, u32 *protkeytype) { - int i, card, dom, rc; struct keytoken_header *hdr = (struct keytoken_header *)key; + int i, card, dom, rc; /* check for at least one apqn given */ if (!apqns || !nr_apqns) @@ -806,7 +954,9 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns, if (ep11_check_aes_key(debug_info, 3, key, keylen, 1)) return -EINVAL; } else { - return pkey_nonccatok2pkey(key, keylen, pkey); + return pkey_nonccatok2pkey(key, keylen, + protkey, protkeylen, + protkeytype); } } else { DEBUG_ERR("%s unknown/unsupported blob type %d\n", @@ -822,20 +972,20 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns, dom = apqns[i].domain; if (hdr->type == TOKTYPE_CCA_INTERNAL && hdr->version == TOKVER_CCA_AES) { - rc = cca_sec2protkey(card, dom, key, pkey->protkey, - &pkey->len, &pkey->type); + rc = cca_sec2protkey(card, dom, key, + protkey, protkeylen, protkeytype); } else if (hdr->type == TOKTYPE_CCA_INTERNAL && hdr->version == TOKVER_CCA_VLSC) { - rc = cca_cipher2protkey(card, dom, key, pkey->protkey, - &pkey->len, &pkey->type); + rc = cca_cipher2protkey(card, dom, key, + protkey, protkeylen, + protkeytype); } else { /* EP11 AES secure key blob */ struct ep11keyblob *kb = (struct ep11keyblob *)key; - pkey->len = sizeof(pkey->protkey); rc = ep11_kblob2protkey(card, dom, key, kb->head.len, - pkey->protkey, &pkey->len, - &pkey->type); + protkey, protkeylen, + protkeytype); } if (rc == 0) break; @@ -847,9 +997,9 @@ static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns, static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags, struct pkey_apqn *apqns, size_t *nr_apqns) { - int rc; - u32 _nr_apqns, *_apqns = NULL; struct keytoken_header *hdr = (struct keytoken_header *)key; + u32 _nr_apqns, *_apqns = NULL; + int rc; if (keylen < sizeof(struct keytoken_header) || flags == 0) return -EINVAL; @@ -860,9 +1010,9 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags, (hdr->version == TOKVER_EP11_AES_WITH_HEADER || hdr->version == TOKVER_EP11_ECC_WITH_HEADER) && is_ep11_keyblob(key + sizeof(struct ep11kblob_header))) { - int minhwtype = 0, api = 0; struct ep11keyblob *kb = (struct ep11keyblob *) (key + sizeof(struct ep11kblob_header)); + int minhwtype = 0, api = 0; if (flags != PKEY_FLAGS_MATCH_CUR_MKVP) return -EINVAL; @@ -877,8 +1027,8 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags, } else if (hdr->type == TOKTYPE_NON_CCA && hdr->version == TOKVER_EP11_AES && is_ep11_keyblob(key)) { - int minhwtype = 0, api = 0; struct ep11keyblob *kb = (struct ep11keyblob *)key; + int minhwtype = 0, api = 0; if (flags != PKEY_FLAGS_MATCH_CUR_MKVP) return -EINVAL; @@ -891,8 +1041,8 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags, if (rc) goto out; } else if (hdr->type == TOKTYPE_CCA_INTERNAL) { - int minhwtype = ZCRYPT_CEX3C; u64 cur_mkvp = 0, old_mkvp = 0; + int minhwtype = ZCRYPT_CEX3C; if (hdr->version == TOKVER_CCA_AES) { struct secaeskeytoken *t = (struct secaeskeytoken *)key; @@ -919,8 +1069,8 @@ static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags, if (rc) goto out; } else if (hdr->type == TOKTYPE_CCA_INTERNAL_PKA) { - u64 cur_mkvp = 0, old_mkvp = 0; struct eccprivkeytoken *t = (struct eccprivkeytoken *)key; + u64 cur_mkvp = 0, old_mkvp = 0; if (t->secid == 0x20) { if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) @@ -957,8 +1107,8 @@ static int pkey_apqns4keytype(enum pkey_key_type ktype, u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, struct pkey_apqn *apqns, size_t *nr_apqns) { - int rc; u32 _nr_apqns, *_apqns = NULL; + int rc; zcrypt_wait_api_operational(); @@ -1020,11 +1170,11 @@ out: } static int pkey_keyblob2pkey3(const struct pkey_apqn *apqns, size_t nr_apqns, - const u8 *key, size_t keylen, u32 *protkeytype, - u8 *protkey, u32 *protkeylen) + const u8 *key, size_t keylen, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) { - int i, card, dom, rc; struct keytoken_header *hdr = (struct keytoken_header *)key; + int i, card, dom, rc; /* check for at least one apqn given */ if (!apqns || !nr_apqns) @@ -1076,15 +1226,8 @@ static int pkey_keyblob2pkey3(const struct pkey_apqn *apqns, size_t nr_apqns, if (cca_check_sececckeytoken(debug_info, 3, key, keylen, 1)) return -EINVAL; } else if (hdr->type == TOKTYPE_NON_CCA) { - struct pkey_protkey pkey; - - rc = pkey_nonccatok2pkey(key, keylen, &pkey); - if (rc) - return rc; - memcpy(protkey, pkey.protkey, pkey.len); - *protkeylen = pkey.len; - *protkeytype = pkey.type; - return 0; + return pkey_nonccatok2pkey(key, keylen, + protkey, protkeylen, protkeytype); } else { DEBUG_ERR("%s unknown/unsupported blob type %d\n", __func__, hdr->type); @@ -1130,7 +1273,7 @@ static int pkey_keyblob2pkey3(const struct pkey_apqn *apqns, size_t nr_apqns, static void *_copy_key_from_user(void __user *ukey, size_t keylen) { - if (!ukey || keylen < MINKEYBLOBSIZE || keylen > KEYBLOBBUFSIZE) + if (!ukey || keylen < MINKEYBLOBBUFSIZE || keylen > KEYBLOBBUFSIZE) return ERR_PTR(-EINVAL); return memdup_user(ukey, keylen); @@ -1187,6 +1330,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&ksp, usp, sizeof(ksp))) return -EFAULT; + ksp.protkey.len = sizeof(ksp.protkey.protkey); rc = cca_sec2protkey(ksp.cardnr, ksp.domain, ksp.seckey.seckey, ksp.protkey.protkey, &ksp.protkey.len, &ksp.protkey.type); @@ -1203,8 +1347,10 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&kcp, ucp, sizeof(kcp))) return -EFAULT; - rc = pkey_clr2protkey(kcp.keytype, - &kcp.clrkey, &kcp.protkey); + kcp.protkey.len = sizeof(kcp.protkey.protkey); + rc = pkey_clr2protkey(kcp.keytype, kcp.clrkey.clrkey, + kcp.protkey.protkey, + &kcp.protkey.len, &kcp.protkey.type); DEBUG_DBG("%s pkey_clr2protkey()=%d\n", __func__, rc); if (rc) break; @@ -1234,7 +1380,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&ksp, usp, sizeof(ksp))) return -EFAULT; - rc = pkey_skey2pkey(ksp.seckey.seckey, &ksp.protkey); + ksp.protkey.len = sizeof(ksp.protkey.protkey); + rc = pkey_skey2pkey(ksp.seckey.seckey, ksp.protkey.protkey, + &ksp.protkey.len, &ksp.protkey.type); DEBUG_DBG("%s pkey_skey2pkey()=%d\n", __func__, rc); if (rc) break; @@ -1263,7 +1411,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&kgp, ugp, sizeof(kgp))) return -EFAULT; - rc = pkey_genprotkey(kgp.keytype, &kgp.protkey); + kgp.protkey.len = sizeof(kgp.protkey.protkey); + rc = pkey_genprotkey(kgp.keytype, kgp.protkey.protkey, + &kgp.protkey.len, &kgp.protkey.type); DEBUG_DBG("%s pkey_genprotkey()=%d\n", __func__, rc); if (rc) break; @@ -1277,7 +1427,8 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&kvp, uvp, sizeof(kvp))) return -EFAULT; - rc = pkey_verifyprotkey(&kvp.protkey); + rc = pkey_verifyprotkey(kvp.protkey.protkey, + kvp.protkey.len, kvp.protkey.type); DEBUG_DBG("%s pkey_verifyprotkey()=%d\n", __func__, rc); break; } @@ -1291,8 +1442,11 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, kkey = _copy_key_from_user(ktp.key, ktp.keylen); if (IS_ERR(kkey)) return PTR_ERR(kkey); - rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey); + ktp.protkey.len = sizeof(ktp.protkey.protkey); + rc = pkey_keyblob2pkey(kkey, ktp.keylen, ktp.protkey.protkey, + &ktp.protkey.len, &ktp.protkey.type); DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc); + memzero_explicit(kkey, ktp.keylen); kfree(kkey); if (rc) break; @@ -1302,9 +1456,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, } case PKEY_GENSECK2: { struct pkey_genseck2 __user *ugs = (void __user *)arg; + size_t klen = KEYBLOBBUFSIZE; struct pkey_genseck2 kgs; struct pkey_apqn *apqns; - size_t klen = KEYBLOBBUFSIZE; u8 *kkey; if (copy_from_user(&kgs, ugs, sizeof(kgs))) @@ -1344,9 +1498,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, } case PKEY_CLR2SECK2: { struct pkey_clr2seck2 __user *ucs = (void __user *)arg; + size_t klen = KEYBLOBBUFSIZE; struct pkey_clr2seck2 kcs; struct pkey_apqn *apqns; - size_t klen = KEYBLOBBUFSIZE; u8 *kkey; if (copy_from_user(&kcs, ucs, sizeof(kcs))) @@ -1408,8 +1562,8 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, } case PKEY_KBLOB2PROTK2: { struct pkey_kblob2pkey2 __user *utp = (void __user *)arg; - struct pkey_kblob2pkey2 ktp; struct pkey_apqn *apqns = NULL; + struct pkey_kblob2pkey2 ktp; u8 *kkey; if (copy_from_user(&ktp, utp, sizeof(ktp))) @@ -1422,10 +1576,14 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, kfree(apqns); return PTR_ERR(kkey); } + ktp.protkey.len = sizeof(ktp.protkey.protkey); rc = pkey_keyblob2pkey2(apqns, ktp.apqn_entries, - kkey, ktp.keylen, &ktp.protkey); + kkey, ktp.keylen, + ktp.protkey.protkey, &ktp.protkey.len, + &ktp.protkey.type); DEBUG_DBG("%s pkey_keyblob2pkey2()=%d\n", __func__, rc); kfree(apqns); + memzero_explicit(kkey, ktp.keylen); kfree(kkey); if (rc) break; @@ -1435,8 +1593,8 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, } case PKEY_APQNS4K: { struct pkey_apqns4key __user *uak = (void __user *)arg; - struct pkey_apqns4key kak; struct pkey_apqn *apqns = NULL; + struct pkey_apqns4key kak; size_t nr_apqns, len; u8 *kkey; @@ -1484,8 +1642,8 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, } case PKEY_APQNS4KT: { struct pkey_apqns4keytype __user *uat = (void __user *)arg; - struct pkey_apqns4keytype kat; struct pkey_apqn *apqns = NULL; + struct pkey_apqns4keytype kat; size_t nr_apqns, len; if (copy_from_user(&kat, uat, sizeof(kat))) @@ -1526,9 +1684,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, } case PKEY_KBLOB2PROTK3: { struct pkey_kblob2pkey3 __user *utp = (void __user *)arg; - struct pkey_kblob2pkey3 ktp; - struct pkey_apqn *apqns = NULL; u32 protkeylen = PROTKEYBLOBBUFSIZE; + struct pkey_apqn *apqns = NULL; + struct pkey_kblob2pkey3 ktp; u8 *kkey, *protkey; if (copy_from_user(&ktp, utp, sizeof(ktp))) @@ -1547,11 +1705,12 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, kfree(kkey); return -ENOMEM; } - rc = pkey_keyblob2pkey3(apqns, ktp.apqn_entries, kkey, - ktp.keylen, &ktp.pkeytype, - protkey, &protkeylen); + rc = pkey_keyblob2pkey3(apqns, ktp.apqn_entries, + kkey, ktp.keylen, + protkey, &protkeylen, &ktp.pkeytype); DEBUG_DBG("%s pkey_keyblob2pkey3()=%d\n", __func__, rc); kfree(apqns); + memzero_explicit(kkey, ktp.keylen); kfree(kkey); if (rc) { kfree(protkey); @@ -1609,7 +1768,9 @@ static ssize_t pkey_protkey_aes_attr_read(u32 keytype, bool is_xts, char *buf, protkeytoken.version = TOKVER_PROTECTED_KEY; protkeytoken.keytype = keytype; - rc = pkey_genprotkey(protkeytoken.keytype, &protkey); + protkey.len = sizeof(protkey.protkey); + rc = pkey_genprotkey(protkeytoken.keytype, + protkey.protkey, &protkey.len, &protkey.type); if (rc) return rc; @@ -1619,7 +1780,10 @@ static ssize_t pkey_protkey_aes_attr_read(u32 keytype, bool is_xts, char *buf, memcpy(buf, &protkeytoken, sizeof(protkeytoken)); if (is_xts) { - rc = pkey_genprotkey(protkeytoken.keytype, &protkey); + /* xts needs a second protected key, reuse protkey struct */ + protkey.len = sizeof(protkey.protkey); + rc = pkey_genprotkey(protkeytoken.keytype, + protkey.protkey, &protkey.len, &protkey.type); if (rc) return rc; @@ -1714,8 +1878,8 @@ static struct attribute_group protkey_attr_group = { static ssize_t pkey_ccadata_aes_attr_read(u32 keytype, bool is_xts, char *buf, loff_t off, size_t count) { - int rc; struct pkey_seckey *seckey = (struct pkey_seckey *)buf; + int rc; if (off != 0 || count < sizeof(struct secaeskeytoken)) return -EINVAL; @@ -1821,9 +1985,9 @@ static ssize_t pkey_ccacipher_aes_attr_read(enum pkey_key_size keybits, bool is_xts, char *buf, loff_t off, size_t count) { - int i, rc, card, dom; - u32 nr_apqns, *apqns = NULL; size_t keysize = CCACIPHERTOKENSIZE; + u32 nr_apqns, *apqns = NULL; + int i, rc, card, dom; if (off != 0 || count < CCACIPHERTOKENSIZE) return -EINVAL; @@ -1944,9 +2108,9 @@ static ssize_t pkey_ep11_aes_attr_read(enum pkey_key_size keybits, bool is_xts, char *buf, loff_t off, size_t count) { - int i, rc, card, dom; - u32 nr_apqns, *apqns = NULL; size_t keysize = MAXEP11AESKEYBLOBSIZE; + u32 nr_apqns, *apqns = NULL; + int i, rc, card, dom; if (off != 0 || count < MAXEP11AESKEYBLOBSIZE) return -EINVAL; diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index cfbcb864ab63..a8f58e133e6e 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -716,6 +716,7 @@ static int vfio_ap_mdev_probe(struct mdev_device *mdev) ret = vfio_register_emulated_iommu_dev(&matrix_mdev->vdev); if (ret) goto err_put_vdev; + matrix_mdev->req_trigger = NULL; dev_set_drvdata(&mdev->dev, matrix_mdev); mutex_lock(&matrix_dev->mdevs_lock); list_add(&matrix_mdev->node, &matrix_dev->mdev_list); @@ -1735,6 +1736,26 @@ static void vfio_ap_mdev_close_device(struct vfio_device *vdev) vfio_ap_mdev_unset_kvm(matrix_mdev); } +static void vfio_ap_mdev_request(struct vfio_device *vdev, unsigned int count) +{ + struct device *dev = vdev->dev; + struct ap_matrix_mdev *matrix_mdev; + + matrix_mdev = container_of(vdev, struct ap_matrix_mdev, vdev); + + if (matrix_mdev->req_trigger) { + if (!(count % 10)) + dev_notice_ratelimited(dev, + "Relaying device request to user (#%u)\n", + count); + + eventfd_signal(matrix_mdev->req_trigger, 1); + } else if (count == 0) { + dev_notice(dev, + "No device request registered, blocked until released by user\n"); + } +} + static int vfio_ap_mdev_get_device_info(unsigned long arg) { unsigned long minsz; @@ -1750,11 +1771,115 @@ static int vfio_ap_mdev_get_device_info(unsigned long arg) info.flags = VFIO_DEVICE_FLAGS_AP | VFIO_DEVICE_FLAGS_RESET; info.num_regions = 0; - info.num_irqs = 0; + info.num_irqs = VFIO_AP_NUM_IRQS; return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0; } +static ssize_t vfio_ap_get_irq_info(unsigned long arg) +{ + unsigned long minsz; + struct vfio_irq_info info; + + minsz = offsetofend(struct vfio_irq_info, count); + + if (copy_from_user(&info, (void __user *)arg, minsz)) + return -EFAULT; + + if (info.argsz < minsz || info.index >= VFIO_AP_NUM_IRQS) + return -EINVAL; + + switch (info.index) { + case VFIO_AP_REQ_IRQ_INDEX: + info.count = 1; + info.flags = VFIO_IRQ_INFO_EVENTFD; + break; + default: + return -EINVAL; + } + + return copy_to_user((void __user *)arg, &info, minsz) ? -EFAULT : 0; +} + +static int vfio_ap_irq_set_init(struct vfio_irq_set *irq_set, unsigned long arg) +{ + int ret; + size_t data_size; + unsigned long minsz; + + minsz = offsetofend(struct vfio_irq_set, count); + + if (copy_from_user(irq_set, (void __user *)arg, minsz)) + return -EFAULT; + + ret = vfio_set_irqs_validate_and_prepare(irq_set, 1, VFIO_AP_NUM_IRQS, + &data_size); + if (ret) + return ret; + + if (!(irq_set->flags & VFIO_IRQ_SET_ACTION_TRIGGER)) + return -EINVAL; + + return 0; +} + +static int vfio_ap_set_request_irq(struct ap_matrix_mdev *matrix_mdev, + unsigned long arg) +{ + s32 fd; + void __user *data; + unsigned long minsz; + struct eventfd_ctx *req_trigger; + + minsz = offsetofend(struct vfio_irq_set, count); + data = (void __user *)(arg + minsz); + + if (get_user(fd, (s32 __user *)data)) + return -EFAULT; + + if (fd == -1) { + if (matrix_mdev->req_trigger) + eventfd_ctx_put(matrix_mdev->req_trigger); + matrix_mdev->req_trigger = NULL; + } else if (fd >= 0) { + req_trigger = eventfd_ctx_fdget(fd); + if (IS_ERR(req_trigger)) + return PTR_ERR(req_trigger); + + if (matrix_mdev->req_trigger) + eventfd_ctx_put(matrix_mdev->req_trigger); + + matrix_mdev->req_trigger = req_trigger; + } else { + return -EINVAL; + } + + return 0; +} + +static int vfio_ap_set_irqs(struct ap_matrix_mdev *matrix_mdev, + unsigned long arg) +{ + int ret; + struct vfio_irq_set irq_set; + + ret = vfio_ap_irq_set_init(&irq_set, arg); + if (ret) + return ret; + + switch (irq_set.flags & VFIO_IRQ_SET_DATA_TYPE_MASK) { + case VFIO_IRQ_SET_DATA_EVENTFD: + switch (irq_set.index) { + case VFIO_AP_REQ_IRQ_INDEX: + return vfio_ap_set_request_irq(matrix_mdev, arg); + default: + return -EINVAL; + } + default: + return -EINVAL; + } +} + static ssize_t vfio_ap_mdev_ioctl(struct vfio_device *vdev, unsigned int cmd, unsigned long arg) { @@ -1770,6 +1895,12 @@ static ssize_t vfio_ap_mdev_ioctl(struct vfio_device *vdev, case VFIO_DEVICE_RESET: ret = vfio_ap_mdev_reset_queues(&matrix_mdev->qtable); break; + case VFIO_DEVICE_GET_IRQ_INFO: + ret = vfio_ap_get_irq_info(arg); + break; + case VFIO_DEVICE_SET_IRQS: + ret = vfio_ap_set_irqs(matrix_mdev, arg); + break; default: ret = -EOPNOTSUPP; break; @@ -1844,6 +1975,7 @@ static const struct vfio_device_ops vfio_ap_matrix_dev_ops = { .bind_iommufd = vfio_iommufd_emulated_bind, .unbind_iommufd = vfio_iommufd_emulated_unbind, .attach_ioas = vfio_iommufd_emulated_attach_ioas, + .request = vfio_ap_mdev_request }; static struct mdev_driver vfio_ap_matrix_driver = { diff --git a/drivers/s390/crypto/vfio_ap_private.h b/drivers/s390/crypto/vfio_ap_private.h index 976a65f32e7d..4642bbdbd1b2 100644 --- a/drivers/s390/crypto/vfio_ap_private.h +++ b/drivers/s390/crypto/vfio_ap_private.h @@ -15,6 +15,7 @@ #include <linux/types.h> #include <linux/mdev.h> #include <linux/delay.h> +#include <linux/eventfd.h> #include <linux/mutex.h> #include <linux/kvm_host.h> #include <linux/vfio.h> @@ -103,6 +104,7 @@ struct ap_queue_table { * PQAP(AQIC) instruction. * @mdev: the mediated device * @qtable: table of queues (struct vfio_ap_queue) assigned to the mdev + * @req_trigger eventfd ctx for signaling userspace to return a device * @apm_add: bitmap of APIDs added to the host's AP configuration * @aqm_add: bitmap of APQIs added to the host's AP configuration * @adm_add: bitmap of control domain numbers added to the host's AP @@ -117,6 +119,7 @@ struct ap_matrix_mdev { crypto_hook pqap_hook; struct mdev_device *mdev; struct ap_queue_table qtable; + struct eventfd_ctx *req_trigger; DECLARE_BITMAP(apm_add, AP_DEVICES); DECLARE_BITMAP(aqm_add, AP_DOMAINS); DECLARE_BITMAP(adm_add, AP_DOMAINS); diff --git a/drivers/s390/net/ctcm_dbug.c b/drivers/s390/net/ctcm_dbug.c index f7ec51db3cd6..b6f0e2f114b4 100644 --- a/drivers/s390/net/ctcm_dbug.c +++ b/drivers/s390/net/ctcm_dbug.c @@ -70,7 +70,7 @@ void ctcm_dbf_longtext(enum ctcm_dbf_names dbf_nix, int level, char *fmt, ...) if (!debug_level_enabled(ctcm_dbf[dbf_nix].id, level)) return; va_start(args, fmt); - vsnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args); + vscnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args); va_end(args); debug_text_event(ctcm_dbf[dbf_nix].id, level, dbf_txt_buf); diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 28db69d91f17..6faf27136024 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -1333,7 +1333,7 @@ static int add_channel(struct ccw_device *cdev, enum ctcm_channel_types type, goto nomem_return; ch->cdev = cdev; - snprintf(ch->id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev->dev)); + scnprintf(ch->id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev->dev)); ch->type = type; /* @@ -1498,8 +1498,8 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) type = get_channel_type(&cdev0->id); - snprintf(read_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev0->dev)); - snprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev)); + scnprintf(read_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev0->dev)); + scnprintf(write_id, CTCM_ID_SIZE, "ch-%s", dev_name(&cdev1->dev)); ret = add_channel(cdev0, type, priv); if (ret) { diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h index 90bd7b3f80c3..25164e8bf13d 100644 --- a/drivers/s390/net/ctcm_main.h +++ b/drivers/s390/net/ctcm_main.h @@ -100,6 +100,7 @@ enum ctcm_channel_types { #define CTCM_PROTO_MPC 4 #define CTCM_PROTO_MAX 4 +#define CTCM_STATSIZE_LIMIT 64 #define CTCM_BUFSIZE_LIMIT 65535 #define CTCM_BUFSIZE_DEFAULT 32768 #define MPC_BUFSIZE_DEFAULT CTCM_BUFSIZE_LIMIT diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c index b8a226c6e1a9..c44ba88f9f47 100644 --- a/drivers/s390/net/ctcm_mpc.c +++ b/drivers/s390/net/ctcm_mpc.c @@ -144,9 +144,9 @@ void ctcmpc_dumpit(char *buf, int len) for (ct = 0; ct < len; ct++, ptr++, rptr++) { if (sw == 0) { - sprintf(addr, "%16.16llx", (__u64)rptr); + scnprintf(addr, sizeof(addr), "%16.16llx", (__u64)rptr); - sprintf(boff, "%4.4X", (__u32)ct); + scnprintf(boff, sizeof(boff), "%4.4X", (__u32)ct); bhex[0] = '\0'; basc[0] = '\0'; } @@ -155,7 +155,7 @@ void ctcmpc_dumpit(char *buf, int len) if (sw == 8) strcat(bhex, " "); - sprintf(tbuf, "%2.2llX", (__u64)*ptr); + scnprintf(tbuf, sizeof(tbuf), "%2.2llX", (__u64)*ptr); tbuf[2] = '\0'; strcat(bhex, tbuf); @@ -171,8 +171,8 @@ void ctcmpc_dumpit(char *buf, int len) continue; if ((strcmp(duphex, bhex)) != 0) { if (dup != 0) { - sprintf(tdup, - "Duplicate as above to %s", addr); + scnprintf(tdup, sizeof(tdup), + "Duplicate as above to %s", addr); ctcm_pr_debug(" --- %s ---\n", tdup); } @@ -197,14 +197,16 @@ void ctcmpc_dumpit(char *buf, int len) strcat(basc, " "); } if (dup != 0) { - sprintf(tdup, "Duplicate as above to %s", addr); + scnprintf(tdup, sizeof(tdup), + "Duplicate as above to %s", addr); ctcm_pr_debug(" --- %s ---\n", tdup); } ctcm_pr_debug(" %s (+%s) : %s [%s]\n", addr, boff, bhex, basc); } else { if (dup >= 1) { - sprintf(tdup, "Duplicate as above to %s", addr); + scnprintf(tdup, sizeof(tdup), + "Duplicate as above to %s", addr); ctcm_pr_debug(" --- %s ---\n", tdup); } if (dup != 0) { @@ -291,7 +293,7 @@ static struct net_device *ctcmpc_get_dev(int port_num) struct net_device *dev; struct ctcm_priv *priv; - sprintf(device, "%s%i", MPC_DEVICE_NAME, port_num); + scnprintf(device, sizeof(device), "%s%i", MPC_DEVICE_NAME, port_num); dev = __dev_get_by_name(&init_net, device); diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c index e3813a7aa5e6..0c5d8a3eaa2e 100644 --- a/drivers/s390/net/ctcm_sysfs.c +++ b/drivers/s390/net/ctcm_sysfs.c @@ -28,7 +28,7 @@ static ssize_t ctcm_buffer_show(struct device *dev, if (!priv) return -ENODEV; - return sprintf(buf, "%d\n", priv->buffer_size); + return sysfs_emit(buf, "%d\n", priv->buffer_size); } static ssize_t ctcm_buffer_write(struct device *dev, @@ -86,24 +86,24 @@ static void ctcm_print_statistics(struct ctcm_priv *priv) return; p = sbuf; - p += sprintf(p, " Device FSM state: %s\n", - fsm_getstate_str(priv->fsm)); - p += sprintf(p, " RX channel FSM state: %s\n", - fsm_getstate_str(priv->channel[CTCM_READ]->fsm)); - p += sprintf(p, " TX channel FSM state: %s\n", - fsm_getstate_str(priv->channel[CTCM_WRITE]->fsm)); - p += sprintf(p, " Max. TX buffer used: %ld\n", - priv->channel[WRITE]->prof.maxmulti); - p += sprintf(p, " Max. chained SKBs: %ld\n", - priv->channel[WRITE]->prof.maxcqueue); - p += sprintf(p, " TX single write ops: %ld\n", - priv->channel[WRITE]->prof.doios_single); - p += sprintf(p, " TX multi write ops: %ld\n", - priv->channel[WRITE]->prof.doios_multi); - p += sprintf(p, " Netto bytes written: %ld\n", - priv->channel[WRITE]->prof.txlen); - p += sprintf(p, " Max. TX IO-time: %u\n", - jiffies_to_usecs(priv->channel[WRITE]->prof.tx_time)); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Device FSM state: %s\n", + fsm_getstate_str(priv->fsm)); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " RX channel FSM state: %s\n", + fsm_getstate_str(priv->channel[CTCM_READ]->fsm)); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " TX channel FSM state: %s\n", + fsm_getstate_str(priv->channel[CTCM_WRITE]->fsm)); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Max. TX buffer used: %ld\n", + priv->channel[WRITE]->prof.maxmulti); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Max. chained SKBs: %ld\n", + priv->channel[WRITE]->prof.maxcqueue); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " TX single write ops: %ld\n", + priv->channel[WRITE]->prof.doios_single); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " TX multi write ops: %ld\n", + priv->channel[WRITE]->prof.doios_multi); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Netto bytes written: %ld\n", + priv->channel[WRITE]->prof.txlen); + p += scnprintf(p, CTCM_STATSIZE_LIMIT, " Max. TX IO-time: %u\n", + jiffies_to_usecs(priv->channel[WRITE]->prof.tx_time)); printk(KERN_INFO "Statistics for %s:\n%s", priv->channel[CTCM_WRITE]->netdev->name, sbuf); @@ -120,7 +120,7 @@ static ssize_t stats_show(struct device *dev, if (!priv || gdev->state != CCWGROUP_ONLINE) return -ENODEV; ctcm_print_statistics(priv); - return sprintf(buf, "0\n"); + return sysfs_emit(buf, "0\n"); } static ssize_t stats_write(struct device *dev, struct device_attribute *attr, @@ -142,7 +142,7 @@ static ssize_t ctcm_proto_show(struct device *dev, if (!priv) return -ENODEV; - return sprintf(buf, "%d\n", priv->protocol); + return sysfs_emit(buf, "%d\n", priv->protocol); } static ssize_t ctcm_proto_store(struct device *dev, @@ -184,8 +184,8 @@ static ssize_t ctcm_type_show(struct device *dev, if (!cgdev) return -ENODEV; - return sprintf(buf, "%s\n", - ctcm_type[cgdev->cdev[0]->id.driver_info]); + return sysfs_emit(buf, "%s\n", + ctcm_type[cgdev->cdev[0]->id.driver_info]); } static DEVICE_ATTR(buffer, 0644, ctcm_buffer_show, ctcm_buffer_write); diff --git a/drivers/s390/net/ism_drv.c b/drivers/s390/net/ism_drv.c index 8acb9eba691b..9b5fccdbc7d6 100644 --- a/drivers/s390/net/ism_drv.c +++ b/drivers/s390/net/ism_drv.c @@ -660,7 +660,7 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto err_disable; - ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (ret) goto err_resource; @@ -771,14 +771,6 @@ static int __init ism_init(void) static void __exit ism_exit(void) { - struct ism_dev *ism; - - mutex_lock(&ism_dev_list.mutex); - list_for_each_entry(ism, &ism_dev_list.list, list) { - ism_dev_exit(ism); - } - mutex_unlock(&ism_dev_list.mutex); - pci_unregister_driver(&ism_driver); debug_unregister(ism_debug_info); } diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 38f312664ce7..9fd8e6f07a03 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1899,14 +1899,14 @@ lcs_open_device(struct net_device *dev) static ssize_t lcs_portno_show (struct device *dev, struct device_attribute *attr, char *buf) { - struct lcs_card *card; + struct lcs_card *card; card = dev_get_drvdata(dev); - if (!card) - return 0; + if (!card) + return 0; - return sprintf(buf, "%d\n", card->portno); + return sysfs_emit(buf, "%d\n", card->portno); } /* @@ -1956,7 +1956,8 @@ lcs_type_show(struct device *dev, struct device_attribute *attr, char *buf) if (!cgdev) return -ENODEV; - return sprintf(buf, "%s\n", lcs_type[cgdev->cdev[0]->id.driver_info]); + return sysfs_emit(buf, "%s\n", + lcs_type[cgdev->cdev[0]->id.driver_info]); } static DEVICE_ATTR(type, 0444, lcs_type_show, NULL); @@ -1968,7 +1969,7 @@ lcs_timeout_show(struct device *dev, struct device_attribute *attr, char *buf) card = dev_get_drvdata(dev); - return card ? sprintf(buf, "%u\n", card->lancmd_timeout) : 0; + return card ? sysfs_emit(buf, "%u\n", card->lancmd_timeout) : 0; } static ssize_t diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index bd52caa3b11b..a2699b70b050 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h @@ -21,7 +21,7 @@ do { \ #define LCS_DBF_TEXT_(level,name,text...) \ do { \ if (debug_level_enabled(lcs_dbf_##name, level)) { \ - sprintf(debug_buffer, text); \ + scnprintf(debug_buffer, sizeof(debug_buffer), text); \ debug_text_event(lcs_dbf_##name, level, debug_buffer); \ } \ } while (0) |