Commit c8431622 authored by David S. Miller's avatar David S. Miller

Merge branch 's390-qeth-fixes'

Julian Wiedmann says:

====================
s390/qeth: fixes 2018-02-27

please apply some more qeth patches for -net and stable.

One patch fixes a performance bug in the TSO path. Then there's several
more fixes for IP management on L3 devices - including a revert, so that
the subsequent fix cleanly applies to earlier kernels.
The final patch takes care of a race in the control IO code that causes
qeth to miss the cmd response, and subsequently trigger device recovery.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 590399dd d22ffb5a
...@@ -2134,24 +2134,25 @@ int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2134,24 +2134,25 @@ int qeth_send_control_data(struct qeth_card *card, int len,
} }
reply->callback = reply_cb; reply->callback = reply_cb;
reply->param = reply_param; reply->param = reply_param;
if (card->state == CARD_STATE_DOWN)
reply->seqno = QETH_IDX_COMMAND_SEQNO;
else
reply->seqno = card->seqno.ipa++;
init_waitqueue_head(&reply->wait_q); init_waitqueue_head(&reply->wait_q);
spin_lock_irqsave(&card->lock, flags);
list_add_tail(&reply->list, &card->cmd_waiter_list);
spin_unlock_irqrestore(&card->lock, flags);
while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ; while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ;
qeth_prepare_control_data(card, len, iob);
if (IS_IPA(iob->data)) { if (IS_IPA(iob->data)) {
cmd = __ipa_cmd(iob); cmd = __ipa_cmd(iob);
cmd->hdr.seqno = card->seqno.ipa++;
reply->seqno = cmd->hdr.seqno;
event_timeout = QETH_IPA_TIMEOUT; event_timeout = QETH_IPA_TIMEOUT;
} else { } else {
reply->seqno = QETH_IDX_COMMAND_SEQNO;
event_timeout = QETH_TIMEOUT; event_timeout = QETH_TIMEOUT;
} }
qeth_prepare_control_data(card, len, iob);
spin_lock_irqsave(&card->lock, flags);
list_add_tail(&reply->list, &card->cmd_waiter_list);
spin_unlock_irqrestore(&card->lock, flags);
timeout = jiffies + event_timeout; timeout = jiffies + event_timeout;
...@@ -2933,7 +2934,7 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card, ...@@ -2933,7 +2934,7 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card,
memset(cmd, 0, sizeof(struct qeth_ipa_cmd)); memset(cmd, 0, sizeof(struct qeth_ipa_cmd));
cmd->hdr.command = command; cmd->hdr.command = command;
cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST; cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST;
cmd->hdr.seqno = card->seqno.ipa; /* cmd->hdr.seqno is set by qeth_send_control_data() */
cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type); cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type);
cmd->hdr.rel_adapter_no = (__u8) card->info.portno; cmd->hdr.rel_adapter_no = (__u8) card->info.portno;
if (card->options.layer2) if (card->options.layer2)
...@@ -3898,10 +3899,12 @@ EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags); ...@@ -3898,10 +3899,12 @@ EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags);
int qeth_get_elements_no(struct qeth_card *card, int qeth_get_elements_no(struct qeth_card *card,
struct sk_buff *skb, int extra_elems, int data_offset) struct sk_buff *skb, int extra_elems, int data_offset)
{ {
int elements = qeth_get_elements_for_range( addr_t end = (addr_t)skb->data + skb_headlen(skb);
(addr_t)skb->data + data_offset, int elements = qeth_get_elements_for_frags(skb);
(addr_t)skb->data + skb_headlen(skb)) + addr_t start = (addr_t)skb->data + data_offset;
qeth_get_elements_for_frags(skb);
if (start != end)
elements += qeth_get_elements_for_range(start, end);
if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
QETH_DBF_MESSAGE(2, "Invalid size of IP packet " QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
......
...@@ -40,8 +40,40 @@ struct qeth_ipaddr { ...@@ -40,8 +40,40 @@ struct qeth_ipaddr {
unsigned int pfxlen; unsigned int pfxlen;
} a6; } a6;
} u; } u;
}; };
static inline bool qeth_l3_addr_match_ip(struct qeth_ipaddr *a1,
struct qeth_ipaddr *a2)
{
if (a1->proto != a2->proto)
return false;
if (a1->proto == QETH_PROT_IPV6)
return ipv6_addr_equal(&a1->u.a6.addr, &a2->u.a6.addr);
return a1->u.a4.addr == a2->u.a4.addr;
}
static inline bool qeth_l3_addr_match_all(struct qeth_ipaddr *a1,
struct qeth_ipaddr *a2)
{
/* Assumes that the pair was obtained via qeth_l3_addr_find_by_ip(),
* so 'proto' and 'addr' match for sure.
*
* For ucast:
* - 'mac' is always 0.
* - 'mask'/'pfxlen' for RXIP/VIPA is always 0. For NORMAL, matching
* values are required to avoid mixups in takeover eligibility.
*
* For mcast,
* - 'mac' is mapped from the IP, and thus always matches.
* - 'mask'/'pfxlen' is always 0.
*/
if (a1->type != a2->type)
return false;
if (a1->proto == QETH_PROT_IPV6)
return a1->u.a6.pfxlen == a2->u.a6.pfxlen;
return a1->u.a4.mask == a2->u.a4.mask;
}
static inline u64 qeth_l3_ipaddr_hash(struct qeth_ipaddr *addr) static inline u64 qeth_l3_ipaddr_hash(struct qeth_ipaddr *addr)
{ {
u64 ret = 0; u64 ret = 0;
......
...@@ -67,6 +67,24 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr, ...@@ -67,6 +67,24 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr,
qeth_l3_ipaddr6_to_string(addr, buf); qeth_l3_ipaddr6_to_string(addr, buf);
} }
static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card,
struct qeth_ipaddr *query)
{
u64 key = qeth_l3_ipaddr_hash(query);
struct qeth_ipaddr *addr;
if (query->is_multicast) {
hash_for_each_possible(card->ip_mc_htable, addr, hnode, key)
if (qeth_l3_addr_match_ip(addr, query))
return addr;
} else {
hash_for_each_possible(card->ip_htable, addr, hnode, key)
if (qeth_l3_addr_match_ip(addr, query))
return addr;
}
return NULL;
}
static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len) static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
{ {
int i, j; int i, j;
...@@ -120,34 +138,6 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card, ...@@ -120,34 +138,6 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card,
return rc; return rc;
} }
inline int
qeth_l3_ipaddrs_is_equal(struct qeth_ipaddr *addr1, struct qeth_ipaddr *addr2)
{
return addr1->proto == addr2->proto &&
!memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) &&
ether_addr_equal_64bits(addr1->mac, addr2->mac);
}
static struct qeth_ipaddr *
qeth_l3_ip_from_hash(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
{
struct qeth_ipaddr *addr;
if (tmp_addr->is_multicast) {
hash_for_each_possible(card->ip_mc_htable, addr,
hnode, qeth_l3_ipaddr_hash(tmp_addr))
if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr))
return addr;
} else {
hash_for_each_possible(card->ip_htable, addr,
hnode, qeth_l3_ipaddr_hash(tmp_addr))
if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr))
return addr;
}
return NULL;
}
int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
{ {
int rc = 0; int rc = 0;
...@@ -162,22 +152,17 @@ int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) ...@@ -162,22 +152,17 @@ int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8); QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8);
} }
addr = qeth_l3_ip_from_hash(card, tmp_addr); addr = qeth_l3_find_addr_by_ip(card, tmp_addr);
if (!addr) if (!addr || !qeth_l3_addr_match_all(addr, tmp_addr))
return -ENOENT; return -ENOENT;
addr->ref_counter--; addr->ref_counter--;
if (addr->ref_counter > 0 && (addr->type == QETH_IP_TYPE_NORMAL || if (addr->type == QETH_IP_TYPE_NORMAL && addr->ref_counter > 0)
addr->type == QETH_IP_TYPE_RXIP))
return rc; return rc;
if (addr->in_progress) if (addr->in_progress)
return -EINPROGRESS; return -EINPROGRESS;
if (!qeth_card_hw_is_reachable(card)) { if (qeth_card_hw_is_reachable(card))
addr->disp_flag = QETH_DISP_ADDR_DELETE;
return 0;
}
rc = qeth_l3_deregister_addr_entry(card, addr); rc = qeth_l3_deregister_addr_entry(card, addr);
hash_del(&addr->hnode); hash_del(&addr->hnode);
...@@ -190,6 +175,7 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) ...@@ -190,6 +175,7 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
{ {
int rc = 0; int rc = 0;
struct qeth_ipaddr *addr; struct qeth_ipaddr *addr;
char buf[40];
QETH_CARD_TEXT(card, 4, "addip"); QETH_CARD_TEXT(card, 4, "addip");
...@@ -200,8 +186,20 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) ...@@ -200,8 +186,20 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8); QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8);
} }
addr = qeth_l3_ip_from_hash(card, tmp_addr); addr = qeth_l3_find_addr_by_ip(card, tmp_addr);
if (!addr) { if (addr) {
if (tmp_addr->type != QETH_IP_TYPE_NORMAL)
return -EADDRINUSE;
if (qeth_l3_addr_match_all(addr, tmp_addr)) {
addr->ref_counter++;
return 0;
}
qeth_l3_ipaddr_to_string(tmp_addr->proto, (u8 *)&tmp_addr->u,
buf);
dev_warn(&card->gdev->dev,
"Registering IP address %s failed\n", buf);
return -EADDRINUSE;
} else {
addr = qeth_l3_get_addr_buffer(tmp_addr->proto); addr = qeth_l3_get_addr_buffer(tmp_addr->proto);
if (!addr) if (!addr)
return -ENOMEM; return -ENOMEM;
...@@ -241,19 +239,15 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) ...@@ -241,19 +239,15 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
(rc == IPA_RC_LAN_OFFLINE)) { (rc == IPA_RC_LAN_OFFLINE)) {
addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING; addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
if (addr->ref_counter < 1) { if (addr->ref_counter < 1) {
qeth_l3_delete_ip(card, addr); qeth_l3_deregister_addr_entry(card, addr);
hash_del(&addr->hnode);
kfree(addr); kfree(addr);
} }
} else { } else {
hash_del(&addr->hnode); hash_del(&addr->hnode);
kfree(addr); kfree(addr);
} }
} else {
if (addr->type == QETH_IP_TYPE_NORMAL ||
addr->type == QETH_IP_TYPE_RXIP)
addr->ref_counter++;
} }
return rc; return rc;
} }
...@@ -321,11 +315,7 @@ static void qeth_l3_recover_ip(struct qeth_card *card) ...@@ -321,11 +315,7 @@ static void qeth_l3_recover_ip(struct qeth_card *card)
spin_lock_bh(&card->ip_lock); spin_lock_bh(&card->ip_lock);
hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) { hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) {
if (addr->disp_flag == QETH_DISP_ADDR_DELETE) { if (addr->disp_flag == QETH_DISP_ADDR_ADD) {
qeth_l3_deregister_addr_entry(card, addr);
hash_del(&addr->hnode);
kfree(addr);
} else if (addr->disp_flag == QETH_DISP_ADDR_ADD) {
if (addr->proto == QETH_PROT_IPV4) { if (addr->proto == QETH_PROT_IPV4) {
addr->in_progress = 1; addr->in_progress = 1;
spin_unlock_bh(&card->ip_lock); spin_unlock_bh(&card->ip_lock);
...@@ -643,12 +633,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, ...@@ -643,12 +633,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
return -ENOMEM; return -ENOMEM;
spin_lock_bh(&card->ip_lock); spin_lock_bh(&card->ip_lock);
if (qeth_l3_ip_from_hash(card, ipaddr))
rc = -EEXIST;
else
rc = qeth_l3_add_ip(card, ipaddr); rc = qeth_l3_add_ip(card, ipaddr);
spin_unlock_bh(&card->ip_lock); spin_unlock_bh(&card->ip_lock);
kfree(ipaddr); kfree(ipaddr);
...@@ -713,12 +698,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, ...@@ -713,12 +698,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
return -ENOMEM; return -ENOMEM;
spin_lock_bh(&card->ip_lock); spin_lock_bh(&card->ip_lock);
if (qeth_l3_ip_from_hash(card, ipaddr))
rc = -EEXIST;
else
rc = qeth_l3_add_ip(card, ipaddr); rc = qeth_l3_add_ip(card, ipaddr);
spin_unlock_bh(&card->ip_lock); spin_unlock_bh(&card->ip_lock);
kfree(ipaddr); kfree(ipaddr);
...@@ -1239,8 +1219,9 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev) ...@@ -1239,8 +1219,9 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev)
tmp->u.a4.addr = be32_to_cpu(im4->multiaddr); tmp->u.a4.addr = be32_to_cpu(im4->multiaddr);
tmp->is_multicast = 1; tmp->is_multicast = 1;
ipm = qeth_l3_ip_from_hash(card, tmp); ipm = qeth_l3_find_addr_by_ip(card, tmp);
if (ipm) { if (ipm) {
/* for mcast, by-IP match means full match */
ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
} else { } else {
ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
...@@ -1319,8 +1300,9 @@ static void qeth_l3_add_mc6_to_hash(struct qeth_card *card, ...@@ -1319,8 +1300,9 @@ static void qeth_l3_add_mc6_to_hash(struct qeth_card *card,
sizeof(struct in6_addr)); sizeof(struct in6_addr));
tmp->is_multicast = 1; tmp->is_multicast = 1;
ipm = qeth_l3_ip_from_hash(card, tmp); ipm = qeth_l3_find_addr_by_ip(card, tmp);
if (ipm) { if (ipm) {
/* for mcast, by-IP match means full match */
ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
continue; continue;
} }
...@@ -2450,11 +2432,12 @@ static void qeth_tso_fill_header(struct qeth_card *card, ...@@ -2450,11 +2432,12 @@ static void qeth_tso_fill_header(struct qeth_card *card,
static int qeth_l3_get_elements_no_tso(struct qeth_card *card, static int qeth_l3_get_elements_no_tso(struct qeth_card *card,
struct sk_buff *skb, int extra_elems) struct sk_buff *skb, int extra_elems)
{ {
addr_t tcpdptr = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb); addr_t start = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb);
int elements = qeth_get_elements_for_range( addr_t end = (addr_t)skb->data + skb_headlen(skb);
tcpdptr, int elements = qeth_get_elements_for_frags(skb);
(addr_t)skb->data + skb_headlen(skb)) +
qeth_get_elements_for_frags(skb); if (start != end)
elements += qeth_get_elements_for_range(start, end);
if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
QETH_DBF_MESSAGE(2, QETH_DBF_MESSAGE(2,
......
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