netiucv.c 58.1 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * IUCV network driver
 *
4
 * Copyright IBM Corp. 2001, 2009
L
Linus Torvalds 已提交
5
 *
6 7 8 9 10 11 12
 * Author(s):
 *	Original netiucv driver:
 *		Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com)
 *	Sysfs integration and all bugs therein:
 *		Cornelia Huck (cornelia.huck@de.ibm.com)
 *	PM functions:
 *		Ursula Braun (ursula.braun@de.ibm.com)
L
Linus Torvalds 已提交
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 *
 * Documentation used:
 *  the source of the original IUCV driver by:
 *    Stefan Hegewald <hegewald@de.ibm.com>
 *    Hartmut Penner <hpenner@de.ibm.com>
 *    Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
 *    Martin Schwidefsky (schwidefsky@de.ibm.com)
 *    Alan Altmark (Alan_Altmark@us.ibm.com)  Sept. 2000
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */
37

38 39 40
#define KMSG_COMPONENT "netiucv"
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt

L
Linus Torvalds 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
#undef DEBUG

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/bitops.h>

#include <linux/signal.h>
#include <linux/string.h>
#include <linux/device.h>

#include <linux/ip.h>
#include <linux/if_arp.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/ctype.h>
#include <net/dst.h>

#include <asm/io.h>
#include <asm/uaccess.h>
66
#include <asm/ebcdic.h>
L
Linus Torvalds 已提交
67

68
#include <net/iucv/iucv.h>
L
Linus Torvalds 已提交
69 70 71 72 73 74
#include "fsm.h"

MODULE_AUTHOR
    ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");

75 76 77 78
/**
 * Debug Facility stuff
 */
#define IUCV_DBF_SETUP_NAME "iucv_setup"
79
#define IUCV_DBF_SETUP_LEN 64
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
#define IUCV_DBF_SETUP_PAGES 2
#define IUCV_DBF_SETUP_NR_AREAS 1
#define IUCV_DBF_SETUP_LEVEL 3

#define IUCV_DBF_DATA_NAME "iucv_data"
#define IUCV_DBF_DATA_LEN 128
#define IUCV_DBF_DATA_PAGES 2
#define IUCV_DBF_DATA_NR_AREAS 1
#define IUCV_DBF_DATA_LEVEL 2

#define IUCV_DBF_TRACE_NAME "iucv_trace"
#define IUCV_DBF_TRACE_LEN 16
#define IUCV_DBF_TRACE_PAGES 4
#define IUCV_DBF_TRACE_NR_AREAS 1
#define IUCV_DBF_TRACE_LEVEL 3

#define IUCV_DBF_TEXT(name,level,text) \
	do { \
		debug_text_event(iucv_dbf_##name,level,text); \
	} while (0)

#define IUCV_DBF_HEX(name,level,addr,len) \
	do { \
		debug_event(iucv_dbf_##name,level,(void*)(addr),len); \
	} while (0)

DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf);

108 109 110 111 112 113 114 115 116
/* Allow to sort out low debug levels early to avoid wasted sprints */
static inline int iucv_dbf_passes(debug_info_t *dbf_grp, int level)
{
	return (level <= dbf_grp->level);
}

#define IUCV_DBF_TEXT_(name, level, text...) \
	do { \
		if (iucv_dbf_passes(iucv_dbf_##name, level)) { \
117 118 119
			char* __buf = get_cpu_var(iucv_dbf_txt_buf); \
			sprintf(__buf, text); \
			debug_text_event(iucv_dbf_##name, level, __buf); \
120 121
			put_cpu_var(iucv_dbf_txt_buf); \
		} \
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
	} while (0)

#define IUCV_DBF_SPRINTF(name,level,text...) \
	do { \
		debug_sprintf_event(iucv_dbf_trace, level, ##text ); \
		debug_sprintf_event(iucv_dbf_trace, level, text ); \
	} while (0)

/**
 * some more debug stuff
 */
#define IUCV_HEXDUMP16(importance,header,ptr) \
PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
		   "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
		   *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
		   *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
		   *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
		   *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
		   *(((char*)ptr)+12),*(((char*)ptr)+13), \
		   *(((char*)ptr)+14),*(((char*)ptr)+15)); \
PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
		   "%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
		   *(((char*)ptr)+16),*(((char*)ptr)+17), \
		   *(((char*)ptr)+18),*(((char*)ptr)+19), \
		   *(((char*)ptr)+20),*(((char*)ptr)+21), \
		   *(((char*)ptr)+22),*(((char*)ptr)+23), \
		   *(((char*)ptr)+24),*(((char*)ptr)+25), \
		   *(((char*)ptr)+26),*(((char*)ptr)+27), \
		   *(((char*)ptr)+28),*(((char*)ptr)+29), \
		   *(((char*)ptr)+30),*(((char*)ptr)+31));

L
Linus Torvalds 已提交
153 154
#define PRINTK_HEADER " iucv: "       /* for debugging */

155 156 157 158 159 160 161 162
/* dummy device to make sure netiucv_pm functions are called */
static struct device *netiucv_dev;

static int netiucv_pm_prepare(struct device *);
static void netiucv_pm_complete(struct device *);
static int netiucv_pm_freeze(struct device *);
static int netiucv_pm_restore_thaw(struct device *);

163
static const struct dev_pm_ops netiucv_pm_ops = {
164 165 166 167 168 169 170
	.prepare = netiucv_pm_prepare,
	.complete = netiucv_pm_complete,
	.freeze = netiucv_pm_freeze,
	.thaw = netiucv_pm_restore_thaw,
	.restore = netiucv_pm_restore_thaw,
};

L
Linus Torvalds 已提交
171
static struct device_driver netiucv_driver = {
172
	.owner = THIS_MODULE,
L
Linus Torvalds 已提交
173 174
	.name = "netiucv",
	.bus  = &iucv_bus,
175
	.pm = &netiucv_pm_ops,
L
Linus Torvalds 已提交
176 177
};

178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
static int netiucv_callback_connreq(struct iucv_path *,
				    u8 ipvmid[8], u8 ipuser[16]);
static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]);
static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]);
static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]);
static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]);
static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *);
static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *);

static struct iucv_handler netiucv_handler = {
	.path_pending	  = netiucv_callback_connreq,
	.path_complete	  = netiucv_callback_connack,
	.path_severed	  = netiucv_callback_connrej,
	.path_quiesced	  = netiucv_callback_connsusp,
	.path_resumed	  = netiucv_callback_connres,
	.message_pending  = netiucv_callback_rx,
	.message_complete = netiucv_callback_txdone
};

L
Linus Torvalds 已提交
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
/**
 * Per connection profiling data
 */
struct connection_profile {
	unsigned long maxmulti;
	unsigned long maxcqueue;
	unsigned long doios_single;
	unsigned long doios_multi;
	unsigned long txlen;
	unsigned long tx_time;
	struct timespec send_stamp;
	unsigned long tx_pending;
	unsigned long tx_max_pending;
};

/**
 * Representation of one iucv connection
 */
struct iucv_connection {
216 217
	struct list_head	  list;
	struct iucv_path	  *path;
L
Linus Torvalds 已提交
218 219 220 221 222 223 224 225 226 227 228 229
	struct sk_buff            *rx_buff;
	struct sk_buff            *tx_buff;
	struct sk_buff_head       collect_queue;
	struct sk_buff_head	  commit_queue;
	spinlock_t                collect_lock;
	int                       collect_len;
	int                       max_buffsize;
	fsm_timer                 timer;
	fsm_instance              *fsm;
	struct net_device         *netdev;
	struct connection_profile prof;
	char                      userid[9];
230
	char			  userdata[17];
L
Linus Torvalds 已提交
231 232 233 234 235
};

/**
 * Linked list of all connection structs.
 */
236
static LIST_HEAD(iucv_connection_list);
237
static DEFINE_RWLOCK(iucv_connection_rwlock);
L
Linus Torvalds 已提交
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256

/**
 * Representation of event-data for the
 * connection state machine.
 */
struct iucv_event {
	struct iucv_connection *conn;
	void                   *data;
};

/**
 * Private part of the network device structure
 */
struct netiucv_priv {
	struct net_device_stats stats;
	unsigned long           tbusy;
	fsm_instance            *fsm;
        struct iucv_connection  *conn;
	struct device           *dev;
257
	int			 pm_state;
L
Linus Torvalds 已提交
258 259 260 261 262
};

/**
 * Link level header for a packet.
 */
263 264 265
struct ll_header {
	u16 next;
};
L
Linus Torvalds 已提交
266

267
#define NETIUCV_HDRLEN		 (sizeof(struct ll_header))
268
#define NETIUCV_BUFSIZE_MAX	 65537
L
Linus Torvalds 已提交
269 270 271 272 273 274 275 276 277 278
#define NETIUCV_BUFSIZE_DEFAULT  NETIUCV_BUFSIZE_MAX
#define NETIUCV_MTU_MAX          (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN)
#define NETIUCV_MTU_DEFAULT      9216
#define NETIUCV_QUEUELEN_DEFAULT 50
#define NETIUCV_TIMEOUT_5SEC     5000

/**
 * Compatibility macros for busy handling
 * of network devices.
 */
279
static inline void netiucv_clear_busy(struct net_device *dev)
L
Linus Torvalds 已提交
280
{
281 282
	struct netiucv_priv *priv = netdev_priv(dev);
	clear_bit(0, &priv->tbusy);
L
Linus Torvalds 已提交
283 284 285
	netif_wake_queue(dev);
}

286
static inline int netiucv_test_and_set_busy(struct net_device *dev)
L
Linus Torvalds 已提交
287
{
288
	struct netiucv_priv *priv = netdev_priv(dev);
L
Linus Torvalds 已提交
289
	netif_stop_queue(dev);
290
	return test_and_set_bit(0, &priv->tbusy);
L
Linus Torvalds 已提交
291 292
}

293 294 295 296 297 298
static u8 iucvMagic_ascii[16] = {
	0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
	0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
};

static u8 iucvMagic_ebcdic[16] = {
L
Linus Torvalds 已提交
299 300 301 302 303 304 305 306 307 308 309 310
	0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
	0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
};

/**
 * Convert an iucv userId to its printable
 * form (strip whitespace at end).
 *
 * @param An iucv userId
 *
 * @returns The printable string (static data!!)
 */
