s390/qeth: allow cmd callbacks to return errnos
Error propagation from cmd callbacks currently works in a way where
qeth_send_control_data_cb() picks the raw HW code from the response,
and the cmd's originator later translates this into an errno.
The callback itself only returns 0 ("done") or 1 ("expect more data").
This is
1. limiting, as the only means for the callback to report an internal
error is to invent pseudo HW codes (such as IPA_RC_ENOMEM), that
the originator then needs to understand. For non-IPA callbacks, we
even provide a separate field in the IO buffer metadata (iob->rc) so
the callback can pass back a return value.
2. fragile, as the originator must take care to not translate any errno
that is returned by qeth's own IO code paths (eg -ENOMEM). Also, any
originator that forgets to translate the HW codes potentially passes
garbage back to its caller. For instance, see
commit 2aa4867198
("s390/qeth: translate SETVLAN/DELVLAN errors").
Introduce a new model where all HW error translation is done within the
callback, and the callback returns
> 0, if it expects more data (as before)
== 0, on success
< 0, with an errno
Start off with converting all callbacks to the new model that either
a) pass back pseudo HW codes, or b) have a dependency on a specific
HW error code. Also convert c) the one callback that uses iob->rc, and
d) qeth_setadpparms_change_macaddr_cb() so that it can pass back an
error back to qeth_l2_request_initial_mac() even when the cmd itself
was successful.
The old model remains supported: if the callback returns 0, we still
propagate the response's HW error code back to the originator.
Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:

committed by
David S. Miller

parent
54daaca702
commit
4b7ae12216
@@ -253,8 +253,7 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
|
||||
} else
|
||||
rc = qeth_l3_register_addr_entry(card, addr);
|
||||
|
||||
if (!rc || (rc == IPA_RC_DUPLICATE_IP_ADDRESS) ||
|
||||
(rc == IPA_RC_LAN_OFFLINE)) {
|
||||
if (!rc || rc == -EADDRINUSE || rc == -ENETDOWN) {
|
||||
addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
|
||||
if (addr->ref_counter < 1) {
|
||||
qeth_l3_deregister_addr_entry(card, addr);
|
||||
@@ -338,10 +337,28 @@ static void qeth_l3_recover_ip(struct qeth_card *card)
|
||||
|
||||
}
|
||||
|
||||
static int qeth_l3_setdelip_cb(struct qeth_card *card, struct qeth_reply *reply,
|
||||
unsigned long data)
|
||||
{
|
||||
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
|
||||
|
||||
switch (cmd->hdr.return_code) {
|
||||
case IPA_RC_SUCCESS:
|
||||
return 0;
|
||||
case IPA_RC_DUPLICATE_IP_ADDRESS:
|
||||
return -EADDRINUSE;
|
||||
case IPA_RC_MC_ADDR_NOT_FOUND:
|
||||
return -ENOENT;
|
||||
case IPA_RC_LAN_OFFLINE:
|
||||
return -ENETDOWN;
|
||||
default:
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
static int qeth_l3_send_setdelmc(struct qeth_card *card,
|
||||
struct qeth_ipaddr *addr, int ipacmd)
|
||||
{
|
||||
int rc;
|
||||
struct qeth_cmd_buffer *iob;
|
||||
struct qeth_ipa_cmd *cmd;
|
||||
|
||||
@@ -358,9 +375,7 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card,
|
||||
else
|
||||
memcpy(&cmd->data.setdelipm.ip4, &addr->u.a4.addr, 4);
|
||||
|
||||
rc = qeth_send_ipa_cmd(card, iob, NULL, NULL);
|
||||
|
||||
return rc;
|
||||
return qeth_send_ipa_cmd(card, iob, qeth_l3_setdelip_cb, NULL);
|
||||
}
|
||||
|
||||
static void qeth_l3_fill_netmask(u8 *netmask, unsigned int len)
|
||||
@@ -422,7 +437,7 @@ static int qeth_l3_send_setdelip(struct qeth_card *card,
|
||||
cmd->data.setdelip4.flags = flags;
|
||||
}
|
||||
|
||||
return qeth_send_ipa_cmd(card, iob, NULL, NULL);
|
||||
return qeth_send_ipa_cmd(card, iob, qeth_l3_setdelip_cb, NULL);
|
||||
}
|
||||
|
||||
static int qeth_l3_send_setrouting(struct qeth_card *card,
|
||||
@@ -1481,14 +1496,14 @@ static void qeth_l3_set_rx_mode(struct net_device *dev)
|
||||
switch (addr->disp_flag) {
|
||||
case QETH_DISP_ADDR_DELETE:
|
||||
rc = qeth_l3_deregister_addr_entry(card, addr);
|
||||
if (!rc || rc == IPA_RC_MC_ADDR_NOT_FOUND) {
|
||||
if (!rc || rc == -ENOENT) {
|
||||
hash_del(&addr->hnode);
|
||||
kfree(addr);
|
||||
}
|
||||
break;
|
||||
case QETH_DISP_ADDR_ADD:
|
||||
rc = qeth_l3_register_addr_entry(card, addr);
|
||||
if (rc && rc != IPA_RC_LAN_OFFLINE) {
|
||||
if (rc && rc != -ENETDOWN) {
|
||||
hash_del(&addr->hnode);
|
||||
kfree(addr);
|
||||
break;
|
||||
@@ -1599,7 +1614,6 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
|
||||
struct qeth_ipa_cmd *cmd;
|
||||
struct qeth_arp_query_data *qdata;
|
||||
struct qeth_arp_query_info *qinfo;
|
||||
int i;
|
||||
int e;
|
||||
int entrybytes_done;
|
||||
int stripped_bytes;
|
||||
@@ -1613,13 +1627,13 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
|
||||
if (cmd->hdr.return_code) {
|
||||
QETH_CARD_TEXT(card, 4, "arpcberr");
|
||||
QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
|
||||
return 0;
|
||||
return qeth_l3_arp_makerc(cmd->hdr.return_code);
|
||||
}
|
||||
if (cmd->data.setassparms.hdr.return_code) {
|
||||
cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
|
||||
QETH_CARD_TEXT(card, 4, "setaperr");
|
||||
QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
|
||||
return 0;
|
||||
return qeth_l3_arp_makerc(cmd->hdr.return_code);
|
||||
}
|
||||
qdata = &cmd->data.setassparms.data.query_arp;
|
||||
QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries);
|
||||
@@ -1646,9 +1660,9 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
|
||||
break;
|
||||
|
||||
if ((qinfo->udata_len - qinfo->udata_offset) < esize) {
|
||||
QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM);
|
||||
cmd->hdr.return_code = IPA_RC_ENOMEM;
|
||||
goto out_error;
|
||||
QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOSPC);
|
||||
memset(qinfo->udata, 0, 4);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
memcpy(qinfo->udata + qinfo->udata_offset,
|
||||
@@ -1671,10 +1685,6 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
|
||||
memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET, &qdata->reply_bits, 2);
|
||||
QETH_CARD_TEXT_(card, 4, "rc%i", 0);
|
||||
return 0;
|
||||
out_error:
|
||||
i = 0;
|
||||
memcpy(qinfo->udata, &i, 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
|
||||
@@ -1700,7 +1710,7 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
|
||||
if (rc)
|
||||
QETH_DBF_MESSAGE(2, "Error while querying ARP cache on device %x: %#x\n",
|
||||
CARD_DEVID(card), rc);
|
||||
return qeth_l3_arp_makerc(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
|
||||
|
Reference in New Issue
Block a user