Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 91f3e3ea authored by Ingo Tuchscherer's avatar Ingo Tuchscherer Committed by Martin Schwidefsky
Browse files

s390/zcrypt: add support for EP11 coprocessor cards



This feature extends the generic cryptographic device driver (zcrypt)
with a new capability to service EP11 requests for the Crypto Express4S
card in EP11 (Enterprise PKCS#11 mode) coprocessor mode.

Signed-off-by: default avatarIngo Tuchscherer <ingo.tuchscherer@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 9efe4f29
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
/*?
 * Text: "Cryptographic device %x failed and was set offline\n"
 * Severity: Error
 * Parameter:
 *   @1: device index
 * Description:
 * A cryptographic device failed to process a cryptographic request.
 * The cryptographic device driver could not correct the error and
 * set the device offline. The application that issued the
 * request received an indication that the request has failed.
 * User action:
 * Use the lszcrypt command to confirm that the cryptographic
 * hardware is still configured to your LPAR or z/VM guest virtual
 * machine. If the device is available to your Linux instance the
 * command output contains a line that begins with 'card<device index>',
 * where <device index> is the two-digit decimal number in the message text.
 * After ensuring that the device is available, use the chzcrypt command to
 * set it online again.
 * If the error persists, contact your support organization.
 */
+65 −0
Original line number Diff line number Diff line
@@ -154,6 +154,67 @@ struct ica_xcRB {
	unsigned short	priority_window;
	unsigned int	status;
} __attribute__((packed));

/**
 * struct ep11_cprb - EP11 connectivity programming request block
 * @cprb_len:		CPRB header length [0x0020]
 * @cprb_ver_id:	CPRB version id.   [0x04]
 * @pad_000:		Alignment pad bytes
 * @flags:		Admin cmd [0x80] or functional cmd [0x00]
 * @func_id:		Function id / subtype [0x5434]
 * @source_id:		Source id [originator id]
 * @target_id:		Target id [usage/ctrl domain id]
 * @ret_code:		Return code
 * @reserved1:		Reserved
 * @reserved2:		Reserved
 * @payload_len:	Payload length
 */
struct ep11_cprb {
	uint16_t	cprb_len;
	unsigned char	cprb_ver_id;
	unsigned char	pad_000[2];
	unsigned char	flags;
	unsigned char	func_id[2];
	uint32_t	source_id;
	uint32_t	target_id;
	uint32_t	ret_code;
	uint32_t	reserved1;
	uint32_t	reserved2;
	uint32_t	payload_len;
} __attribute__((packed));

/**
 * struct ep11_target_dev - EP11 target device list
 * @ap_id:	AP device id
 * @dom_id:	Usage domain id
 */
struct ep11_target_dev {
	uint16_t ap_id;
	uint16_t dom_id;
};

/**
 * struct ep11_urb - EP11 user request block
 * @targets_num:	Number of target adapters
 * @targets:		Addr to target adapter list
 * @weight:		Level of request priority
 * @req_no:		Request id/number
 * @req_len:		Request length
 * @req:		Addr to request block
 * @resp_len:		Response length
 * @resp:		Addr to response block
 */
struct ep11_urb {
	uint16_t		targets_num;
	uint64_t		targets;
	uint64_t		weight;
	uint64_t		req_no;
	uint64_t		req_len;
	uint64_t		req;
	uint64_t		resp_len;
	uint64_t		resp;
} __attribute__((packed));

#define AUTOSELECT ((unsigned int)0xFFFFFFFF)

#define ZCRYPT_IOCTL_MAGIC 'z'
@@ -183,6 +244,9 @@ struct ica_xcRB {
 *   ZSECSENDCPRB
 *     Send an arbitrary CPRB to a crypto card.
 *
 *   ZSENDEP11CPRB
 *     Send an arbitrary EP11 CPRB to an EP11 coprocessor crypto card.
 *
 *   Z90STAT_STATUS_MASK
 *     Return an 64 element array of unsigned chars for the status of
 *     all devices.
@@ -256,6 +320,7 @@ struct ica_xcRB {
#define ICARSAMODEXPO	_IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x05, 0)
#define ICARSACRT	_IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x06, 0)
#define ZSECSENDCPRB	_IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x81, 0)
#define ZSENDEP11CPRB	_IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x04, 0)

/* New status calls */
#define Z90STAT_TOTALCOUNT	_IOR(ZCRYPT_IOCTL_MAGIC, 0x40, int)
+30 −1
Original line number Diff line number Diff line
@@ -591,7 +591,13 @@ static int ap_init_queue(ap_qid_t qid)
		if (rc != -ENODEV && rc != -EBUSY)
			break;
		if (i < AP_MAX_RESET - 1) {
			udelay(5);
			/* Time we are waiting until we give up (0.7sec * 90).
			 * Since the actual request (in progress) will not
			 * interrupted immediately for the reset command,
			 * we have to be patient. In worst case we have to
			 * wait 60sec + reset time (some msec).
			 */
			schedule_timeout(AP_RESET_TIMEOUT);
			status = ap_test_queue(qid, &dummy, &dummy);
		}
	}
@@ -992,6 +998,28 @@ static ssize_t ap_domain_show(struct bus_type *bus, char *buf)

static BUS_ATTR(ap_domain, 0444, ap_domain_show, NULL);

static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf)
{
	if (ap_configuration != NULL) { /* QCI not supported */
		if (test_facility(76)) { /* format 1 - 256 bit domain field */
			return snprintf(buf, PAGE_SIZE,
				"0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
			ap_configuration->adm[0], ap_configuration->adm[1],
			ap_configuration->adm[2], ap_configuration->adm[3],
			ap_configuration->adm[4], ap_configuration->adm[5],
			ap_configuration->adm[6], ap_configuration->adm[7]);
		} else { /* format 0 - 16 bit domain field */
			return snprintf(buf, PAGE_SIZE, "%08x%08x\n",
			ap_configuration->adm[0], ap_configuration->adm[1]);
		  }
	} else {
		return snprintf(buf, PAGE_SIZE, "not supported\n");
	  }
}

static BUS_ATTR(ap_control_domain_mask, 0444,
		ap_control_domain_mask_show, NULL);

static ssize_t ap_config_time_show(struct bus_type *bus, char *buf)
{
	return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time);
@@ -1077,6 +1105,7 @@ static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store);

