Commit b4d72c08b358fc5b259fad0f4971112d949efd1c

Authored by Eugene Crosser
Committed by David S. Miller
1 parent 3977458c9c

qeth: bridgeport support - basic control

Introduce functions to assign roles and check state of bridgeport-capable
HiperSocket devices, and sysfs attributes providing access to these
functions from userspace. Introduce udev events emitted when the state
of a bridgeport device changes.

Signed-off-by: Eugene Crosser <eugene.crosser@ru.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Reviewed-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 9 changed files with 685 additions and 2 deletions Side-by-side Diff

Documentation/s390/qeth.txt
  1 +IBM s390 QDIO Ethernet Driver
  2 +
  3 +HiperSockets Bridge Port Support
  4 +
  5 +Uevents
  6 +
  7 +To generate the events the device must be assigned a role of either
  8 +a primary or a secondary Bridge Port. For more information, see
  9 +"z/VM Connectivity, SC24-6174".
  10 +
  11 +When run on HiperSockets Bridge Capable Port hardware, and the state
  12 +of some configured Bridge Port device on the channel changes, a udev
  13 +event with ACTION=CHANGE is emitted on behalf of the corresponding
  14 +ccwgroup device. The event has the following attributes:
  15 +
  16 +BRIDGEPORT=statechange - indicates that the Bridge Port device changed
  17 + its state.
  18 +
  19 +ROLE={primary|secondary|none} - the role assigned to the port.
  20 +
  21 +STATE={active|standby|inactive} - the newly assumed state of the port.
drivers/s390/net/Makefile
... ... @@ -11,7 +11,7 @@
11 11 obj-$(CONFIG_CLAW) += claw.o
12 12 qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o
13 13 obj-$(CONFIG_QETH) += qeth.o
14   -qeth_l2-y += qeth_l2_main.o
  14 +qeth_l2-y += qeth_l2_main.o qeth_l2_sys.o
15 15 obj-$(CONFIG_QETH_L2) += qeth_l2.o
16 16 qeth_l3-y += qeth_l3_main.o qeth_l3_sys.o
17 17 obj-$(CONFIG_QETH_L3) += qeth_l3.o
drivers/s390/net/qeth_core.h
... ... @@ -156,6 +156,24 @@
156 156 __u32 enabled_funcs;
157 157 };
158 158  
  159 +/* SETBRIDGEPORT stuff */
  160 +enum qeth_sbp_roles {
  161 + QETH_SBP_ROLE_NONE = 0,
  162 + QETH_SBP_ROLE_PRIMARY = 1,
  163 + QETH_SBP_ROLE_SECONDARY = 2,
  164 +};
  165 +
  166 +enum qeth_sbp_states {
  167 + QETH_SBP_STATE_INACTIVE = 0,
  168 + QETH_SBP_STATE_STANDBY = 1,
  169 + QETH_SBP_STATE_ACTIVE = 2,
  170 +};
  171 +
  172 +struct qeth_sbp_info {
  173 + __u32 supported_funcs;
  174 + enum qeth_sbp_roles role;
  175 +};
  176 +
159 177 static inline int qeth_is_ipa_supported(struct qeth_ipa_info *ipa,
160 178 enum qeth_ipa_funcs func)
161 179 {
... ... @@ -672,6 +690,7 @@
672 690 struct qeth_ipa_info adp; /*Adapter parameters*/
673 691 struct qeth_routing_info route6;
674 692 struct qeth_ipa_info ipa6;
  693 + struct qeth_sbp_info sbp; /* SETBRIDGEPORT options */
675 694 int fake_broadcast;
676 695 int add_hhlen;
677 696 int layer2;
... ... @@ -857,6 +876,7 @@
857 876 extern struct qeth_discipline qeth_l3_discipline;
858 877 extern const struct attribute_group *qeth_generic_attr_groups[];
859 878 extern const struct attribute_group *qeth_osn_attr_groups[];
  879 +extern struct workqueue_struct *qeth_wq;
860 880  
861 881 const char *qeth_get_cardname_short(struct qeth_card *);
862 882 int qeth_realloc_buffer_pool(struct qeth_card *, int);
... ... @@ -925,6 +945,11 @@
925 945 int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
926 946 int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long),
927 947 void *reply_param);
  948 +void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd);
  949 +void qeth_bridgeport_query_support(struct qeth_card *card);
  950 +int qeth_bridgeport_query_ports(struct qeth_card *card,
  951 + enum qeth_sbp_roles *role, enum qeth_sbp_states *state);
  952 +int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role);
