aboutsummaryrefslogtreecommitdiff
path: root/drivers/s390/crypto/ap_queue.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/crypto/ap_queue.c')
-rw-r--r--drivers/s390/crypto/ap_queue.c39
1 files changed, 33 insertions, 6 deletions
diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c
index ecefc25eff0c..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;
@@ -135,12 +135,28 @@ 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->len);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
- aq->queue_count--;
+ aq->queue_count = max_t(int, 0, aq->queue_count - 1);
if (aq->queue_count > 0)
mod_timer(&aq->timeout,
jiffies + aq->request_timeout);
@@ -149,9 +165,20 @@ 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;
}
+ if (!found) {
+ AP_DBF_WARN("%s unassociated reply psmid=0x%016llx on 0x%02x.%04x\n",
+ __func__, aq->reply->psmid,
+ AP_QID_CARD(aq->qid), AP_QID_QUEUE(aq->qid));
+ }
fallthrough;
case AP_RESPONSE_NO_PENDING_REPLY:
if (!status.queue_empty || aq->queue_count <= 0)
@@ -232,7 +259,7 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq)
ap_msg->flags & AP_MSG_FLAG_SPECIAL);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
- aq->queue_count++;
+ aq->queue_count = max_t(int, 1, aq->queue_count + 1);
if (aq->queue_count == 1)
mod_timer(&aq->timeout, jiffies + aq->request_timeout);
list_move_tail(&ap_msg->list, &aq->pendingq);