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>
Cette révision appartient à :

révisé par
David S. Miller

Parent
0da9581ddb
révision
b333293058
@@ -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,
|
||||
};
|
||||
|
||||
|
Référencer dans un nouveau ticket
Bloquer un utilisateur