928 953 int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
929 954 int qeth_get_elements_no(struct qeth_card *, struct sk_buff *, int);
930 955 int qeth_get_elements_for_frags(struct sk_buff *);
drivers/s390/net/qeth_core_main.c
... ... @@ -68,7 +68,7 @@
68 68 enum qeth_qdio_buffer_states newbufstate);
69 69 static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
70 70  
71   -static struct workqueue_struct *qeth_wq;
  71 +struct workqueue_struct *qeth_wq;
72 72  
73 73 static void qeth_close_dev_handler(struct work_struct *work)
74 74 {
... ... @@ -615,6 +615,13 @@
615 615 card->info.hwtrap = 2;
616 616 qeth_schedule_recovery(card);
617 617 return NULL;
  618 + case IPA_CMD_SETBRIDGEPORT:
  619 + if (cmd->data.sbp.hdr.command_code ==
  620 + IPA_SBP_BRIDGE_PORT_STATE_CHANGE) {
  621 + qeth_bridge_state_change(card, cmd);
  622 + return NULL;
  623 + } else
  624 + return cmd;
618 625 case IPA_CMD_MODCCID:
619 626 return cmd;
620 627 case IPA_CMD_REGISTER_LOCAL_ADDR:
621 628  
... ... @@ -4956,12 +4963,17 @@
4956 4963  
4957 4964 card->options.ipa4.supported_funcs = 0;
4958 4965 card->options.adp.supported_funcs = 0;
  4966 + card->options.sbp.supported_funcs = 0;
4959 4967 card->info.diagass_support = 0;
4960 4968 qeth_query_ipassists(card, QETH_PROT_IPV4);
4961 4969 if (qeth_is_supported(card, IPA_SETADAPTERPARMS))
4962 4970 qeth_query_setadapterparms(card);
4963 4971 if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST))
4964 4972 qeth_query_setdiagass(card);
  4973 + qeth_bridgeport_query_support(card);
  4974 + if (card->options.sbp.supported_funcs)
  4975 + dev_info(&card->gdev->dev,
  4976 + "The device represents a HiperSockets Bridge Capable Port\n");
4965 4977 return 0;
4966 4978 out:
4967 4979 dev_warn(&card->gdev->dev, "The qeth device driver failed to recover "
drivers/s390/net/qeth_core_mpc.c
... ... @@ -249,6 +249,7 @@
249 249 {IPA_CMD_DELIP, "delip"},
250 250 {IPA_CMD_SETADAPTERPARMS, "setadapterparms"},
251 251 {IPA_CMD_SET_DIAG_ASS, "set_diag_ass"},
  252 + {IPA_CMD_SETBRIDGEPORT, "set_bridge_port"},
252 253 {IPA_CMD_CREATE_ADDR, "create_addr"},
253 254 {IPA_CMD_DESTROY_ADDR, "destroy_addr"},
254 255 {IPA_CMD_REGISTER_LOCAL_ADDR, "register_local_addr"},
drivers/s390/net/qeth_core_mpc.h
... ... @@ -104,6 +104,7 @@
104 104 IPA_CMD_DELIP = 0xb7,
105 105 IPA_CMD_SETADAPTERPARMS = 0xb8,
106 106 IPA_CMD_SET_DIAG_ASS = 0xb9,
  107 + IPA_CMD_SETBRIDGEPORT = 0xbe,
107 108 IPA_CMD_CREATE_ADDR = 0xc3,
108 109 IPA_CMD_DESTROY_ADDR = 0xc4,
109 110 IPA_CMD_REGISTER_LOCAL_ADDR = 0xd1,
... ... @@ -500,6 +501,88 @@
500 501 __u8 cdata[64];
501 502 } __attribute__ ((packed));
502 503  
  504 +/* SETBRIDGEPORT IPA Command: *********************************************/
  505 +enum qeth_ipa_sbp_cmd {
  506 + IPA_SBP_QUERY_COMMANDS_SUPPORTED = 0x00000000L,
  507 + IPA_SBP_RESET_BRIDGE_PORT_ROLE = 0x00000001L,
  508 + IPA_SBP_SET_PRIMARY_BRIDGE_PORT = 0x00000002L,
  509 + IPA_SBP_SET_SECONDARY_BRIDGE_PORT = 0x00000004L,
  510 + IPA_SBP_QUERY_BRIDGE_PORTS = 0x00000008L,
  511 + IPA_SBP_BRIDGE_PORT_STATE_CHANGE = 0x00000010L,
  512 +};
  513 +
  514 +struct net_if_token {
  515 + __u16 devnum;
  516 + __u8 cssid;
  517 + __u8 iid;
  518 + __u8 ssid;
  519 + __u8 chpid;
  520 + __u16 chid;
  521 +} __packed;
  522 +
  523 +struct qeth_ipacmd_sbp_hdr {
  524 + __u32 supported_sbp_cmds;
  525 + __u32 enabled_sbp_cmds;
  526 + __u16 cmdlength;
  527 + __u16 reserved1;
  528 + __u32 command_code;
  529 + __u16 return_code;
  530 + __u8 used_total;
  531 + __u8 seq_no;
  532 + __u32 reserved2;
  533 +} __packed;
  534 +
  535 +struct qeth_sbp_query_cmds_supp {
  536 + __u32 supported_cmds;
  537 + __u32 reserved;
  538 +} __packed;
  539 +
  540 +struct qeth_sbp_reset_role {
  541 +} __packed;
  542 +
  543 +struct qeth_sbp_set_primary {
  544 + struct net_if_token token;
  545 +} __packed;
  546 +
  547 +struct qeth_sbp_set_secondary {
  548 +} __packed;
  549 +
  550 +struct qeth_sbp_port_entry {
  551 + __u8 role;
  552 + __u8 state;
  553 + __u8 reserved1;
  554 + __u8 reserved2;
  555 + struct net_if_token token;
  556 +} __packed;
  557 +
  558 +struct qeth_sbp_query_ports {
  559 + __u8 primary_bp_supported;
  560 + __u8 secondary_bp_supported;
  561 + __u8 num_entries;
  562 + __u8 entry_length;
  563 + struct qeth_sbp_port_entry entry[];
  564 +} __packed;
  565 +
  566 +struct qeth_sbp_state_change {
  567 + __u8 primary_bp_supported;
  568 + __u8 secondary_bp_supported;
  569 + __u8 num_entries;
  570 + __u8 entry_length;
  571 + struct qeth_sbp_port_entry entry[];
  572 +} __packed;
  573 +
  574 +struct qeth_ipacmd_setbridgeport {
  575 + struct qeth_ipacmd_sbp_hdr hdr;
  576 + union {
  577 + struct qeth_sbp_query_cmds_supp query_cmds_supp;
  578 + struct qeth_sbp_reset_role reset_role;
  579 + struct qeth_sbp_set_primary set_primary;
  580 + struct qeth_sbp_set_secondary set_secondary;
  581 + struct qeth_sbp_query_ports query_ports;
  582 + struct qeth_sbp_state_change state_change;
  583 + } data;
  584 +} __packed;
  585 +
