diff options
author | Frank Blaschka <frank.blaschka@de.ibm.com> | 2012-02-08 00:19:49 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-02-08 18:50:20 -0500 |
commit | c3ab96f36aa308fa5bf432d5a4dafc80b7373805 (patch) | |
tree | 8ab0bb57340bf267fd6921b8f8db008b1b352cbd /drivers/s390/net/qeth_core_main.c | |
parent | 51363b8751a673a00ad48eea895266396d53fa52 (diff) |
qeth: add query OSA address table support
Add qeth device private ioctl to query the OSA address table.
This helps debugging hw related problems.
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390/net/qeth_core_main.c')
-rw-r--r-- | drivers/s390/net/qeth_core_main.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 9c3f38da4c0..0565584b52c 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -26,6 +26,7 @@ #include <asm/ebcdic.h> #include <asm/io.h> #include <asm/sysinfo.h> +#include <asm/compat.h> #include "qeth_core.h" @@ -4402,6 +4403,104 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata) } EXPORT_SYMBOL_GPL(qeth_snmp_command); +static int qeth_setadpparms_query_oat_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) +{ + struct qeth_ipa_cmd *cmd; + struct qeth_qoat_priv *priv; + char *resdata; + int resdatalen; + + QETH_CARD_TEXT(card, 3, "qoatcb"); + + cmd = (struct qeth_ipa_cmd *)data; + priv = (struct qeth_qoat_priv *)reply->param; + resdatalen = cmd->data.setadapterparms.hdr.cmdlength; + resdata = (char *)data + 28; + + if (resdatalen > (priv->buffer_len - priv->response_len)) { + cmd->hdr.return_code = IPA_RC_FFFF; + return 0; + } + + memcpy((priv->buffer + priv->response_len), resdata, + resdatalen); + priv->response_len += resdatalen; + + if (cmd->data.setadapterparms.hdr.seq_no < + cmd->data.setadapterparms.hdr.used_total) + return 1; + return 0; +} + +int qeth_query_oat_command(struct qeth_card *card, char __user *udata) +{ + int rc = 0; + struct qeth_cmd_buffer *iob; + struct qeth_ipa_cmd *cmd; + struct qeth_query_oat *oat_req; + struct qeth_query_oat_data oat_data; + struct qeth_qoat_priv priv; + void __user *tmp; + + QETH_CARD_TEXT(card, 3, "qoatcmd"); + + if (!qeth_adp_supported(card, IPA_SETADP_QUERY_OAT)) { + rc = -EOPNOTSUPP; + goto out; + } + + if (copy_from_user(&oat_data, udata, + sizeof(struct qeth_query_oat_data))) { + rc = -EFAULT; + goto out; + } + + priv.buffer_len = oat_data.buffer_len; + priv.response_len = 0; + priv.buffer = kzalloc(oat_data.buffer_len, GFP_KERNEL); + if (!priv.buffer) { + rc = -ENOMEM; + goto out; + } + + iob = qeth_get_adapter_cmd(card, IPA_SETADP_QUERY_OAT, + sizeof(struct qeth_ipacmd_setadpparms_hdr) + + sizeof(struct qeth_query_oat)); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + oat_req = &cmd->data.setadapterparms.data.query_oat; + oat_req->subcmd_code = oat_data.command; + + rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_query_oat_cb, + &priv); + if (!rc) { + if (is_compat_task()) + tmp = compat_ptr(oat_data.ptr); + else + tmp = (void __user *)(unsigned long)oat_data.ptr; + + if (copy_to_user(tmp, priv.buffer, + priv.response_len)) { + rc = -EFAULT; + goto out_free; + } + + oat_data.response_len = priv.response_len; + + if (copy_to_user(udata, &oat_data, + sizeof(struct qeth_query_oat_data))) + rc = -EFAULT; + } else + if (rc == IPA_RC_FFFF) + rc = -EFAULT; + +out_free: + kfree(priv.buffer); +out: + return rc; +} +EXPORT_SYMBOL_GPL(qeth_query_oat_command); + static inline int qeth_get_qdio_q_format(struct qeth_card *card) { switch (card->info.type) { |