311
static char *netiucv_printname(char *name, int len)
L
Linus Torvalds 已提交
312
{
313
	static char tmp[17];
L
Linus Torvalds 已提交
314
	char *p = tmp;
315 316 317
	memcpy(tmp, name, len);
	tmp[len] = '\0';
	while (*p && ((p - tmp) < len) && (!isspace(*p)))
L
Linus Torvalds 已提交
318 319 320 321
		p++;
	*p = '\0';
	return tmp;
}
322

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
static char *netiucv_printuser(struct iucv_connection *conn)
{
	static char tmp_uid[9];
	static char tmp_udat[17];
	static char buf[100];

	if (memcmp(conn->userdata, iucvMagic_ebcdic, 16)) {
		tmp_uid[8] = '\0';
		tmp_udat[16] = '\0';
		memcpy(tmp_uid, conn->userid, 8);
		memcpy(tmp_uid, netiucv_printname(tmp_uid, 8), 8);
		memcpy(tmp_udat, conn->userdata, 16);
		EBCASC(tmp_udat, 16);
		memcpy(tmp_udat, netiucv_printname(tmp_udat, 16), 16);
		sprintf(buf, "%s.%s", tmp_uid, tmp_udat);
		return buf;
	} else
		return netiucv_printname(conn->userid, 8);
}

L
Linus Torvalds 已提交
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
/**
 * States of the interface statemachine.
 */
enum dev_states {
	DEV_STATE_STOPPED,
	DEV_STATE_STARTWAIT,
	DEV_STATE_STOPWAIT,
	DEV_STATE_RUNNING,
	/**
	 * MUST be always the last element!!
	 */
	NR_DEV_STATES
};

static const char *dev_state_names[] = {
	"Stopped",
	"StartWait",
	"StopWait",
	"Running",
};

/**
 * Events of the interface statemachine.
 */
enum dev_events {
	DEV_EVENT_START,
	DEV_EVENT_STOP,
	DEV_EVENT_CONUP,
	DEV_EVENT_CONDOWN,
	/**
	 * MUST be always the last element!!
	 */
	NR_DEV_EVENTS
};

static const char *dev_event_names[] = {
	"Start",
	"Stop",
	"Connection up",
	"Connection down",
};
384

L
Linus Torvalds 已提交
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
/**
 * Events of the connection statemachine
 */
enum conn_events {
	/**
	 * Events, representing callbacks from
	 * lowlevel iucv layer)
	 */
	CONN_EVENT_CONN_REQ,
	CONN_EVENT_CONN_ACK,
	CONN_EVENT_CONN_REJ,
	CONN_EVENT_CONN_SUS,
	CONN_EVENT_CONN_RES,
	CONN_EVENT_RX,
	CONN_EVENT_TXDONE,

	/**
	 * Events, representing errors return codes from
	 * calls to lowlevel iucv layer
	 */

	/**
	 * Event, representing timer expiry.
	 */
	CONN_EVENT_TIMER,

	/**
	 * Events, representing commands from upper levels.
	 */
	CONN_EVENT_START,
	CONN_EVENT_STOP,

	/**
	 * MUST be always the last element!!
	 */
	NR_CONN_EVENTS,
};

static const char *conn_event_names[] = {
	"Remote connection request",
	"Remote connection acknowledge",
	"Remote connection reject",
	"Connection suspended",
	"Connection resumed",
	"Data received",
	"Data sent",

	"Timer",

	"Start",
	"Stop",
};

/**
 * States of the connection statemachine.
 */
enum conn_states {
	/**
	 * Connection not assigned to any device,
	 * initial state, invalid
	 */
	CONN_STATE_INVALID,

	/**
	 * Userid assigned but not operating
	 */
	CONN_STATE_STOPPED,

	/**
	 * Connection registered,
	 * no connection request sent yet,
	 * no connection request received
	 */
	CONN_STATE_STARTWAIT,

	/**
	 * Connection registered and connection request sent,
	 * no acknowledge and no connection request received yet.
	 */
	CONN_STATE_SETUPWAIT,

	/**
	 * Connection up and running idle
	 */
	CONN_STATE_IDLE,

	/**
	 * Data sent, awaiting CONN_EVENT_TXDONE
	 */
	CONN_STATE_TX,

	/**
	 * Error during registration.
	 */
	CONN_STATE_REGERR,

	/**
	 * Error during registration.
	 */
	CONN_STATE_CONNERR,

	/**
	 * MUST be always the last element!!
	 */
	NR_CONN_STATES,
};

static const char *conn_state_names[] = {
	"Invalid",
	"Stopped",
	"StartWait",
	"SetupWait",
	"Idle",
	"TX",
	"Terminating",
	"Registration error",
	"Connect error",
};

504

L
Linus Torvalds 已提交
505 506 507 508 509 510 511 512 513
/**
 * Debug Facility Stuff
 */
static debug_info_t *iucv_dbf_setup = NULL;
static debug_info_t *iucv_dbf_data = NULL;
static debug_info_t *iucv_dbf_trace = NULL;

DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf);

514
static void iucv_unregister_dbf_views(void)
L
Linus Torvalds 已提交
515 516 517 518 519 520 521 522
{
	if (iucv_dbf_setup)
		debug_unregister(iucv_dbf_setup);
	if (iucv_dbf_data)
		debug_unregister(iucv_dbf_data);
	if (iucv_dbf_trace)
		debug_unregister(iucv_dbf_trace);
}
523
static int iucv_register_dbf_views(void)
L
Linus Torvalds 已提交
524 525
{
	iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME,
526
					IUCV_DBF_SETUP_PAGES,
L
Linus Torvalds 已提交
527 528 529
					IUCV_DBF_SETUP_NR_AREAS,
					IUCV_DBF_SETUP_LEN);
	iucv_dbf_data = debug_register(IUCV_DBF_DATA_NAME,
530
				       IUCV_DBF_DATA_PAGES,
L
Linus Torvalds 已提交
531 532 533
				       IUCV_DBF_DATA_NR_AREAS,
				       IUCV_DBF_DATA_LEN);
	iucv_dbf_trace = debug_register(IUCV_DBF_TRACE_NAME,
534
					IUCV_DBF_TRACE_PAGES,
L
Linus Torvalds 已提交
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
					IUCV_DBF_TRACE_NR_AREAS,
					IUCV_DBF_TRACE_LEN);

	if ((iucv_dbf_setup == NULL) || (iucv_dbf_data == NULL) ||
	    (iucv_dbf_trace == NULL)) {
		iucv_unregister_dbf_views();
		return -ENOMEM;
	}
	debug_register_view(iucv_dbf_setup, &debug_hex_ascii_view);
	debug_set_level(iucv_dbf_setup, IUCV_DBF_SETUP_LEVEL);

	debug_register_view(iucv_dbf_data, &debug_hex_ascii_view);
	debug_set_level(iucv_dbf_data, IUCV_DBF_DATA_LEVEL);

	debug_register_view(iucv_dbf_trace, &debug_hex_ascii_view);
	debug_set_level(iucv_dbf_trace, IUCV_DBF_TRACE_LEVEL);

	return 0;
}

555
/*
L
Linus Torvalds 已提交
556
 * Callback-wrappers, called from lowlevel iucv layer.
557
 */
L
Linus Torvalds 已提交
558

559 560
static void netiucv_callback_rx(struct iucv_path *path,
				struct iucv_message *msg)
L
Linus Torvalds 已提交
561
{
562
	struct iucv_connection *conn = path->private;
L
Linus Torvalds 已提交
563 564 565
	struct iucv_event ev;

	ev.conn = conn;
566
	ev.data = msg;
L
Linus Torvalds 已提交
567 568 569
	fsm_event(conn->fsm, CONN_EVENT_RX, &ev);
}

570 571
static void netiucv_callback_txdone(struct iucv_path *path,
				    struct iucv_message *msg)
L
Linus Torvalds 已提交
572
{
573
	struct iucv_connection *conn = path->private;
L
Linus Torvalds 已提交
574 575 576
	struct iucv_event ev;

	ev.conn = conn;
577
	ev.data = msg;
L
Linus Torvalds 已提交
578 579 580
	fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev);
}

581
static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16])
L
Linus Torvalds 已提交
582
{
583
	struct iucv_connection *conn = path->private;
L
Linus Torvalds 已提交
584

585
	fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn);
L
Linus Torvalds 已提交
586 587
}

588 589
static int netiucv_callback_connreq(struct iucv_path *path,
				    u8 ipvmid[8], u8 ipuser[16])
L
Linus Torvalds 已提交
590
{
591
	struct iucv_connection *conn = path->private;
L
Linus Torvalds 已提交
592
	struct iucv_event ev;
593 594
	static char tmp_user[9];
	static char tmp_udat[17];
595
	int rc;
L
Linus Torvalds 已提交
596

597
	rc = -EINVAL;
598 599 600
	memcpy(tmp_user, netiucv_printname(ipvmid, 8), 8);
	memcpy(tmp_udat, ipuser, 16);
	EBCASC(tmp_udat, 16);
601 602
	read_lock_bh(&iucv_connection_rwlock);
	list_for_each_entry(conn, &iucv_connection_list, list) {
603 604
		if (strncmp(ipvmid, conn->userid, 8) ||
		    strncmp(ipuser, conn->userdata, 16))
605 606 607 608 609 610 611 612
			continue;
		/* Found a matching connection for this path. */
		conn->path = path;
		ev.conn = conn;
		ev.data = path;
		fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);
		rc = 0;
	}
613 614
	IUCV_DBF_TEXT_(setup, 2, "Connection requested for %s.%s\n",
		       tmp_user, netiucv_printname(tmp_udat, 16));
615 616
	read_unlock_bh(&iucv_connection_rwlock);
	return rc;
L
Linus Torvalds 已提交
617 618
}

619
static void netiucv_callback_connrej(struct iucv_path *path, u8 ipuser[16])
L
Linus Torvalds 已提交
620
{
621
	struct iucv_connection *conn = path->private;
L
Linus Torvalds 已提交
622

623
	fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, conn);
L
Linus Torvalds 已提交
624 625
}

626
static void netiucv_callback_connsusp(struct iucv_path *path, u8 ipuser[16])
L
Linus Torvalds 已提交
627
{
628
	struct iucv_connection *conn = path->private;
L
Linus Torvalds 已提交
629

630
	fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, conn);
L
Linus Torvalds 已提交
631 632
}

633
static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16])
L
Linus Torvalds 已提交
634
{
635
	struct iucv_connection *conn = path->private;
L
Linus Torvalds 已提交
636

637 638
	fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn);
}
L
Linus Torvalds 已提交
639 640

/**
641
 * NOP action for statemachines
L
Linus Torvalds 已提交
642
 */