503 586 /* Header for each IPA command */
504 587 struct qeth_ipacmd_hdr {
505 588 __u8 command;
... ... @@ -529,6 +612,7 @@
529 612 struct qeth_ipacmd_setadpparms setadapterparms;
530 613 struct qeth_set_routing setrtg;
531 614 struct qeth_ipacmd_diagass diagass;
  615 + struct qeth_ipacmd_setbridgeport sbp;
532 616 } data;
533 617 } __attribute__ ((packed));
534 618  
drivers/s390/net/qeth_l2.h
  1 +/*
  2 + * Copyright IBM Corp. 2013
  3 + * Author(s): Eugene Crosser <eugene.crosser@ru.ibm.com>
  4 + */
  5 +
  6 +#ifndef __QETH_L2_H__
  7 +#define __QETH_L2_H__
  8 +
  9 +#include "qeth_core.h"
  10 +
  11 +int qeth_l2_create_device_attributes(struct device *);
  12 +void qeth_l2_remove_device_attributes(struct device *);
  13 +void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card);
  14 +
  15 +#endif /* __QETH_L2_H__ */
drivers/s390/net/qeth_l2_main.c
... ... @@ -21,6 +21,7 @@
21 21 #include <linux/list.h>
22 22  
23 23 #include "qeth_core.h"
  24 +#include "qeth_l2.h"
24 25  
25 26 static int qeth_l2_set_offline(struct ccwgroup_device *);
26 27 static int qeth_l2_stop(struct net_device *);
... ... @@ -880,6 +881,7 @@
880 881 {
881 882 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
882 883  
  884 + qeth_l2_create_device_attributes(&gdev->dev);
883 885 INIT_LIST_HEAD(&card->vid_list);
884 886 INIT_LIST_HEAD(&card->mc_list);
885 887 card->options.layer2 = 1;
... ... @@ -891,6 +893,7 @@
891 893 {
892 894 struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
893 895  
  896 + qeth_l2_remove_device_attributes(&cgdev->dev);
894 897 qeth_set_allowed_threads(card, 0, 1);
895 898 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
896 899  
... ... @@ -1003,6 +1006,8 @@
1003 1006 } else
1004 1007 card->info.hwtrap = 0;
1005 1008  
  1009 + qeth_l2_setup_bridgeport_attrs(card);
  1010 +
1006 1011 card->state = CARD_STATE_HARDSETUP;
1007 1012 memset(&card->rx, 0, sizeof(struct qeth_rx));
1008 1013 qeth_print_status_message(card);
... ... @@ -1346,6 +1351,365 @@
1346 1351 return;
1347 1352 }
1348 1353 EXPORT_SYMBOL(qeth_osn_deregister);
  1354 +
  1355 +/* SETBRIDGEPORT support, async notifications */
  1356 +
  1357 +struct qeth_bridge_state_data {
  1358 + struct work_struct worker;
  1359 + struct qeth_card *card;
  1360 + struct qeth_sbp_state_change qports;
  1361 +};
  1362 +
  1363 +static void qeth_bridge_state_change_worker(struct work_struct *work)
  1364 +{
  1365 + struct qeth_bridge_state_data *data =
  1366 + container_of(work, struct qeth_bridge_state_data, worker);
  1367 + /* We are only interested in the first entry - local port */
  1368 + struct qeth_sbp_port_entry *entry = &data->qports.entry[0];
  1369 + char env_locrem[32];
  1370 + char env_role[32];
  1371 + char env_state[32];
  1372 + char *env[] = {
  1373 + env_locrem,
  1374 + env_role,
  1375 + env_state,
  1376 + NULL
  1377 + };
  1378 +
  1379 + /* Role should not change by itself, but if it did, */
  1380 + /* information from the hardware is authoritative. */
  1381 + mutex_lock(&data->card->conf_mutex);
  1382 + data->card->options.sbp.role = entry->role;
  1383 + mutex_unlock(&data->card->conf_mutex);
  1384 +
  1385 + snprintf(env_locrem, sizeof(env_locrem), "BRIDGEPORT=statechange");
  1386 + snprintf(env_role, sizeof(env_role), "ROLE=%s",
  1387 + (entry->role == QETH_SBP_ROLE_NONE) ? "none" :
  1388 + (entry->role == QETH_SBP_ROLE_PRIMARY) ? "primary" :
  1389 + (entry->role == QETH_SBP_ROLE_SECONDARY) ? "secondary" :
  1390 + "<INVALID>");
  1391 + snprintf(env_state, sizeof(env_state), "STATE=%s",
  1392 + (entry->state == QETH_SBP_STATE_INACTIVE) ? "inactive" :
  1393 + (entry->state == QETH_SBP_STATE_STANDBY) ? "standby" :
  1394 + (entry->state == QETH_SBP_STATE_ACTIVE) ? "active" :
  1395 + "<INVALID>");
  1396 + kobject_uevent_env(&data->card->gdev->dev.kobj,
  1397 + KOBJ_CHANGE, env);
  1398 + kfree(data);
  1399 +}
  1400 +
  1401 +void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd)
  1402 +{
  1403 + struct qeth_sbp_state_change *qports =
  1404 + &cmd->data.sbp.data.state_change;
  1405 + struct qeth_bridge_state_data *data;
  1406 + int extrasize;
  1407 +
  1408 + QETH_CARD_TEXT(card, 2, "brstchng");
  1409 + if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) {
  1410 + QETH_CARD_TEXT_(card, 2, "BPsz%.8d", qports->entry_length);
  1411 + return;
  1412 + }
  1413 + extrasize = sizeof(struct qeth_sbp_port_entry) * qports->num_entries;
  1414 + data = kzalloc(sizeof(struct qeth_bridge_state_data) + extrasize,
  1415 + GFP_ATOMIC);
  1416 + if (!data) {
  1417 + QETH_CARD_TEXT(card, 2, "BPSalloc");
  1418 + return;
  1419 + }
  1420 + INIT_WORK(&data->worker, qeth_bridge_state_change_worker);
  1421 + data->card = card;
  1422 + memcpy(&data->qports, qports,
  1423 + sizeof(struct qeth_sbp_state_change) + extrasize);
  1424 + queue_work(qeth_wq, &data->worker);
  1425 +}
  1426 +EXPORT_SYMBOL(qeth_bridge_state_change);
  1427 +
  1428 +/* SETBRIDGEPORT support; sending commands */
  1429 +
  1430 +struct _qeth_sbp_cbctl {
  1431 + u16 ipa_rc;
  1432 + u16 cmd_rc;
  1433 + union {
  1434 + u32 supported;
  1435 + struct {
  1436 + enum qeth_sbp_roles *role;
  1437 + enum qeth_sbp_states *state;
  1438 + } qports;
  1439 + } data;
  1440 +};
  1441 +
  1442 +/**
  1443 + * qeth_bridgeport_makerc() - derive "traditional" error from hardware codes.
  1444 + * @card: qeth_card structure pointer, for debug messages.
  1445 + * @cbctl: state structure with hardware return codes.
  1446 + * @setcmd: IPA command code
  1447 + *
  1448 + * Returns negative errno-compatible error indication or 0 on success.
  1449 + */
  1450 +static int qeth_bridgeport_makerc(struct qeth_card *card,
  1451 + struct _qeth_sbp_cbctl *cbctl, enum qeth_ipa_sbp_cmd setcmd)
  1452 +{
  1453 + int rc;
  1454 +
  1455 + switch (cbctl->ipa_rc) {
  1456 + case IPA_RC_SUCCESS:
  1457 + switch (cbctl->cmd_rc) {
  1458 + case 0x0000:
  1459 + rc = 0;
  1460 + break;
  1461 + case 0x0004:
  1462 + rc = -ENOSYS;
  1463 + break;
  1464 + case 0x000C: /* Not configured as bridge Port */
  1465 + rc = -ENODEV; /* maybe not the best code here? */
  1466 + dev_err(&card->gdev->dev,
  1467 + "The HiperSockets device is not configured as a Bridge Port\n");
  1468 + break;
  1469 + case 0x0014: /* Another device is Primary */
  1470 + switch (setcmd) {
  1471 + case IPA_SBP_SET_PRIMARY_BRIDGE_PORT:
  1472 + rc = -EEXIST;
  1473 + dev_err(&card->gdev->dev,
  1474 + "The HiperSockets LAN already has a primary Bridge Port\n");
  1475 + break;
  1476 + case IPA_SBP_SET_SECONDARY_BRIDGE_PORT:
  1477 + rc = -EBUSY;
  1478 + dev_err(&card->gdev->dev,
  1479 + "The HiperSockets device is already a primary Bridge Port\n");
  1480 + break;
  1481 + default:
  1482 + rc = -EIO;
  1483 + }
  1484 + break;
  1485 + case 0x0018: /* This device is currently Secondary */
  1486 + rc = -EBUSY;
  1487 + dev_err(&card->gdev->dev,
  1488 + "The HiperSockets device is already a secondary Bridge Port\n");
  1489 + break;
  1490 + case 0x001C: /* Limit for Secondary devices reached */
  1491 + rc = -EEXIST;
  1492 + dev_err(&card->gdev->dev,
  1493 + "The HiperSockets LAN cannot have more secondary Bridge Ports\n");
  1494 + break;
  1495 + case 0x0024: /* This device is currently Primary */
  1496 + rc = -EBUSY;
  1497 + dev_err(&card->gdev->dev,
  1498 + "The HiperSockets device is already a primary Bridge Port\n");
  1499 + break;
  1500 + case 0x0020: /* Not authorized by zManager */
  1501 + rc = -EACCES;
  1502 + dev_err(&card->gdev->dev,
  1503 + "The HiperSockets device is not authorized to be a Bridge Port\n");
  1504 + break;
  1505 + default:
  1506 + rc = -EIO;
  1507 + }
  1508 + break;
  1509 + case IPA_RC_NOTSUPP:
  1510 + rc = -ENOSYS;
  1511 + break;
  1512 + case IPA_RC_UNSUPPORTED_COMMAND:
  1513 + rc = -ENOSYS;
  1514 + break;
  1515 + default:
  1516 + rc = -EIO;
  1517 + }
  1518 + if (rc) {
  1519 + QETH_CARD_TEXT_(card, 2, "SBPi%04x", cbctl->ipa_rc);
  1520 + QETH_CARD_TEXT_(card, 2, "SBPc%04x", cbctl->cmd_rc);
  1521 + }
  1522 + return rc;
  1523 +}
  1524 +
  1525 +static int qeth_bridgeport_query_support_cb(struct qeth_card *card,
  1526 + struct qeth_reply *reply, unsigned long data)
  1527 +{
  1528 + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
  1529 + struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
  1530 + QETH_CARD_TEXT(card, 2, "brqsupcb");
  1531 + cbctl->ipa_rc = cmd->hdr.return_code;
  1532 + cbctl->cmd_rc = cmd->data.sbp.hdr.return_code;
  1533 + if ((cbctl->ipa_rc == 0) && (cbctl->cmd_rc == 0)) {
  1534 + cbctl->data.supported =
  1535 + cmd->data.sbp.data.query_cmds_supp.supported_cmds;
  1536 + } else {
  1537 + cbctl->data.supported = 0;
  1538 + }
  1539 + return 0;
  1540 +}
  1541 +
  1542 +/**
  1543 + * qeth_bridgeport_query_support() - store bitmask of supported subfunctions.
  1544 + * @card: qeth_card structure pointer.
  1545 + *
  1546 + * Sets bitmask of supported setbridgeport subfunctions in the qeth_card
  1547 + * strucutre: card->options.sbp.supported_funcs.
  1548 + */
  1549 +void qeth_bridgeport_query_support(struct qeth_card *card)
  1550 +{
  1551 + struct qeth_cmd_buffer *iob;
  1552 + struct qeth_ipa_cmd *cmd;
  1553 + struct _qeth_sbp_cbctl cbctl;
  1554 +
  1555 + QETH_CARD_TEXT(card, 2, "brqsuppo");
  1556 + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
  1557 + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
  1558 + cmd->data.sbp.hdr.cmdlength =
  1559 + sizeof(struct qeth_ipacmd_sbp_hdr) +
  1560 + sizeof(struct qeth_sbp_query_cmds_supp);
  1561 + cmd->data.sbp.hdr.command_code =
  1562 + IPA_SBP_QUERY_COMMANDS_SUPPORTED;
  1563 + cmd->data.sbp.hdr.used_total = 1;
  1564 + cmd->data.sbp.hdr.seq_no = 1;
  1565 + if (qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_support_cb,
  1566 + (void *)&cbctl) ||
  1567 + qeth_bridgeport_makerc(card, &cbctl,
  1568 + IPA_SBP_QUERY_COMMANDS_SUPPORTED)) {
  1569 + /* non-zero makerc signifies failure, and produce messages */
  1570 + card->options.sbp.role = QETH_SBP_ROLE_NONE;
  1571 + return;
  1572 + }
  1573 + card->options.sbp.supported_funcs = cbctl.data.supported;
  1574 +}
  1575 +EXPORT_SYMBOL_GPL(qeth_bridgeport_query_support);
  1576 +
  1577 +static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
  1578 + struct qeth_reply *reply, unsigned long data)
  1579 +{
  1580 + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
  1581 + struct qeth_sbp_query_ports *qports = &cmd->data.sbp.data.query_ports;
  1582 + struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
  1583 +
  1584 + QETH_CARD_TEXT(card, 2, "brqprtcb");
  1585 + cbctl->ipa_rc = cmd->hdr.return_code;
  1586 + cbctl->cmd_rc = cmd->data.sbp.hdr.return_code;
  1587 + if ((cbctl->ipa_rc != 0) || (cbctl->cmd_rc != 0))
  1588 + return 0;
  1589 + if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) {
  1590 + cbctl->cmd_rc = 0xffff;
  1591 + QETH_CARD_TEXT_(card, 2, "SBPs%04x", qports->entry_length);
  1592 + return 0;
  1593 + }
  1594 + /* first entry contains the state of the local port */
  1595 + if (qports->num_entries > 0) {
  1596 + if (cbctl->data.qports.role)
  1597 + *cbctl->data.qports.role = qports->entry[0].role;
  1598 + if (cbctl->data.qports.state)
  1599 + *cbctl->data.qports.state = qports->entry[0].state;
  1600 + }
  1601 + return 0;
  1602 +}
  1603 +
  1604 +/**
  1605 + * qeth_bridgeport_query_ports() - query local bridgeport status.
  1606 + * @card: qeth_card structure pointer.
  1607 + * @role: Role of the port: 0-none, 1-primary, 2-secondary.
  1608 + * @state: State of the port: 0-inactive, 1-standby, 2-active.
  1609 + *
  1610 + * Returns negative errno-compatible error indication or 0 on success.
  1611 + *
  1612 + * 'role' and 'state' are not updated in case of hardware operation failure.
  1613 + */
  1614 +int qeth_bridgeport_query_ports(struct qeth_card *card,
  1615 + enum qeth_sbp_roles *role, enum qeth_sbp_states *state)
  1616 +{
  1617 + int rc = 0;
  1618 + struct qeth_cmd_buffer *iob;
  1619 + struct qeth_ipa_cmd *cmd;
  1620 + struct _qeth_sbp_cbctl cbctl = {
  1621 + .data = {
  1622 + .qports = {
  1623 + .role = role,
  1624 + .state = state,
  1625 + },
  1626 + },
  1627 + };
  1628 +
  1629 + QETH_CARD_TEXT(card, 2, "brqports");
  1630 + if (!(card->options.sbp.supported_funcs & IPA_SBP_QUERY_BRIDGE_PORTS))
  1631 + return -EOPNOTSUPP;
  1632 + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
  1633 + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
  1634 + cmd->data.sbp.hdr.cmdlength =
  1635 + sizeof(struct qeth_ipacmd_sbp_hdr);
  1636 + cmd->data.sbp.hdr.command_code =
  1637 + IPA_SBP_QUERY_BRIDGE_PORTS;
  1638 + cmd->data.sbp.hdr.used_total = 1;
  1639 + cmd->data.sbp.hdr.seq_no = 1;
  1640 + rc = qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_ports_cb,
  1641 + (void *)&cbctl);
  1642 + if (rc)
  1643 + return rc;
  1644 + rc = qeth_bridgeport_makerc(card, &cbctl, IPA_SBP_QUERY_BRIDGE_PORTS);
  1645 + if (rc)
  1646 + return rc;
  1647 + return 0;
  1648 +}
  1649 +EXPORT_SYMBOL_GPL(qeth_bridgeport_query_ports);
  1650 +
  1651 +static int qeth_bridgeport_set_cb(struct qeth_card *card,
  1652 + struct qeth_reply *reply, unsigned long data)
  1653 +{
  1654 + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data;
  1655 + struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
  1656 + QETH_CARD_TEXT(card, 2, "brsetrcb");
  1657 + cbctl->ipa_rc = cmd->hdr.return_code;
  1658 + cbctl->cmd_rc = cmd->data.sbp.hdr.return_code;
  1659 + return 0;
  1660 +}
  1661 +
  1662 +/**
  1663 + * qeth_bridgeport_setrole() - Assign primary role to the port.
  1664 + * @card: qeth_card structure pointer.
  1665 + * @role: Role to assign.
  1666 + *
  1667 + * Returns negative errno-compatible error indication or 0 on success.
  1668 + */
  1669 +int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role)
  1670 +{
  1671 + int rc = 0;
  1672 + int cmdlength;
  1673 + struct qeth_cmd_buffer *iob;
  1674 + struct qeth_ipa_cmd *cmd;
  1675 + struct _qeth_sbp_cbctl cbctl;
  1676 + enum qeth_ipa_sbp_cmd setcmd;
  1677 +
  1678 + QETH_CARD_TEXT(card, 2, "brsetrol");
  1679 + switch (role) {
  1680 + case QETH_SBP_ROLE_NONE:
  1681 + setcmd = IPA_SBP_RESET_BRIDGE_PORT_ROLE;
  1682 + cmdlength = sizeof(struct qeth_ipacmd_sbp_hdr) +
  1683 + sizeof(struct qeth_sbp_reset_role);
  1684 + break;
  1685 + case QETH_SBP_ROLE_PRIMARY:
  1686 + setcmd = IPA_SBP_SET_PRIMARY_BRIDGE_PORT;
  1687 + cmdlength = sizeof(struct qeth_ipacmd_sbp_hdr) +
  1688 + sizeof(struct qeth_sbp_set_primary);
  1689 + break;
  1690 + case QETH_SBP_ROLE_SECONDARY:
  1691 + setcmd = IPA_SBP_SET_SECONDARY_BRIDGE_PORT;
  1692 + cmdlength = sizeof(struct qeth_ipacmd_sbp_hdr) +
  1693 + sizeof(struct qeth_sbp_set_secondary);
  1694 + break;
  1695 + default:
  1696 + return -EINVAL;
  1697 + }
  1698 + if (!(card->options.sbp.supported_funcs & setcmd))
  1699 + return -EOPNOTSUPP;
  1700 + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0);
  1701 + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
  1702 + cmd->data.sbp.hdr.cmdlength = cmdlength;
  1703 + cmd->data.sbp.hdr.command_code = setcmd;
  1704 + cmd->data.sbp.hdr.used_total = 1;
  1705 + cmd->data.sbp.hdr.seq_no = 1;
  1706 + rc = qeth_send_ipa_cmd(card, iob, qeth_bridgeport_set_cb,
  1707 + (void *)&cbctl);
  1708 + if (rc)
  1709 + return rc;
  1710 + rc = qeth_bridgeport_makerc(card, &cbctl, setcmd);
  1711 + return rc;
  1712 +}
