Commit 7f92316c authored by Julian Wiedmann's avatar Julian Wiedmann Committed by David S. Miller

s390/qeth: make cmd/reply matching more flexible

When data is received on the READ channel, the matching logic for cmds
that are waiting for a reply is currently hard-coded into the channel's
main IO callback.
Move this into a per-cmd callback, so that we can apply custom matching
logic for each individual cmd.

This also allows us to remove the coarse-grained check for unexpected
non-IPA replies, since they will no longer match against _all_ pending
cmds.

Note that IDX cmds use _no_ matcher, since their reply is synchronously
received as part of the cmd's IO.
Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 91003f35
...@@ -608,6 +608,8 @@ struct qeth_cmd_buffer { ...@@ -608,6 +608,8 @@ struct qeth_cmd_buffer {
long timeout; long timeout;
unsigned char *data; unsigned char *data;
void (*finalize)(struct qeth_card *card, struct qeth_cmd_buffer *iob); void (*finalize)(struct qeth_card *card, struct qeth_cmd_buffer *iob);
bool (*match)(struct qeth_cmd_buffer *iob,
struct qeth_cmd_buffer *reply);
void (*callback)(struct qeth_card *card, struct qeth_cmd_buffer *iob, void (*callback)(struct qeth_card *card, struct qeth_cmd_buffer *iob,
unsigned int data_length); unsigned int data_length);
int rc; int rc;
...@@ -618,6 +620,14 @@ static inline void qeth_get_cmd(struct qeth_cmd_buffer *iob) ...@@ -618,6 +620,14 @@ static inline void qeth_get_cmd(struct qeth_cmd_buffer *iob)
refcount_inc(&iob->ref_count); refcount_inc(&iob->ref_count);
} }
static inline struct qeth_ipa_cmd *__ipa_reply(struct qeth_cmd_buffer *iob)
{
if (!IS_IPA(iob->data))
return NULL;
return (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
}
static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob) static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob)
{ {
return (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE); return (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE);
...@@ -1023,7 +1033,9 @@ void qeth_setadp_promisc_mode(struct qeth_card *card, bool enable); ...@@ -1023,7 +1033,9 @@ void qeth_setadp_promisc_mode(struct qeth_card *card, bool enable);
int qeth_setadpparms_change_macaddr(struct qeth_card *); int qeth_setadpparms_change_macaddr(struct qeth_card *);
void qeth_tx_timeout(struct net_device *, unsigned int txqueue); void qeth_tx_timeout(struct net_device *, unsigned int txqueue);
void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
u16 cmd_length); u16 cmd_length,
bool (*match)(struct qeth_cmd_buffer *iob,
struct qeth_cmd_buffer *reply));
int qeth_query_switch_attributes(struct qeth_card *card, int qeth_query_switch_attributes(struct qeth_card *card,
struct qeth_switch_info *sw_info); struct qeth_switch_info *sw_info);
int qeth_query_card_info(struct qeth_card *card, int qeth_query_card_info(struct qeth_card *card,
......
...@@ -748,8 +748,8 @@ static void qeth_issue_next_read_cb(struct qeth_card *card, ...@@ -748,8 +748,8 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
goto out; goto out;
} }
if (IS_IPA(iob->data)) { cmd = __ipa_reply(iob);
cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data); if (cmd) {
cmd = qeth_check_ipa_data(card, cmd); cmd = qeth_check_ipa_data(card, cmd);
if (!cmd) if (!cmd)
goto out; goto out;
...@@ -758,17 +758,12 @@ static void qeth_issue_next_read_cb(struct qeth_card *card, ...@@ -758,17 +758,12 @@ static void qeth_issue_next_read_cb(struct qeth_card *card,
card->osn_info.assist_cb(card->dev, cmd); card->osn_info.assist_cb(card->dev, cmd);
goto out; goto out;
} }
} else {
/* non-IPA commands should only flow during initialization */
if (card->state != CARD_STATE_DOWN)
goto out;
} }
/* match against pending cmd requests */ /* match against pending cmd requests */
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
list_for_each_entry(tmp, &card->cmd_waiter_list, list) { list_for_each_entry(tmp, &card->cmd_waiter_list, list) {
if (!IS_IPA(tmp->data) || if (tmp->match && tmp->match(tmp, iob)) {
__ipa_cmd(tmp)->hdr.seqno == cmd->hdr.seqno) {
request = tmp; request = tmp;
/* take the object outside the lock */ /* take the object outside the lock */
qeth_get_cmd(request); qeth_get_cmd(request);
...@@ -1688,6 +1683,13 @@ static void qeth_mpc_finalize_cmd(struct qeth_card *card, ...@@ -1688,6 +1683,13 @@ static void qeth_mpc_finalize_cmd(struct qeth_card *card,
iob->callback = qeth_release_buffer_cb; iob->callback = qeth_release_buffer_cb;
} }
static bool qeth_mpc_match_reply(struct qeth_cmd_buffer *iob,
struct qeth_cmd_buffer *reply)
{
/* MPC cmds are issued strictly in sequence. */
return !IS_IPA(reply->data);
}
static struct qeth_cmd_buffer *qeth_mpc_alloc_cmd(struct qeth_card *card, static struct qeth_cmd_buffer *qeth_mpc_alloc_cmd(struct qeth_card *card,
void *data, void *data,
unsigned int data_length) unsigned int data_length)
...@@ -1702,6 +1704,7 @@ static struct qeth_cmd_buffer *qeth_mpc_alloc_cmd(struct qeth_card *card, ...@@ -1702,6 +1704,7 @@ static struct qeth_cmd_buffer *qeth_mpc_alloc_cmd(struct qeth_card *card,
qeth_setup_ccw(__ccw_from_cmd(iob), CCW_CMD_WRITE, 0, data_length, qeth_setup_ccw(__ccw_from_cmd(iob), CCW_CMD_WRITE, 0, data_length,
iob->data); iob->data);
iob->finalize = qeth_mpc_finalize_cmd; iob->finalize = qeth_mpc_finalize_cmd;
iob->match = qeth_mpc_match_reply;
return iob; return iob;
} }
...@@ -2722,7 +2725,9 @@ static void qeth_ipa_finalize_cmd(struct qeth_card *card, ...@@ -2722,7 +2725,9 @@ static void qeth_ipa_finalize_cmd(struct qeth_card *card,
} }
void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
u16 cmd_length) u16 cmd_length,
bool (*match)(struct qeth_cmd_buffer *iob,
struct qeth_cmd_buffer *reply))
{ {
u8 prot_type = qeth_mpc_select_prot_type(card); u8 prot_type = qeth_mpc_select_prot_type(card);
u16 total_length = iob->length; u16 total_length = iob->length;
...@@ -2730,6 +2735,7 @@ void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, ...@@ -2730,6 +2735,7 @@ void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
qeth_setup_ccw(__ccw_from_cmd(iob), CCW_CMD_WRITE, 0, total_length, qeth_setup_ccw(__ccw_from_cmd(iob), CCW_CMD_WRITE, 0, total_length,
iob->data); iob->data);
iob->finalize = qeth_ipa_finalize_cmd; iob->finalize = qeth_ipa_finalize_cmd;
iob->match = match;
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &total_length, 2); memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &total_length, 2);
...@@ -2742,6 +2748,14 @@ void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, ...@@ -2742,6 +2748,14 @@ void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
} }
EXPORT_SYMBOL_GPL(qeth_prepare_ipa_cmd); EXPORT_SYMBOL_GPL(qeth_prepare_ipa_cmd);
static bool qeth_ipa_match_reply(struct qeth_cmd_buffer *iob,
struct qeth_cmd_buffer *reply)
{
struct qeth_ipa_cmd *ipa_reply = __ipa_reply(reply);
return ipa_reply && (__ipa_cmd(iob)->hdr.seqno == ipa_reply->hdr.seqno);
}
struct qeth_cmd_buffer *qeth_ipa_alloc_cmd(struct qeth_card *card, struct qeth_cmd_buffer *qeth_ipa_alloc_cmd(struct qeth_card *card,
enum qeth_ipa_cmds cmd_code, enum qeth_ipa_cmds cmd_code,
enum qeth_prot_versions prot, enum qeth_prot_versions prot,
...@@ -2757,7 +2771,7 @@ struct qeth_cmd_buffer *qeth_ipa_alloc_cmd(struct qeth_card *card, ...@@ -2757,7 +2771,7 @@ struct qeth_cmd_buffer *qeth_ipa_alloc_cmd(struct qeth_card *card,
if (!iob) if (!iob)
return NULL; return NULL;
qeth_prepare_ipa_cmd(card, iob, data_length); qeth_prepare_ipa_cmd(card, iob, data_length, qeth_ipa_match_reply);
hdr = &__ipa_cmd(iob)->hdr; hdr = &__ipa_cmd(iob)->hdr;
hdr->command = cmd_code; hdr->command = cmd_code;
......
...@@ -896,7 +896,8 @@ int qeth_osn_assist(struct net_device *dev, void *data, int data_len) ...@@ -896,7 +896,8 @@ int qeth_osn_assist(struct net_device *dev, void *data, int data_len)
if (!iob) if (!iob)
return -ENOMEM; return -ENOMEM;
qeth_prepare_ipa_cmd(card, iob, (u16) data_len); qeth_prepare_ipa_cmd(card, iob, (u16) data_len, NULL);
memcpy(__ipa_cmd(iob), data, data_len); memcpy(__ipa_cmd(iob), data, data_len);
iob->callback = qeth_osn_assist_cb; iob->callback = qeth_osn_assist_cb;
return qeth_send_ipa_cmd(card, iob, NULL, NULL); return qeth_send_ipa_cmd(card, iob, NULL, NULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment