aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/crypto/zcrypt_msgtype6.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/crypto/zcrypt_msgtype6.c')
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.c403
1 files changed, 294 insertions, 109 deletions
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index f71949685ff5..957a88d5768b 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -149,6 +149,112 @@ static struct CPRBX static_cprbx = {
.func_id = {0x54, 0x32},
};
+int speed_idx_cca(int req_type)
+{
+ switch (req_type) {
+ case 0x4142:
+ case 0x4149:
+ case 0x414D:
+ case 0x4341:
+ case 0x4344:
+ case 0x4354:
+ case 0x4358:
+ case 0x444B:
+ case 0x4558:
+ case 0x4643:
+ case 0x4651:
+ case 0x4C47:
+ case 0x4C4B:
+ case 0x4C51:
+ case 0x4F48:
+ case 0x504F:
+ case 0x5053:
+ case 0x5058:
+ case 0x5343:
+ case 0x5344:
+ case 0x5345:
+ case 0x5350:
+ return LOW;
+ case 0x414B:
+ case 0x4345:
+ case 0x4349:
+ case 0x434D:
+ case 0x4847:
+ case 0x4849:
+ case 0x484D:
+ case 0x4850:
+ case 0x4851:
+ case 0x4954:
+ case 0x4958:
+ case 0x4B43:
+ case 0x4B44:
+ case 0x4B45:
+ case 0x4B47:
+ case 0x4B48:
+ case 0x4B49:
+ case 0x4B4E:
+ case 0x4B50:
+ case 0x4B52:
+ case 0x4B54:
+ case 0x4B58:
+ case 0x4D50:
+ case 0x4D53:
+ case 0x4D56:
+ case 0x4D58:
+ case 0x5044:
+ case 0x5045:
+ case 0x5046:
+ case 0x5047:
+ case 0x5049:
+ case 0x504B:
+ case 0x504D:
+ case 0x5254:
+ case 0x5347:
+ case 0x5349:
+ case 0x534B:
+ case 0x534D:
+ case 0x5356:
+ case 0x5358:
+ case 0x5443:
+ case 0x544B:
+ case 0x5647:
+ return HIGH;
+ default:
+ return MEDIUM;
+ }
+}
+
+int speed_idx_ep11(int req_type)
+{
+ switch (req_type) {
+ case 1:
+ case 2:
+ case 36:
+ case 37:
+ case 38:
+ case 39:
+ case 40:
+ return LOW;
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 26:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ return HIGH;
+ default:
+ return MEDIUM;
+ }
+}
+
+
/**
* Convert a ICAMEX message to a type6 MEX message.
*
@@ -297,9 +403,9 @@ struct type86_fmt2_msg {
struct type86_fmt2_ext fmt2;
} __packed;
-static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
- struct ap_message *ap_msg,
- struct ica_xcRB *xcRB)
+static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg,
+ struct ica_xcRB *xcRB,
+ unsigned int *fcode)
{
static struct type6_hdr static_type6_hdrX = {
.type = 0x06,
@@ -379,6 +485,8 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
memcpy(msg->hdr.function_code, function_code,
sizeof(msg->hdr.function_code));
+ *fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1];
+
if (memcmp(function_code, "US", 2) == 0)
ap_msg->special = 1;
else
@@ -392,12 +500,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
return 0;
}
-static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev,
- struct ap_message *ap_msg,
- struct ep11_urb *xcRB)
+static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg,
+ struct ep11_urb *xcRB,
+ unsigned int *fcode)
{
- unsigned int lfmt;
-
static struct type6_hdr static_type6_ep11_hdr = {
.type = 0x06,
.rqid = {0x00, 0x01},
@@ -421,7 +527,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev,
unsigned char dom_tag; /* fixed value 0x4 */
unsigned char dom_len; /* fixed value 0x4 */
unsigned int dom_val; /* domain id */
- } __packed * payload_hdr;
+ } __packed * payload_hdr = NULL;
if (CEIL4(xcRB->req_len) < xcRB->req_len)
return -EINVAL; /* overflow after alignment*/
@@ -450,36 +556,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev,
return -EFAULT;
}
- /*
- The target domain field within the cprb body/payload block will be
- replaced by the usage domain for non-management commands only.
- Therefore we check the first bit of the 'flags' parameter for
- management command indication.
- 0 - non management command
- 1 - management command
- */
- if (!((msg->cprbx.flags & 0x80) == 0x80)) {
- msg->cprbx.target_id = (unsigned int)
- AP_QID_QUEUE(zdev->ap_dev->qid);
-
- if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/
- switch (msg->pld_lenfmt & 0x03) {
- case 1:
- lfmt = 2;
- break;
- case 2:
- lfmt = 3;
- break;
- default:
- return -EINVAL;
- }
- } else {
- lfmt = 1; /* length format #1 */
- }
- payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt);
- payload_hdr->dom_val = (unsigned int)
- AP_QID_QUEUE(zdev->ap_dev->qid);
- }
+ *fcode = speed_idx_ep11(payload_hdr->func_val & 0xFFFF);
return 0;
}
@@ -989,6 +1066,36 @@ out_free:
return rc;
}
+unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
+ struct ap_message *ap_msg,
+ int *func_code)
+{
+ struct response_type resp_type = {
+ .type = PCIXCC_RESPONSE_TYPE_XCRB,
+ };
+ int rc;
+
+ ap_init_message(ap_msg);
+ ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+ if (!ap_msg->message)
+ return -ENOMEM;
+ 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);
+ if (!ap_msg->private) {
+ kzfree(ap_msg->message);
+ return -ENOMEM;
+ }
+ memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
+ rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code);
+ if (rc) {
+ kzfree(ap_msg->message);
+ kzfree(ap_msg->private);
+ }
+ return rc;
+}
+
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* device to handle a send_cprb request.
@@ -997,37 +1104,55 @@ out_free:
* @xcRB: pointer to the send_cprb request buffer
*/
static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev,
- struct ica_xcRB *xcRB)
+ struct ica_xcRB *xcRB,
+ struct ap_message *ap_msg)
{
- struct ap_message ap_msg;
- struct response_type resp_type = {
- .type = PCIXCC_RESPONSE_TYPE_XCRB,
- };
int rc;
+ struct response_type *rtype = (struct response_type *)(ap_msg->private);
- ap_init_message(&ap_msg);
- ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
- if (!ap_msg.message)
- return -ENOMEM;
- ap_msg.receive = zcrypt_msgtype6_receive;
- ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
- atomic_inc_return(&zcrypt_step);
- ap_msg.private = &resp_type;
- rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB);
- if (rc)
- goto out_free;
- init_completion(&resp_type.work);
- ap_queue_message(zdev->ap_dev, &ap_msg);
- rc = wait_for_completion_interruptible(&resp_type.work);
+ init_completion(&rtype->work);
+ ap_queue_message(zdev->ap_dev, ap_msg);
+ rc = wait_for_completion_interruptible(&rtype->work);
if (rc == 0) {
- rc = ap_msg.rc;
+ rc = ap_msg->rc;
if (rc == 0)
- rc = convert_response_xcrb(zdev, &ap_msg, xcRB);
+ rc = convert_response_xcrb(zdev, ap_msg, xcRB);
} else
/* Signal pending. */
- ap_cancel_message(zdev->ap_dev, &ap_msg);
-out_free:
- kzfree(ap_msg.message);
+ ap_cancel_message(zdev->ap_dev, ap_msg);
+
+ kzfree(ap_msg->message);
+ kzfree(ap_msg->private);
+ return rc;
+}
+
+unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
+ struct ap_message *ap_msg,
+ int *func_code)
+{
+ struct response_type resp_type = {
+ .type = PCIXCC_RESPONSE_TYPE_EP11,
+ };
+ int rc;
+
+ ap_init_message(ap_msg);
+ ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+ if (!ap_msg->message)
+ return -ENOMEM;
+ 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);
+ if (!ap_msg->private) {
+ kzfree(ap_msg->message);
+ return -ENOMEM;
+ }
+ memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
+ rc = xcrb_msg_to_type6_ep11cprb_msgx(ap_msg, xcrb, func_code);
+ if (rc) {
+ kzfree(ap_msg->message);
+ kzfree(ap_msg->private);
+ }
return rc;
}
@@ -1039,41 +1164,101 @@ out_free:
* @xcRB: pointer to the ep11 user request block
*/
static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev,
- struct ep11_urb *xcrb)
+ struct ep11_urb *xcrb,
+ struct ap_message *ap_msg)
{
- struct ap_message ap_msg;
- struct response_type resp_type = {
- .type = PCIXCC_RESPONSE_TYPE_EP11,
- };
int rc;
+ unsigned int lfmt;
+ struct response_type *rtype = (struct response_type *)(ap_msg->private);
+ struct {
+ struct type6_hdr hdr;
+ struct ep11_cprb cprbx;
+ unsigned char pld_tag; /* fixed value 0x30 */
+ unsigned char pld_lenfmt; /* payload length format */
+ } __packed * msg = ap_msg->message;
+ struct pld_hdr {
+ unsigned char func_tag; /* fixed value 0x4 */
+ unsigned char func_len; /* fixed value 0x4 */
+ unsigned int func_val; /* function ID */
+ unsigned char dom_tag; /* fixed value 0x4 */
+ unsigned char dom_len; /* fixed value 0x4 */
+ unsigned int dom_val; /* domain id */
+ } __packed * payload_hdr = NULL;
- ap_init_message(&ap_msg);
- ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
- if (!ap_msg.message)
- return -ENOMEM;
- ap_msg.receive = zcrypt_msgtype6_receive_ep11;
- ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
- atomic_inc_return(&zcrypt_step);
- ap_msg.private = &resp_type;
- rc = xcrb_msg_to_type6_ep11cprb_msgx(zdev, &ap_msg, xcrb);
- if (rc)
- goto out_free;
- init_completion(&resp_type.work);
- ap_queue_message(zdev->ap_dev, &ap_msg);
- rc = wait_for_completion_interruptible(&resp_type.work);
+
+ /**
+ * The target domain field within the cprb body/payload block will be
+ * replaced by the usage domain for non-management commands only.
+ * Therefore we check the first bit of the 'flags' parameter for
+ * management command indication.
+ * 0 - non management command
+ * 1 - management command
+ */
+ if (!((msg->cprbx.flags & 0x80) == 0x80)) {
+ msg->cprbx.target_id = (unsigned int)
+ AP_QID_QUEUE(zdev->ap_dev->qid);
+
+ if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/
+ switch (msg->pld_lenfmt & 0x03) {
+ case 1:
+ lfmt = 2;
+ break;
+ case 2:
+ lfmt = 3;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ lfmt = 1; /* length format #1 */
+ }
+ payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt);
+ payload_hdr->dom_val = (unsigned int)
+ AP_QID_QUEUE(zdev->ap_dev->qid);
+ }
+
+ init_completion(&rtype->work);
+ ap_queue_message(zdev->ap_dev, ap_msg);
+ rc = wait_for_completion_interruptible(&rtype->work);
if (rc == 0) {
- rc = ap_msg.rc;
+ rc = ap_msg->rc;
if (rc == 0)
- rc = convert_response_ep11_xcrb(zdev, &ap_msg, xcrb);
+ rc = convert_response_ep11_xcrb(zdev, ap_msg, xcrb);
} else
/* Signal pending. */
- ap_cancel_message(zdev->ap_dev, &ap_msg);
+ ap_cancel_message(zdev->ap_dev, ap_msg);
-out_free:
- kzfree(ap_msg.message);
+ kzfree(ap_msg->message);
+ kzfree(ap_msg->private);
return rc;
}
+unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code)
+{
+ struct response_type resp_type = {
+ .type = PCIXCC_RESPONSE_TYPE_XCRB,
+ };
+
+ ap_init_message(ap_msg);
+ ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
+ if (!ap_msg->message)
+ return -ENOMEM;
+ 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);
+ if (!ap_msg->private) {
+ kzfree(ap_msg->message);
+ return -ENOMEM;
+ }
+ memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
+
+ rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE);
+
+ *func_code = HWRNG;
+ return 0;
+}
+
/**
* The request distributor calls this function if it picked the PCIXCC/CEX2C
* device to generate random data.
@@ -1081,36 +1266,36 @@ out_free:
* PCIXCC/CEX2C device to the request distributor
* @buffer: pointer to a memory page to return random data
*/
-
static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev,
- char *buffer)
+ char *buffer, struct ap_message *ap_msg)
{
- struct ap_message ap_msg;
- struct response_type resp_type = {
- .type = PCIXCC_RESPONSE_TYPE_XCRB,
- };
+ struct {
+ struct type6_hdr hdr;
+ struct CPRBX cprbx;
+ char function_code[2];
+ short int rule_length;
+ char rule[8];
+ short int verb_length;
+ short int key_length;
+ } __packed * msg = ap_msg->message;
+ struct response_type *rtype = (struct response_type *)(ap_msg->private);
int rc;
- ap_init_message(&ap_msg);
- ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
- if (!ap_msg.message)
- return -ENOMEM;
- ap_msg.receive = zcrypt_msgtype6_receive;
- ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
- atomic_inc_return(&zcrypt_step);
- ap_msg.private = &resp_type;
- rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE);
- init_completion(&resp_type.work);
- ap_queue_message(zdev->ap_dev, &ap_msg);
- rc = wait_for_completion_interruptible(&resp_type.work);
+ msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
+
+ init_completion(&rtype->work);
+ ap_queue_message(zdev->ap_dev, ap_msg);
+ rc = wait_for_completion_interruptible(&rtype->work);
if (rc == 0) {
- rc = ap_msg.rc;
+ rc = ap_msg->rc;
if (rc == 0)
- rc = convert_response_rng(zdev, &ap_msg, buffer);
+ rc = convert_response_rng(zdev, ap_msg, buffer);
} else
/* Signal pending. */
- ap_cancel_message(zdev->ap_dev, &ap_msg);
- kfree(ap_msg.message);
+ ap_cancel_message(zdev->ap_dev, ap_msg);
+
+ kzfree(ap_msg->message);
+ kzfree(ap_msg->private);
return rc;
}