aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorEugene Crosser <Eugene.Crosser@ru.ibm.com>2014-01-14 09:54:11 -0500
committerDavid S. Miller <davem@davemloft.net>2014-01-15 17:48:01 -0500
commitb4d72c08b358fc5b259fad0f4971112d949efd1c (patch)
treef2bcd879d3957e353e3c7d61a91b5d1a594d7db8 /drivers/s390
parent3977458c9c61fc27a5a88cfcf51696b838d1ecc9 (diff)
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>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/net/Makefile2
-rw-r--r--drivers/s390/net/qeth_core.h25
-rw-r--r--drivers/s390/net/qeth_core_main.c14
-rw-r--r--drivers/s390/net/qeth_core_mpc.c1
-rw-r--r--drivers/s390/net/qeth_core_mpc.h84
-rw-r--r--drivers/s390/net/qeth_l2.h15
-rw-r--r--drivers/s390/net/qeth_l2_main.c364
-rw-r--r--drivers/s390/net/qeth_l2_sys.c161
8 files changed, 664 insertions, 2 deletions
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index 4dfe8c1092da..d28f05d0c75a 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -11,7 +11,7 @@ obj-$(CONFIG_LCS) += lcs.o
11obj-$(CONFIG_CLAW) += claw.o 11obj-$(CONFIG_CLAW) += claw.o
12qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o 12qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o
13obj-$(CONFIG_QETH) += qeth.o 13obj-$(CONFIG_QETH) += qeth.o
14qeth_l2-y += qeth_l2_main.o 14qeth_l2-y += qeth_l2_main.o qeth_l2_sys.o
15obj-$(CONFIG_QETH_L2) += qeth_l2.o 15obj-$(CONFIG_QETH_L2) += qeth_l2.o
16qeth_l3-y += qeth_l3_main.o qeth_l3_sys.o 16qeth_l3-y += qeth_l3_main.o qeth_l3_sys.o
17obj-$(CONFIG_QETH_L3) += qeth_l3.o 17obj-$(CONFIG_QETH_L3) += qeth_l3.o
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index d45427c553b0..010f49e3e3ac 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -156,6 +156,24 @@ struct qeth_ipa_info {
156 __u32 enabled_funcs; 156 __u32 enabled_funcs;
157}; 157};
158 158
159/* SETBRIDGEPORT stuff */
160enum qeth_sbp_roles {
161 QETH_SBP_ROLE_NONE = 0,
162 QETH_SBP_ROLE_PRIMARY = 1,
163 QETH_SBP_ROLE_SECONDARY = 2,
164};
165
166enum qeth_sbp_states {
167 QETH_SBP_STATE_INACTIVE = 0,
168 QETH_SBP_STATE_STANDBY = 1,
169 QETH_SBP_STATE_ACTIVE = 2,
170};
171
172struct qeth_sbp_info {
173 __u32 supported_funcs;
174 enum qeth_sbp_roles role;
175};
176
159static inline int qeth_is_ipa_supported(struct qeth_ipa_info *ipa, 177static inline int qeth_is_ipa_supported(struct qeth_ipa_info *ipa,
160 enum qeth_ipa_funcs func) 178 enum qeth_ipa_funcs func)
161{ 179{
@@ -672,6 +690,7 @@ struct qeth_card_options {
672 struct qeth_ipa_info adp; /*Adapter parameters*/ 690 struct qeth_ipa_info adp; /*Adapter parameters*/
673 struct qeth_routing_info route6; 691 struct qeth_routing_info route6;
674 struct qeth_ipa_info ipa6; 692 struct qeth_ipa_info ipa6;
693 struct qeth_sbp_info sbp; /* SETBRIDGEPORT options */
675 int fake_broadcast; 694 int fake_broadcast;
676 int add_hhlen; 695 int add_hhlen;
677 int layer2; 696 int layer2;
@@ -857,6 +876,7 @@ extern struct qeth_discipline qeth_l2_discipline;
857extern struct qeth_discipline qeth_l3_discipline; 876extern struct qeth_discipline qeth_l3_discipline;
858extern const struct attribute_group *qeth_generic_attr_groups[]; 877extern const struct attribute_group *qeth_generic_attr_groups[];
859extern const struct attribute_group *qeth_osn_attr_groups[]; 878extern const struct attribute_group *qeth_osn_attr_groups[];
879extern struct workqueue_struct *qeth_wq;
860 880
861const char *qeth_get_cardname_short(struct qeth_card *); 881const char *qeth_get_cardname_short(struct qeth_card *);
862int qeth_realloc_buffer_pool(struct qeth_card *, int); 882int qeth_realloc_buffer_pool(struct qeth_card *, int);
@@ -925,6 +945,11 @@ int qeth_query_card_info(struct qeth_card *card,
925int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *, 945int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
926 int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long), 946 int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long),
927 void *reply_param); 947 void *reply_param);
948void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd);
949void qeth_bridgeport_query_support(struct qeth_card *card);
950int qeth_bridgeport_query_ports(struct qeth_card *card,
951 enum qeth_sbp_roles *role, enum qeth_sbp_states *state);
952int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role);
928int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); 953int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
929int qeth_get_elements_no(struct qeth_card *, struct sk_buff *, int); 954int qeth_get_elements_no(struct qeth_card *, struct sk_buff *, int);
930int qeth_get_elements_for_frags(struct sk_buff *); 955int qeth_get_elements_for_frags(struct sk_buff *);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index f9a85b47e3c3..1ffea16f51c6 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -68,7 +68,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
68 enum qeth_qdio_buffer_states newbufstate); 68 enum qeth_qdio_buffer_states newbufstate);
69static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int); 69static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
70 70
71static struct workqueue_struct *qeth_wq; 71struct workqueue_struct *qeth_wq;
72 72
73static void qeth_close_dev_handler(struct work_struct *work) 73static void qeth_close_dev_handler(struct work_struct *work)
74{ 74{
@@ -615,6 +615,13 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
615 card->info.hwtrap = 2; 615 card->info.hwtrap = 2;
616 qeth_schedule_recovery(card); 616 qeth_schedule_recovery(card);
617 return NULL; 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 case IPA_CMD_MODCCID: 625 case IPA_CMD_MODCCID:
619 return cmd; 626 return cmd;
620 case IPA_CMD_REGISTER_LOCAL_ADDR: 627 case IPA_CMD_REGISTER_LOCAL_ADDR:
@@ -4956,12 +4963,17 @@ retriable:
4956 4963
4957 card->options.ipa4.supported_funcs = 0; 4964 card->options.ipa4.supported_funcs = 0;
4958 card->options.adp.supported_funcs = 0; 4965 card->options.adp.supported_funcs = 0;
4966 card->options.sbp.supported_funcs = 0;
4959 card->info.diagass_support = 0; 4967 card->info.diagass_support = 0;
4960 qeth_query_ipassists(card, QETH_PROT_IPV4); 4968 qeth_query_ipassists(card, QETH_PROT_IPV4);
4961 if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) 4969 if (qeth_is_supported(card, IPA_SETADAPTERPARMS))
4962 qeth_query_setadapterparms(card); 4970 qeth_query_setadapterparms(card);
4963 if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) 4971 if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST))
4964 qeth_query_setdiagass(card); 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 return 0; 4977 return 0;
4966out: 4978out:
4967 dev_warn(&card->gdev->dev, "The qeth device driver failed to recover " 4979 dev_warn(&card->gdev->dev, "The qeth device driver failed to recover "
diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c
index 06c55780005e..2f44cfd5dd00 100644
--- a/drivers/s390/net/qeth_core_mpc.c
+++ b/drivers/s390/net/qeth_core_mpc.c
@@ -249,6 +249,7 @@ static struct ipa_cmd_names qeth_ipa_cmd_names[] = {
249 {IPA_CMD_DELIP, "delip"}, 249 {IPA_CMD_DELIP, "delip"},
250 {IPA_CMD_SETADAPTERPARMS, "setadapterparms"}, 250 {IPA_CMD_SETADAPTERPARMS, "setadapterparms"},
251 {IPA_CMD_SET_DIAG_ASS, "set_diag_ass"}, 251 {IPA_CMD_SET_DIAG_ASS, "set_diag_ass"},
252 {IPA_CMD_SETBRIDGEPORT, "set_bridge_port"},
252 {IPA_CMD_CREATE_ADDR, "create_addr"}, 253 {IPA_CMD_CREATE_ADDR, "create_addr"},
253 {IPA_CMD_DESTROY_ADDR, "destroy_addr"}, 254 {IPA_CMD_DESTROY_ADDR, "destroy_addr"},
254 {IPA_CMD_REGISTER_LOCAL_ADDR, "register_local_addr"}, 255 {IPA_CMD_REGISTER_LOCAL_ADDR, "register_local_addr"},
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index 0a6e695578cd..de6267990c5e 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -104,6 +104,7 @@ enum qeth_ipa_cmds {
104 IPA_CMD_DELIP = 0xb7, 104 IPA_CMD_DELIP = 0xb7,
105 IPA_CMD_SETADAPTERPARMS = 0xb8, 105 IPA_CMD_SETADAPTERPARMS = 0xb8,
106 IPA_CMD_SET_DIAG_ASS = 0xb9, 106 IPA_CMD_SET_DIAG_ASS = 0xb9,
107 IPA_CMD_SETBRIDGEPORT = 0xbe,
107 IPA_CMD_CREATE_ADDR = 0xc3, 108 IPA_CMD_CREATE_ADDR = 0xc3,
108 IPA_CMD_DESTROY_ADDR = 0xc4, 109 IPA_CMD_DESTROY_ADDR = 0xc4,
109 IPA_CMD_REGISTER_LOCAL_ADDR = 0xd1, 110 IPA_CMD_REGISTER_LOCAL_ADDR = 0xd1,
@@ -500,6 +501,88 @@ struct qeth_ipacmd_diagass {
500 __u8 cdata[64]; 501 __u8 cdata[64];
501} __attribute__ ((packed)); 502} __attribute__ ((packed));
502 503
504/* SETBRIDGEPORT IPA Command: *********************************************/
505enum 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
514struct net_if_token {
515 __u16 devnum;
516 __u8 cssid;
517 __u8 iid;
518 __u8 ssid;
519 __u8 chpid;
520 __u16 chid;
521} __packed;
522
523struct 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
535struct qeth_sbp_query_cmds_supp {
536 __u32 supported_cmds;
537 __u32 reserved;
538} __packed;
539
540struct qeth_sbp_reset_role {
541} __packed;
542
543struct qeth_sbp_set_primary {
544 struct net_if_token token;
545} __packed;
546
547struct qeth_sbp_set_secondary {
548} __packed;
549
550struct 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
558struct 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
566struct 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
574struct 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/* Header for each IPA command */ 586/* Header for each IPA command */
504struct qeth_ipacmd_hdr { 587struct qeth_ipacmd_hdr {
505 __u8 command; 588 __u8 command;
@@ -529,6 +612,7 @@ struct qeth_ipa_cmd {
529 struct qeth_ipacmd_setadpparms setadapterparms; 612 struct qeth_ipacmd_setadpparms setadapterparms;
530 struct qeth_set_routing setrtg; 613 struct qeth_set_routing setrtg;
531 struct qeth_ipacmd_diagass diagass; 614 struct qeth_ipacmd_diagass diagass;
615 struct qeth_ipacmd_setbridgeport sbp;
532 } data; 616 } data;
533} __attribute__ ((packed)); 617} __attribute__ ((packed));
534 618
diff --git a/drivers/s390/net/qeth_l2.h b/drivers/s390/net/qeth_l2.h
new file mode 100644
index 000000000000..0767556404bd
--- /dev/null
+++ b/drivers/s390/net/qeth_l2.h
@@ -0,0 +1,15 @@
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
11int qeth_l2_create_device_attributes(struct device *);
12void qeth_l2_remove_device_attributes(struct device *);
13void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card);
14
15#endif /* __QETH_L2_H__ */
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index ec8ccdae7aba..875d080e4e86 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -21,6 +21,7 @@
21#include <linux/list.h> 21#include <linux/list.h>
22 22
23#include "qeth_core.h" 23#include "qeth_core.h"
24#include "qeth_l2.h"
24 25
25static int qeth_l2_set_offline(struct ccwgroup_device *); 26static int qeth_l2_set_offline(struct ccwgroup_device *);
26static int qeth_l2_stop(struct net_device *); 27static int qeth_l2_stop(struct net_device *);
@@ -880,6 +881,7 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
880{ 881{
881 struct qeth_card *card = dev_get_drvdata(&gdev->dev); 882 struct qeth_card *card = dev_get_drvdata(&gdev->dev);
882 883
884 qeth_l2_create_device_attributes(&gdev->dev);
883 INIT_LIST_HEAD(&card->vid_list); 885 INIT_LIST_HEAD(&card->vid_list);
884 INIT_LIST_HEAD(&card->mc_list); 886 INIT_LIST_HEAD(&card->mc_list);
885 card->options.layer2 = 1; 887 card->options.layer2 = 1;
@@ -891,6 +893,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
891{ 893{
892 struct qeth_card *card = dev_get_drvdata(&cgdev->dev); 894 struct qeth_card *card = dev_get_drvdata(&cgdev->dev);
893 895
896 qeth_l2_remove_device_attributes(&cgdev->dev);
894 qeth_set_allowed_threads(card, 0, 1); 897 qeth_set_allowed_threads(card, 0, 1);
895 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); 898 wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0);
896 899
@@ -1003,6 +1006,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
1003 } else 1006 } else
1004 card->info.hwtrap = 0; 1007 card->info.hwtrap = 0;
1005 1008
1009 qeth_l2_setup_bridgeport_attrs(card);
1010
1006 card->state = CARD_STATE_HARDSETUP; 1011 card->state = CARD_STATE_HARDSETUP;
1007 memset(&card->rx, 0, sizeof(struct qeth_rx)); 1012 memset(&card->rx, 0, sizeof(struct qeth_rx));
1008 qeth_print_status_message(card); 1013 qeth_print_status_message(card);
@@ -1347,6 +1352,365 @@ void qeth_osn_deregister(struct net_device *dev)
1347} 1352}
1348EXPORT_SYMBOL(qeth_osn_deregister); 1353EXPORT_SYMBOL(qeth_osn_deregister);
1349 1354
1355/* SETBRIDGEPORT support, async notifications */
1356
1357struct qeth_bridge_state_data {
1358 struct work_struct worker;
1359 struct qeth_card *card;
1360 struct qeth_sbp_state_change qports;
1361};
1362
1363static 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
1401void 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}
1426EXPORT_SYMBOL(qeth_bridge_state_change);
1427
1428/* SETBRIDGEPORT support; sending commands */
1429
1430struct _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 */
1450static 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
1525static 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 */
1549void 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}
1575EXPORT_SYMBOL_GPL(qeth_bridgeport_query_support);
1576
1577static 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 */
1614int 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}
1649EXPORT_SYMBOL_GPL(qeth_bridgeport_query_ports);
1650
1651static 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 */
1669int 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}
1713
1350module_init(qeth_l2_init); 1714module_init(qeth_l2_init);
1351module_exit(qeth_l2_exit); 1715module_exit(qeth_l2_exit);
1352MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>"); 1716MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>");
diff --git a/drivers/s390/net/qeth_l2_sys.c b/drivers/s390/net/qeth_l2_sys.c
new file mode 100644
index 000000000000..17fd4cd888f9
--- /dev/null
+++ b/drivers/s390/net/qeth_l2_sys.c
@@ -0,0 +1,161 @@
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) \
11struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
12
13static 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
19static 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
72static 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
78static 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
110static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show,
111 qeth_bridge_port_role_store);
112
113static 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
119static DEVICE_ATTR(bridge_state, 0644, qeth_bridge_port_state_show,
120 NULL);
121
122static struct attribute *qeth_l2_bridgeport_attrs[] = {
123 &dev_attr_bridge_role.attr,
124 &dev_attr_bridge_state.attr,
125 NULL,
126};
127
128static struct attribute_group qeth_l2_bridgeport_attr_group = {
129 .attrs = qeth_l2_bridgeport_attrs,
130};
131
132int qeth_l2_create_device_attributes(struct device *dev)
133{
134 return sysfs_create_group(&dev->kobj, &qeth_l2_bridgeport_attr_group);
135}
136
137void 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 */
148void 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}