diff options
author | Frank Blaschka <frank.blaschka@de.ibm.com> | 2011-08-08 01:33:59 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-08-13 01:10:17 -0700 |
commit | b333293058aa2d401737c7246bce58f8ba00906d (patch) | |
tree | dace4eab8f669d29b4e10cd784d16ca1690cbbbf /drivers/s390/net/qeth_l3_sys.c | |
parent | 0da9581ddb0ffbec8129504d661b563749160e70 (diff) |
qeth: add support for af_iucv HiperSockets transport
This patch extends the HiperSockets device driver to send and receive
af_iucv traffic over HiperSockets transport.
TX: Driver uses new asynchronous delivery of storage blocks to pass
flow control/congestion information from the HiperSockets microcode
to the af_iucv socket.
RX: Memory for incoming traffic is preallocated and passed to
HiperSockets layer. If receiver is not capable to clean its buffers
shared with HiperSockets and pass new memory to the HiperSockets
layer this will cause flow control/congestion events on the
sender.
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: Einar Lueck <elelueck@de.ibm.com>
Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/s390/net/qeth_l3_sys.c')
-rw-r--r-- | drivers/s390/net/qeth_l3_sys.c | 110 |
1 files changed, 109 insertions, 1 deletions
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index cd99210296e..0ea2fbfe0e9 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -9,7 +9,7 @@ */ #include <linux/slab.h> - +#include <asm/ebcdic.h> #include "qeth_l3.h" #define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ @@ -308,6 +308,8 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, if (card->info.type != QETH_CARD_TYPE_IQD) return -EPERM; + if (card->options.cq == QETH_CQ_ENABLED) + return -EPERM; mutex_lock(&card->conf_mutex); if ((card->state != CARD_STATE_DOWN) && @@ -347,6 +349,111 @@ out: static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show, qeth_l3_dev_sniffer_store); + +static ssize_t qeth_l3_dev_hsuid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qeth_card *card = dev_get_drvdata(dev); + char tmp_hsuid[9]; + + if (!card) + return -EINVAL; + + if (card->info.type != QETH_CARD_TYPE_IQD) + return -EPERM; + + if (card->state == CARD_STATE_DOWN) + return -EPERM; + + memcpy(tmp_hsuid, card->options.hsuid, sizeof(tmp_hsuid)); + EBCASC(tmp_hsuid, 8); + return sprintf(buf, "%s\n", tmp_hsuid); +} + +static ssize_t qeth_l3_dev_hsuid_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct qeth_card *card = dev_get_drvdata(dev); + struct qeth_ipaddr *addr; + char *tmp; + int i; + + if (!card) + return -EINVAL; + + if (card->info.type != QETH_CARD_TYPE_IQD) + return -EPERM; + if (card->state != CARD_STATE_DOWN && + card->state != CARD_STATE_RECOVER) + return -EPERM; + if (card->options.sniffer) + return -EPERM; + if (card->options.cq == QETH_CQ_NOTAVAILABLE) + return -EPERM; + + tmp = strsep((char **)&buf, "\n"); + if (strlen(tmp) > 8) + return -EINVAL; + + if (card->options.hsuid[0]) { + /* delete old ip address */ + addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6); + if (addr != NULL) { + addr->u.a6.addr.s6_addr32[0] = 0xfe800000; + addr->u.a6.addr.s6_addr32[1] = 0x00000000; + for (i = 8; i < 16; i++) + addr->u.a6.addr.s6_addr[i] = + card->options.hsuid[i - 8]; + addr->u.a6.pfxlen = 0; + addr->type = QETH_IP_TYPE_NORMAL; + } else + return -ENOMEM; + if (!qeth_l3_delete_ip(card, addr)) + kfree(addr); + qeth_l3_set_ip_addr_list(card); + } + + if (strlen(tmp) == 0) { + /* delete ip address only */ + card->options.hsuid[0] = '\0'; + if (card->dev) + memcpy(card->dev->perm_addr, card->options.hsuid, 9); + qeth_configure_cq(card, QETH_CQ_DISABLED); + return count; + } + + if (qeth_configure_cq(card, QETH_CQ_ENABLED)) + return -EPERM; + + for (i = 0; i < 8; i++) + card->options.hsuid[i] = ' '; + card->options.hsuid[8] = '\0'; + strncpy(card->options.hsuid, tmp, strlen(tmp)); + ASCEBC(card->options.hsuid, 8); + if (card->dev) + memcpy(card->dev->perm_addr, card->options.hsuid, 9); + + addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6); + if (addr != NULL) { + addr->u.a6.addr.s6_addr32[0] = 0xfe800000; + addr->u.a6.addr.s6_addr32[1] = 0x00000000; + for (i = 8; i < 16; i++) + addr->u.a6.addr.s6_addr[i] = card->options.hsuid[i - 8]; + addr->u.a6.pfxlen = 0; + addr->type = QETH_IP_TYPE_NORMAL; + } else + return -ENOMEM; + if (!qeth_l3_add_ip(card, addr)) + kfree(addr); + qeth_l3_set_ip_addr_list(card); + + return count; +} + +static DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show, + qeth_l3_dev_hsuid_store); + + static struct attribute *qeth_l3_device_attrs[] = { &dev_attr_route4.attr, &dev_attr_route6.attr, @@ -354,6 +461,7 @@ static struct attribute *qeth_l3_device_attrs[] = { &dev_attr_broadcast_mode.attr, &dev_attr_canonical_macaddr.attr, &dev_attr_sniffer.attr, + &dev_attr_hsuid.attr, NULL, }; |