Skip to content

Commit f3d26ce

Browse files
julianwiedmanngregkh
authored andcommitted
s390/qeth: fix IPA command submission race
[ Upstream commit d22ffb5 ] If multiple IPA commands are build & sent out concurrently, fill_ipacmd_header() may assign a seqno value to a command that's different from what send_control_data() later assigns to this command's reply. This is due to other commands passing through send_control_data(), and incrementing card->seqno.ipa along the way. So one IPA command has no reply that's waiting for its seqno, while some other IPA command has multiple reply objects waiting for it. Only one of those waiting replies wins, and the other(s) times out and triggers a recovery via send_ipa_cmd(). Fix this by making sure that the same seqno value is assigned to a command and its reply object. Do so immediately before submitting the command & while holding the irq_pending "lock", to produce nicely ascending seqnos. As a side effect, *all* IPA commands now use a reply object that's waiting for its actual seqno. Previously, early IPA commands that were submitted while the card was still DOWN used the "catch-all" IDX seqno. Signed-off-by: Julian Wiedmann <jwi@linux.vnet.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 058db71 commit f3d26ce

1 file changed

Lines changed: 10 additions & 9 deletions

File tree

drivers/s390/net/qeth_core_main.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2064,25 +2064,26 @@ int qeth_send_control_data(struct qeth_card *card, int len,
20642064
}
20652065
reply->callback = reply_cb;
20662066
reply->param = reply_param;
2067-
if (card->state == CARD_STATE_DOWN)
2068-
reply->seqno = QETH_IDX_COMMAND_SEQNO;
2069-
else
2070-
reply->seqno = card->seqno.ipa++;
2067+
20712068
init_waitqueue_head(&reply->wait_q);
2072-
spin_lock_irqsave(&card->lock, flags);
2073-
list_add_tail(&reply->list, &card->cmd_waiter_list);
2074-
spin_unlock_irqrestore(&card->lock, flags);
20752069
QETH_DBF_HEX(CTRL, 2, iob->data, QETH_DBF_CTRL_LEN);
20762070

20772071
while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ;
2078-
qeth_prepare_control_data(card, len, iob);
20792072

20802073
if (IS_IPA(iob->data)) {
20812074
cmd = __ipa_cmd(iob);
2075+
cmd->hdr.seqno = card->seqno.ipa++;
2076+
reply->seqno = cmd->hdr.seqno;
20822077
event_timeout = QETH_IPA_TIMEOUT;
20832078
} else {
2079+
reply->seqno = QETH_IDX_COMMAND_SEQNO;
20842080
event_timeout = QETH_TIMEOUT;
20852081
}
2082+
qeth_prepare_control_data(card, len, iob);
2083+
2084+
spin_lock_irqsave(&card->lock, flags);
2085+
list_add_tail(&reply->list, &card->cmd_waiter_list);
2086+
spin_unlock_irqrestore(&card->lock, flags);
20862087

20872088
timeout = jiffies + event_timeout;
20882089

@@ -2873,7 +2874,7 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card,
28732874
memset(cmd, 0, sizeof(struct qeth_ipa_cmd));
28742875
cmd->hdr.command = command;
28752876
cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST;
2876-
cmd->hdr.seqno = card->seqno.ipa;
2877+
/* cmd->hdr.seqno is set by qeth_send_control_data() */
28772878
cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type);
28782879
cmd->hdr.rel_adapter_no = (__u8) card->info.portno;
28792880
if (card->options.layer2)

0 commit comments

Comments
 (0)