643
static void netiucv_action_nop(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
644 645
{
}
646

647
/*
L
Linus Torvalds 已提交
648
 * Actions of the connection statemachine
649
 */
L
Linus Torvalds 已提交
650 651

/**
652 653 654
 * netiucv_unpack_skb
 * @conn: The connection where this skb has been received.
 * @pskb: The received skb.
L
Linus Torvalds 已提交
655
 *
656 657
 * Unpack a just received skb and hand it over to upper layers.
 * Helper function for conn_action_rx.
L
Linus Torvalds 已提交
658
 */
659 660
static void netiucv_unpack_skb(struct iucv_connection *conn,
			       struct sk_buff *pskb)
L
Linus Torvalds 已提交
661 662
{
	struct net_device     *dev = conn->netdev;
663 664
	struct netiucv_priv   *privptr = netdev_priv(dev);
	u16 offset = 0;
L
Linus Torvalds 已提交
665 666 667 668 669 670 671 672

	skb_put(pskb, NETIUCV_HDRLEN);
	pskb->dev = dev;
	pskb->ip_summed = CHECKSUM_NONE;
	pskb->protocol = ntohs(ETH_P_IP);

	while (1) {
		struct sk_buff *skb;
673
		struct ll_header *header = (struct ll_header *) pskb->data;
L
Linus Torvalds 已提交
674 675 676 677 678 679 680 681 682 683 684 685 686 687

		if (!header->next)
			break;

		skb_pull(pskb, NETIUCV_HDRLEN);
		header->next -= offset;
		offset += header->next;
		header->next -= NETIUCV_HDRLEN;
		if (skb_tailroom(pskb) < header->next) {
			IUCV_DBF_TEXT_(data, 2, "Illegal next field: %d > %d\n",
				header->next, skb_tailroom(pskb));
			return;
		}
		skb_put(pskb, header->next);
688
		skb_reset_mac_header(pskb);
L
Linus Torvalds 已提交
689 690 691 692 693 694 695
		skb = dev_alloc_skb(pskb->len);
		if (!skb) {
			IUCV_DBF_TEXT(data, 2,
				"Out of memory in netiucv_unpack_skb\n");
			privptr->stats.rx_dropped++;
			return;
		}
696 697
		skb_copy_from_linear_data(pskb, skb_put(skb, pskb->len),
					  pskb->len);
698
		skb_reset_mac_header(skb);
L
Linus Torvalds 已提交
699 700 701
		skb->dev = pskb->dev;
		skb->protocol = pskb->protocol;
		pskb->ip_summed = CHECKSUM_UNNECESSARY;
702 703
		privptr->stats.rx_packets++;
		privptr->stats.rx_bytes += skb->len;
L
Linus Torvalds 已提交
704 705 706 707 708 709 710 711 712 713
		/*
		 * Since receiving is always initiated from a tasklet (in iucv.c),
		 * we must use netif_rx_ni() instead of netif_rx()
		 */
		netif_rx_ni(skb);
		skb_pull(pskb, header->next);
		skb_put(pskb, NETIUCV_HDRLEN);
	}
}

714
static void conn_action_rx(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
715
{
716
	struct iucv_event *ev = arg;
L
Linus Torvalds 已提交
717
	struct iucv_connection *conn = ev->conn;
718 719
	struct iucv_message *msg = ev->data;
	struct netiucv_priv *privptr = netdev_priv(conn->netdev);
L
Linus Torvalds 已提交
720 721
	int rc;

722
	IUCV_DBF_TEXT(trace, 4, __func__);
L
Linus Torvalds 已提交
723 724

	if (!conn->netdev) {
725
		iucv_message_reject(conn->path, msg);
L
Linus Torvalds 已提交
726
		IUCV_DBF_TEXT(data, 2,
727
			      "Received data for unlinked connection\n");
L
Linus Torvalds 已提交
728 729
		return;
	}
730 731
	if (msg->length > conn->max_buffsize) {
		iucv_message_reject(conn->path, msg);
L
Linus Torvalds 已提交
732 733
		privptr->stats.rx_dropped++;
		IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n",
734
			       msg->length, conn->max_buffsize);
L
Linus Torvalds 已提交
735 736
		return;
	}
737 738
	conn->rx_buff->data = conn->rx_buff->head;
	skb_reset_tail_pointer(conn->rx_buff);
L
Linus Torvalds 已提交
739
	conn->rx_buff->len = 0;
740 741 742
	rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data,
				  msg->length, NULL);
	if (rc || msg->length < 5) {
L
Linus Torvalds 已提交
743 744 745 746 747 748 749
		privptr->stats.rx_errors++;
		IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc);
		return;
	}
	netiucv_unpack_skb(conn, conn->rx_buff);
}

750
static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
751
{
752
	struct iucv_event *ev = arg;
L
Linus Torvalds 已提交
753
	struct iucv_connection *conn = ev->conn;
754 755
	struct iucv_message *msg = ev->data;
	struct iucv_message txmsg;
L
Linus Torvalds 已提交
756
	struct netiucv_priv *privptr = NULL;
757 758 759 760
	u32 single_flag = msg->tag;
	u32 txbytes = 0;
	u32 txpackets = 0;
	u32 stat_maxcq = 0;
L
Linus Torvalds 已提交
761 762
	struct sk_buff *skb;
	unsigned long saveflags;
763 764
	struct ll_header header;
	int rc;
L
Linus Torvalds 已提交
765

766
	IUCV_DBF_TEXT(trace, 4, __func__);
L
Linus Torvalds 已提交
767

768 769
	if (conn && conn->netdev)
		privptr = netdev_priv(conn->netdev);
L
Linus Torvalds 已提交
770 771 772 773 774 775 776 777
	conn->prof.tx_pending--;
	if (single_flag) {
		if ((skb = skb_dequeue(&conn->commit_queue))) {
			atomic_dec(&skb->users);
			if (privptr) {
				privptr->stats.tx_packets++;
				privptr->stats.tx_bytes +=
					(skb->len - NETIUCV_HDRLEN
778
						  - NETIUCV_HDRLEN);
L
Linus Torvalds 已提交
779
			}
780
			dev_kfree_skb_any(skb);
L
Linus Torvalds 已提交
781 782
		}
	}
783 784
	conn->tx_buff->data = conn->tx_buff->head;
	skb_reset_tail_pointer(conn->tx_buff);
L
Linus Torvalds 已提交
785 786 787 788 789 790
	conn->tx_buff->len = 0;
	spin_lock_irqsave(&conn->collect_lock, saveflags);
	while ((skb = skb_dequeue(&conn->collect_queue))) {
		header.next = conn->tx_buff->len + skb->len + NETIUCV_HDRLEN;
		memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header,
		       NETIUCV_HDRLEN);
791 792 793
		skb_copy_from_linear_data(skb,
					  skb_put(conn->tx_buff, skb->len),
					  skb->len);
L
Linus Torvalds 已提交
794 795 796 797 798 799 800 801 802 803
		txbytes += skb->len;
		txpackets++;
		stat_maxcq++;
		atomic_dec(&skb->users);
		dev_kfree_skb_any(skb);
	}
	if (conn->collect_len > conn->prof.maxmulti)
		conn->prof.maxmulti = conn->collect_len;
	conn->collect_len = 0;
	spin_unlock_irqrestore(&conn->collect_lock, saveflags);
804 805 806 807
	if (conn->tx_buff->len == 0) {
		fsm_newstate(fi, CONN_STATE_IDLE);
		return;
	}
L
Linus Torvalds 已提交
808

809 810
	header.next = 0;
	memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
811
	conn->prof.send_stamp = current_kernel_time();
812 813 814
	txmsg.class = 0;
	txmsg.tag = 0;
	rc = iucv_message_send(conn->path, &txmsg, 0, 0,
L
Linus Torvalds 已提交
815
			       conn->tx_buff->data, conn->tx_buff->len);
816 817 818 819 820 821 822
	conn->prof.doios_multi++;
	conn->prof.txlen += conn->tx_buff->len;
	conn->prof.tx_pending++;
	if (conn->prof.tx_pending > conn->prof.tx_max_pending)
		conn->prof.tx_max_pending = conn->prof.tx_pending;
	if (rc) {
		conn->prof.tx_pending--;
L
Linus Torvalds 已提交
823
		fsm_newstate(fi, CONN_STATE_IDLE);
824 825 826 827 828 829 830 831 832 833 834
		if (privptr)
			privptr->stats.tx_errors += txpackets;
		IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
	} else {
		if (privptr) {
			privptr->stats.tx_packets += txpackets;
			privptr->stats.tx_bytes += txbytes;
		}
		if (stat_maxcq > conn->prof.maxcqueue)
			conn->prof.maxcqueue = stat_maxcq;
	}
L
Linus Torvalds 已提交
835 836
}

837
static void conn_action_connaccept(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
838
{
839
	struct iucv_event *ev = arg;
L
Linus Torvalds 已提交
840
	struct iucv_connection *conn = ev->conn;
841
	struct iucv_path *path = ev->data;
L
Linus Torvalds 已提交
842
	struct net_device *netdev = conn->netdev;
843
	struct netiucv_priv *privptr = netdev_priv(netdev);
L
Linus Torvalds 已提交
844 845
	int rc;

846
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
847

848 849 850
	conn->path = path;
	path->msglim = NETIUCV_QUEUELEN_DEFAULT;
	path->flags = 0;
851
	rc = iucv_path_accept(path, &netiucv_handler, conn->userdata , conn);
L
Linus Torvalds 已提交
852 853 854 855 856
	if (rc) {
		IUCV_DBF_TEXT_(setup, 2, "rc %d from iucv_accept", rc);
		return;
	}
	fsm_newstate(fi, CONN_STATE_IDLE);
857
	netdev->tx_queue_len = conn->path->msglim;
L
Linus Torvalds 已提交
858 859 860
	fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);
}

