summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/net/qeth_core.h2
-rw-r--r--drivers/s390/net/qeth_core_main.c151
-rw-r--r--drivers/s390/net/qeth_core_mpc.h45
-rw-r--r--drivers/s390/net/qeth_core_sys.c77
-rw-r--r--drivers/s390/net/qeth_l2_main.c2
-rw-r--r--drivers/s390/net/qeth_l3_main.c2
6 files changed, 267 insertions, 12 deletions
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index e8f72d715eba..4df5eaad6f94 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -648,6 +648,7 @@ struct qeth_card_options {
enum qeth_large_send_types large_send;
int performance_stats;
int rx_sg_cb;
+ enum qeth_ipa_isolation_modes isolation;
};
/*
@@ -856,6 +857,7 @@ void qeth_core_get_strings(struct net_device *, u32, u8 *);
void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...);
int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
+int qeth_set_access_ctrl_online(struct qeth_card *card);
/* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index edee4dc6430c..2c71948c71a1 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -1079,6 +1079,7 @@ static void qeth_set_intial_options(struct qeth_card *card)
card->options.add_hhlen = DEFAULT_ADD_HHLEN;
card->options.performance_stats = 0;
card->options.rx_sg_cb = QETH_RX_SG_CB;
+ card->options.isolation = ISOLATION_MODE_NONE;
}
static int qeth_do_start_thread(struct qeth_card *card, unsigned long thread)
@@ -3389,6 +3390,156 @@ int qeth_setadpparms_change_macaddr(struct qeth_card *card)
}
EXPORT_SYMBOL_GPL(qeth_setadpparms_change_macaddr);
+static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
+ struct qeth_reply *reply, unsigned long data)
+{
+ struct qeth_ipa_cmd *cmd;
+ struct qeth_set_access_ctrl *access_ctrl_req;
+ int rc;
+
+ QETH_DBF_TEXT(TRACE, 4, "setaccb");
+
+ cmd = (struct qeth_ipa_cmd *) data;
+ access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl;
+ QETH_DBF_TEXT_(SETUP, 2, "setaccb");
+ QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
+ QETH_DBF_TEXT_(SETUP, 2, "rc=%d",
+ cmd->data.setadapterparms.hdr.return_code);
+ switch (cmd->data.setadapterparms.hdr.return_code) {
+ case SET_ACCESS_CTRL_RC_SUCCESS:
+ case SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED:
+ case SET_ACCESS_CTRL_RC_ALREADY_ISOLATED:
+ {
+ card->options.isolation = access_ctrl_req->subcmd_code;
+ if (card->options.isolation == ISOLATION_MODE_NONE) {
+ dev_info(&card->gdev->dev,
+ "QDIO data connection isolation is deactivated\n");
+ } else {
+ dev_info(&card->gdev->dev,
+ "QDIO data connection isolation is activated\n");
+ }
+ QETH_DBF_MESSAGE(3, "OK:SET_ACCESS_CTRL(%s, %d)==%d\n",
+ card->gdev->dev.kobj.name,
+ access_ctrl_req->subcmd_code,
+ cmd->data.setadapterparms.hdr.return_code);
+ rc = 0;
+ break;
+ }
+ case SET_ACCESS_CTRL_RC_NOT_SUPPORTED:
+ {
+ QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_CTRL(%s,%d)==%d\n",
+ card->gdev->dev.kobj.name,
+ access_ctrl_req->subcmd_code,
+ cmd->data.setadapterparms.hdr.return_code);
+ dev_err(&card->gdev->dev, "Adapter does not "
+ "support QDIO data connection isolation\n");
+
+ /* ensure isolation mode is "none" */
+ card->options.isolation = ISOLATION_MODE_NONE;
+ rc = -EOPNOTSUPP;
+ break;
+ }
+ case SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER:
+ {
+ QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n",
+ card->gdev->dev.kobj.name,
+ access_ctrl_req->subcmd_code,
+ cmd->data.setadapterparms.hdr.return_code);
+ dev_err(&card->gdev->dev,
+ "Adapter is dedicated. "
+ "QDIO data connection isolation not supported\n");
+
+ /* ensure isolation mode is "none" */
+ card->options.isolation = ISOLATION_MODE_NONE;
+ rc = -EOPNOTSUPP;
+ break;
+ }
+ case SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF:
+ {
+ QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d\n",
+ card->gdev->dev.kobj.name,
+ access_ctrl_req->subcmd_code,
+ cmd->data.setadapterparms.hdr.return_code);
+ dev_err(&card->gdev->dev,
+ "TSO does not permit QDIO data connection isolation\n");
+
+ /* ensure isolation mode is "none" */
+ card->options.isolation = ISOLATION_MODE_NONE;
+ rc = -EPERM;
+ break;
+ }
+ default:
+ {
+ /* this should never happen */
+ QETH_DBF_MESSAGE(3, "ERR:SET_ACCESS_MODE(%s,%d)==%d"
+ "==UNKNOWN\n",
+ card->gdev->dev.kobj.name,
+ access_ctrl_req->subcmd_code,
+ cmd->data.setadapterparms.hdr.return_code);
+
+ /* ensure isolation mode is "none" */
+ card->options.isolation = ISOLATION_MODE_NONE;
+ rc = 0;
+ break;
+ }
+ }
+ qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
+ return rc;
+}
+
+static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
+ enum qeth_ipa_isolation_modes isolation)
+{
+ int rc;
+ struct qeth_cmd_buffer *iob;
+ struct qeth_ipa_cmd *cmd;
+ struct qeth_set_access_ctrl *access_ctrl_req;
+
+ QETH_DBF_TEXT(TRACE, 4, "setacctl");
+
+ QETH_DBF_TEXT_(SETUP, 2, "setacctl");
+ QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
+
+ iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_ACCESS_CONTROL,
+ sizeof(struct qeth_ipacmd_setadpparms_hdr) +
+ sizeof(struct qeth_set_access_ctrl));
+ cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+ access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl;
+ access_ctrl_req->subcmd_code = isolation;
+
+ rc = qeth_send_ipa_cmd(card, iob, qeth_setadpparms_set_access_ctrl_cb,
+ NULL);
+ QETH_DBF_TEXT_(SETUP, 2, "rc=%d", rc);
+ return rc;
+}
+
+int qeth_set_access_ctrl_online(struct qeth_card *card)
+{
+ int rc = 0;
+
+ QETH_DBF_TEXT(TRACE, 4, "setactlo");
+
+ if (card->info.type == QETH_CARD_TYPE_OSAE &&
+ qeth_adp_supported(card, IPA_SETADP_SET_ACCESS_CONTROL)) {
+ rc = qeth_setadpparms_set_access_ctrl(card,
+ card->options.isolation);
+ if (rc) {
+ QETH_DBF_MESSAGE(3,
+ "IPA(SET_ACCESS_CTRL,%s,%d) sent failed",
+ card->gdev->dev.kobj.name,
+ rc);
+ }
+ } else if (card->options.isolation != ISOLATION_MODE_NONE) {
+ card->options.isolation = ISOLATION_MODE_NONE;
+
+ dev_err(&card->gdev->dev, "Adapter does not "
+ "support QDIO data connection isolation\n");
+ rc = -EOPNOTSUPP;
+ }
+ return rc;
+}
+EXPORT_SYMBOL_GPL(qeth_set_access_ctrl_online);
+
void qeth_tx_timeout(struct net_device *dev)
{
struct qeth_card *card;
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index eecb2ee62e85..52c03438dbec 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -234,18 +234,19 @@ enum qeth_ipa_setdelip_flags {
/* SETADAPTER IPA Command: ****************************************************/
enum qeth_ipa_setadp_cmd {
- IPA_SETADP_QUERY_COMMANDS_SUPPORTED = 0x0001,
- IPA_SETADP_ALTER_MAC_ADDRESS = 0x0002,
- IPA_SETADP_ADD_DELETE_GROUP_ADDRESS = 0x0004,
- IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR = 0x0008,
- IPA_SETADP_SET_ADDRESSING_MODE = 0x0010,
- IPA_SETADP_SET_CONFIG_PARMS = 0x0020,
- IPA_SETADP_SET_CONFIG_PARMS_EXTENDED = 0x0040,
- IPA_SETADP_SET_BROADCAST_MODE = 0x0080,
- IPA_SETADP_SEND_OSA_MESSAGE = 0x0100,
- IPA_SETADP_SET_SNMP_CONTROL = 0x0200,
- IPA_SETADP_QUERY_CARD_INFO = 0x0400,
- IPA_SETADP_SET_PROMISC_MODE = 0x0800,
+ IPA_SETADP_QUERY_COMMANDS_SUPPORTED = 0x00000001L,
+ IPA_SETADP_ALTER_MAC_ADDRESS = 0x00000002L,
+ IPA_SETADP_ADD_DELETE_GROUP_ADDRESS = 0x00000004L,
+ IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR = 0x00000008L,
+ IPA_SETADP_SET_ADDRESSING_MODE = 0x00000010L,
+ IPA_SETADP_SET_CONFIG_PARMS = 0x00000020L,
+ IPA_SETADP_SET_CONFIG_PARMS_EXTENDED = 0x00000040L,
+ IPA_SETADP_SET_BROADCAST_MODE = 0x00000080L,
+ IPA_SETADP_SEND_OSA_MESSAGE = 0x00000100L,
+ IPA_SETADP_SET_SNMP_CONTROL = 0x00000200L,
+ IPA_SETADP_QUERY_CARD_INFO = 0x00000400L,
+ IPA_SETADP_SET_PROMISC_MODE = 0x00000800L,
+ IPA_SETADP_SET_ACCESS_CONTROL = 0x00010000L,
};
enum qeth_ipa_mac_ops {
CHANGE_ADDR_READ_MAC = 0,
@@ -264,6 +265,20 @@ enum qeth_ipa_promisc_modes {
SET_PROMISC_MODE_OFF = 0,
SET_PROMISC_MODE_ON = 1,
};
+enum qeth_ipa_isolation_modes {
+ ISOLATION_MODE_NONE = 0x00000000L,
+ ISOLATION_MODE_FWD = 0x00000001L,
+ ISOLATION_MODE_DROP = 0x00000002L,
+};
+enum qeth_ipa_set_access_mode_rc {
+ SET_ACCESS_CTRL_RC_SUCCESS = 0x0000,
+ SET_ACCESS_CTRL_RC_NOT_SUPPORTED = 0x0004,
+ SET_ACCESS_CTRL_RC_ALREADY_NOT_ISOLATED = 0x0008,
+ SET_ACCESS_CTRL_RC_ALREADY_ISOLATED = 0x0010,
+ SET_ACCESS_CTRL_RC_NONE_SHARED_ADAPTER = 0x0014,
+ SET_ACCESS_CTRL_RC_ACTIVE_CHECKSUM_OFF = 0x0018,
+};
+
/* (SET)DELIP(M) IPA stuff ***************************************************/
struct qeth_ipacmd_setdelip4 {
@@ -376,6 +391,11 @@ struct qeth_snmp_ureq {
struct qeth_snmp_cmd cmd;
} __attribute__((packed));
+/* SET_ACCESS_CONTROL: same format for request and reply */
+struct qeth_set_access_ctrl {
+ __u32 subcmd_code;
+} __attribute__((packed));
+
struct qeth_ipacmd_setadpparms_hdr {
__u32 supp_hw_cmds;
__u32 reserved1;
@@ -394,6 +414,7 @@ struct qeth_ipacmd_setadpparms {
struct qeth_query_cmds_supp query_cmds_supp;
struct qeth_change_addr change_addr;
struct qeth_snmp_cmd snmp;
+ struct qeth_set_access_ctrl set_access_ctrl;
__u32 mode;
} data;
} __attribute__ ((packed));
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index 33505c2a0e3a..f2358a75ed0c 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -463,6 +463,82 @@ static ssize_t qeth_dev_large_send_store(struct device *dev,
static DEVICE_ATTR(large_send, 0644, qeth_dev_large_send_show,
qeth_dev_large_send_store);
+#define ATTR_QETH_ISOLATION_NONE ("none")
+#define ATTR_QETH_ISOLATION_FWD ("forward")
+#define ATTR_QETH_ISOLATION_DROP ("drop")
+
+static ssize_t qeth_dev_isolation_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qeth_card *card = dev_get_drvdata(dev);
+
+ if (!card)
+ return -EINVAL;
+
+ switch (card->options.isolation) {
+ case ISOLATION_MODE_NONE:
+ return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_NONE);
+ case ISOLATION_MODE_FWD:
+ return snprintf(buf, 9, "%s\n", ATTR_QETH_ISOLATION_FWD);
+ case ISOLATION_MODE_DROP:
+ return snprintf(buf, 6, "%s\n", ATTR_QETH_ISOLATION_DROP);
+ default:
+ return snprintf(buf, 5, "%s\n", "N/A");
+ }
+}
+
+static ssize_t qeth_dev_isolation_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct qeth_card *card = dev_get_drvdata(dev);
+ enum qeth_ipa_isolation_modes isolation;
+ int rc = 0;
+ char *tmp, *curtoken;
+ curtoken = (char *) buf;
+
+ if (!card) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* check for unknown, too, in case we do not yet know who we are */
+ if (card->info.type != QETH_CARD_TYPE_OSAE &&
+ card->info.type != QETH_CARD_TYPE_UNKNOWN) {
+ rc = -EOPNOTSUPP;
+ dev_err(&card->gdev->dev, "Adapter does not "
+ "support QDIO data connection isolation\n");
+ goto out;
+ }
+
+ /* parse input into isolation mode */
+ tmp = strsep(&curtoken, "\n");
+ if (!strcmp(tmp, ATTR_QETH_ISOLATION_NONE)) {
+ isolation = ISOLATION_MODE_NONE;
+ } else if (!strcmp(tmp, ATTR_QETH_ISOLATION_FWD)) {
+ isolation = ISOLATION_MODE_FWD;
+ } else if (!strcmp(tmp, ATTR_QETH_ISOLATION_DROP)) {
+ isolation = ISOLATION_MODE_DROP;
+ } else {
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = count;
+
+ /* defer IP assist if device is offline (until discipline->set_online)*/
+ card->options.isolation = isolation;
+ if (card->state == CARD_STATE_SOFTSETUP ||
+ card->state == CARD_STATE_UP) {
+ int ipa_rc = qeth_set_access_ctrl_online(card);
+ if (ipa_rc != 0)
+ rc = ipa_rc;
+ }
+out:
+ return rc;
+}
+
+static DEVICE_ATTR(isolation, 0644, qeth_dev_isolation_show,
+ qeth_dev_isolation_store);
+
static ssize_t qeth_dev_blkt_show(char *buf, struct qeth_card *card, int value)
{
@@ -583,6 +659,7 @@ static struct attribute *qeth_device_attrs[] = {
&dev_attr_performance_stats.attr,
&dev_attr_layer2.attr,
&dev_attr_large_send.attr,
+ &dev_attr_isolation.attr,
NULL,
};
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index b61d5c723c50..a63a3dfcdf63 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -988,6 +988,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
card->lan_online = 1;
if (card->info.type != QETH_CARD_TYPE_OSN) {
+ /* configure isolation level */
+ qeth_set_access_ctrl_online(card);
qeth_set_large_send(card, card->options.large_send);
qeth_l2_process_vlans(card, 0);
}
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index 4ca28c16ca83..dd6766672a00 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -1506,6 +1506,8 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card)
static int qeth_l3_start_ipassists(struct qeth_card *card)
{
QETH_DBF_TEXT(TRACE, 3, "strtipas");
+
+ qeth_set_access_ctrl_online(card); /* go on*/
qeth_l3_start_ipa_arp_processing(card); /* go on*/
qeth_l3_start_ipa_ip_fragmentation(card); /* go on*/
qeth_l3_start_ipa_source_mac(card); /* go on*/