1349 1713  
1350 1714 module_init(qeth_l2_init);
1351 1715 module_exit(qeth_l2_exit);
drivers/s390/net/qeth_l2_sys.c
  1 +/*
  2 + * Copyright IBM Corp. 2013
  3 + * Author(s): Eugene Crosser <eugene.crosser@ru.ibm.com>
  4 + */
  5 +
  6 +#include <linux/slab.h>
  7 +#include <asm/ebcdic.h>
  8 +#include "qeth_l2.h"
  9 +
  10 +#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
  11 +struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
  12 +
  13 +static int qeth_card_hw_is_reachable(struct qeth_card *card)
  14 +{
  15 + return (card->state == CARD_STATE_SOFTSETUP) ||
  16 + (card->state == CARD_STATE_UP);
  17 +}
  18 +
  19 +static ssize_t qeth_bridge_port_role_state_show(struct device *dev,
  20 + struct device_attribute *attr, char *buf,
  21 + int show_state)
  22 +{
  23 + struct qeth_card *card = dev_get_drvdata(dev);
  24 + enum qeth_sbp_states state = QETH_SBP_STATE_INACTIVE;
  25 + int rc = 0;
  26 + char *word;
  27 +
  28 + if (!card)
  29 + return -EINVAL;
  30 +
  31 + mutex_lock(&card->conf_mutex);
  32 +
  33 + if (qeth_card_hw_is_reachable(card) &&
  34 + card->options.sbp.supported_funcs)
  35 + rc = qeth_bridgeport_query_ports(card,
  36 + &card->options.sbp.role, &state);
  37 + if (!rc) {
  38 + if (show_state)
  39 + switch (state) {
  40 + case QETH_SBP_STATE_INACTIVE:
  41 + word = "inactive"; break;
  42 + case QETH_SBP_STATE_STANDBY:
  43 + word = "standby"; break;
  44 + case QETH_SBP_STATE_ACTIVE:
  45 + word = "active"; break;
  46 + default:
  47 + rc = -EIO;
  48 + }
  49 + else
  50 + switch (card->options.sbp.role) {
  51 + case QETH_SBP_ROLE_NONE:
  52 + word = "none"; break;
  53 + case QETH_SBP_ROLE_PRIMARY:
  54 + word = "primary"; break;
  55 + case QETH_SBP_ROLE_SECONDARY:
  56 + word = "secondary"; break;
  57 + default:
  58 + rc = -EIO;
  59 + }
  60 + if (rc)
  61 + QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x",
  62 + card->options.sbp.role, state);
  63 + else
  64 + rc = sprintf(buf, "%s\n", word);
  65 + }
  66 +
  67 + mutex_unlock(&card->conf_mutex);
  68 +
  69 + return rc;
  70 +}
  71 +
  72 +static ssize_t qeth_bridge_port_role_show(struct device *dev,
  73 + struct device_attribute *attr, char *buf)
  74 +{
  75 + return qeth_bridge_port_role_state_show(dev, attr, buf, 0);
  76 +}
  77 +
  78 +static ssize_t qeth_bridge_port_role_store(struct device *dev,
  79 + struct device_attribute *attr, const char *buf, size_t count)
  80 +{
  81 + struct qeth_card *card = dev_get_drvdata(dev);
  82 + int rc = 0;
  83 + enum qeth_sbp_roles role;
  84 +
  85 + if (!card)
  86 + return -EINVAL;
  87 + if (sysfs_streq(buf, "primary"))
  88 + role = QETH_SBP_ROLE_PRIMARY;
  89 + else if (sysfs_streq(buf, "secondary"))
  90 + role = QETH_SBP_ROLE_SECONDARY;
  91 + else if (sysfs_streq(buf, "none"))
  92 + role = QETH_SBP_ROLE_NONE;
  93 + else
  94 + return -EINVAL;
  95 +
  96 + mutex_lock(&card->conf_mutex);
  97 +
  98 + if (qeth_card_hw_is_reachable(card)) {
  99 + rc = qeth_bridgeport_setrole(card, role);
  100 + if (!rc)
  101 + card->options.sbp.role = role;
  102 + } else
  103 + card->options.sbp.role = role;
  104 +
  105 + mutex_unlock(&card->conf_mutex);
  106 +
  107 + return rc ? rc : count;
  108 +}
  109 +
  110 +static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show,
  111 + qeth_bridge_port_role_store);
  112 +
  113 +static ssize_t qeth_bridge_port_state_show(struct device *dev,
  114 + struct device_attribute *attr, char *buf)
  115 +{
  116 + return qeth_bridge_port_role_state_show(dev, attr, buf, 1);
  117 +}
  118 +
  119 +static DEVICE_ATTR(bridge_state, 0644, qeth_bridge_port_state_show,
  120 + NULL);
  121 +
  122 +static struct attribute *qeth_l2_bridgeport_attrs[] = {
  123 + &dev_attr_bridge_role.attr,
  124 + &dev_attr_bridge_state.attr,
  125 + NULL,
  126 +};
  127 +
  128 +static struct attribute_group qeth_l2_bridgeport_attr_group = {
  129 + .attrs = qeth_l2_bridgeport_attrs,
  130 +};
  131 +
  132 +int qeth_l2_create_device_attributes(struct device *dev)
  133 +{
  134 + return sysfs_create_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
  135 +}
  136 +
  137 +void qeth_l2_remove_device_attributes(struct device *dev)
  138 +{
  139 + sysfs_remove_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
  140 +}
  141 +
  142 +/**
  143 + * qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online.
  144 + * @card: qeth_card structure pointer
  145 + *
  146 + * Note: this function is called with conf_mutex held by the caller
  147 + */
  148 +void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card)
  149 +{
  150 + if (!card)
  151 + return;
  152 + if (!card->options.sbp.supported_funcs)
  153 + return;
  154 + if (card->options.sbp.role != QETH_SBP_ROLE_NONE) {
  155 + /* Conditional to avoid spurious error messages */
  156 + qeth_bridgeport_setrole(card, card->options.sbp.role);
  157 + /* Let the callback function refresh the stored role value. */
  158 + qeth_bridgeport_query_ports(card,
  159 + &card->options.sbp.role, NULL);
  160 + }
  161 +}