861
static void conn_action_connreject(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
862
{
863 864
	struct iucv_event *ev = arg;
	struct iucv_path *path = ev->data;
L
Linus Torvalds 已提交
865

866
	IUCV_DBF_TEXT(trace, 3, __func__);
867
	iucv_path_sever(path, NULL);
L
Linus Torvalds 已提交
868 869
}

870
static void conn_action_connack(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
871
{
872
	struct iucv_connection *conn = arg;
L
Linus Torvalds 已提交
873
	struct net_device *netdev = conn->netdev;
874
	struct netiucv_priv *privptr = netdev_priv(netdev);
L
Linus Torvalds 已提交
875

876
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
877 878
	fsm_deltimer(&conn->timer);
	fsm_newstate(fi, CONN_STATE_IDLE);
879
	netdev->tx_queue_len = conn->path->msglim;
L
Linus Torvalds 已提交
880 881 882
	fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);
}

883
static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
884
{
885
	struct iucv_connection *conn = arg;
L
Linus Torvalds 已提交
886

887
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
888
	fsm_deltimer(&conn->timer);
889
	iucv_path_sever(conn->path, conn->userdata);
L
Linus Torvalds 已提交
890 891 892
	fsm_newstate(fi, CONN_STATE_STARTWAIT);
}

893
static void conn_action_connsever(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
894
{
895
	struct iucv_connection *conn = arg;
L
Linus Torvalds 已提交
896
	struct net_device *netdev = conn->netdev;
897
	struct netiucv_priv *privptr = netdev_priv(netdev);
L
Linus Torvalds 已提交
898

899
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
900 901

	fsm_deltimer(&conn->timer);
902 903 904
	iucv_path_sever(conn->path, conn->userdata);
	dev_info(privptr->dev, "The peer z/VM guest %s has closed the "
			       "connection\n", netiucv_printuser(conn));
L
Linus Torvalds 已提交
905
	IUCV_DBF_TEXT(data, 2,
906
		      "conn_action_connsever: Remote dropped connection\n");
L
Linus Torvalds 已提交
907 908 909 910
	fsm_newstate(fi, CONN_STATE_STARTWAIT);
	fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
}

911
static void conn_action_start(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
912
{
913
	struct iucv_connection *conn = arg;
914 915
	struct net_device *netdev = conn->netdev;
	struct netiucv_priv *privptr = netdev_priv(netdev);
L
Linus Torvalds 已提交
916 917
	int rc;

918
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
919

920
	fsm_newstate(fi, CONN_STATE_STARTWAIT);
L
Linus Torvalds 已提交
921

922 923 924 925 926
	/*
	 * We must set the state before calling iucv_connect because the
	 * callback handler could be called at any point after the connection
	 * request is sent
	 */
L
Linus Torvalds 已提交
927 928

	fsm_newstate(fi, CONN_STATE_SETUPWAIT);
929
	conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL);
930 931 932
	IUCV_DBF_TEXT_(setup, 2, "%s: connecting to %s ...\n",
		netdev->name, netiucv_printuser(conn));

933
	rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid,
934
			       NULL, conn->userdata, conn);
L
Linus Torvalds 已提交
935
	switch (rc) {
936
	case 0:
937
		netdev->tx_queue_len = conn->path->msglim;
938 939 940 941
		fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
			     CONN_EVENT_TIMER, conn);
		return;
	case 11:
942 943
		dev_warn(privptr->dev,
			"The IUCV device failed to connect to z/VM guest %s\n",
944
			netiucv_printname(conn->userid, 8));
945 946 947
		fsm_newstate(fi, CONN_STATE_STARTWAIT);
		break;
	case 12:
948 949
		dev_warn(privptr->dev,
			"The IUCV device failed to connect to the peer on z/VM"
950
			" guest %s\n", netiucv_printname(conn->userid, 8));
951 952 953
		fsm_newstate(fi, CONN_STATE_STARTWAIT);
		break;
	case 13:
954 955 956
		dev_err(privptr->dev,
			"Connecting the IUCV device would exceed the maximum"
			" number of IUCV connections\n");
957 958 959
		fsm_newstate(fi, CONN_STATE_CONNERR);
		break;
	case 14:
960 961 962
		dev_err(privptr->dev,
			"z/VM guest %s has too many IUCV connections"
			" to connect with the IUCV device\n",
963
			netiucv_printname(conn->userid, 8));
964 965 966
		fsm_newstate(fi, CONN_STATE_CONNERR);
		break;
	case 15:
967 968 969
		dev_err(privptr->dev,
			"The IUCV device cannot connect to a z/VM guest with no"
			" IUCV authorization\n");
970 971 972
		fsm_newstate(fi, CONN_STATE_CONNERR);
		break;
	default:
973 974 975
		dev_err(privptr->dev,
			"Connecting the IUCV device failed with error %d\n",
			rc);
976 977
		fsm_newstate(fi, CONN_STATE_CONNERR);
		break;
L
Linus Torvalds 已提交
978 979
	}
	IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc);
980 981
	kfree(conn->path);
	conn->path = NULL;
L
Linus Torvalds 已提交
982 983
}

984
static void netiucv_purge_skb_queue(struct sk_buff_head *q)
L
Linus Torvalds 已提交
985 986 987 988 989 990 991 992 993
{
	struct sk_buff *skb;

	while ((skb = skb_dequeue(q))) {
		atomic_dec(&skb->users);
		dev_kfree_skb_any(skb);
	}
}

994
static void conn_action_stop(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
995
{
996
	struct iucv_event *ev = arg;
L
Linus Torvalds 已提交
997 998
	struct iucv_connection *conn = ev->conn;
	struct net_device *netdev = conn->netdev;
999
	struct netiucv_priv *privptr = netdev_priv(netdev);
L
Linus Torvalds 已提交
1000

1001
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
1002 1003 1004 1005

	fsm_deltimer(&conn->timer);
	fsm_newstate(fi, CONN_STATE_STOPPED);
	netiucv_purge_skb_queue(&conn->collect_queue);
1006 1007
	if (conn->path) {
		IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n");
1008
		iucv_path_sever(conn->path, conn->userdata);
1009 1010 1011
		kfree(conn->path);
		conn->path = NULL;
	}
L
Linus Torvalds 已提交
1012 1013 1014 1015
	netiucv_purge_skb_queue(&conn->commit_queue);
	fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
}

1016
static void conn_action_inval(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
1017
{
1018
	struct iucv_connection *conn = arg;
L
Linus Torvalds 已提交
1019 1020
	struct net_device *netdev = conn->netdev;

1021 1022
	IUCV_DBF_TEXT_(data, 2, "%s('%s'): conn_action_inval called\n",
		netdev->name, conn->userid);
L
Linus Torvalds 已提交
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
}

static const fsm_node conn_fsm[] = {
	{ CONN_STATE_INVALID,   CONN_EVENT_START,    conn_action_inval      },
	{ CONN_STATE_STOPPED,   CONN_EVENT_START,    conn_action_start      },

	{ CONN_STATE_STOPPED,   CONN_EVENT_STOP,     conn_action_stop       },
	{ CONN_STATE_STARTWAIT, CONN_EVENT_STOP,     conn_action_stop       },
	{ CONN_STATE_SETUPWAIT, CONN_EVENT_STOP,     conn_action_stop       },
	{ CONN_STATE_IDLE,      CONN_EVENT_STOP,     conn_action_stop       },
	{ CONN_STATE_TX,        CONN_EVENT_STOP,     conn_action_stop       },
	{ CONN_STATE_REGERR,    CONN_EVENT_STOP,     conn_action_stop       },
	{ CONN_STATE_CONNERR,   CONN_EVENT_STOP,     conn_action_stop       },

	{ CONN_STATE_STOPPED,   CONN_EVENT_CONN_REQ, conn_action_connreject },
        { CONN_STATE_STARTWAIT, CONN_EVENT_CONN_REQ, conn_action_connaccept },
	{ CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_REQ, conn_action_connaccept },
	{ CONN_STATE_IDLE,      CONN_EVENT_CONN_REQ, conn_action_connreject },
	{ CONN_STATE_TX,        CONN_EVENT_CONN_REQ, conn_action_connreject },

	{ CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_ACK, conn_action_connack    },
	{ CONN_STATE_SETUPWAIT, CONN_EVENT_TIMER,    conn_action_conntimsev },

	{ CONN_STATE_SETUPWAIT, CONN_EVENT_CONN_REJ, conn_action_connsever  },
	{ CONN_STATE_IDLE,      CONN_EVENT_CONN_REJ, conn_action_connsever  },
	{ CONN_STATE_TX,        CONN_EVENT_CONN_REJ, conn_action_connsever  },

	{ CONN_STATE_IDLE,      CONN_EVENT_RX,       conn_action_rx         },
	{ CONN_STATE_TX,        CONN_EVENT_RX,       conn_action_rx         },

	{ CONN_STATE_TX,        CONN_EVENT_TXDONE,   conn_action_txdone     },
	{ CONN_STATE_IDLE,      CONN_EVENT_TXDONE,   conn_action_txdone     },
};

static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);

1059

1060
/*
L
Linus Torvalds 已提交
1061
 * Actions for interface - statemachine.
1062
 */
L
Linus Torvalds 已提交
1063 1064

/**
1065 1066 1067 1068
 * dev_action_start
 * @fi: An instance of an interface statemachine.
 * @event: The event, just happened.
 * @arg: Generic pointer, casted from struct net_device * upon call.
L
Linus Torvalds 已提交
1069
 *
1070
 * Startup connection by sending CONN_EVENT_START to it.
L
Linus Torvalds 已提交
1071
 */
1072
static void dev_action_start(fsm_instance *fi, int event, void *arg)
L
Linus Torvalds 已提交
1073
{
1074 1075
	struct net_device   *dev = arg;
	struct netiucv_priv *privptr = netdev_priv(dev);
L
Linus Torvalds 已提交
1076

1077
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
1078 1079

	fsm_newstate(fi, DEV_STATE_STARTWAIT);
1080
	fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn);
L
Linus Torvalds 已提交
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
}

/**
 * Shutdown connection by sending CONN_EVENT_STOP to it.
 *
 * @param fi    An instance of an interface statemachine.
 * @param event The event, just happened.
 * @param arg   Generic pointer, casted from struct net_device * upon call.
 */
static void
dev_action_stop(fsm_instance *fi, int event, void *arg)
{
1093 1094
	struct net_device   *dev = arg;
	struct netiucv_priv *privptr = netdev_priv(dev);
L
Linus Torvalds 已提交
1095 1096
	struct iucv_event   ev;

1097
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115

	ev.conn = privptr->conn;

	fsm_newstate(fi, DEV_STATE_STOPWAIT);
	fsm_event(privptr->conn->fsm, CONN_EVENT_STOP, &ev);
}

/**
 * Called from connection statemachine
 * when a connection is up and running.
 *
 * @param fi    An instance of an interface statemachine.
 * @param event The event, just happened.
 * @param arg   Generic pointer, casted from struct net_device * upon call.
 */
static void
dev_action_connup(fsm_instance *fi, int event, void *arg)
{
1116 1117
	struct net_device   *dev = arg;
	struct netiucv_priv *privptr = netdev_priv(dev);
L
Linus Torvalds 已提交
1118

1119
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
1120 1121 1122 1123

	switch (fsm_getstate(fi)) {
		case DEV_STATE_STARTWAIT:
			fsm_newstate(fi, DEV_STATE_RUNNING);
1124 1125
			dev_info(privptr->dev,
				"The IUCV device has been connected"
1126 1127
				" successfully to %s\n",
				netiucv_printuser(privptr->conn));
L
Linus Torvalds 已提交
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
			IUCV_DBF_TEXT(setup, 3,
				"connection is up and running\n");
			break;
		case DEV_STATE_STOPWAIT:
			IUCV_DBF_TEXT(data, 2,
				"dev_action_connup: in DEV_STATE_STOPWAIT\n");
			break;
	}
}

/**
 * Called from connection statemachine
 * when a connection has been shutdown.
 *
 * @param fi    An instance of an interface statemachine.
 * @param event The event, just happened.
 * @param arg   Generic pointer, casted from struct net_device * upon call.
 */