static struct bus_attribute *const ap_bus_attrs[] = {
	&bus_attr_ap_domain,
	&bus_attr_ap_control_domain_mask,
	&bus_attr_config_time,
	&bus_attr_poll_thread,
	&bus_attr_ap_interrupts,
+3 −1
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@
#define AP_DEVICES 64		/* Number of AP devices. */
#define AP_DOMAINS 16		/* Number of AP domains. */
#define AP_MAX_RESET 90		/* Maximum number of resets. */
#define AP_RESET_TIMEOUT (HZ/2)	/* Time in ticks for reset timeouts. */
#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. */

@@ -125,6 +125,8 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
#define AP_FUNC_CRT4K 2
#define AP_FUNC_COPRO 3
#define AP_FUNC_ACCEL 4
#define AP_FUNC_EP11  5
#define AP_FUNC_APXA  6

/*
 * AP reset flag states
+106 −3
Original line number Diff line number Diff line
@@ -44,6 +44,8 @@
#include "zcrypt_debug.h"
#include "zcrypt_api.h"

#include "zcrypt_msgtype6.h"

/*
 * Module description.
 */
@@ -554,9 +556,9 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB)
	spin_lock_bh(&zcrypt_device_lock);
	list_for_each_entry(zdev, &zcrypt_device_list, list) {
		if (!zdev->online || !zdev->ops->send_cprb ||
		   (zdev->ops->variant == MSGTYPE06_VARIANT_EP11) ||
		   (xcRB->user_defined != AUTOSELECT &&
			AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)
		    )
		    AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined))
			continue;
		zcrypt_device_get(zdev);
		get_device(&zdev->ap_dev->device);
