diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/crypto/ap_queue.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index c5e0fe0286e5..669f96fddad6 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -101,7 +101,7 @@ int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) if (msg == NULL) return -EINVAL; - status = ap_dqap(qid, psmid, msg, length); + status = ap_dqap(qid, psmid, msg, length, NULL, NULL); switch (status.response_code) { case AP_RESPONSE_NORMAL: return 0; @@ -136,9 +136,24 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) struct ap_queue_status status; struct ap_message *ap_msg; bool found = false; + size_t reslen; + unsigned long resgr0 = 0; + int parts = 0; + + /* + * DQAP loop until response code and resgr0 indicate that + * the msg is totally received. As we use the very same buffer + * the msg is overwritten with each invocation. That's intended + * and the receiver of the msg is informed with a msg rc code + * of EMSGSIZE in such a case. + */ + do { + status = ap_dqap(aq->qid, &aq->reply->psmid, + aq->reply->msg, aq->reply->bufsize, + &reslen, &resgr0); + parts++; + } while (status.response_code == 0xFF && resgr0 != 0); - status = ap_dqap(aq->qid, &aq->reply->psmid, - aq->reply->msg, aq->reply->bufsize); switch (status.response_code) { case AP_RESPONSE_NORMAL: aq->queue_count = max_t(int, 0, aq->queue_count - 1); @@ -150,7 +165,12 @@ static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) continue; list_del_init(&ap_msg->list); aq->pendingq_count--; - ap_msg->receive(aq, ap_msg, aq->reply); + if (parts > 1) { + ap_msg->rc = -EMSGSIZE; + ap_msg->receive(aq, ap_msg, NULL); + } else { + ap_msg->receive(aq, ap_msg, aq->reply); + } found = true; break; } |