Skip to content

Commit d22ffb5

Browse files
julianwiedmanndavem330
authored andcommitted
s390/qeth: fix IPA command submission race
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c5c48c5 commit d22ffb5

File tree

1 file changed

+10
-9
lines changed

1 file changed

+10
-9
lines changed

drivers/s390/net/qeth_core_main.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2134,24 +2134,25 @@ int qeth_send_control_data(struct qeth_card *card, int len,
21342134
}
21352135
reply->callback = reply_cb;
21362136
reply->param = reply_param;
2137-
if (card->state == CARD_STATE_DOWN)
2138-
reply->seqno = QETH_IDX_COMMAND_SEQNO;
2139-
else
2140-
reply->seqno = card->seqno.ipa++;
2137+
21412138
init_waitqueue_head(&reply->wait_q);
2142-
spin_lock_irqsave(&card->lock, flags);
2143-
list_add_tail(&reply->list, &card->cmd_waiter_list);
2144-
spin_unlock_irqrestore(&card->lock, flags);
21452139

21462140
while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ;
2147-
qeth_prepare_control_data(card, len, iob);
21482141

21492142
if (IS_IPA(iob->data)) {
21502143
cmd = __ipa_cmd(iob);
2144+
cmd->hdr.seqno = card->seqno.ipa++;
2145+
reply->seqno = cmd->hdr.seqno;
21512146
event_timeout = QETH_IPA_TIMEOUT;
21522147
} else {
2148+
reply->seqno = QETH_IDX_COMMAND_SEQNO;
21532149
event_timeout = QETH_TIMEOUT;
21542150
}
2151+
qeth_prepare_control_data(card, len, iob);
2152+
2153+
spin_lock_irqsave(&card->lock, flags);
2154+
list_add_tail(&reply->list, &card->cmd_waiter_list);
2155+
spin_unlock_irqrestore(&card->lock, flags);
21552156

21562157
timeout = jiffies + event_timeout;
21572158

@@ -2933,7 +2934,7 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card,
29332934
memset(cmd, 0, sizeof(struct qeth_ipa_cmd));
29342935
cmd->hdr.command = command;
29352936
cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST;
2936-
cmd->hdr.seqno = card->seqno.ipa;
2937+
/* cmd->hdr.seqno is set by qeth_send_control_data() */
29372938
cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type);
29382939
cmd->hdr.rel_adapter_no = (__u8) card->info.portno;
29392940
if (card->options.layer2)

0 commit comments

Comments
 (0)