Skip to contentSkip to conversation

s390: network driver features and fixes for net-next

PATCH In review [email protected] 2 participants 8 messages Feb 8, 2012 – Feb 9, 2012

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

cover s390: network driver features and fixes for net-next

Hi Dave,

here are some s390 network driver features and fixes for net-next

shortlog:

Ursula Braun (5)
af_iucv: remove IUCV-pathes completely
af_iucv: block writing if msg limit is exceeded
af_iucv: change net_device handling for HS transport
af_iucv: allow retrieval of maximum message size
qeth: add wake_up on write channel

Frank Blaschka (1)
qeth: add query OSA address table support

Thanks,
Frank

#1 lore raw

PATCH 1/6 af_iucv: remove IUCV-pathes completely

From: Ursula Braun <[email protected]>

A SEVER is missing in the callback of a receiving SEVERED. This may inhibit z/VM to remove the corresponding IUCV-path completely. This patch adds a SEVER in iucv_callback_connrej (together with additional locking.

---

 net/iucv/af_iucv.c |   71 +++++++++++++++++++++++++++--------------------------
 1 file changed, 37 insertions(+), 34 deletions(-)
net/iucv/af_iucv.c +37 -34
@@ -90,6 +90,7 @@ do {									\
 
 static void iucv_sock_kill(struct sock *sk);
 static void iucv_sock_close(struct sock *sk);
+static void iucv_sever_path(struct sock *, int);
 
 static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev,
 	struct packet_type *pt, struct net_device *orig_dev);
@@ -181,11 +182,7 @@ static int afiucv_pm_freeze(struct devic
 		case IUCV_DISCONN:
 		case IUCV_CLOSING:
 		case IUCV_CONNECTED:
-			if (iucv->path) {
-				err = pr_iucv->path_sever(iucv->path, NULL);
-				iucv_path_free(iucv->path);
-				iucv->path = NULL;
-			}
+			iucv_sever_path(sk, 0);
 			break;
 		case IUCV_OPEN:
 		case IUCV_BOUND:
@@ -194,6 +191,8 @@ static int afiucv_pm_freeze(struct devic
 		default:
 			break;
 		}
+		skb_queue_purge(&iucv->send_skb_q);
+		skb_queue_purge(&iucv->backlog_skb_q);
 	}
 	read_unlock(&iucv_sk_list.lock);
 	return err;
@@ -447,10 +446,29 @@ static void iucv_sock_kill(struct sock *
 	sock_put(sk);
 }
 
+/* Terminate an IUCV path */
+static void iucv_sever_path(struct sock *sk, int with_user_data)
+{
+	unsigned char user_data[16];
+	struct iucv_sock *iucv = iucv_sk(sk);
+	struct iucv_path *path = iucv->path;
+
+	if (iucv->path) {
+		iucv->path = NULL;
+		if (with_user_data) {
+			low_nmcpy(user_data, iucv->src_name);
+			high_nmcpy(user_data, iucv->dst_name);
+			ASCEBC(user_data, sizeof(user_data));
+			pr_iucv->path_sever(path, user_data);
+		} else
+			pr_iucv->path_sever(path, NULL);
+		iucv_path_free(path);
+	}
+}
+
 /* Close an IUCV socket */
 static void iucv_sock_close(struct sock *sk)
 {
-	unsigned char user_data[16];
 	struct iucv_sock *iucv = iucv_sk(sk);
 	unsigned long timeo;
 	int err, blen;
@@ -494,25 +512,14 @@ static void iucv_sock_close(struct sock
 		sk->sk_state = IUCV_CLOSED;
 		sk->sk_state_change(sk);
 
-		if (iucv->path) {
-			low_nmcpy(user_data, iucv->src_name);
-			high_nmcpy(user_data, iucv->dst_name);
-			ASCEBC(user_data, sizeof(user_data));
-			pr_iucv->path_sever(iucv->path, user_data);
-			iucv_path_free(iucv->path);
-			iucv->path = NULL;
-		}
-
 		sk->sk_err = ECONNRESET;
 		sk->sk_state_change(sk);
 
 		iucv_skb_queue_purge(&iucv->send_skb_q);
 		skb_queue_purge(&iucv->backlog_skb_q);
-		break;
 
-	default:
-		/* nothing to do here */
-		break;
+	default:   /* fall through */
+		iucv_sever_path(sk, 1);
 	}
 
 	/* mark socket for deletion by iucv_sock_kill() */
@@ -894,11 +901,8 @@ static int iucv_sock_connect(struct sock
 	if (sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_CLOSED)
 		err = -ECONNREFUSED;
 
-	if (err && iucv->transport == AF_IUCV_TRANS_IUCV) {
-		pr_iucv->path_sever(iucv->path, NULL);
-		iucv_path_free(iucv->path);
-		iucv->path = NULL;
-	}
+	if (err && iucv->transport == AF_IUCV_TRANS_IUCV)
+		iucv_sever_path(sk, 0);
 
 done:
 	release_sock(sk);
@@ -1565,13 +1569,6 @@ static int iucv_sock_release(struct sock
 
 	iucv_sock_close(sk);
 
-	/* Unregister with IUCV base support */
-	if (iucv_sk(sk)->path) {
-		pr_iucv->path_sever(iucv_sk(sk)->path, NULL);
-		iucv_path_free(iucv_sk(sk)->path);
-		iucv_sk(sk)->path = NULL;
-	}
-
 	sock_orphan(sk);
 	iucv_sock_kill(sk);
 	return err;
@@ -1750,8 +1747,7 @@ static int iucv_callback_connreq(struct
 	path->msglim = iucv->msglimit;
 	err = pr_iucv->path_accept(path, &af_iucv_handler, nuser_data, nsk);
 	if (err) {
-		err = pr_iucv->path_sever(path, user_data);
-		iucv_path_free(path);
+		iucv_sever_path(nsk, 1);
 		iucv_sock_kill(nsk);
 		goto fail;
 	}
@@ -1828,6 +1824,7 @@ static void iucv_callback_txdone(struct
 	struct sk_buff *list_skb = list->next;
 	unsigned long flags;
 
+	bh_lock_sock(sk);
 	if (!skb_queue_empty(list)) {
 		spin_lock_irqsave(&list->lock, flags);
 
@@ -1849,7 +1846,6 @@ static void iucv_callback_txdone(struct
 			iucv_sock_wake_msglim(sk);
 		}
 	}
-	BUG_ON(!this);
 
 	if (sk->sk_state == IUCV_CLOSING) {
 		if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) {
@@ -1857,6 +1853,7 @@ static void iucv_callback_txdone(struct
 			sk->sk_state_change(sk);
 		}
 	}
+	bh_unlock_sock(sk);
 
 }
 
@@ -1864,9 +1861,15 @@ static void iucv_callback_connrej(struct
 {
 	struct sock *sk = path->private;
 
+	if (sk->sk_state == IUCV_CLOSED)
+		return;
+
+	bh_lock_sock(sk);
+	iucv_sever_path(sk, 1);
 	sk->sk_state = IUCV_DISCONN;
 
 	sk->sk_state_change(sk);
+	bh_unlock_sock(sk);
 }
 
 /* called if the other communication side shuts down its RECV direction;
#2 lore raw

PATCH 2/6 af_iucv: block writing if msg limit is exceeded

In reply to [email protected]

From: Ursula Braun <[email protected]>

When polling on an AF_IUCV socket, writing should be blocked if the number of pending messages exceeds a defined limit.

---

 net/iucv/af_iucv.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/iucv/af_iucv.c +1 -1
@@ -1490,7 +1490,7 @@ unsigned int iucv_sock_poll(struct file
 	if (sk->sk_state == IUCV_DISCONN)
 		mask |= POLLIN;
 
-	if (sock_writeable(sk))
+	if (sock_writeable(sk) && iucv_below_msglim(sk))
 		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
 	else
 		set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
#3 lore raw

PATCH 3/6 af_iucv: change net_device handling for HS transport

In reply to [email protected]

From: Ursula Braun <[email protected]>

This patch saves the net_device in the iucv_sock structure during bind in order to fasten skb sending.
In addition some other small improvements are made for HS transport:
- error checking when sending skbs
- locking changes in afiucv_hs_callback_txnotify
- skb freeing in afiucv_hs_callback_txnotify
And finally it contains code cleanup to get rid of iucv_skb_queue_purge.

---

 include/net/iucv/af_iucv.h |    1 
 net/iucv/af_iucv.c         |  119 +++++++++++++++++++++++----------------------
 2 files changed, 63 insertions(+), 57 deletions(-)
include/net/iucv/af_iucv.h +1 -0
@@ -113,6 +113,7 @@ struct iucv_sock {
 	spinlock_t		accept_q_lock;
 	struct sock		*parent;
 	struct iucv_path	*path;
+	struct net_device	*hs_dev;
 	struct sk_buff_head	send_skb_q;
 	struct sk_buff_head	backlog_skb_q;
 	struct sock_msg_q	message_q;
net/iucv/af_iucv.c +62 -57

289 lines not on this page · raw message

#4 lore raw

PATCH 4/6 af_iucv: allow retrieval of maximum message size

In reply to [email protected]

From: Ursula Braun <[email protected]>

For HS transport the maximum message size depends on the MTU-size of the HS-device bound to the AF_IUCV socket. This patch adds a getsockopt option MSGSIZE returning the maximum message size that can be handled for this AF_IUCV socket.

---

 include/net/iucv/af_iucv.h |    1 +
 net/iucv/af_iucv.c         |   10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)
include/net/iucv/af_iucv.h +1 -0
@@ -132,6 +132,7 @@ struct iucv_sock {
 /* iucv socket options (SOL_IUCV) */
 #define SO_IPRMDATA_MSG	0x0080		/* send/recv IPRM_DATA msgs */
 #define SO_MSGLIMIT	0x1000		/* get/set IUCV MSGLIMIT */
+#define SO_MSGSIZE	0x0800		/* get maximum msgsize */
 
 /* iucv related control messages (scm) */
 #define SCM_IUCV_TRGCLS	0x0001		/* target class control message */
net/iucv/af_iucv.c +9 -1
@@ -1633,7 +1633,8 @@ static int iucv_sock_getsockopt(struct s
 {
 	struct sock *sk = sock->sk;
 	struct iucv_sock *iucv = iucv_sk(sk);
-	int val, len;
+	unsigned int val;
+	int len;
 
 	if (level != SOL_IUCV)
 		return -ENOPROTOOPT;
@@ -1656,6 +1657,13 @@ static int iucv_sock_getsockopt(struct s
 					   : iucv->msglimit;	/* default */
 		release_sock(sk);
 		break;
+	case SO_MSGSIZE:
+		if (sk->sk_state == IUCV_OPEN)
+			return -EBADFD;
+		val = (iucv->hs_dev) ? iucv->hs_dev->mtu -
+				sizeof(struct af_iucv_trans_hdr) - ETH_HLEN :
+				0x7fffffff;
+		break;
 	default:
 		return -ENOPROTOOPT;
 	}
#5 lore raw

PATCH 5/6 qeth: add query OSA address table support

In reply to [email protected]

From: Frank Blaschka <[email protected]>

Add qeth device private ioctl to query the OSA address table. This helps debugging hw related problems.

---

 arch/s390/include/asm/qeth.h      |    7 ++
 drivers/s390/net/qeth_core.h      |    1 
 drivers/s390/net/qeth_core_main.c |   99 ++++++++++++++++++++++++++++++++++++++
 drivers/s390/net/qeth_core_mpc.h  |   13 ++++
 drivers/s390/net/qeth_l2_main.c   |    3 +
 drivers/s390/net/qeth_l3_main.c   |    3 +
 6 files changed, 126 insertions(+)
arch/s390/include/asm/qeth.h +7 -0
@@ -20,6 +20,7 @@
 #define SIOC_QETH_ARP_FLUSH_CACHE       (SIOCDEVPRIVATE + 4)
 #define SIOC_QETH_ADP_SET_SNMP_CONTROL  (SIOCDEVPRIVATE + 5)
 #define SIOC_QETH_GET_CARD_TYPE         (SIOCDEVPRIVATE + 6)
+#define SIOC_QETH_QUERY_OAT		(SIOCDEVPRIVATE + 7)
 
 struct qeth_arp_cache_entry {
 	__u8  macaddr[6];
@@ -107,4 +108,10 @@ struct qeth_arp_query_user_data {
 	char *entries;
 } __attribute__((packed));
 
+struct qeth_query_oat_data {
+	__u32 command;
+	__u32 buffer_len;
+	__u32 response_len;
+	__u64 ptr;
+};
 #endif /* __ASM_S390_QETH_IOCTL_H__ */
drivers/s390/net/qeth_core.h +1 -0
@@ -906,6 +906,7 @@ void qeth_prepare_ipa_cmd(struct qeth_ca
 struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *);
 int qeth_mdio_read(struct net_device *, int, int);
 int qeth_snmp_command(struct qeth_card *, char __user *);
+int qeth_query_oat_command(struct qeth_card *, char __user *);
 struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *, __u32, __u32);
 int qeth_default_setadapterparms_cb(struct qeth_card *, struct qeth_reply *,
 					unsigned long);
drivers/s390/net/qeth_core_main.c +99 -0

111 lines not on this page · raw message

drivers/s390/net/qeth_core_mpc.h +13 -0
@@ -249,6 +249,7 @@ enum qeth_ipa_setadp_cmd {
 	IPA_SETADP_SET_PROMISC_MODE		= 0x00000800L,
 	IPA_SETADP_SET_DIAG_ASSIST		= 0x00002000L,
 	IPA_SETADP_SET_ACCESS_CONTROL		= 0x00010000L,
+	IPA_SETADP_QUERY_OAT			= 0x00080000L,
 };
 enum qeth_ipa_mac_ops {
 	CHANGE_ADDR_READ_MAC		= 0,
@@ -398,6 +399,17 @@ struct qeth_set_access_ctrl {
 	__u32 subcmd_code;
 } __attribute__((packed));
 
+struct qeth_query_oat {
+	__u32 subcmd_code;
+	__u8 reserved[12];
+} __packed;
+
+struct qeth_qoat_priv {
+	__u32 buffer_len;
+	__u32 response_len;
+	char *buffer;
+};
+
 struct qeth_ipacmd_setadpparms_hdr {
 	__u32 supp_hw_cmds;
 	__u32 reserved1;
@@ -417,6 +429,7 @@ struct qeth_ipacmd_setadpparms {
 		struct qeth_change_addr change_addr;
 		struct qeth_snmp_cmd snmp;
 		struct qeth_set_access_ctrl set_access_ctrl;
+		struct qeth_query_oat query_oat;
 		__u32 mode;
 	} data;
 } __attribute__ ((packed));
drivers/s390/net/qeth_l2_main.c +3 -0
@@ -75,6 +75,9 @@ static int qeth_l2_do_ioctl(struct net_d
 			mii_data->val_out = qeth_mdio_read(dev,
 				mii_data->phy_id, mii_data->reg_num);
 		break;
+	case SIOC_QETH_QUERY_OAT:
+		rc = qeth_query_oat_command(card, rq->ifr_ifru.ifru_data);
+		break;
 	default:
 		rc = -EOPNOTSUPP;
 	}
drivers/s390/net/qeth_l3_main.c +3 -0
@@ -2745,6 +2745,9 @@ static int qeth_l3_do_ioctl(struct net_d
 							mii_data->phy_id,
 							mii_data->reg_num);
 		break;
+	case SIOC_QETH_QUERY_OAT:
+		rc = qeth_query_oat_command(card, rq->ifr_ifru.ifru_data);
+		break;
 	default:
 		rc = -EOPNOTSUPP;
 	}
#6 lore raw

PATCH 6/6 qeth: add wake_up on write channel

In reply to [email protected]

From: Ursula Braun <[email protected]>

To send commands on the write channel 8 buffers exist. If all 8 buffers are used, a wait is triggered on the write channel. When such buffer are freed, a wake_up is needed. This patch adds the missing wake_up in qeth_release_buffer().
This fix is especially important when running Communications Controller for Linux on System z.

---

 drivers/s390/net/qeth_core_main.c |    1 +
 1 file changed, 1 insertion(+)
drivers/s390/net/qeth_core_main.c +1 -0
@@ -678,6 +678,7 @@ void qeth_release_buffer(struct qeth_cha
 	iob->callback = qeth_send_control_data_cb;
 	iob->rc = 0;
 	spin_unlock_irqrestore(&channel->iob_lock, flags);
+	wake_up(&channel->wait_q);
 }
 EXPORT_SYMBOL_GPL(qeth_release_buffer);
 
maintainer
#7 lore raw
In reply to [email protected]

From: [email protected]
Date: Wed, 08 Feb 2012 11:19:44 +0100

Quoted 11 lines

here are some s390 network driver features and fixes for net-next

shortlog:

Ursula Braun (5)
af_iucv: remove IUCV-pathes completely
af_iucv: block writing if msg limit is exceeded
af_iucv: change net_device handling for HS transport
af_iucv: allow retrieval of maximum message size
qeth: add wake_up on write channel

Quoted 2 lines

Frank Blaschka (1)
qeth: add query OSA address table support

All applied.