]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/s390/net/qeth_core_main.c
qeth: add query OSA address table support
[mv-sheeva.git] / drivers / s390 / net / qeth_core_main.c
index 9c3f38da4c01f7b9996c4d44feb7c53423fd4e23..0565584b52c32de8a3360f8763a710d9cac44da1 100644 (file)
@@ -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) {