static void
dev_action_conndown(fsm_instance *fi, int event, void *arg)
{
1149
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172

	switch (fsm_getstate(fi)) {
		case DEV_STATE_RUNNING:
			fsm_newstate(fi, DEV_STATE_STARTWAIT);
			break;
		case DEV_STATE_STOPWAIT:
			fsm_newstate(fi, DEV_STATE_STOPPED);
			IUCV_DBF_TEXT(setup, 3, "connection is down\n");
			break;
	}
}

static const fsm_node dev_fsm[] = {
	{ DEV_STATE_STOPPED,    DEV_EVENT_START,   dev_action_start    },

	{ DEV_STATE_STOPWAIT,   DEV_EVENT_START,   dev_action_start    },
	{ DEV_STATE_STOPWAIT,   DEV_EVENT_CONDOWN, dev_action_conndown },

	{ DEV_STATE_STARTWAIT,  DEV_EVENT_STOP,    dev_action_stop     },
	{ DEV_STATE_STARTWAIT,  DEV_EVENT_CONUP,   dev_action_connup   },

	{ DEV_STATE_RUNNING,    DEV_EVENT_STOP,    dev_action_stop     },
	{ DEV_STATE_RUNNING,    DEV_EVENT_CONDOWN, dev_action_conndown },
1173
	{ DEV_STATE_RUNNING,    DEV_EVENT_CONUP,   netiucv_action_nop  },
L
Linus Torvalds 已提交
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
};

static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node);

/**
 * Transmit a packet.
 * This is a helper function for netiucv_tx().
 *
 * @param conn Connection to be used for sending.
 * @param skb Pointer to struct sk_buff of packet to send.
 *            The linklevel header has already been set up
 *            by netiucv_tx().
 *
 * @return 0 on success, -ERRNO on failure. (Never fails.)
 */
1189 1190 1191 1192
static int netiucv_transmit_skb(struct iucv_connection *conn,
				struct sk_buff *skb)
{
	struct iucv_message msg;
L
Linus Torvalds 已提交
1193
	unsigned long saveflags;
1194 1195
	struct ll_header header;
	int rc;
L
Linus Torvalds 已提交
1196 1197 1198 1199 1200 1201 1202 1203 1204

	if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) {
		int l = skb->len + NETIUCV_HDRLEN;

		spin_lock_irqsave(&conn->collect_lock, saveflags);
		if (conn->collect_len + l >
		    (conn->max_buffsize - NETIUCV_HDRLEN)) {
			rc = -EBUSY;
			IUCV_DBF_TEXT(data, 2,
1205
				      "EBUSY from netiucv_transmit_skb\n");
L
Linus Torvalds 已提交
1206 1207 1208 1209
		} else {
			atomic_inc(&skb->users);
			skb_queue_tail(&conn->collect_queue, skb);
			conn->collect_len += l;
1210
			rc = 0;
L
Linus Torvalds 已提交
1211 1212 1213 1214 1215 1216 1217 1218
		}
		spin_unlock_irqrestore(&conn->collect_lock, saveflags);
	} else {
		struct sk_buff *nskb = skb;
		/**
		 * Copy the skb to a new allocated skb in lowmem only if the
		 * data is located above 2G in memory or tailroom is < 2.
		 */
1219 1220
		unsigned long hi = ((unsigned long)(skb_tail_pointer(skb) +
				    NETIUCV_HDRLEN)) >> 31;
L
Linus Torvalds 已提交
1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
		int copied = 0;
		if (hi || (skb_tailroom(skb) < 2)) {
			nskb = alloc_skb(skb->len + NETIUCV_HDRLEN +
					 NETIUCV_HDRLEN, GFP_ATOMIC | GFP_DMA);
			if (!nskb) {
				IUCV_DBF_TEXT(data, 2, "alloc_skb failed\n");
				rc = -ENOMEM;
				return rc;
			} else {
				skb_reserve(nskb, NETIUCV_HDRLEN);
				memcpy(skb_put(nskb, skb->len),
				       skb->data, skb->len);
			}
			copied = 1;
		}
		/**
		 * skb now is below 2G and has enough room. Add headers.
		 */
		header.next = nskb->len + NETIUCV_HDRLEN;
		memcpy(skb_push(nskb, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
		header.next = 0;
		memcpy(skb_put(nskb, NETIUCV_HDRLEN), &header,  NETIUCV_HDRLEN);

		fsm_newstate(conn->fsm, CONN_STATE_TX);
1245
		conn->prof.send_stamp = current_kernel_time();
1246

1247 1248 1249 1250
		msg.tag = 1;
		msg.class = 0;
		rc = iucv_message_send(conn->path, &msg, 0, 0,
				       nskb->data, nskb->len);
L
Linus Torvalds 已提交
1251 1252 1253 1254 1255 1256 1257 1258 1259
		conn->prof.doios_single++;
		conn->prof.txlen += skb->len;
		conn->prof.tx_pending++;
		if (conn->prof.tx_pending > conn->prof.tx_max_pending)
			conn->prof.tx_max_pending = conn->prof.tx_pending;
		if (rc) {
			struct netiucv_priv *privptr;
			fsm_newstate(conn->fsm, CONN_STATE_IDLE);
			conn->prof.tx_pending--;
1260
			privptr = netdev_priv(conn->netdev);
L
Linus Torvalds 已提交
1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
			if (privptr)
				privptr->stats.tx_errors++;
			if (copied)
				dev_kfree_skb(nskb);
			else {
				/**
				 * Remove our headers. They get added
				 * again on retransmit.
				 */
				skb_pull(skb, NETIUCV_HDRLEN);
				skb_trim(skb, skb->len - NETIUCV_HDRLEN);
			}
			IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc);
		} else {
			if (copied)
				dev_kfree_skb(skb);
			atomic_inc(&nskb->users);
			skb_queue_tail(&conn->commit_queue, nskb);
		}
	}

	return rc;
}
1284

1285
/*
L
Linus Torvalds 已提交
1286
 * Interface API for upper network layers
1287
 */
L
Linus Torvalds 已提交
1288 1289 1290 1291 1292 1293 1294 1295 1296

/**
 * Open an interface.
 * Called from generic network layer when ifconfig up is run.
 *
 * @param dev Pointer to interface struct.
 *
 * @return 0 on success, -ERRNO on failure. (Never fails.)
 */
1297 1298 1299 1300 1301
static int netiucv_open(struct net_device *dev)
{
	struct netiucv_priv *priv = netdev_priv(dev);

	fsm_event(priv->fsm, DEV_EVENT_START, dev);
L
Linus Torvalds 已提交
1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312
	return 0;
}

/**
 * Close an interface.
 * Called from generic network layer when ifconfig down is run.
 *
 * @param dev Pointer to interface struct.
 *
 * @return 0 on success, -ERRNO on failure. (Never fails.)
 */
1313 1314 1315 1316 1317
static int netiucv_close(struct net_device *dev)
{
	struct netiucv_priv *priv = netdev_priv(dev);

	fsm_event(priv->fsm, DEV_EVENT_STOP, dev);
L
Linus Torvalds 已提交
1318 1319 1320
	return 0;
}

1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
static int netiucv_pm_prepare(struct device *dev)
{
	IUCV_DBF_TEXT(trace, 3, __func__);
	return 0;
}

static void netiucv_pm_complete(struct device *dev)
{
	IUCV_DBF_TEXT(trace, 3, __func__);
	return;
}

/**
 * netiucv_pm_freeze() - Freeze PM callback
 * @dev:	netiucv device
 *
 * close open netiucv interfaces
 */
static int netiucv_pm_freeze(struct device *dev)
{
M
Martin Schwidefsky 已提交
1341
	struct netiucv_priv *priv = dev_get_drvdata(dev);
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364
	struct net_device *ndev = NULL;
	int rc = 0;

	IUCV_DBF_TEXT(trace, 3, __func__);
	if (priv && priv->conn)
		ndev = priv->conn->netdev;
	if (!ndev)
		goto out;
	netif_device_detach(ndev);
	priv->pm_state = fsm_getstate(priv->fsm);
	rc = netiucv_close(ndev);
out:
	return rc;
}

/**
 * netiucv_pm_restore_thaw() - Thaw and restore PM callback
 * @dev:	netiucv device
 *
 * re-open netiucv interfaces closed during freeze
 */
static int netiucv_pm_restore_thaw(struct device *dev)
{
M
Martin Schwidefsky 已提交
1365
	struct netiucv_priv *priv = dev_get_drvdata(dev);
1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
	struct net_device *ndev = NULL;
	int rc = 0;

	IUCV_DBF_TEXT(trace, 3, __func__);
	if (priv && priv->conn)
		ndev = priv->conn->netdev;
	if (!ndev)
		goto out;
	switch (priv->pm_state) {
	case DEV_STATE_RUNNING:
	case DEV_STATE_STARTWAIT:
		rc = netiucv_open(ndev);
		break;
	default:
		break;
	}
	netif_device_attach(ndev);
out:
	return rc;
}

L
Linus Torvalds 已提交
1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399
/**
 * Start transmission of a packet.
 * Called from generic network device layer.
 *
 * @param skb Pointer to buffer containing the packet.
 * @param dev Pointer to interface struct.
 *
 * @return 0 if packet consumed, !0 if packet rejected.
 *         Note: If we return !0, then the packet is free'd by
 *               the generic network layer.
 */
static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
{
1400 1401
	struct netiucv_priv *privptr = netdev_priv(dev);
	int rc;
L
Linus Torvalds 已提交
1402

1403
	IUCV_DBF_TEXT(trace, 4, __func__);
L
Linus Torvalds 已提交
1404 1405 1406 1407 1408 1409
	/**
	 * Some sanity checks ...
	 */
	if (skb == NULL) {
		IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb is NULL\n");
		privptr->stats.tx_dropped++;
1410
		return NETDEV_TX_OK;
L
Linus Torvalds 已提交
1411 1412 1413 1414 1415 1416
	}
	if (skb_headroom(skb) < NETIUCV_HDRLEN) {
		IUCV_DBF_TEXT(data, 2,
			"netiucv_tx: skb_headroom < NETIUCV_HDRLEN\n");
		dev_kfree_skb(skb);
		privptr->stats.tx_dropped++;
1417
		return NETDEV_TX_OK;
L
Linus Torvalds 已提交
1418 1419 1420 1421
	}

	/**
	 * If connection is not running, try to restart it
1422
	 * and throw away packet.
L
Linus Torvalds 已提交
1423 1424 1425 1426 1427 1428
	 */
	if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
		dev_kfree_skb(skb);
		privptr->stats.tx_dropped++;
		privptr->stats.tx_errors++;
		privptr->stats.tx_carrier_errors++;
1429
		return NETDEV_TX_OK;
L
Linus Torvalds 已提交
1430 1431 1432 1433
	}

	if (netiucv_test_and_set_busy(dev)) {
		IUCV_DBF_TEXT(data, 2, "EBUSY from netiucv_tx\n");
1434
		return NETDEV_TX_BUSY;
L
Linus Torvalds 已提交
1435 1436
	}
	dev->trans_start = jiffies;