@@ -581,6 +583,90 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB)
	return -ENODEV;
}

struct ep11_target_dev_list {
	unsigned short		targets_num;
	struct ep11_target_dev	*targets;
};

static bool is_desired_ep11dev(unsigned int dev_qid,
			       struct ep11_target_dev_list dev_list)
{
	int n;

	for (n = 0; n < dev_list.targets_num; n++, dev_list.targets++) {
		if ((AP_QID_DEVICE(dev_qid) == dev_list.targets->ap_id) &&
		    (AP_QID_QUEUE(dev_qid) == dev_list.targets->dom_id)) {
			return true;
		}
	}
	return false;
}

static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
{
	struct zcrypt_device *zdev;
	bool autoselect = false;
	int rc;
	struct ep11_target_dev_list ep11_dev_list = {
		.targets_num	=  0x00,
		.targets	=  NULL,
	};

	ep11_dev_list.targets_num = (unsigned short) xcrb->targets_num;

	/* empty list indicates autoselect (all available targets) */
	if (ep11_dev_list.targets_num == 0)
		autoselect = true;
	else {
		ep11_dev_list.targets = kcalloc((unsigned short)
						xcrb->targets_num,
						sizeof(struct ep11_target_dev),
						GFP_KERNEL);
		if (!ep11_dev_list.targets)
			return -ENOMEM;

		if (copy_from_user(ep11_dev_list.targets,
				   (struct ep11_target_dev *)xcrb->targets,
				   xcrb->targets_num *
				   sizeof(struct ep11_target_dev)))
			return -EFAULT;
	}

	spin_lock_bh(&zcrypt_device_lock);
	list_for_each_entry(zdev, &zcrypt_device_list, list) {
		/* check if device is eligible */
		if (!zdev->online ||
		    zdev->ops->variant != MSGTYPE06_VARIANT_EP11)
			continue;

		/* check if device is selected as valid target */
		if (!is_desired_ep11dev(zdev->ap_dev->qid, ep11_dev_list) &&
		    !autoselect)
			continue;

		zcrypt_device_get(zdev);
		get_device(&zdev->ap_dev->device);
		zdev->request_count++;
		__zcrypt_decrease_preference(zdev);
		if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
			spin_unlock_bh(&zcrypt_device_lock);
			rc = zdev->ops->send_ep11_cprb(zdev, xcrb);
			spin_lock_bh(&zcrypt_device_lock);
			module_put(zdev->ap_dev->drv->driver.owner);
		} else {
			rc = -EAGAIN;
		  }
		zdev->request_count--;
		__zcrypt_increase_preference(zdev);
		put_device(&zdev->ap_dev->device);
		zcrypt_device_put(zdev);
		spin_unlock_bh(&zcrypt_device_lock);
		return rc;
	}
	spin_unlock_bh(&zcrypt_device_lock);
	return -ENODEV;
}

static long zcrypt_rng(char *buffer)
{
	struct zcrypt_device *zdev;
@@ -784,6 +870,23 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
			return -EFAULT;
		return rc;
	}
	case ZSENDEP11CPRB: {
		struct ep11_urb __user *uxcrb = (void __user *)arg;
		struct ep11_urb xcrb;
		if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb)))
			return -EFAULT;
		do {
			rc = zcrypt_send_ep11_cprb(&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);
			} while (rc == -EAGAIN);
		if (copy_to_user(uxcrb, &xcrb, sizeof(xcrb)))
			return -EFAULT;
		return rc;
	}
	case Z90STAT_STATUS_MASK: {
		char status[AP_DEVICES];
		zcrypt_status_mask(status);
Loading