aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/net/qeth_l3_sys.c
diff options
context:
space:
mode:
authorFrank Blaschka <frank.blaschka@de.ibm.com>2011-08-07 21:33:59 -0400
committerDavid S. Miller <davem@davemloft.net>2011-08-13 04:10:17 -0400
commitb333293058aa2d401737c7246bce58f8ba00906d (patch)
treedace4eab8f669d29b4e10cd784d16ca1690cbbbf /drivers/s390/net/qeth_l3_sys.c
parent0da9581ddb0ffbec8129504d661b563749160e70 (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.c110
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 @@
9 */ 9 */
10 10
11#include <linux/slab.h> 11#include <linux/slab.h>
12 12#include <asm/ebcdic.h>
13#include "qeth_l3.h" 13#include "qeth_l3.h"
14 14
15#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ 15#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
@@ -308,6 +308,8 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev,
308 308
309 if (card->info.type != QETH_CARD_TYPE_IQD) 309 if (card->info.type != QETH_CARD_TYPE_IQD)
310 return -EPERM; 310 return -EPERM;
311 if (card->options.cq == QETH_CQ_ENABLED)
312 return -EPERM;
311 313
312 mutex_lock(&card->conf_mutex); 314 mutex_lock(&card->conf_mutex);
313 if ((card->state != CARD_STATE_DOWN) && 315 if ((card->state != CARD_STATE_DOWN) &&
@@ -347,6 +349,111 @@ out:
347static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show, 349static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
348 qeth_l3_dev_sniffer_store); 350 qeth_l3_dev_sniffer_store);
349 351
352
353static ssize_t qeth_l3_dev_hsuid_show(struct device *dev,
354 struct device_attribute *attr, char *buf)
355{
356 struct qeth_card *card = dev_get_drvdata(dev);
357 char tmp_hsuid[9];
358
359 if (!card)
360 return -EINVAL;
361
362 if (card->info.type != QETH_CARD_TYPE_IQD)
363 return -EPERM;
364
365 if (card->state == CARD_STATE_DOWN)
366 return -EPERM;
367
368 memcpy(tmp_hsuid, card->options.hsuid, sizeof(tmp_hsuid));
369 EBCASC(tmp_hsuid, 8);
370 return sprintf(buf, "%s\n", tmp_hsuid);
371}
372
373static ssize_t qeth_l3_dev_hsuid_store(struct device *dev,
374 struct device_attribute *attr, const char *buf, size_t count)
375{
376 struct qeth_card *card = dev_get_drvdata(dev);
377 struct qeth_ipaddr *addr;
378 char *tmp;
379 int i;
380
381 if (!card)
382 return -EINVAL;
383
384 if (card->info.type != QETH_CARD_TYPE_IQD)
385 return -EPERM;
386 if (card->state != CARD_STATE_DOWN &&
387 card->state != CARD_STATE_RECOVER)
388 return -EPERM;
389 if (card->options.sniffer)
390 return -EPERM;
391 if (card->options.cq == QETH_CQ_NOTAVAILABLE)
392 return -EPERM;
393
394 tmp = strsep((char **)&buf, "\n");
395 if (strlen(tmp) > 8)
396 return -EINVAL;
397
398 if (card->options.hsuid[0]) {
399 /* delete old ip address */
400 addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
401 if (addr != NULL) {
402 addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
403 addr->u.a6.addr.s6_addr32[1] = 0x00000000;
404 for (i = 8; i < 16; i++)
405 addr->u.a6.addr.s6_addr[i] =
406 card->options.hsuid[i - 8];
407 addr->u.a6.pfxlen = 0;
408 addr->type = QETH_IP_TYPE_NORMAL;
409 } else
410 return -ENOMEM;
411 if (!qeth_l3_delete_ip(card, addr))
412 kfree(addr);
413 qeth_l3_set_ip_addr_list(card);
414 }
415
416 if (strlen(tmp) == 0) {
417 /* delete ip address only */
418 card->options.hsuid[0] = '\0';
419 if (card->dev)
420 memcpy(card->dev->perm_addr, card->options.hsuid, 9);
421 qeth_configure_cq(card, QETH_CQ_DISABLED);
422 return count;
423 }
424
425 if (qeth_configure_cq(card, QETH_CQ_ENABLED))
426 return -EPERM;
427
428 for (i = 0; i < 8; i++)
429 card->options.hsuid[i] = ' ';
430 card->options.hsuid[8] = '\0';
431 strncpy(card->options.hsuid, tmp, strlen(tmp));
432 ASCEBC(card->options.hsuid, 8);
433 if (card->dev)
434 memcpy(card->dev->perm_addr, card->options.hsuid, 9);
435
436 addr = qeth_l3_get_addr_buffer(QETH_PROT_IPV6);
437 if (addr != NULL) {
438 addr->u.a6.addr.s6_addr32[0] = 0xfe800000;
439 addr->u.a6.addr.s6_addr32[1] = 0x00000000;
440 for (i = 8; i < 16; i++)
441 addr->u.a6.addr.s6_addr[i] = card->options.hsuid[i - 8];
442 addr->u.a6.pfxlen = 0;
443 addr->type = QETH_IP_TYPE_NORMAL;
444 } else
445 return -ENOMEM;
446 if (!qeth_l3_add_ip(card, addr))
447 kfree(addr);
448 qeth_l3_set_ip_addr_list(card);
449
450 return count;
451}
452
453static DEVICE_ATTR(hsuid, 0644, qeth_l3_dev_hsuid_show,
454 qeth_l3_dev_hsuid_store);
455
456
350static struct attribute *qeth_l3_device_attrs[] = { 457static struct attribute *qeth_l3_device_attrs[] = {
351 &dev_attr_route4.attr, 458 &dev_attr_route4.attr,
352 &dev_attr_route6.attr, 459 &dev_attr_route6.attr,
@@ -354,6 +461,7 @@ static struct attribute *qeth_l3_device_attrs[] = {
354 &dev_attr_broadcast_mode.attr, 461 &dev_attr_broadcast_mode.attr,
355 &dev_attr_canonical_macaddr.attr, 462 &dev_attr_canonical_macaddr.attr,
356 &dev_attr_sniffer.attr, 463 &dev_attr_sniffer.attr,
464 &dev_attr_hsuid.attr,
357 NULL, 465 NULL,
358}; 466};
359 467