1437
	rc = netiucv_transmit_skb(privptr->conn, skb);
L
Linus Torvalds 已提交
1438
	netiucv_clear_busy(dev);
1439
	return rc ? NETDEV_TX_BUSY : NETDEV_TX_OK;
L
Linus Torvalds 已提交
1440 1441 1442
}

/**
1443 1444
 * netiucv_stats
 * @dev: Pointer to interface struct.
L
Linus Torvalds 已提交
1445
 *
1446
 * Returns interface statistics of a device.
L
Linus Torvalds 已提交
1447
 *
1448
 * Returns pointer to stats struct of this interface.
L
Linus Torvalds 已提交
1449
 */
1450
static struct net_device_stats *netiucv_stats (struct net_device * dev)
L
Linus Torvalds 已提交
1451
{
1452 1453
	struct netiucv_priv *priv = netdev_priv(dev);

1454
	IUCV_DBF_TEXT(trace, 5, __func__);
1455
	return &priv->stats;
L
Linus Torvalds 已提交
1456 1457 1458
}

/**
1459 1460 1461
 * netiucv_change_mtu
 * @dev: Pointer to interface struct.
 * @new_mtu: The new MTU to use for this interface.
L
Linus Torvalds 已提交
1462
 *
1463
 * Sets MTU of an interface.
L
Linus Torvalds 已提交
1464
 *
1465
 * Returns 0 on success, -EINVAL if MTU is out of valid range.
L
Linus Torvalds 已提交
1466 1467
 *         (valid range is 576 .. NETIUCV_MTU_MAX).
 */
1468
static int netiucv_change_mtu(struct net_device * dev, int new_mtu)
L
Linus Torvalds 已提交
1469
{
1470
	IUCV_DBF_TEXT(trace, 3, __func__);
1471
	if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) {
L
Linus Torvalds 已提交
1472 1473 1474 1475 1476 1477 1478
		IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n");
		return -EINVAL;
	}
	dev->mtu = new_mtu;
	return 0;
}

1479
/*
L
Linus Torvalds 已提交
1480
 * attributes in sysfs
1481
 */
L
Linus Torvalds 已提交
1482

1483 1484
static ssize_t user_show(struct device *dev, struct device_attribute *attr,
			 char *buf)
L
Linus Torvalds 已提交
1485
{
1486
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1487

1488
	IUCV_DBF_TEXT(trace, 5, __func__);
1489
	return sprintf(buf, "%s\n", netiucv_printuser(priv->conn));
L
Linus Torvalds 已提交
1490 1491
}

1492 1493
static int netiucv_check_user(const char *buf, size_t count, char *username,
			      char *userdata)
L
Linus Torvalds 已提交
1494
{
1495 1496
	const char *p;
	int i;
L
Linus Torvalds 已提交
1497

1498 1499 1500 1501 1502 1503
	p = strchr(buf, '.');
	if ((p && ((count > 26) ||
		   ((p - buf) > 8) ||
		   (buf + count - p > 18))) ||
	    (!p && (count > 9))) {
		IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n");
L
Linus Torvalds 已提交
1504 1505 1506
		return -EINVAL;
	}

1507 1508 1509
	for (i = 0, p = buf; i < 8 && *p && *p != '.'; i++, p++) {
		if (isalnum(*p) || *p == '$') {
			username[i] = toupper(*p);
1510 1511
			continue;
		}
1512
		if (*p == '\n')
L
Linus Torvalds 已提交
1513 1514
			/* trailing lf, grr */
			break;
1515
		IUCV_DBF_TEXT_(setup, 2,
1516
			       "conn_write: invalid character %02x\n", *p);
1517
		return -EINVAL;
L
Linus Torvalds 已提交
1518
	}
1519
	while (i < 8)
L
Linus Torvalds 已提交
1520
		username[i++] = ' ';
1521
	username[8] = '\0';
L
Linus Torvalds 已提交
1522

1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554
	if (*p == '.') {
		p++;
		for (i = 0; i < 16 && *p; i++, p++) {
			if (*p == '\n')
				break;
			userdata[i] = toupper(*p);
		}
		while (i > 0 && i < 16)
			userdata[i++] = ' ';
	} else
		memcpy(userdata, iucvMagic_ascii, 16);
	userdata[16] = '\0';
	ASCEBC(userdata, 16);

	return 0;
}

static ssize_t user_write(struct device *dev, struct device_attribute *attr,
			  const char *buf, size_t count)
{
	struct netiucv_priv *priv = dev_get_drvdata(dev);
	struct net_device *ndev = priv->conn->netdev;
	char	username[9];
	char	userdata[17];
	int	rc;
	struct iucv_connection *cp;

	IUCV_DBF_TEXT(trace, 3, __func__);
	rc = netiucv_check_user(buf, count, username, userdata);
	if (rc)
		return rc;

1555 1556 1557 1558
	if (memcmp(username, priv->conn->userid, 9) &&
	    (ndev->flags & (IFF_UP | IFF_RUNNING))) {
		/* username changed while the interface is active. */
		IUCV_DBF_TEXT(setup, 2, "user_write: device active\n");
1559
		return -EPERM;
1560 1561 1562
	}
	read_lock_bh(&iucv_connection_rwlock);
	list_for_each_entry(cp, &iucv_connection_list, list) {
1563 1564
		if (!strncmp(username, cp->userid, 9) &&
		   !strncmp(userdata, cp->userdata, 17) && cp->netdev != ndev) {
1565
			read_unlock_bh(&iucv_connection_rwlock);
1566 1567
			IUCV_DBF_TEXT_(setup, 2, "user_write: Connection to %s "
				"already exists\n", netiucv_printuser(cp));
1568
			return -EEXIST;
L
Linus Torvalds 已提交
1569 1570
		}
	}
1571
	read_unlock_bh(&iucv_connection_rwlock);
L
Linus Torvalds 已提交
1572
	memcpy(priv->conn->userid, username, 9);
1573
	memcpy(priv->conn->userdata, userdata, 17);
L
Linus Torvalds 已提交
1574 1575 1576 1577 1578
	return count;
}

static DEVICE_ATTR(user, 0644, user_show, user_write);

1579 1580
static ssize_t buffer_show (struct device *dev, struct device_attribute *attr,
			    char *buf)
1581 1582
{
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1583

1584
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1585 1586 1587
	return sprintf(buf, "%d\n", priv->conn->max_buffsize);
}

1588 1589
static ssize_t buffer_write (struct device *dev, struct device_attribute *attr,
			     const char *buf, size_t count)
L
Linus Torvalds 已提交
1590
{
1591
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1592 1593 1594 1595
	struct net_device *ndev = priv->conn->netdev;
	char         *e;
	int          bs1;

1596
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
1597 1598 1599 1600 1601 1602
	if (count >= 39)
		return -EINVAL;

	bs1 = simple_strtoul(buf, &e, 0);

	if (e && (!isspace(*e))) {
1603 1604
		IUCV_DBF_TEXT_(setup, 2, "buffer_write: invalid char %02x\n",
			*e);
L
Linus Torvalds 已提交
1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636
		return -EINVAL;
	}
	if (bs1 > NETIUCV_BUFSIZE_MAX) {
		IUCV_DBF_TEXT_(setup, 2,
			"buffer_write: buffer size %d too large\n",
			bs1);
		return -EINVAL;
	}
	if ((ndev->flags & IFF_RUNNING) &&
	    (bs1 < (ndev->mtu + NETIUCV_HDRLEN + 2))) {
		IUCV_DBF_TEXT_(setup, 2,
			"buffer_write: buffer size %d too small\n",
			bs1);
		return -EINVAL;
	}
	if (bs1 < (576 + NETIUCV_HDRLEN + NETIUCV_HDRLEN)) {
		IUCV_DBF_TEXT_(setup, 2,
			"buffer_write: buffer size %d too small\n",
			bs1);
		return -EINVAL;
	}

	priv->conn->max_buffsize = bs1;
	if (!(ndev->flags & IFF_RUNNING))
		ndev->mtu = bs1 - NETIUCV_HDRLEN - NETIUCV_HDRLEN;

	return count;

}

static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write);

1637 1638
static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr,
			     char *buf)
L
Linus Torvalds 已提交
1639
{
1640
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1641

1642
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1643 1644 1645 1646 1647
	return sprintf(buf, "%s\n", fsm_getstate_str(priv->fsm));
}

static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL);

1648 1649
static ssize_t conn_fsm_show (struct device *dev,
			      struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
1650
{
1651
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1652

1653
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1654 1655 1656 1657 1658
	return sprintf(buf, "%s\n", fsm_getstate_str(priv->conn->fsm));
}

static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL);

1659 1660
static ssize_t maxmulti_show (struct device *dev,
			      struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
1661
{
1662
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1663

1664
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1665 1666 1667
	return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti);
}

1668 1669 1670
static ssize_t maxmulti_write (struct device *dev,
			       struct device_attribute *attr,
			       const char *buf, size_t count)
L
Linus Torvalds 已提交
1671
{
1672
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1673

1674
	IUCV_DBF_TEXT(trace, 4, __func__);
L
Linus Torvalds 已提交
1675 1676 1677 1678 1679 1680
	priv->conn->prof.maxmulti = 0;
	return count;
}

static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write);

1681 1682
static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr,
			   char *buf)
L
Linus Torvalds 已提交
1683
{
1684
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1685

1686
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1687 1688 1689
	return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue);
}

1690 1691
static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr,
			    const char *buf, size_t count)
L
Linus Torvalds 已提交
1692
{
1693
	struct netiucv_priv *priv = dev_get_drvdata(dev);
1694

1695
	IUCV_DBF_TEXT(trace, 4, __func__);
L
Linus Torvalds 已提交
1696 1697 1698 1699 1700 1701
	priv->conn->prof.maxcqueue = 0;
	return count;
}

static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write);

1702 1703
static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr,
			   char *buf)
L
Linus Torvalds 已提交
1704
{
1705
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1706

1707
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1708 1709 1710
	return sprintf(buf, "%ld\n", priv->conn->prof.doios_single);
}

1711 1712
static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr,
			    const char *buf, size_t count)
L
Linus Torvalds 已提交
1713
{
1714
	struct netiucv_priv *priv = dev_get_drvdata(dev);
1715

1716
	IUCV_DBF_TEXT(trace, 4, __func__);
L
Linus Torvalds 已提交
1717 1718 1719 1720 1721 1722
	priv->conn->prof.doios_single = 0;
	return count;
}

static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write);

1723 1724
static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr,
			   char *buf)
L
Linus Torvalds 已提交
1725
{
1726
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1727

1728
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1729 1730 1731
	return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi);
}

1732 1733
static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr,
			    const char *buf, size_t count)
L
Linus Torvalds 已提交
1734
{
1735
	struct netiucv_priv *priv = dev_get_drvdata(dev);
1736

1737
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1738 1739 1740 1741 1742 1743
	priv->conn->prof.doios_multi = 0;
	return count;
}

static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write);

1744 1745
static ssize_t txlen_show (struct device *dev, struct device_attribute *attr,
			   char *buf)
L
Linus Torvalds 已提交
1746
{
1747
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1748

1749
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1750 1751 1752
	return sprintf(buf, "%ld\n", priv->conn->prof.txlen);
}

1753 1754
static ssize_t txlen_write (struct device *dev, struct device_attribute *attr,
			    const char *buf, size_t count)
L
Linus Torvalds 已提交
1755
{
1756
	struct netiucv_priv *priv = dev_get_drvdata(dev);
1757

1758
	IUCV_DBF_TEXT(trace, 4, __func__);
L
Linus Torvalds 已提交
1759 1760 1761 1762 1763 1764
	priv->conn->prof.txlen = 0;
	return count;
}

static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write);

1765 1766
static ssize_t txtime_show (struct device *dev, struct device_attribute *attr,
			    char *buf)
L
Linus Torvalds 已提交
1767
{
1768
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1769

1770
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1771 1772 1773
	return sprintf(buf, "%ld\n", priv->conn->prof.tx_time);
}

1774 1775
static ssize_t txtime_write (struct device *dev, struct device_attribute *attr,
			     const char *buf, size_t count)
L
Linus Torvalds 已提交
1776
{
1777
	struct netiucv_priv *priv = dev_get_drvdata(dev);
1778

1779
	IUCV_DBF_TEXT(trace, 4, __func__);
L
Linus Torvalds 已提交
1780 1781 1782 1783 1784 1785
	priv->conn->prof.tx_time = 0;
	return count;
}

static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write);

1786 1787
static ssize_t txpend_show (struct device *dev, struct device_attribute *attr,
			    char *buf)
L
Linus Torvalds 已提交
1788
{
1789
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1790

1791
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1792 1793 1794
	return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending);
}

1795 1796
static ssize_t txpend_write (struct device *dev, struct device_attribute *attr,
			     const char *buf, size_t count)
L
Linus Torvalds 已提交
1797
{
1798
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1799

1800
	IUCV_DBF_TEXT(trace, 4, __func__);
L
Linus Torvalds 已提交
1801 1802 1803 1804 1805 1806
	priv->conn->prof.tx_pending = 0;
	return count;
}

static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write);

1807 1808
static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr,
			    char *buf)
L
Linus Torvalds 已提交
1809
{
1810
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1811

1812
	IUCV_DBF_TEXT(trace, 5, __func__);
L
Linus Torvalds 已提交
1813 1814 1815
	return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending);
}

1816 1817
static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr,
			     const char *buf, size_t count)
L
Linus Torvalds 已提交
1818
{
1819
	struct netiucv_priv *priv = dev_get_drvdata(dev);
L
Linus Torvalds 已提交
1820

1821
	IUCV_DBF_TEXT(trace, 4, __func__);
L
Linus Torvalds 已提交
1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856
	priv->conn->prof.tx_max_pending = 0;
	return count;
}

static DEVICE_ATTR(tx_max_pending, 0644, txmpnd_show, txmpnd_write);

static struct attribute *netiucv_attrs[] = {
	&dev_attr_buffer.attr,
	&dev_attr_user.attr,
	NULL,
};

static struct attribute_group netiucv_attr_group = {
	.attrs = netiucv_attrs,
};

static struct attribute *netiucv_stat_attrs[] = {
	&dev_attr_device_fsm_state.attr,
	&dev_attr_connection_fsm_state.attr,
	&dev_attr_max_tx_buffer_used.attr,
	&dev_attr_max_chained_skbs.attr,
	&dev_attr_tx_single_write_ops.attr,
	&dev_attr_tx_multi_write_ops.attr,
	&dev_attr_netto_bytes.attr,
	&dev_attr_max_tx_io_time.attr,
	&dev_attr_tx_pending.attr,
	&dev_attr_tx_max_pending.attr,
	NULL,
};

static struct attribute_group netiucv_stat_attr_group = {
	.name  = "stats",
	.attrs = netiucv_stat_attrs,
};

1857 1858 1859 1860 1861
static const struct attribute_group *netiucv_attr_groups[] = {
	&netiucv_stat_attr_group,
	&netiucv_attr_group,
	NULL,
};
L
Linus Torvalds 已提交
1862

1863
static int netiucv_register_device(struct net_device *ndev)
L
Linus Torvalds 已提交
1864
{
1865
	struct netiucv_priv *priv = netdev_priv(ndev);
1866
	struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL);
L
Linus Torvalds 已提交
1867 1868
	int ret;

1869
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
1870 1871

	if (dev) {
1872
		dev_set_name(dev, "net%s", ndev->name);
L
Linus Torvalds 已提交
1873 1874
		dev->bus = &iucv_bus;
		dev->parent = iucv_root;
1875
		dev->groups = netiucv_attr_groups;
L
Linus Torvalds 已提交
1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888
		/*
		 * The release function could be called after the
		 * module has been unloaded. It's _only_ task is to
		 * free the struct. Therefore, we specify kfree()
		 * directly here. (Probably a little bit obfuscating
		 * but legitime ...).
		 */
		dev->release = (void (*)(struct device *))kfree;
		dev->driver = &netiucv_driver;
	} else
		return -ENOMEM;

	ret = device_register(dev);
1889 1890
	if (ret) {
		put_device(dev);
L
Linus Torvalds 已提交
1891
		return ret;
1892
	}
L
Linus Torvalds 已提交
1893
	priv->dev = dev;
1894
	dev_set_drvdata(dev, priv);
L
Linus Torvalds 已提交
1895 1896 1897
	return 0;
}

1898
static void netiucv_unregister_device(struct device *dev)
L
Linus Torvalds 已提交
1899
{
1900
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
1901 1902 1903 1904 1905 1906 1907
	device_unregister(dev);
}

/**
 * Allocate and initialize a new connection structure.
 * Add it to the list of netiucv connections;
 */
1908
static struct iucv_connection *netiucv_new_connection(struct net_device *dev,
1909 1910
						      char *username,
						      char *userdata)
1911 1912
{
	struct iucv_connection *conn;
L
Linus Torvalds 已提交
1913

1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938
	conn = kzalloc(sizeof(*conn), GFP_KERNEL);
	if (!conn)
		goto out;
	skb_queue_head_init(&conn->collect_queue);
	skb_queue_head_init(&conn->commit_queue);
	spin_lock_init(&conn->collect_lock);
	conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
	conn->netdev = dev;

	conn->rx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA);
	if (!conn->rx_buff)
		goto out_conn;
	conn->tx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA);
	if (!conn->tx_buff)
		goto out_rx;
	conn->fsm = init_fsm("netiucvconn", conn_state_names,
			     conn_event_names, NR_CONN_STATES,
			     NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN,
			     GFP_KERNEL);
	if (!conn->fsm)
		goto out_tx;

	fsm_settimer(conn->fsm, &conn->timer);
	fsm_newstate(conn->fsm, CONN_STATE_INVALID);

1939 1940
	if (userdata)
		memcpy(conn->userdata, userdata, 17);
1941 1942 1943
	if (username) {
		memcpy(conn->userid, username, 9);
		fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
L
Linus Torvalds 已提交
1944
	}
1945 1946 1947 1948

	write_lock_bh(&iucv_connection_rwlock);
	list_add_tail(&conn->list, &iucv_connection_list);
	write_unlock_bh(&iucv_connection_rwlock);
L
Linus Torvalds 已提交
1949
	return conn;
1950 1951 1952 1953 1954 1955 1956 1957 1958

out_tx:
	kfree_skb(conn->tx_buff);
out_rx:
	kfree_skb(conn->rx_buff);
out_conn:
	kfree(conn);
out:
	return NULL;
L
Linus Torvalds 已提交
1959 1960 1961 1962 1963 1964
}

/**
 * Release a connection structure and remove it from the
 * list of netiucv connections.
 */
1965
static void netiucv_remove_connection(struct iucv_connection *conn)
L
Linus Torvalds 已提交
1966
{
1967

1968
	IUCV_DBF_TEXT(trace, 3, __func__);
1969 1970 1971
	write_lock_bh(&iucv_connection_rwlock);
	list_del_init(&conn->list);
	write_unlock_bh(&iucv_connection_rwlock);
1972 1973
	fsm_deltimer(&conn->timer);
	netiucv_purge_skb_queue(&conn->collect_queue);
1974
	if (conn->path) {
1975
		iucv_path_sever(conn->path, conn->userdata);
1976 1977
		kfree(conn->path);
		conn->path = NULL;
L
Linus Torvalds 已提交
1978
	}
1979
	netiucv_purge_skb_queue(&conn->commit_queue);
1980 1981 1982
	kfree_fsm(conn->fsm);
	kfree_skb(conn->rx_buff);
	kfree_skb(conn->tx_buff);
L
Linus Torvalds 已提交
1983 1984 1985 1986 1987
}

/**
 * Release everything of a net device.
 */
1988
static void netiucv_free_netdevice(struct net_device *dev)
L
Linus Torvalds 已提交
1989
{
1990
	struct netiucv_priv *privptr = netdev_priv(dev);
L
Linus Torvalds 已提交
1991

1992
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010

	if (!dev)
		return;

	if (privptr) {
		if (privptr->conn)
			netiucv_remove_connection(privptr->conn);
		if (privptr->fsm)
			kfree_fsm(privptr->fsm);
		privptr->conn = NULL; privptr->fsm = NULL;
		/* privptr gets freed by free_netdev() */
	}
	free_netdev(dev);
}

/**
 * Initialize a net device. (Called from kernel in alloc_netdev())
 */
2011 2012 2013 2014 2015 2016 2017 2018
static const struct net_device_ops netiucv_netdev_ops = {
	.ndo_open		= netiucv_open,
	.ndo_stop		= netiucv_close,
	.ndo_get_stats		= netiucv_stats,
	.ndo_start_xmit		= netiucv_tx,
	.ndo_change_mtu	   	= netiucv_change_mtu,
};

2019
static void netiucv_setup_netdevice(struct net_device *dev)
L
Linus Torvalds 已提交
2020 2021 2022 2023 2024 2025 2026 2027
{
	dev->mtu	         = NETIUCV_MTU_DEFAULT;
	dev->destructor          = netiucv_free_netdevice;
	dev->hard_header_len     = NETIUCV_HDRLEN;
	dev->addr_len            = 0;
	dev->type                = ARPHRD_SLIP;
	dev->tx_queue_len        = NETIUCV_QUEUELEN_DEFAULT;
	dev->flags	         = IFF_POINTOPOINT | IFF_NOARP;
2028
	dev->netdev_ops		 = &netiucv_netdev_ops;
L
Linus Torvalds 已提交
2029 2030 2031 2032 2033
}

/**
 * Allocate and initialize everything of a net device.
 */
2034
static struct net_device *netiucv_init_netdevice(char *username, char *userdata)
L
Linus Torvalds 已提交
2035 2036 2037 2038 2039 2040 2041 2042
{
	struct netiucv_priv *privptr;
	struct net_device *dev;

	dev = alloc_netdev(sizeof(struct netiucv_priv), "iucv%d",
			   netiucv_setup_netdevice);
	if (!dev)
		return NULL;
2043 2044
	if (dev_alloc_name(dev, dev->name) < 0)
		goto out_netdev;
L
Linus Torvalds 已提交
2045

2046
	privptr = netdev_priv(dev);
L
Linus Torvalds 已提交
2047 2048 2049
	privptr->fsm = init_fsm("netiucvdev", dev_state_names,
				dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
				dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
2050 2051 2052
	if (!privptr->fsm)
		goto out_netdev;

2053
	privptr->conn = netiucv_new_connection(dev, username, userdata);
L
Linus Torvalds 已提交
2054 2055
	if (!privptr->conn) {
		IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n");
2056
		goto out_fsm;
L
Linus Torvalds 已提交
2057 2058 2059
	}
	fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
	return dev;
2060 2061 2062 2063 2064 2065

out_fsm:
	kfree_fsm(privptr->fsm);
out_netdev:
	free_netdev(dev);
	return NULL;
L
Linus Torvalds 已提交
2066 2067
}

2068 2069
static ssize_t conn_write(struct device_driver *drv,
			  const char *buf, size_t count)
L
Linus Torvalds 已提交
2070
{
2071
	char username[9];
2072 2073
	char userdata[17];
	int rc;
L
Linus Torvalds 已提交
2074
	struct net_device *dev;
2075 2076
	struct netiucv_priv *priv;
	struct iucv_connection *cp;
L
Linus Torvalds 已提交
2077

2078
	IUCV_DBF_TEXT(trace, 3, __func__);
2079 2080 2081
	rc = netiucv_check_user(buf, count, username, userdata);
	if (rc)
		return rc;
2082

2083 2084
	read_lock_bh(&iucv_connection_rwlock);
	list_for_each_entry(cp, &iucv_connection_list, list) {
2085 2086
		if (!strncmp(username, cp->userid, 9) &&
		    !strncmp(userdata, cp->userdata, 17)) {
2087
			read_unlock_bh(&iucv_connection_rwlock);
2088 2089
			IUCV_DBF_TEXT_(setup, 2, "conn_write: Connection to %s "
				"already exists\n", netiucv_printuser(cp));
2090 2091
			return -EEXIST;
		}
2092
	}
2093 2094
	read_unlock_bh(&iucv_connection_rwlock);

2095
	dev = netiucv_init_netdevice(username, userdata);
L
Linus Torvalds 已提交
2096 2097 2098 2099 2100
	if (!dev) {
		IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n");
		return -ENODEV;
	}

2101 2102
	rc = netiucv_register_device(dev);
	if (rc) {
L
Linus Torvalds 已提交
2103
		IUCV_DBF_TEXT_(setup, 2,
2104
			"ret %d from netiucv_register_device\n", rc);
L
Linus Torvalds 已提交
2105 2106 2107 2108
		goto out_free_ndev;
	}

	/* sysfs magic */
2109 2110
	priv = netdev_priv(dev);
	SET_NETDEV_DEV(dev, priv->dev);
L
Linus Torvalds 已提交
2111

2112 2113 2114
	rc = register_netdev(dev);
	if (rc)
		goto out_unreg;
L
Linus Torvalds 已提交
2115

2116 2117 2118
	dev_info(priv->dev, "The IUCV interface to %s has been established "
			    "successfully\n",
		netiucv_printuser(priv->conn));
2119

L
Linus Torvalds 已提交
2120 2121
	return count;

2122 2123
out_unreg:
	netiucv_unregister_device(priv->dev);
L
Linus Torvalds 已提交
2124 2125
out_free_ndev:
	netiucv_free_netdevice(dev);
2126
	return rc;
L
Linus Torvalds 已提交
2127 2128
}

2129
static DRIVER_ATTR(connection, 0200, NULL, conn_write);
L
Linus Torvalds 已提交
2130

2131 2132
static ssize_t remove_write (struct device_driver *drv,
			     const char *buf, size_t count)
L
Linus Torvalds 已提交
2133
{
2134
	struct iucv_connection *cp;
L
Linus Torvalds 已提交
2135 2136 2137 2138
        struct net_device *ndev;
        struct netiucv_priv *priv;
        struct device *dev;
        char name[IFNAMSIZ];
2139
	const char *p;
L
Linus Torvalds 已提交
2140 2141
        int i;

2142
	IUCV_DBF_TEXT(trace, 3, __func__);
L
Linus Torvalds 已提交
2143 2144

        if (count >= IFNAMSIZ)
2145
                count = IFNAMSIZ - 1;
L
Linus Torvalds 已提交
2146

2147 2148
	for (i = 0, p = buf; i < count && *p; i++, p++) {
		if (*p == '\n' || *p == ' ')
L
Linus Torvalds 已提交
2149 2150
                        /* trailing lf, grr */
                        break;
2151
		name[i] = *p;
L
Linus Torvalds 已提交
2152 2153 2154
        }
        name[i] = '\0';

2155 2156 2157 2158
	read_lock_bh(&iucv_connection_rwlock);
	list_for_each_entry(cp, &iucv_connection_list, list) {
		ndev = cp->netdev;
		priv = netdev_priv(ndev);
L
Linus Torvalds 已提交
2159
                dev = priv->dev;
2160 2161 2162
		if (strncmp(name, ndev->name, count))
			continue;
		read_unlock_bh(&iucv_connection_rwlock);
L
Linus Torvalds 已提交
2163
                if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
2164 2165 2166
			dev_warn(dev, "The IUCV device is connected"
				" to %s and cannot be removed\n",
				priv->conn->userid);
L
Linus Torvalds 已提交
2167
			IUCV_DBF_TEXT(data, 2, "remove_write: still active\n");
2168
			return -EPERM;
L
Linus Torvalds 已提交
2169 2170 2171 2172 2173
                }
                unregister_netdev(ndev);
                netiucv_unregister_device(dev);
                return count;
        }
2174
	read_unlock_bh(&iucv_connection_rwlock);
L
Linus Torvalds 已提交
2175 2176 2177 2178
	IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
        return -EINVAL;
}

2179
static DRIVER_ATTR(remove, 0200, NULL, remove_write);
L
Linus Torvalds 已提交
2180

2181 2182 2183 2184 2185 2186 2187 2188 2189 2190
static struct attribute * netiucv_drv_attrs[] = {
	&driver_attr_connection.attr,
	&driver_attr_remove.attr,
	NULL,
};

static struct attribute_group netiucv_drv_attr_group = {
	.attrs = netiucv_drv_attrs,
};

2191
static const struct attribute_group *netiucv_drv_attr_groups[] = {
2192 2193 2194 2195
	&netiucv_drv_attr_group,
	NULL,
};

2196
static void netiucv_banner(void)
L
Linus Torvalds 已提交
2197
{
2198
	pr_info("driver initialized\n");
L
Linus Torvalds 已提交
2199 2200
}

2201
static void __exit netiucv_exit(void)
L
Linus Torvalds 已提交
2202
{
2203 2204 2205 2206 2207
	struct iucv_connection *cp;
	struct net_device *ndev;
	struct netiucv_priv *priv;
	struct device *dev;

2208
	IUCV_DBF_TEXT(trace, 3, __func__);
2209 2210 2211 2212 2213 2214
	while (!list_empty(&iucv_connection_list)) {
		cp = list_entry(iucv_connection_list.next,
				struct iucv_connection, list);
		ndev = cp->netdev;
		priv = netdev_priv(ndev);
		dev = priv->dev;
L
Linus Torvalds 已提交
2215 2216 2217 2218 2219

		unregister_netdev(ndev);
		netiucv_unregister_device(dev);
	}

2220
	device_unregister(netiucv_dev);
L
Linus Torvalds 已提交
2221
	driver_unregister(&netiucv_driver);
2222
	iucv_unregister(&netiucv_handler, 1);
L
Linus Torvalds 已提交
2223 2224
	iucv_unregister_dbf_views();

2225
	pr_info("driver unloaded\n");
L
Linus Torvalds 已提交
2226 2227 2228
	return;
}

2229
static int __init netiucv_init(void)
L
Linus Torvalds 已提交
2230
{
2231
	int rc;
2232

2233 2234 2235 2236 2237 2238
	rc = iucv_register_dbf_views();
	if (rc)
		goto out;
	rc = iucv_register(&netiucv_handler, 1);
	if (rc)
		goto out_dbf;
2239
	IUCV_DBF_TEXT(trace, 3, __func__);
2240
	netiucv_driver.groups = netiucv_drv_attr_groups;
2241 2242 2243 2244
	rc = driver_register(&netiucv_driver);
	if (rc) {
		IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc);
		goto out_iucv;
L
Linus Torvalds 已提交
2245
	}
2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257
	/* establish dummy device */
	netiucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
	if (!netiucv_dev) {
		rc = -ENOMEM;
		goto out_driver;
	}
	dev_set_name(netiucv_dev, "netiucv");
	netiucv_dev->bus = &iucv_bus;
	netiucv_dev->parent = iucv_root;
	netiucv_dev->release = (void (*)(struct device *))kfree;
	netiucv_dev->driver = &netiucv_driver;
	rc = device_register(netiucv_dev);
2258 2259
	if (rc) {
		put_device(netiucv_dev);
2260
		goto out_driver;
2261
	}
2262 2263 2264
	netiucv_banner();
	return rc;

2265 2266
out_driver:
	driver_unregister(&netiucv_driver);
2267 2268 2269 2270 2271 2272
out_iucv:
	iucv_unregister(&netiucv_handler, 1);
out_dbf:
	iucv_unregister_dbf_views();
out:
	return rc;
L
Linus Torvalds 已提交
2273
}
2274

L
Linus Torvalds 已提交
2275 2276 2277
module_init(netiucv_init);
module_exit(netiucv_exit);
MODULE_LICENSE("GPL");