Commit fa7bb531 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: rewritten qeth driver

From: Martin Schwidefsky <schwidefsky@de.ibm.com>

The rewritten qeth network driver.
parent a1171283
......@@ -63,7 +63,7 @@ config QETH
<http://www10.software.ibm.com/developerworks/opensource/linux390>
To compile this driver as a module, choose M here: the
module will be called qeth.
module will be called qeth.ko.
comment "Gigabit Ethernet default settings"
......
......@@ -9,6 +9,6 @@ obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
obj-$(CONFIG_LCS) += lcs.o cu3088.o
qeth_mod-objs := qeth.o qeth_mpc.o
obj-$(CONFIG_QETH) += qeth_mod.o
qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o
qeth-$(CONFIG_PROC_FS) += qeth_proc.o
obj-$(CONFIG_QETH) += qeth.o
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* linux/drivers/s390/net/qeth.h
*
* Linux on zSeries OSA Express and HiperSockets support
*
* Copyright 2000,2003 IBM Corporation
* Author(s): Utz Bacher <utz.bacher@de.ibm.com>
*
*/
#ifndef __QETH_H__
#define __QETH_H__
#include <asm/qdio.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/if_tr.h>
#include <linux/trdevice.h>
#include <linux/etherdevice.h>
#include <linux/if_vlan.h>
#include <net/ipv6.h>
#include <linux/in6.h>
#include <net/if_inet6.h>
#include <net/addrconf.h>
#define QETH_NAME " qeth"
#define VERSION_QETH_H "$Revision: 1.60 $"
#include <asm/bitops.h>
#include <asm/debug.h>
#include <asm/qdio.h>
#include <asm/ccwdev.h>
#include <asm/ccwgroup.h>
#include "qeth_mpc.h"
/******************** CONFIG STUFF ***********************/
//#define QETH_DBF_LIKE_HELL
#define VERSION_QETH_H "$Revision: 1.98 $"
#ifdef CONFIG_QETH_IPV6
#define QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6"
#else
#define QETH_VERSION_IPV6 ""
#endif /* CONFIG_QETH_IPV6 */
#endif
#ifdef CONFIG_QETH_VLAN
#define QETH_VLAN
#define QETH_VERSION_VLAN ":VLAN"
#else
#define QETH_VERSION_VLAN ""
#endif /* CONFIG_QETH_VLAN */
/* these values match CHECKSUM_* in include/linux/skbuff.h */
#define SW_CHECKSUMMING 0
#define HW_CHECKSUMMING 1
#define NO_CHECKSUMMING 2
#define QETH_CHECKSUM_DEFAULT NO_CHECKSUMMING
#define QETH_PRIOQ_DEFAULT NO_PRIO_QUEUEING
#define QETH_DEFAULT_QUEUE 2
/******************** CONFIG STUFF END ***********************/
/********************* TUNING STUFF **************************/
#define HIGH_WATERMARK_PACK 5
#define LOW_WATERMARK_PACK 2
#define WATERMARK_FUZZ 2
#define QETH_MAX_INPUT_THRESHOLD 500
#define QETH_MAX_OUTPUT_THRESHOLD 300 /* ? */
/* only the MAX values are used */
#define QETH_MIN_INPUT_THRESHOLD 1
#define QETH_MIN_OUTPUT_THRESHOLD 1
#define QETH_REQUEUE_THRESHOLD (card->options.inbound_buffer_count/4)
#ifdef CONFIG_QETH_PERF_STATS
#define QETH_PERFORMANCE_STATS
#endif /* CONFIG_QETH_PERF_STATS */
#ifdef QETH_DBF_LIKE_HELL
#define QETH_VERBOSE_LEVEL 8
#else /* QETH_DBF_LIKE_HELL */
#define QETH_VERBOSE_LEVEL 5
#endif /* QETH_DBF_LIKE_HELL */
#define PCI_THRESHOLD_A (card->options.inbound_buffer_count+1)
/* buffers we have to be behind before we get a PCI */
#define PCI_THRESHOLD_B 0 /* enqueued free buffers left before we get a PCI */
#define PCI_TIMER_VALUE 3 /* not used, unless the microcode gets patched */
#define DEFAULT_SPARE_BUFFERS 0
#define MAX_SPARE_BUFFERS 1024
#define SPAREBUF_MASK 65536
#define MAX_PORTNO 15
#define QETH_PROCFILE_NAME "qeth"
#define QETH_PERF_PROCFILE_NAME "qeth_perf"
#define QETH_IPA_PROCFILE_NAME "qeth_ipa_takeover"
#define SEND_RETRIES_ALLOWED 5
#define QETH_ROUTING_ATTEMPTS 2
#define QETH_HARDSETUP_LAPS 5
#define QETH_HARDSETUP_CLEAR_LAPS 3
#define QETH_RECOVERY_HARDSETUP_RETRY 2
/************************* DEBUG FACILITY STUFF *********************/
#define QETH_DBF_HEX(ex,name,level,addr,len) \
do { \
if (ex) \
debug_exception(qeth_dbf_##name,level,(void*)addr,len); \
else \
debug_event(qeth_dbf_##name,level,(void*)addr,len); \
} while (0)
#define QETH_DBF_TEXT(ex,name,level,text) \
do { \
if (ex) \
debug_text_exception(qeth_dbf_##name,level,text); \
else \
debug_text_event(qeth_dbf_##name,level,text); \
} while (0)
#define QETH_DBF_CARD(ex,name,level,text,card) \
do { \
QETH_DBF_TEXT(ex,name,level,text); \
QETH_DBF_TEXT(ex,name,level,card->gdev->dev.bus_id); \
} while (0)
#define QETH_DBF_HEX0(ex,name,addr,len) QETH_DBF_HEX(ex,name,0,addr,len)
#define QETH_DBF_HEX1(ex,name,addr,len) QETH_DBF_HEX(ex,name,1,addr,len)
#define QETH_DBF_HEX2(ex,name,addr,len) QETH_DBF_HEX(ex,name,2,addr,len)
#ifdef QETH_DBF_LIKE_HELL
#define QETH_DBF_HEX3(ex,name,addr,len) QETH_DBF_HEX(ex,name,3,addr,len)
#define QETH_DBF_HEX4(ex,name,addr,len) QETH_DBF_HEX(ex,name,4,addr,len)
#define QETH_DBF_HEX5(ex,name,addr,len) QETH_DBF_HEX(ex,name,5,addr,len)
#define QETH_DBF_HEX6(ex,name,addr,len) QETH_DBF_HEX(ex,name,6,addr,len)
#else /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_HEX3(ex,name,addr,len) do {} while (0)
#define QETH_DBF_HEX4(ex,name,addr,len) do {} while (0)
#define QETH_DBF_HEX5(ex,name,addr,len) do {} while (0)
#define QETH_DBF_HEX6(ex,name,addr,len) do {} while (0)
#endif /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_TEXT0(ex,name,text) QETH_DBF_TEXT(ex,name,0,text)
#define QETH_DBF_TEXT1(ex,name,text) QETH_DBF_TEXT(ex,name,1,text)
#define QETH_DBF_TEXT2(ex,name,text) QETH_DBF_TEXT(ex,name,2,text)
#ifdef QETH_DBF_LIKE_HELL
#define QETH_DBF_TEXT3(ex,name,text) QETH_DBF_TEXT(ex,name,3,text)
#define QETH_DBF_TEXT4(ex,name,text) QETH_DBF_TEXT(ex,name,4,text)
#define QETH_DBF_TEXT5(ex,name,text) QETH_DBF_TEXT(ex,name,5,text)
#define QETH_DBF_TEXT6(ex,name,text) QETH_DBF_TEXT(ex,name,6,text)
#else /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_TEXT3(ex,name,text) do {} while (0)
#define QETH_DBF_TEXT4(ex,name,text) do {} while (0)
#define QETH_DBF_TEXT5(ex,name,text) do {} while (0)
#define QETH_DBF_TEXT6(ex,name,text) do {} while (0)
#endif /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_CARD0(ex,name,text,card) QETH_DBF_CARD(ex,name,0,text,card)
#define QETH_DBF_CARD1(ex,name,text,card) QETH_DBF_CARD(ex,name,1,text,card)
#define QETH_DBF_CARD2(ex,name,text,card) QETH_DBF_CARD(ex,name,2,text,card)
#ifdef QETH_DBF_LIKE_HELL
#define QETH_DBF_CARD3(ex,name,text,card) QETH_DBF_CARD(ex,name,3,text,card)
#define QETH_DBF_CARD4(ex,name,text,card) QETH_DBF_CARD(ex,name,4,text,card)
#define QETH_DBF_CARD5(ex,name,text,card) QETH_DBF_CARD(ex,name,5,text,card)
#define QETH_DBF_CARD6(ex,name,text,card) QETH_DBF_CARD(ex,name,6,text,card)
#else /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_CARD3(ex,name,text,card) do {} while (0)
#define QETH_DBF_CARD4(ex,name,text,card) do {} while (0)
#define QETH_DBF_CARD5(ex,name,text,card) do {} while (0)
#define QETH_DBF_CARD6(ex,name,text,card) do {} while (0)
#endif /* QETH_DBF_LIKE_HELL */
#endif
/**
* Debug Facility stuff
*/
#define QETH_DBF_SETUP_NAME "qeth_setup"
#define QETH_DBF_SETUP_LEN 8
#define QETH_DBF_SETUP_INDEX 3
#define QETH_DBF_SETUP_NR_AREAS 1
#ifdef QETH_DBF_LIKE_HELL
#define QETH_DBF_SETUP_LEVEL 6
#else /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_SETUP_LEVEL 3
#endif /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_MISC_NAME "qeth_misc"
#define QETH_DBF_MISC_LEN 128
#define QETH_DBF_MISC_INDEX 1
#define QETH_DBF_MISC_NR_AREAS 1
#ifdef QETH_DBF_LIKE_HELL
#define QETH_DBF_MISC_LEVEL 6
#else /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_MISC_LEVEL 2
#endif /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_DATA_NAME "qeth_data"
#define QETH_DBF_DATA_LEN 96
#define QETH_DBF_DATA_INDEX 3
#define QETH_DBF_DATA_NR_AREAS 1
#ifdef QETH_DBF_LIKE_HELL
#define QETH_DBF_DATA_LEVEL 6
#else /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_DATA_LEVEL 2
#endif /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_CONTROL_NAME "qeth_control"
/* buffers are 255 bytes long, but no prob */
#define QETH_DBF_CONTROL_LEN 256
#define QETH_DBF_CONTROL_INDEX 3
#define QETH_DBF_CONTROL_NR_AREAS 2
#ifdef QETH_DBF_LIKE_HELL
#define QETH_DBF_CONTROL_LEVEL 6
#else /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_CONTROL_LEVEL 2
#endif /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_TRACE_NAME "qeth_trace"
#define QETH_DBF_TRACE_LEN 8
#ifdef QETH_DBF_LIKE_HELL
#define QETH_DBF_TRACE_INDEX 3
#else /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_TRACE_INDEX 2
#endif /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_TRACE_NR_AREAS 2
#ifdef QETH_DBF_LIKE_HELL
#define QETH_DBF_TRACE_LEVEL 6
#else /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_TRACE_LEVEL 2
#endif /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_TRACE_LEVEL 3
#define QETH_DBF_SENSE_NAME "qeth_sense"
#define QETH_DBF_SENSE_LEN 64
#define QETH_DBF_SENSE_INDEX 1
#define QETH_DBF_SENSE_NR_AREAS 1
#ifdef QETH_DBF_LIKE_HELL
#define QETH_DBF_SENSE_LEVEL 6
#else /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_SENSE_LEVEL 2
#endif /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_QERR_NAME "qeth_qerr"
#define QETH_DBF_QERR_LEN 8
#define QETH_DBF_QERR_INDEX 1
#define QETH_DBF_QERR_NR_AREAS 2
#ifdef QETH_DBF_LIKE_HELL
#define QETH_DBF_QERR_LEVEL 6
#else /* QETH_DBF_LIKE_HELL */
#define QETH_DBF_QERR_LEVEL 2
#endif /* QETH_DBF_LIKE_HELL */
/****************** END OF DEBUG FACILITY STUFF *********************/
/********************* CARD DATA STUFF **************************/
#define QETH_MAX_PARAMS 150
#define QETH_CARD_TYPE_UNKNOWN 0
#define QETH_CARD_TYPE_OSAE 10
#define QETH_CARD_TYPE_IQD 1234
#define QETH_DBF_TEXT(name,level,text) \
do { \
debug_text_event(qeth_dbf_##name,level,text); \
} while (0)
#define QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT 0x0101
#define QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT 0x0101
#define QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT 0x4108
#define QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT 0x5108
#define QETH_DBF_HEX(name,level,addr,len) \
do { \
debug_event(qeth_dbf_##name,level,(void*)(addr),len); \
} while (0)
#define QETH_MAX_QUEUES 4
#define QETH_DBF_TEXT_(name,level,text...) \
do { \
sprintf(qeth_dbf_text_buf, text); \
debug_text_event(qeth_dbf_##name,level,qeth_dbf_text_buf);\
} while (0)
#define UNIQUE_ID_IF_CREATE_ADDR_FAILED 0xfffe
#define UNIQUE_ID_NOT_BY_CARD 0x10000
#define QETH_DBF_SPRINTF(name,level,text...) \
do { \
debug_sprintf_event(qeth_dbf_trace, level, ##text ); \
debug_sprintf_event(qeth_dbf_trace, level, text ); \
} while (0)
/*
* CU type & model, Dev type & model, card_type, odd_even_restriction,
* func level, no of queues, multicast is different (multicast-queue_no + 0x100)
/**
* some more debug stuff
*/
#define QETH_MODELLIST_ARRAY \
{{0x1731,0x01,0x1732,0x01,QETH_CARD_TYPE_OSAE,1, \
QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT, \
QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT, \
QETH_MAX_QUEUES,0}, \
{0x1731,0x05,0x1732,0x05,QETH_CARD_TYPE_IQD,0, \
QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT, \
QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT, \
QETH_MAX_QUEUES,0x103}, \
{0,0,0,0,0,0,0,0,0}}
#define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18
/* only the first two bytes are looked at in qeth_get_cardname_short */
#define QETH_MPC_LINK_TYPE_FAST_ETHERNET 0x01
#define QETH_MPC_LINK_TYPE_HSTR 0x02
#define QETH_MPC_LINK_TYPE_GIGABIT_ETHERNET 0x03
#define QETH_MPC_LINK_TYPE_10GIGABIT_ETHERNET 0x10
#define QETH_MPC_LINK_TYPE_LANE_ETH100 0x81
#define QETH_MPC_LINK_TYPE_LANE_TR 0x82
#define QETH_MPC_LINK_TYPE_LANE_ETH1000 0x83
#define QETH_MPC_LINK_TYPE_LANE 0x88
#define QETH_MPC_LINK_TYPE_ATM_NATIVE 0x90
#define PRINTK_HEADER "qeth: "
#define DEFAULT_ADD_HHLEN 0
#define MAX_ADD_HHLEN 1024
#define QETH_HEADER_SIZE 32
#define QETH_IP_HEADER_SIZE 40
#define QETH_HEADER_LEN_POS 8
/* flags for the header: */
#define QETH_HEADER_PASSTHRU 0x10
#define QETH_HEADER_IPV6 0x80
#define QETH_ETH_MAC_V4 0x0100 /* like v4 */
#define QETH_ETH_MAC_V6 0x3333 /* like v6 */
/* tr mc mac is longer, but that will be enough to detect mc frames */
#define QETH_TR_MAC_NC 0xc000 /* non-canonical */
#define QETH_TR_MAC_C 0x0300 /* canonical */
#define QETH_CAST_FLAGS 0x07
#define QETH_CAST_UNICAST 6
#define QETH_CAST_MULTICAST 4
#define QETH_CAST_BROADCAST 5
#define QETH_CAST_ANYCAST 7
#define QETH_CAST_NOCAST 0
/* VLAN defines */
#define QETH_EXT_HEADER_VLAN_FRAME 0x01
#define QETH_EXT_HEADER_TOKEN_ID 0x02
#define QETH_EXT_HEADER_INCLUDE_VLAN_TAG 0x04
#define QETH_EXT_HEADER_SRC_MAC_ADDRESS 0x08
#define QETH_EXT_HEADER_CSUM_HDR_REQ 0x10
#define QETH_EXT_HEADER_CSUM_TRANSP_REQ 0x20
#define QETH_EXT_HEADER_CSUM_TRANSP_FRAME_TYPE 0x40
#define QETH_UDP_CSUM_OFFSET 6
#define QETH_TCP_CSUM_OFFSET 16
#define QETH_VERIFY_IS_REAL_DEV 1
#define QETH_VERIFY_IS_VLAN_DEV 2
#define 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));
inline static unsigned int
qeth_get_ipa_timeout(int cardtype)
static inline void
qeth_hex_dump(unsigned char *buf, size_t len)
{
switch (cardtype) {
case QETH_CARD_TYPE_IQD:
return 2000;
default:
return 20000;
}
}
size_t i;
inline static unsigned short
qeth_get_additional_dev_flags(int cardtype)
{
switch (cardtype) {
case QETH_CARD_TYPE_IQD:
return IFF_NOARP;
#ifdef QETH_IPV6
default:
return 0;
#else /* QETH_IPV6 */
default:
return IFF_NOARP;
#endif /* QETH_IPV6 */
for (i = 0; i < len; i++) {
if (i && !(i % 16))
printk("\n");
printk("%02x ", *(buf + i));
}
printk("\n");
}
inline static int
qeth_get_hlen(__u8 link_type)
{
#ifdef QETH_IPV6
switch (link_type) {
case QETH_MPC_LINK_TYPE_HSTR:
case QETH_MPC_LINK_TYPE_LANE_TR:
return QETH_HEADER_SIZE + TR_HLEN;
default:
#ifdef QETH_VLAN
return QETH_HEADER_SIZE + VLAN_ETH_HLEN;
#else
return QETH_HEADER_SIZE + ETH_HLEN;
#endif
}
#else /* QETH_IPV6 */
#ifdef QETH_VLAN
return QETH_HEADER_SIZE + VLAN_HLEN;
#else
return QETH_HEADER_SIZE;
#endif
#define SENSE_COMMAND_REJECT_BYTE 0
#define SENSE_COMMAND_REJECT_FLAG 0x80
#define SENSE_RESETTING_EVENT_BYTE 1
#define SENSE_RESETTING_EVENT_FLAG 0x80
#endif /* QETH_IPV6 */
}
/*
* Common IO related definitions
*/
extern struct device *qeth_root_dev;
extern struct ccw_driver qeth_ccw_driver;
extern struct ccwgroup_driver qeth_ccwgroup_driver;
static int (*qeth_my_eth_header) (struct sk_buff *, struct net_device *,
unsigned short, void *, void *, unsigned);
#ifdef CONFIG_TR
static int (*qeth_my_tr_header) (struct sk_buff *, struct net_device *,
unsigned short, void *, void *, unsigned);
#endif /* CONFIG_TR */
static int (*qeth_my_eth_rebuild_header) (struct sk_buff *);
#ifdef CONFIG_TR
static int (*qeth_my_tr_rebuild_header) (struct sk_buff *);
#endif /* CONFIG_TR */
static int (*qeth_my_eth_header_cache) (struct neighbour *, struct hh_cache *);
static void (*qeth_my_eth_header_cache_update) (struct hh_cache *,
struct net_device *,
unsigned char *);
#ifdef QETH_IPV6
typedef int (*__qeth_temp1) (struct sk_buff *, struct net_device *,
unsigned short, void *, void *, unsigned);
inline static __qeth_temp1
qeth_get_hard_header(__u8 link_type)
{
switch (link_type) {
#ifdef CONFIG_TR
case QETH_MPC_LINK_TYPE_HSTR:
case QETH_MPC_LINK_TYPE_LANE_TR:
return qeth_my_tr_header;
#endif /* CONFIG_TR */
default:
return qeth_my_eth_header;
}
}
#define CARD_RDEV(card) card->read.ccwdev
#define CARD_WDEV(card) card->write.ccwdev
#define CARD_DDEV(card) card->data.ccwdev
#define CARD_BUS_ID(card) card->gdev->dev.bus_id
#define CARD_RDEV_ID(card) card->read.ccwdev->dev.bus_id
#define CARD_WDEV_ID(card) card->write.ccwdev->dev.bus_id
#define CARD_DDEV_ID(card) card->data.ccwdev->dev.bus_id
#define CHANNEL_ID(channel) channel->ccwdev->dev.bus_id
typedef int (*__qeth_temp2) (struct sk_buff *);
inline static __qeth_temp2
qeth_get_rebuild_header(__u8 link_type)
{
switch (link_type) {
#ifdef CONFIG_TR
case QETH_MPC_LINK_TYPE_HSTR:
case QETH_MPC_LINK_TYPE_LANE_TR:
return qeth_my_tr_rebuild_header;
#endif /* CONFIG_TR */
default:
return qeth_my_eth_rebuild_header;
}
}
#define CARD_FROM_CDEV(cdev) (struct qeth_card *) \
((struct ccwgroup_device *)cdev->dev.driver_data)\
->dev.driver_data;
typedef int (*__qeth_temp3) (struct neighbour *, struct hh_cache *);
inline static __qeth_temp3
qeth_get_hard_header_cache(__u8 link_type)
{
switch (link_type) {
case QETH_MPC_LINK_TYPE_HSTR:
case QETH_MPC_LINK_TYPE_LANE_TR:
return NULL;
default:
return qeth_my_eth_header_cache;
}
}
/**
* card stuff
*/
#ifdef CONFIG_QETH_PERF_STATS
struct qeth_perf_stats {
unsigned int bufs_rec;
unsigned int bufs_sent;
typedef void (*__qeth_temp4) (struct hh_cache *, struct net_device *,
unsigned char *);
inline static __qeth_temp4
qeth_get_header_cache_update(__u8 link_type)
{
switch (link_type) {
case QETH_MPC_LINK_TYPE_HSTR:
case QETH_MPC_LINK_TYPE_LANE_TR:
return NULL;
default:
return qeth_my_eth_header_cache_update;
}
}
unsigned int skbs_sent_pack;
unsigned int bufs_sent_pack;
static unsigned short
qeth_eth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned int sc_dp_p;
unsigned int sc_p_dp;
skb->mac.raw = skb->data;
skb_pull(skb, ETH_ALEN * 2 + sizeof (short));
eth = skb->mac.ethernet;
__u64 inbound_start_time;
unsigned int inbound_cnt;
unsigned int inbound_time;
__u64 outbound_start_time;
unsigned int outbound_cnt;
unsigned int outbound_time;
};
#endif /* CONFIG_QETH_PERF_STATS */
if (*eth->h_dest & 1) {
if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
skb->pkt_type = PACKET_BROADCAST;
else
skb->pkt_type = PACKET_MULTICAST;
} else {
skb->pkt_type = PACKET_OTHERHOST;
}
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
if (*(unsigned short *) (skb->data) == 0xFFFF)
return htons(ETH_P_802_3);
return htons(ETH_P_802_2);
}
/* Routing stuff */
struct qeth_routing_info {
enum qeth_routing_types type;
};
typedef unsigned short (*__qeth_temp5) (struct sk_buff *, struct net_device *);
inline static __qeth_temp5
qeth_get_type_trans(__u8 link_type)
{
switch (link_type) {
#ifdef CONFIG_TR
case QETH_MPC_LINK_TYPE_HSTR:
case QETH_MPC_LINK_TYPE_LANE_TR:
return tr_type_trans;
#endif
default:
return qeth_eth_type_trans;
}
}
#endif /* QETH_IPV6 */
/* IPA stuff */
struct qeth_ipa_info {
__u32 supported_funcs;
__u32 enabled_funcs;
};
inline static const char *
qeth_get_link_type_name(int cardtype, __u8 linktype)
static inline int
qeth_is_ipa_supported(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
{
switch (cardtype) {
case QETH_CARD_TYPE_UNKNOWN:
return "unknown";
case QETH_CARD_TYPE_OSAE:
switch (linktype) {
case QETH_MPC_LINK_TYPE_FAST_ETHERNET:
return "Fast Eth";
case QETH_MPC_LINK_TYPE_HSTR:
return "HSTR";
case QETH_MPC_LINK_TYPE_GIGABIT_ETHERNET:
return "Gigabit Eth";
case QETH_MPC_LINK_TYPE_LANE_ETH100:
return "LANE Eth100";
case QETH_MPC_LINK_TYPE_LANE_TR:
return "LANE TR";
case QETH_MPC_LINK_TYPE_LANE_ETH1000:
return "LANE Eth1000";
default:
return "unknown";
}
case QETH_CARD_TYPE_IQD:
return "magic";
default:
return "unknown";
}
return (ipa->supported_funcs & func);
}
inline static const char *
qeth_get_dev_basename(int cardtype, __u8 link_type)
static inline int
qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func)
{
switch (cardtype) {
case QETH_CARD_TYPE_UNKNOWN:
return "eth";
case QETH_CARD_TYPE_OSAE:
switch (link_type) {
case QETH_MPC_LINK_TYPE_LANE_TR:
/* fallthrough */
case QETH_MPC_LINK_TYPE_HSTR:
return "tr";
default:
return "eth";
}
case QETH_CARD_TYPE_IQD:
return "hsi";
default:
return "eth";
}
return (ipa->supported_funcs & ipa->enabled_funcs & func);
}
/* inbound: */
#define DEFAULT_BUFFER_SIZE 65536
#define DEFAULT_BUFFER_COUNT 128
#define BUFCNT_MIN 8
#define BUFCNT_MAX 128
#define BUFFER_SIZE (card->inbound_buffer_size)
#define BUFFER_MAX_ELEMENTS (BUFFER_SIZE>>12)
/* 8k for each pair header-buffer: */
#define qeth_adp_supported(c,f) \
qeth_is_ipa_supported(&c->options.adp, f)
#define qeth_adp_enabled(c,f) \
qeth_is_ipa_enabled(&c->options.adp, f)
#define qeth_is_supported(c,f) \
qeth_is_ipa_supported(&c->options.ipa4, f)
#define qeth_is_enabled(c,f) \
qeth_is_ipa_enabled(&c->options.ipa4, f)
#ifdef CONFIG_QETH_IPV6
#define qeth_is_supported6(c,f) \
qeth_is_ipa_supported(&c->options.ipa6, f)
#define qeth_is_enabled6(c,f) \
qeth_is_ipa_enabled(&c->options.ipa6, f)
#else /* CONFIG_QETH_IPV6 */
#define qeth_is_supported6(c,f) 0
#define qeth_is_enabled6(c,f) 0
#endif /* CONFIG_QETH_IPV6 */
#define qeth_is_ipafunc_supported(c,prot,f) \
(prot==QETH_PROT_IPV6)? qeth_is_supported6(c,f):qeth_is_supported(c,f)
#define qeth_is_ipafunc_enabled(c,prot,f) \
(prot==QETH_PROT_IPV6)? qeth_is_enabled6(c,f):qeth_is_enabled(c,f)
inline static int
qeth_sbal_packing_on_card(int cardtype)
{
switch (cardtype) {
case QETH_CARD_TYPE_IQD:
return 0;
default:
return 1;
}
}
/*
* do it this way round -> __MODULE_STRING needs with
* QETH_PRIO_NICE_LEVELS a single number
*/
#define QETH_MAX_PRIO_QUEUES QETH_PRIO_NICE_LEVELS+1
#define QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT 0x0101
#define QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT 0x0101
#define QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT 0x4108
#define QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT 0x5108
static inline int
qeth_sbalf15_in_retrieable_range(int sbalf15)
{
return ((sbalf15 >= 15) && (sbalf15 <= 31));
}
#define QETH_MODELLIST_ARRAY \
{{0x1731,0x01,0x1732,0x01,QETH_CARD_TYPE_OSAE,1, \
QETH_IDX_FUNC_LEVEL_OSAE_ENA_IPAT, \
QETH_IDX_FUNC_LEVEL_OSAE_DIS_IPAT, \
QETH_MAX_QUEUES,0}, \
{0x1731,0x05,0x1732,0x05,QETH_CARD_TYPE_IQD,0, \
QETH_IDX_FUNC_LEVEL_IQD_ENA_IPAT, \
QETH_IDX_FUNC_LEVEL_IQD_DIS_IPAT, \
QETH_MAX_QUEUES,0x103}, \
{0,0,0,0,0,0,0,0,0}}
#define INBOUND_BUFFER_POS(card,bufno,sbale) \
( (bufno&SPAREBUF_MASK)? \
( \
(sparebufs[bufno&(~SPAREBUF_MASK)].buf+ \
PAGE_SIZE*sbale) \
):( \
(card->inbound_buffer_pool_entry[card-> \
inbound_buffer_entry_no[bufno]][sbale]) \
) )
#define SPAREBUF_UNAVAIL 0
#define SPAREBUF_FREE 1
#define SPAREBUF_USED 2
struct sparebufs {
char *buf;
atomic_t status;
};
#define QETH_REAL_CARD 1
#define QETH_VLAN_CARD 2
#define QETH_BUFSIZE 4096
#define SEND_STATE_INACTIVE 0
#define SEND_STATE_DONT_PACK 1
#define SEND_STATE_PACK 2
#define QETH_LOCK_UNLOCKED 0
#define QETH_LOCK_NORMAL 1
#define QETH_LOCK_FLUSH 2
#define QETH_TX_TIMEOUT 100*HZ /* 100 seconds */
#define QETH_REMOVE_WAIT_TIME 200
#define QETH_WAIT_FOR_THREAD_TIME 20
#define QETH_IDLE_WAIT_TIME 10
#define QETH_WAIT_BEFORE_2ND_DOIO 1000
#define QETH_FAKE_LL_LEN ETH_HLEN /* 14 */
#define QETH_FAKE_LL_PROT_LEN 2
#define QETH_FAKE_LL_ADDR_LEN ETH_ALEN /* 6 */
#define QETH_FAKE_LL_DEST_MAC_POS 0
#define QETH_FAKE_LL_SRC_MAC_POS 6
#define QETH_FAKE_LL_SRC_MAC_POS_IN_QDIO_HDR 6
#define QETH_FAKE_LL_PROT_POS 12
#define QETH_FAKE_LL_V4_ADDR_POS 16
/**
* some more defs
*/
#define IF_NAME_LEN 16
#define QETH_TX_TIMEOUT 100 * HZ
#define QETH_HEADER_SIZE 32
#define MAX_PORTNO 15
#define QETH_FAKE_LL_LEN ETH_HLEN
#define QETH_FAKE_LL_V6_ADDR_POS 24
#define DEV_NAME_LEN 16
#define IOCTL_MAX_TRANSFER_SIZE 65535
/*IPv6 address autoconfiguration stuff*/
#define UNIQUE_ID_IF_CREATE_ADDR_FAILED 0xfffe
#define UNIQUE_ID_NOT_BY_CARD 0x10000
/*****************************************************************************/
/* QDIO queue and buffer handling */
/*****************************************************************************/
#define QETH_MAX_QUEUES 4
#define QETH_IN_BUF_SIZE_DEFAULT 65536
#define QETH_IN_BUF_COUNT_DEFAULT 16
#define QETH_IN_BUF_COUNT_MIN 8
#define QETH_IN_BUF_COUNT_MAX 128
#define QETH_MAX_BUFFER_ELEMENTS(card) ((card)->qdio.in_buf_size >> 12)
#define QETH_IN_BUF_REQUEUE_THRESHOLD(card) \
((card)->qdio.in_buf_pool.buf_count / 4)
/* buffers we have to be behind before we get a PCI */
#define QETH_PCI_THRESHOLD_A(card) ((card)->qdio.in_buf_pool.buf_count+1)
/*enqueued free buffers left before we get a PCI*/
#define QETH_PCI_THRESHOLD_B(card) 0
/*not used unless the microcode gets patched*/
#define QETH_PCI_TIMER_VALUE(card) 3
#define QETH_MIN_INPUT_THRESHOLD 1
#define QETH_MAX_INPUT_THRESHOLD 500
#define QETH_MIN_OUTPUT_THRESHOLD 1
#define QETH_MAX_OUTPUT_THRESHOLD 300
/* priority queing */
#define QETH_PRIOQ_DEFAULT QETH_NO_PRIO_QUEUEING
#define QETH_DEFAULT_QUEUE 2
#define QETH_NO_PRIO_QUEUEING 0
#define QETH_PRIO_Q_ING_PREC 1
#define QETH_PRIO_Q_ING_TOS 2
#define IP_TOS_LOWDELAY 0x10
#define IP_TOS_HIGHTHROUGHPUT 0x08
#define IP_TOS_HIGHRELIABILITY 0x04
#define IP_TOS_NOTIMPORTANT 0x02
#define QETH_RCD_LENGTH 128
#define __max(a,b) ( ((a)>(b))?(a):(b) )
#define __min(a,b) ( ((a)<(b))?(a):(b) )
#define QETH_BUFSIZE __max(__max(IPA_PDU_HEADER_SIZE+sizeof(struct arp_cmd), \
IPA_PDU_HEADER_SIZE+sizeof(struct ipa_cmd)), \
QETH_RCD_LENGTH)
#define QETH_NOP_TIMEOUT 1500
#define QETH_QUIESCE_NETDEV_TIME 300
#define QETH_QUIESCE_WAIT_BEFORE_CLEAR 4000
#define QETH_QUIESCE_WAIT_AFTER_CLEAR 4000
#define NOP_STATE 0x1001
#define IDX_ACTIVATE_READ_STATE 0x1003
#define IDX_ACTIVATE_WRITE_STATE 0x1004
#define MPC_SETUP_STATE 0x1005
#define CLEAR_STATE 0x1006
#define IPA_CMD_STATE 0x1007
#define IPA_IOCTL_STATE 0x1009
#define IPA_SETIP_FLAG 0x100000
#define QETH_REMOVE_CARD_PROPER 1
#define QETH_REMOVE_CARD_QUICK 2
#define NO_PRIO_QUEUEING 0
#define PRIO_QUEUEING_PREC 1
#define PRIO_QUEUEING_TOS 2
#define NO_ROUTER 0
#define PRIMARY_ROUTER 1
#define SECONDARY_ROUTER 2
#define MULTICAST_ROUTER 3
#define PRIMARY_CONNECTOR 4
#define SECONDARY_CONNECTOR 5
#define ROUTER_MASK 0xf /* used to remove SET_ROUTING_FLAG
from routing_type */
#define RESET_ROUTING_FLAG 0x10 /* used to indicate, that setting
the routing type is desired */
#define BROADCAST_ALLRINGS 0
#define BROADCAST_LOCAL 1
#define MACADDR_NONCANONICAL 0
#define MACADDR_CANONICAL 1
#define ENABLE_TAKEOVER 0
#define DISABLE_TAKEOVER 1
#define FAKE_BROADCAST 0
#define DONT_FAKE_BROADCAST 1
#define FAKE_LL 0
#define DONT_FAKE_LL 1
#define QETH_BREAKOUT_LEAVE 1
#define QETH_BREAKOUT_AGAIN 2
#define QETH_WAIT_FOR_LOCK 0
#define QETH_DONT_WAIT_FOR_LOCK 1
#define QETH_LOCK_ALREADY_HELD 2
#define PROBLEM_CARD_HAS_STARTLANED 1
#define PROBLEM_RECEIVED_IDX_TERMINATE 2
#define PROBLEM_ACTIVATE_CHECK_CONDITION 3
#define PROBLEM_RESETTING_EVENT_INDICATOR 4
#define PROBLEM_COMMAND_REJECT 5
#define PROBLEM_ZERO_SENSE_DATA 6
#define PROBLEM_GENERAL_CHECK 7
#define PROBLEM_BAD_SIGA_RESULT 8
#define PROBLEM_USER_TRIGGERED_RECOVERY 9
#define PROBLEM_AFFE 10
#define PROBLEM_MACHINE_CHECK 11
#define PROBLEM_TX_TIMEOUT 12
#define CARD_RDEV(card) card->gdev->cdev[0]
#define CARD_WDEV(card) card->gdev->cdev[1]
#define CARD_DDEV(card) card->gdev->cdev[2]
#define CARD_BUS_ID(card) card->gdev->dev.bus_id
#define CARD_RDEV_ID(card) card->gdev->cdev[0]->dev.bus_id
#define CARD_WDEV_ID(card) card->gdev->cdev[1]->dev.bus_id
#define CARD_DDEV_ID(card) card->gdev->cdev[2]->dev.bus_id
#define CARD_FROM_CDEV(cdev) (struct qeth_card *) \
((struct ccwgroup_device *) cdev->dev.driver_data)->dev.driver_data
/* Packing */
#define QETH_LOW_WATERMARK_PACK 2
#define QETH_HIGH_WATERMARK_PACK 5
#define QETH_WATERMARK_PACK_FUZZ 1
#define SENSE_COMMAND_REJECT_BYTE 0
#define SENSE_COMMAND_REJECT_FLAG 0x80
#define SENSE_RESETTING_EVENT_BYTE 1
#define SENSE_RESETTING_EVENT_FLAG 0x80
#define BUFFER_USED 1
#define BUFFER_UNUSED -1
#define QETH_IP_HEADER_SIZE 40
/* VLAN defines */
#define QETH_EXT_HDR_VLAN_FRAME 0x01
#define QETH_EXT_HDR_TOKEN_ID 0x02
#define QETH_EXT_HDR_INCLUDE_VLAN_TAG 0x04
typedef int (*reg_notifier_t) (struct notifier_block *);
struct qeth_hdr {
__u8 id;
__u8 flags;
__u16 inbound_checksum;
__u32 token;
__u16 length;
__u8 vlan_prio;
__u8 ext_flags;
__u16 vlan_id;
__u16 frame_offset;
__u8 dest_addr[16];
} __attribute__ ((packed));
struct ipato_entry {
int version;
__u8 addr[16];
int mask_bits;
char dev_name[DEV_NAME_LEN];
struct ipato_entry *next;
/* flags for qeth_hdr.flags */
#define QETH_HDR_PASSTHRU 0x10
#define QETH_HDR_IPV6 0x80
#define QETH_HDR_CAST_MASK 0x07
enum qeth_cast_flags {
QETH_CAST_UNICAST = 0x06,
QETH_CAST_MULTICAST = 0x04,
QETH_CAST_BROADCAST = 0x05,
QETH_CAST_ANYCAST = 0x07,
QETH_CAST_NOCAST = 0x00,
};
struct qeth_vipa_entry {
int version;
__u8 ip[16];
int flag;
volatile int state;
struct qeth_vipa_entry *next;
};
/* flags for qeth_hdr.ext_flags */
#define QETH_HDR_EXT_VLAN_FRAME 0x01
#define QETH_HDR_EXT_CSUM_HDR_REQ 0x10
#define QETH_HDR_EXT_CSUM_TRANSP_REQ 0x20
#define QETH_HDR_EXT_SRC_MAC_ADDR 0x08
struct ip_state {
struct in_ifaddr *ip_ifa; /* pointer to IPv4 adresses */
struct inet6_ifaddr *ip6_ifa;
};
static inline int
qeth_is_last_sbale(struct qdio_buffer_element *sbale)
{
return (sbale->flags & SBAL_FLAGS_LAST_ENTRY);
}
struct qeth_ipm_mac {
__u8 mac[ETH_ALEN];
__u8 ip[16];
struct qeth_ipm_mac *next;
enum qeth_qdio_buffer_states {
/*
* inbound: read out by driver; owned by hardware in order to be filled
* outbound: owned by driver in order to be filled
*/
QETH_QDIO_BUF_EMPTY,
/*
* inbound: filled by hardware; owned by driver in order to be read out
* outbound: filled by driver; owned by hardware in order to be sent
*/
QETH_QDIO_BUF_PRIMED,
/*
* inbound only: an error condition has been detected for a buffer
* the buffer will be discarded (not read out)
*/
QETH_QDIO_BUF_ERROR,
};
struct ip_mc_state {
struct qeth_ipm_mac *ipm_ifa;
struct qeth_ipm_mac *ipm6_ifa;
enum qeth_qdio_info_states {
QETH_QDIO_UNINITIALIZED,
QETH_QDIO_ALLOCATED,
QETH_QDIO_ESTABLISHED,
};
struct addr_request {
struct addr_request *next;
int request_type;
__u8 mac[ETH_ALEN];
__u8 ip[16];
struct qeth_buffer_pool_entry {
struct list_head list;
struct list_head init_list;
void *elements[QDIO_MAX_ELEMENTS_PER_BUFFER];
};
struct qeth_card_options {
char devname[DEV_NAME_LEN];
volatile int routing_type4;
#ifdef QETH_IPV6
volatile int routing_type6;
#endif /* QETH_IPV6 */
int checksum_type;
int do_prio_queueing;
int default_queue;
int inbound_buffer_count;
int polltime;
char portname[9];
int portno;
int broadcast_mode;
int macaddr_mode;
int ena_ipat;
int fake_broadcast;
int add_hhlen;
int fake_ll;
struct qeth_qdio_buffer_pool {
struct list_head entry_list;
int buf_count;
};
struct qeth_hdr {
__u8 id;
__u8 flags;
__u16 inbound_checksum;
__u32 token;
__u16 length;
__u8 vlan_prio;
__u8 ext_flags;
__u16 vlan_id;
__u16 frame_offset;
__u8 dest_addr[16];
struct qeth_qdio_buffer {
struct qdio_buffer *buffer;
volatile enum qeth_qdio_buffer_states state;
/* the buffer pool entry currently associated to this buffer */
struct qeth_buffer_pool_entry *pool_entry;
};
struct qeth_ringbuffer_element {
struct qeth_qdio_q {
struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
struct qeth_qdio_buffer bufs[QDIO_MAX_BUFFERS_PER_Q];
/*
* buf_to_process means "buffer primed by hardware,
* has to be read in by driver"; current state PRIMED
*/
volatile int next_buf_to_process;
/*
* buf_to_init means "buffer must be initialized by driver and must
* be made available for hardware" -> state is set to EMPTY
*/
volatile int next_buf_to_init;
} __attribute__ ((aligned(256)));
struct qeth_qdio_out_buffer {
struct qdio_buffer *buffer;
volatile enum qeth_qdio_buffer_states state;
volatile int next_element_to_fill;
struct sk_buff_head skb_list;
int next_element_to_fill;
} __attribute__ ((packed));
};
struct qeth_ringbuffer {
struct qdio_buffer buffer[QDIO_MAX_BUFFERS_PER_Q];
struct qeth_ringbuffer_element ringbuf_element[QDIO_MAX_BUFFERS_PER_Q];
}__attribute__ ((packed, aligned(PAGE_SIZE)));
struct qeth_card;
struct qeth_qdio_out_q {
struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
struct qeth_qdio_out_buffer bufs[QDIO_MAX_BUFFERS_PER_Q];
int queue_no;
struct qeth_card *card;
struct tasklet_struct tasklet;
spinlock_t lock;
volatile int do_pack;
/*
* index of buffer to be filled by driver; state EMPTY or PACKING
*/
volatile int next_buf_to_fill;
volatile int next_buf_to_flush;
/*
* number of buffers that are currently filled (PRIMED)
* -> these buffers are hardware-owned
*/
atomic_t used_buffers;
/* indicates whether PCI flag must be set (or if one is outstanding) */
atomic_t set_pci_flags_count;
} __attribute__ ((aligned(256)));
struct qeth_qdio_info {
volatile enum qeth_qdio_info_states state;
/* input */
struct qeth_qdio_q *in_q;
struct qeth_qdio_buffer_pool in_buf_pool;
struct qeth_qdio_buffer_pool init_pool;
int in_buf_size;
struct tasklet_struct in_tasklet;
/* output */
int no_out_queues;
struct qeth_qdio_out_q **out_qs;
/* priority queueing */
int do_prio_queueing;
int default_out_queue;
};
struct qeth_dma_stuff {
unsigned char *sendbuf;
unsigned char *recbuf;
struct ccw1 read_ccw;
struct ccw1 write_ccw;
}__attribute__ ((packed, aligned(PAGE_SIZE)));
enum qeth_send_errors {
QETH_SEND_ERROR_NONE,
QETH_SEND_ERROR_LINK_FAILURE,
QETH_SEND_ERROR_RETRY,
QETH_SEND_ERROR_KICK_IT,
};
struct qeth_perf_stats {
unsigned int skbs_rec;
unsigned int bufs_rec;
#define QETH_ETH_MAC_V4 0x0100 /* like v4 */
#define QETH_ETH_MAC_V6 0x3333 /* like v6 */
/* tr mc mac is longer, but that will be enough to detect mc frames */
#define QETH_TR_MAC_NC 0xc000 /* non-canonical */
#define QETH_TR_MAC_C 0x0300 /* canonical */
unsigned int skbs_sent;
unsigned int bufs_sent;
#define DEFAULT_ADD_HHLEN 0
#define MAX_ADD_HHLEN 1024
unsigned int skbs_sent_dont_pack;
unsigned int bufs_sent_dont_pack;
unsigned int skbs_sent_pack;
unsigned int bufs_sent_pack;
unsigned int skbs_sent_pack_better;
unsigned int bufs_sent_pack_better;
/**
* buffer stuff for read channel
*/
#define QETH_CMD_BUFFER_NO 8
unsigned int sc_dp_p;
unsigned int sc_p_dp;
/**
* channel state machine
*/
enum qeth_channel_states {
CH_STATE_UP,
CH_STATE_DOWN,
CH_STATE_ACTIVATING,
CH_STATE_HALTED,
CH_STATE_STOPPED,
};
/**
* card state machine
*/
enum qeth_card_states {
CARD_STATE_DOWN,
CARD_STATE_HARDSETUP,
CARD_STATE_SOFTSETUP,
CARD_STATE_UP_LAN_OFFLINE,
CARD_STATE_UP_LAN_ONLINE,
CARD_STATE_RECOVER,
};
__u64 inbound_start_time;
unsigned int inbound_cnt;
unsigned int inbound_time;
__u64 outbound_start_time;
unsigned int outbound_cnt;
unsigned int outbound_time;
/**
* Protocol versions
*/
enum qeth_prot_versions {
QETH_PROT_SNA = 0x0001,
QETH_PROT_IPV4 = 0x0004,
QETH_PROT_IPV6 = 0x0006,
};
/* ugly. I know. */
struct qeth_card { /* pointed to by dev->priv */
enum qeth_ip_types {
QETH_IP_TYPE_NORMAL,
QETH_IP_TYPE_VIPA,
QETH_IP_TYPE_RXIP,
};
/* pointer to options (defaults + parameters) */
struct qeth_card_options options;
enum qeth_cmd_buffer_state {
BUF_STATE_FREE,
BUF_STATE_LOCKED,
BUF_STATE_PROCESSED,
};
/**
* IP address and multicast list
*/
struct qeth_ipaddr {
struct list_head entry;
enum qeth_ip_types type;
enum qeth_ipa_setdelip_flags set_flags;
enum qeth_ipa_setdelip_flags del_flags;
int is_multicast;
volatile int users;
enum qeth_prot_versions proto;
unsigned char mac[OSA_ADDR_LEN];
union {
struct {
unsigned int addr;
unsigned int mask;
} a4;
struct {
struct in6_addr addr;
unsigned int pfxlen;
} a6;
} u;
};
atomic_t is_startlaned; /* card did not get a stoplan */
/* also 0 when card is gone after a
* machine check */
__u8 link_type;
int is_guest_lan;
/* inbound buffer management */
atomic_t inbound_buffer_refcnt[QDIO_MAX_BUFFERS_PER_Q];
struct qdio_buffer inbound_qdio_buffers[QDIO_MAX_BUFFERS_PER_Q];
/* inbound data area */
void *inbound_buffer_pool_entry[QDIO_MAX_BUFFERS_PER_Q]
[QDIO_MAX_ELEMENTS_PER_BUFFER];
volatile int inbound_buffer_pool_entry_used[QDIO_MAX_BUFFERS_PER_Q];
int inbound_buffer_entry_no[QDIO_MAX_BUFFERS_PER_Q];
/* for requeueing of buffers */
spinlock_t requeue_input_lock;
atomic_t requeue_position;
atomic_t requeue_counter;
/* outbound QDIO stuff */
volatile int send_state[QETH_MAX_QUEUES];
volatile int outbound_first_free_buffer[QETH_MAX_QUEUES];
atomic_t outbound_used_buffers[QETH_MAX_QUEUES];
int outbound_buffer_send_state[QETH_MAX_QUEUES]
[QDIO_MAX_BUFFERS_PER_Q];
int send_retries[QETH_MAX_QUEUES][QDIO_MAX_BUFFERS_PER_Q];
volatile int outbound_bytes_in_buffer[QETH_MAX_QUEUES];
struct qeth_ringbuffer *outbound_ringbuffer[QETH_MAX_QUEUES];
atomic_t outbound_ringbuffer_lock[QETH_MAX_QUEUES];
atomic_t last_pci_pos[QETH_MAX_QUEUES];
#ifdef QETH_IPV6
int (*hard_header) (struct sk_buff *, struct net_device *,
unsigned short, void *, void *, unsigned);
int (*rebuild_header) (struct sk_buff *);
int (*hard_header_cache) (struct neighbour *, struct hh_cache *);
void (*header_cache_update) (struct hh_cache *, struct net_device *,
unsigned char *);
unsigned short (*type_trans) (struct sk_buff *, struct net_device *);
#endif /* QETH_IPV6 */
struct qeth_ipato_entry {
struct list_head entry;
enum qeth_prot_versions proto;
char addr[16];
int mask_bits;
};
#ifdef QETH_VLAN
struct vlan_group *vlangrp;
spinlock_t vlan_lock;
#endif
struct qeth_ipato {
int enabled;
int invert4;
int invert6;
struct list_head entries;
};
char dev_name[DEV_NAME_LEN]; /* pointed to by dev->name */
struct net_device *dev;
struct net_device_stats *stats;
struct qeth_channel;
int no_queues;
struct qeth_cmd_buffer {
enum qeth_cmd_buffer_state state;
struct qeth_channel *channel;
unsigned char *data;
int rc;
void (*callback) (struct qeth_channel *, struct qeth_cmd_buffer *);
};
#ifdef QETH_PERFORMANCE_STATS
struct qeth_perf_stats perf_stats;
#endif /* QETH_PERFORMANCE_STATS */
/* our state */
atomic_t is_registered; /* card registered as netdev? */
atomic_t is_hardsetup; /* card has gone through hardsetup */
atomic_t is_softsetup; /* card is setup by softsetup */
atomic_t is_open; /* card is in use */
/* prevents deadlocks :-O */
struct semaphore softsetup_sema;
struct semaphore hardsetup_sema;
spinlock_t ioctl_lock;
atomic_t softsetup_thread_is_running;
struct semaphore softsetup_thread_sem;
struct work_struct tqueue_sst;
atomic_t escape_softsetup; /* active, when recovery has to
wait for softsetup */
struct semaphore reinit_thread_sem;
atomic_t in_recovery;
atomic_t reinit_counter;
/* problem management */
atomic_t break_out;
atomic_t problem;
struct work_struct tqueue;
struct {
__u32 trans_hdr;
__u32 pdu_hdr;
__u32 pdu_hdr_ack;
__u32 ipa;
} seqno;
/**
* definition of a qeth channel, used for read and write
*/
struct qeth_channel {
enum qeth_channel_states state;
struct ccw1 ccw;
spinlock_t iob_lock;
wait_queue_head_t wait_q;
struct tasklet_struct irq_tasklet;
struct ccw_device *ccwdev;
/*command buffer for control data*/
struct qeth_cmd_buffer iob[QETH_CMD_BUFFER_NO];
atomic_t irq_pending;
volatile int io_buf_no;
volatile int buf_no;
};
struct {
/**
* OSA card related definitions
*/
struct qeth_token {
__u32 issuer_rm_w;
__u32 issuer_rm_r;
__u32 cm_filter_w;
......@@ -932,216 +601,189 @@ struct qeth_card { /* pointed to by dev->priv */
__u32 ulp_filter_r;
__u32 ulp_connection_w;
__u32 ulp_connection_r;
} token;
};
/* this is card-related */
int type;
__u16 func_level;
int initial_mtu;
int max_mtu;
int inbound_buffer_size;
int is_multicast_different; /* if multicast traffic is to be sent
on a different queue, this is the
queue+no_queues */
__u32 ipa_supported;
__u32 ipa_enabled;
__u32 ipa6_supported;
__u32 ipa6_enabled;
__u32 adp_supported;
__u32 csum_enable_mask;
atomic_t startlan_attempts;
atomic_t enable_routing_attempts4;
atomic_t rt4fld;
#ifdef QETH_IPV6
atomic_t enable_routing_attempts6;
atomic_t rt6fld;
#endif /* QETH_IPV6 */
int unique_id;
struct qeth_seqno {
__u32 trans_hdr;
__u32 pdu_hdr;
__u32 pdu_hdr_ack;
__u32 ipa;
};
/* device and I/O data */
struct ccwgroup_device *gdev;
struct qeth_reply {
struct list_head list;
wait_queue_head_t wait_q;
int (*callback)(struct qeth_card *,struct qeth_reply *,unsigned long);
int seqno;
int received;
int rc;
void *param;
struct qeth_card *card;
atomic_t refcnt;
};
struct qeth_card_info {
char if_name[IF_NAME_LEN];
unsigned short unit_addr2;
unsigned short cula;
unsigned short chpid;
__u16 func_level;
char mcl_level[QETH_MCL_LENGTH + 1];
int guestlan;
int portname_required;
int portno;
char portname[9];
enum qeth_card_types type;
enum qeth_link_types link_type;
int is_multicast_different;
int initial_mtu;
int max_mtu;
int broadcast_capable;
int unique_id;
__u32 csum_mask;
};
unsigned char ipa_buf[QETH_BUFSIZE];
unsigned char send_buf[QETH_BUFSIZE];
/* IOCTL Stuff */
unsigned char *ioctl_data_buffer;
unsigned char *ioctl_buffer_pointer;
int ioctl_returncode;
int ioctl_buffersize;
int number_of_entries;
atomic_t ioctl_data_has_arrived;
wait_queue_head_t ioctl_wait_q;
struct qeth_card_options {
struct qeth_routing_info route4;
struct qeth_ipa_info ipa4;
struct qeth_ipa_info adp; /*Adapter parameters*/
#ifdef CONFIG_QETH_IPV6
struct qeth_routing_info route6;
struct qeth_ipa_info ipa6;
#endif /* QETH_IPV6 */
enum qeth_checksum_types checksum_type;
int broadcast_mode;
int macaddr_mode;
int enable_takeover;
int fake_broadcast;
int add_hhlen;
int fake_ll;
};
/* stuff under 2 gb */
struct qeth_dma_stuff *dma_stuff;
/*
* thread bits for qeth_card thread masks
*/
enum qeth_threads {
QETH_SET_IP_THREAD = 1,
QETH_SET_MC_THREAD = 2,
QETH_RECOVER_THREAD = 4,
};
unsigned int ipa_timeout;
struct qeth_card {
struct list_head list;
enum qeth_card_states state;
int lan_online;
spinlock_t lock;
/*hardware and sysfs stuff*/
struct ccwgroup_device *gdev;
struct qeth_channel read;
struct qeth_channel write;
struct qeth_channel data;
atomic_t write_busy;
struct net_device *dev;
struct net_device_stats stats;
/* vipa stuff */
rwlock_t vipa_list_lock;
struct qeth_vipa_entry *vipa_list;
struct qeth_card_info info;
struct qeth_token token;
struct qeth_seqno seqno;
struct qeth_card_options options;
/* state information when doing I/O */
atomic_t shutdown_phase;
atomic_t data_has_arrived;
wait_queue_head_t wait_q;
#ifdef CONFIG_QETH_VLAN
spinlock_t vlanlock;
struct vlan_group *vlangrp;
#endif
struct work_struct kernel_thread_starter;
spinlock_t thread_mask_lock;
volatile unsigned long thread_start_mask;
volatile unsigned long thread_allowed_mask;
volatile unsigned long thread_running_mask;
spinlock_t ip_lock;
struct list_head ip_list;
struct list_head ip_tbd_list;
struct qeth_ipato ipato;
struct list_head cmd_waiter_list;
/* QDIO buffer handling */
struct qeth_qdio_info qdio;
#ifdef CONFIG_QETH_PERF_STATS
struct qeth_perf_stats perf_stats;
#endif /* CONFIG_QETH_PERF_STATS */
int use_hard_stop;
};
atomic_t clear_succeeded0;
atomic_t clear_succeeded1;
atomic_t clear_succeeded2;
/* bookkeeping of IP and multicast addresses */
struct ip_state ip_current_state;
struct ip_state ip_new_state;
struct ip_mc_state ip_mc_current_state;
struct ip_mc_state ip_mc_new_state;
int broadcast_capable;
int portname_required;
int realloc_message;
char level[QETH_MCL_LENGTH + 1];
volatile int saved_dev_flags;
/* for our linked list */
struct qeth_card *next;
struct qeth_card_list_struct {
struct list_head list;
rwlock_t rwlock;
};
inline static int
qeth_get_arphrd_type(int cardtype, int linktype)
{
switch (cardtype) {
case QETH_CARD_TYPE_OSAE:
switch (linktype) {
case QETH_MPC_LINK_TYPE_LANE_TR:
/* fallthrough */
case QETH_MPC_LINK_TYPE_HSTR:
return ARPHRD_IEEE802_TR;
default:
return ARPHRD_ETHER;
}
case QETH_CARD_TYPE_IQD:
return ARPHRD_ETHER;
default:
return ARPHRD_ETHER;
}
}
extern struct qeth_card_list_struct qeth_card_list;
/*some helper functions*/
inline static __u8
qeth_get_adapter_type_for_ipa(int link_type)
qeth_get_ipa_adp_type(enum qeth_link_types link_type)
{
switch (link_type) {
case QETH_MPC_LINK_TYPE_HSTR:
case QETH_LINK_TYPE_HSTR:
return 2;
default:
return 1;
}
}
inline static const char *
qeth_get_cardname(int cardtype, int is_guest_lan)
inline static int
qeth_get_hlen(__u8 link_type)
{
if (is_guest_lan) {
switch (cardtype) {
case QETH_CARD_TYPE_UNKNOWN:
return "n unknown";
case QETH_CARD_TYPE_OSAE:
return " Guest LAN QDIO";
case QETH_CARD_TYPE_IQD:
return " Guest LAN Hiper";
default: return
" strange";
}
} else {
switch (cardtype) {
case QETH_CARD_TYPE_UNKNOWN:
return "n unknown";
case QETH_CARD_TYPE_OSAE:
return "n OSD Express";
case QETH_CARD_TYPE_IQD:
return " HiperSockets";
#ifdef CONFIG_QETH_IPV6
switch (link_type) {
case QETH_LINK_TYPE_HSTR:
case QETH_LINK_TYPE_LANE_TR:
return sizeof(struct qeth_hdr) + TR_HLEN;
default:
return " strange";
}
#ifdef CONFIG_QETH_VLAN
return sizeof(struct qeth_hdr) + VLAN_ETH_HLEN;
#else
return sizeof(struct qeth_hdr) + ETH_HLEN;
#endif
}
#else /* CONFIG_QETH_IPV6 */
#ifdef CONFIG_QETH_VLAN
return sizeof(struct qeth_hdr) + VLAN_HLEN;
#else
return sizeof(struct qeth_hdr);
#endif
#endif /* CONFIG_QETH_IPV6 */
}
/* max length to be returned: 14 */
inline static const char *
qeth_get_cardname_short(int cardtype, __u8 link_type, int is_guest_lan)
inline static unsigned short
qeth_get_netdev_flags(int cardtype)
{
switch (cardtype) {
case QETH_CARD_TYPE_UNKNOWN:
return "unknown";
case QETH_CARD_TYPE_OSAE:
if (is_guest_lan)
return "GuestLAN QDIO";
switch (link_type) {
case QETH_MPC_LINK_TYPE_FAST_ETHERNET:
return "OSD_100";
case QETH_MPC_LINK_TYPE_HSTR:
return "HSTR";
case QETH_MPC_LINK_TYPE_GIGABIT_ETHERNET:
return "OSD_1000";
case QETH_MPC_LINK_TYPE_LANE_ETH100:
return "OSD_FE_LANE";
case QETH_MPC_LINK_TYPE_LANE_TR:
return "OSD_TR_LANE";
case QETH_MPC_LINK_TYPE_LANE_ETH1000:
return "OSD_GbE_LANE";
case QETH_MPC_LINK_TYPE_LANE:
return "OSD_ATM_LANE";
default:
return "OSD_Express";
}
case QETH_CARD_TYPE_IQD:
return is_guest_lan ? "GuestLAN Hiper" : "HiperSockets";
return IFF_NOARP;
#ifdef CONFIG_QETH_IPV6
default:
return " strange";
}
}
inline static int
qeth_mtu_is_valid(struct qeth_card * card, int mtu)
{
switch (card->type) {
case QETH_CARD_TYPE_UNKNOWN:
return 1;
case QETH_CARD_TYPE_OSAE:
return ((mtu >= 576) && (mtu <= 61440));
case QETH_CARD_TYPE_IQD:
return ((mtu >= 576) && (mtu <= card->max_mtu + 4096 - 32));
return 0;
#else
default:
return 1;
return IFF_NOARP;
#endif
}
}
inline static int
qeth_get_initial_mtu_for_card(struct qeth_card * card)
{
switch (card->type) {
switch (card->info.type) {
case QETH_CARD_TYPE_UNKNOWN:
return 1500;
case QETH_CARD_TYPE_IQD:
return card->max_mtu;
return card->info.max_mtu;
case QETH_CARD_TYPE_OSAE:
switch (card->link_type) {
case QETH_MPC_LINK_TYPE_HSTR:
case QETH_MPC_LINK_TYPE_LANE_TR:
switch (card->info.link_type) {
case QETH_LINK_TYPE_HSTR:
case QETH_LINK_TYPE_LANE_TR:
return 2000;
default:
return 1492;
......@@ -1195,39 +837,50 @@ qeth_get_mtu_outof_framesize(int framesize)
}
inline static int
qeth_get_buffersize_for_card(int cardtype)
qeth_mtu_is_valid(struct qeth_card * card, int mtu)
{
switch (cardtype) {
case QETH_CARD_TYPE_UNKNOWN:
return 65536;
switch (card->info.type) {
case QETH_CARD_TYPE_OSAE:
return 65536;
return ((mtu >= 576) && (mtu <= 61440));
case QETH_CARD_TYPE_IQD:
return 16384;
return ((mtu >= 576) &&
(mtu <= card->info.max_mtu + 4096 - 32));
case QETH_CARD_TYPE_UNKNOWN:
default:
return 65536;
return 1;
}
}
inline static int
qeth_get_min_number_of_buffers(int cardtype)
qeth_get_arphdr_type(int cardtype, int linktype)
{
switch (cardtype) {
case QETH_CARD_TYPE_UNKNOWN:
return 32;
case QETH_CARD_TYPE_OSAE:
return 32;
switch (linktype) {
case QETH_LINK_TYPE_LANE_TR:
case QETH_LINK_TYPE_HSTR:
return ARPHRD_IEEE802_TR;
default:
return ARPHRD_ETHER;
}
case QETH_CARD_TYPE_IQD:
return 64;
default:
return 64;
return ARPHRD_ETHER;
}
}
#ifdef CONFIG_QETH_PERF_STATS
inline static int
qeth_get_q_format(int cardtype)
qeth_get_micros(void)
{
switch (cardtype) {
return (int) (get_clock() >> 12);
}
#endif
static inline int
qeth_get_qdio_q_format(struct qeth_card *card)
{
switch (card->info.type) {
case QETH_CARD_TYPE_IQD:
return 2;
default:
......@@ -1235,100 +888,120 @@ qeth_get_q_format(int cardtype)
}
}
inline static int
qeth_get_device_tx_q_len(int cardtype)
static inline void
qeth_ipaddr4_to_string(const __u8 *addr, char *buf)
{
return 100;
sprintf(buf, "%i.%i.%i.%i", addr[0], addr[1], addr[2], addr[3]);
}
inline static int
qeth_get_max_number_of_buffers(int cardtype)
static inline int
qeth_string_to_ipaddr4(const char *buf, __u8 *addr)
{
return 127;
const char *start, *end;
char abuf[4];
char *tmp;
int len;
int i;
start = buf;
for (i = 0; i < 3; i++) {
if (!(end = strchr(start, '.')))
return -EINVAL;
len = end - start;
memset(abuf, 0, 4);
strncpy(abuf, start, len);
addr[i] = simple_strtoul(abuf, &tmp, 10);
start = end + 1;
}
memset(abuf, 0, 4);
strcpy(abuf, start);
addr[3] = simple_strtoul(abuf, &tmp, 10);
return 0;
}
/******************** OUTPUT FACILITIES **************************/
#ifdef PRINT_INFO
#undef PRINTK_HEADER
#undef PRINT_STUPID
#undef PRINT_ALL
#undef PRINT_INFO
#undef PRINT_WARN
#undef PRINT_ERR
#undef PRINT_CRIT
#undef PRINT_ALERT
#undef PRINT_EMERG
#endif /* PRINT_INFO */
static inline void
qeth_ipaddr6_to_string(const __u8 *addr, char *buf)
{
sprintf(buf, "%02x%02x:%02x%02x:%02x%02x:%02x%02x"
":%02x%02x:%02x%02x:%02x%02x:%02x%02x",
addr[0], addr[1], addr[2], addr[3],
addr[4], addr[5], addr[6], addr[7],
addr[8], addr[9], addr[10], addr[11],
addr[12], addr[13], addr[14], addr[15]);
}
#define PRINTK_HEADER QETH_NAME ": "
static inline int
qeth_string_to_ipaddr6(const char *buf, __u8 *addr)
{
const char *start, *end;
u16 *tmp_addr;
char abuf[5];
char *tmp;
int len;
int i;
tmp_addr = (u16 *)addr;
start = buf;
for (i = 0; i < 7; i++) {
if (!(end = strchr(start, ':')))
return -EINVAL;
len = end - start;
memset(abuf, 0, 5);
strncpy(abuf, start, len);
tmp_addr[i] = simple_strtoul(abuf, &tmp, 16);
start = end + 1;
}
memset(abuf, 0, 5);
strcpy(abuf, start);
tmp_addr[7] = simple_strtoul(abuf, &tmp, 16);
return 0;
}
#if QETH_VERBOSE_LEVEL>8
#define PRINT_STUPID(x...) printk( KERN_DEBUG PRINTK_HEADER x)
#else
#define PRINT_STUPID(x...)
#endif
static inline void
qeth_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr,
char *buf)
{
if (proto == QETH_PROT_IPV4)
return qeth_ipaddr4_to_string(addr, buf);
else if (proto == QETH_PROT_IPV6)
return qeth_ipaddr6_to_string(addr, buf);
}
#if QETH_VERBOSE_LEVEL>7
#define PRINT_ALL(x...) printk( KERN_DEBUG PRINTK_HEADER x)
#else
#define PRINT_ALL(x...)
#endif
static inline int
qeth_string_to_ipaddr(const char *buf, enum qeth_prot_versions proto,
__u8 *addr)
{
if (proto == QETH_PROT_IPV4)
return qeth_string_to_ipaddr4(buf, addr);
else if (proto == QETH_PROT_IPV6)
return qeth_string_to_ipaddr6(buf, addr);
else
return -EINVAL;
}
#if QETH_VERBOSE_LEVEL>6
#define PRINT_INFO(x...) printk( KERN_INFO PRINTK_HEADER x)
#else
#define PRINT_INFO(x...)
#endif
extern int
qeth_setrouting_v4(struct qeth_card *);
extern int
qeth_setrouting_v6(struct qeth_card *);
#if QETH_VERBOSE_LEVEL>5
#define PRINT_WARN(x...) printk( KERN_WARNING PRINTK_HEADER x)
#else
#define PRINT_WARN(x...)
#endif
int
qeth_add_ipato_entry(struct qeth_card *, struct qeth_ipato_entry *);
#if QETH_VERBOSE_LEVEL>4
#define PRINT_ERR(x...) printk( KERN_ERR PRINTK_HEADER x)
#else
#define PRINT_ERR(x...)
#endif
void
qeth_del_ipato_entry(struct qeth_card *, enum qeth_prot_versions, u8 *, int);
#if QETH_VERBOSE_LEVEL>3
#define PRINT_CRIT(x...) printk( KERN_CRIT PRINTK_HEADER x)
#else
#define PRINT_CRIT(x...)
#endif
int
qeth_add_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *);
#if QETH_VERBOSE_LEVEL>2
#define PRINT_ALERT(x...) printk( KERN_ALERT PRINTK_HEADER x)
#else
#define PRINT_ALERT(x...)
#endif
void
qeth_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *);
#if QETH_VERBOSE_LEVEL>1
#define PRINT_EMERG(x...) printk( KERN_EMERG PRINTK_HEADER x)
#else
#define PRINT_EMERG(x...)
#endif
int
qeth_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *);
#define 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));
void
qeth_del_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *);
void
qeth_schedule_recovery(struct qeth_card *);
#endif /* __QETH_H__ */
/*
* linux/drivers/s390/net/qeth_fs.h
*
* Linux on zSeries OSA Express and HiperSockets support.
*
* This header file contains definitions related to sysfs and procfs.
*
* Copyright 2000,2003 IBM Corporation
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
*
*/
#ifndef __QETH_FS_H__
#define __QETH_FS_H__
#ifdef CONFIG_PROC_FS
extern int
qeth_create_procfs_entries(void);
extern void
qeth_remove_procfs_entries(void);
#else
static inline int
qeth_create_procfs_entries(void)
{
return 0;
}
static inline void
qeth_remove_procfs_entries(void)
{
}
#endif /* CONFIG_PROC_FS */
extern int
qeth_create_device_attributes(struct device *dev);
extern void
qeth_remove_device_attributes(struct device *dev);
extern int
qeth_create_driver_attributes(void);
extern void
qeth_remove_driver_attributes(void);
/*
* utility functions used in qeth_proc.c and qeth_sys.c
*/
static inline const char *
qeth_get_checksum_str(struct qeth_card *card)
{
if (card->options.checksum_type == SW_CHECKSUMMING)
return "sw";
else if (card->options.checksum_type == HW_CHECKSUMMING)
return "hw";
else
return "no";
}
static inline const char *
qeth_get_prioq_str(struct qeth_card *card, char *buf)
{
if (card->qdio.do_prio_queueing == QETH_NO_PRIO_QUEUEING)
sprintf(buf, "always_q_%i", card->qdio.default_out_queue);
else
strcpy(buf, (card->qdio.do_prio_queueing ==
QETH_PRIO_Q_ING_PREC)?
"by_prec." : "by_ToS");
return buf;
}
static inline const char *
qeth_get_bufsize_str(struct qeth_card *card)
{
if (card->qdio.in_buf_size == 16384)
return "16k";
else if (card->qdio.in_buf_size == 24576)
return "24k";
else if (card->qdio.in_buf_size == 32768)
return "32k";
else if (card->qdio.in_buf_size == 40960)
return "40k";
else
return "64k";
}
static inline const char *
qeth_get_cardname(struct qeth_card *card)
{
if (card->info.guestlan) {
switch (card->info.type) {
case QETH_CARD_TYPE_OSAE:
return " Guest LAN QDIO";
case QETH_CARD_TYPE_IQD:
return " Guest LAN Hiper";
default:
return " unknown";
}
} else {
switch (card->info.type) {
case QETH_CARD_TYPE_OSAE:
return " OSD Express";
case QETH_CARD_TYPE_IQD:
return " HiperSockets";
default:
return " unknown";
}
}
return " n/a";
}
/* max length to be returned: 14 */
static inline const char *
qeth_get_cardname_short(struct qeth_card *card)
{
if (card->info.guestlan){
switch (card->info.type){
case QETH_CARD_TYPE_OSAE:
return "GuestLAN QDIO";
case QETH_CARD_TYPE_IQD:
return "GuestLAN Hiper";
default:
return "unknown";
}
} else {
switch (card->info.type) {
case QETH_CARD_TYPE_OSAE:
switch (card->info.link_type) {
case QETH_LINK_TYPE_FAST_ETH:
return "OSD_100";
case QETH_LINK_TYPE_HSTR:
return "HSTR";
case QETH_LINK_TYPE_GBIT_ETH:
return "OSD_1000";
case QETH_LINK_TYPE_LANE_ETH100:
return "OSD_FE_LANE";
case QETH_LINK_TYPE_LANE_TR:
return "OSD_TR_LANE";
case QETH_LINK_TYPE_LANE_ETH1000:
return "OSD_GbE_LANE";
case QETH_LINK_TYPE_LANE:
return "OSD_ATM_LANE";
default:
return "OSD_Express";
}
case QETH_CARD_TYPE_IQD:
return "HiperSockets";
default:
return "unknown";
}
}
return "n/a";
}
#endif /* __QETH_FS_H__ */
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -4,7 +4,8 @@
* Linux on zSeries OSA Express and HiperSockets support
*
* Copyright 2000,2003 IBM Corporation
* Author(s): Utz Bacher <utz.bacher@de.ibm.com>
* Author(s): Frank Pavlic <pavlic@de.ibm.com>
* Thomas Spatzier <tspat@de.ibm.com>
*
*/
#include <asm/cio.h>
......@@ -126,15 +127,21 @@ unsigned char DM_ACT[]={
unsigned char IPA_PDU_HEADER[]={
0x00,0xe0,0x00,0x00, 0x77,0x77,0x77,0x77,
0x00,0x00,0x00,0x14, 0x00,0x00,
(IPA_PDU_HEADER_SIZE+sizeof(struct ipa_cmd))/256,
(IPA_PDU_HEADER_SIZE+sizeof(struct ipa_cmd))%256,
(IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_cmd))/256,
(IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_cmd))%256,
0x10,0x00,0x00,0x01,
0x00,0x00,0x00,0x00,
0xc1,0x03,0x00,0x01, 0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00, 0x00,0x24,0x00,sizeof(struct ipa_cmd),
0x00,0x00,sizeof(struct ipa_cmd),0x05, 0x77,0x77,0x77,0x77,
0x00,0x00,0x00,0x00, 0x00,0x24,
sizeof(struct qeth_ipa_cmd)/256,
sizeof(struct qeth_ipa_cmd)%256,
0x00,
sizeof(struct qeth_ipa_cmd)/256,
sizeof(struct qeth_ipa_cmd),0x05, 0x77,0x77,0x77,0x77,
0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
0x01,0x00,sizeof(struct ipa_cmd)/256,sizeof(struct ipa_cmd)%256,
0x01,0x00,
sizeof(struct qeth_ipa_cmd)/256,
sizeof(struct qeth_ipa_cmd)%256,
0x00,0x00,0x00,0x40,
};
......@@ -158,4 +165,3 @@ unsigned char READ_CCW[]={
......@@ -5,346 +5,279 @@
*
* Copyright 2000,2003 IBM Corporation
* Author(s): Utz Bacher <utz.bacher@de.ibm.com>
* Thomas Spatzier <tspat@de.ibm.com>
* Frank Pavlic <pavlic@de.ibm.com>
*
*/
#ifndef __QETH_MPC_H__
#define __QETH_MPC_H__
#define VERSION_QETH_MPC_H "$Revision: 1.18 $"
#include <asm/qeth.h>
#define QETH_IPA_TIMEOUT (card->ipa_timeout)
#define QETH_MPC_TIMEOUT 2000
#define QETH_ADDR_TIMEOUT 1000
#define VERSION_QETH_MPC_H "$Revision: 1.27 $"
#define QETH_SETIP_RETRIES 2
#define IPA_PDU_HEADER_SIZE 0x40
#define QETH_IPA_PDU_LEN_TOTAL(buffer) (buffer+0x0e)
#define QETH_IPA_PDU_LEN_PDU1(buffer) (buffer+0x26)
#define QETH_IPA_PDU_LEN_PDU2(buffer) (buffer+0x2a)
#define QETH_IPA_PDU_LEN_PDU3(buffer) (buffer+0x3a)
#define IDX_ACTIVATE_SIZE 0x22
#define CM_ENABLE_SIZE 0x63
#define CM_SETUP_SIZE 0x64
#define ULP_ENABLE_SIZE 0x6b
#define ULP_SETUP_SIZE 0x6c
#define DM_ACT_SIZE 0x55
extern unsigned char IPA_PDU_HEADER[];
#define QETH_IPA_CMD_DEST_ADDR(buffer) (buffer+0x2c)
#define IPA_CMD_LENGTH (IPA_PDU_HEADER_SIZE + sizeof(struct qeth_ipa_cmd))
#define QETH_MPC_TOKEN_LENGTH 4
#define QETH_SEQ_NO_LENGTH 4
#define QETH_IPA_SEQ_NO_LENGTH 2
#define QETH_MPC_TOKEN_LENGTH 4
#define QETH_MCL_LENGTH 4
#define OSA_ADDR_LEN 6
#define QETH_TRANSPORT_HEADER_SEQ_NO(buffer) (buffer+4)
#define QETH_PDU_HEADER_SEQ_NO(buffer) (buffer+0x1c)
#define QETH_PDU_HEADER_ACK_SEQ_NO(buffer) (buffer+0x20)
#define QETH_TIMEOUT (10 * HZ)
#define QETH_IDX_COMMAND_SEQNO -1
#define SR_INFO_LEN 16
extern unsigned char IDX_ACTIVATE_READ[];
#define QETH_CLEAR_CHANNEL_PARM -10
#define QETH_HALT_CHANNEL_PARM -11
extern unsigned char IDX_ACTIVATE_WRITE[];
/*****************************************************************************/
/* IP Assist related definitions */
/*****************************************************************************/
#define IPA_CMD_INITIATOR_HOST 0x00
#define IPA_CMD_INITIATOR_HYDRA 0x01
#define IPA_CMD_PRIM_VERSION_NO 0x01
#define QETH_IDX_ACT_ISSUER_RM_TOKEN(buffer) (buffer+0x0c)
#define QETH_IDX_NO_PORTNAME_REQUIRED(buffer) ((buffer)[0x0b]&0x80)
#define QETH_IDX_ACT_FUNC_LEVEL(buffer) (buffer+0x10)
#define QETH_IDX_ACT_DATASET_NAME(buffer) (buffer+0x16)
#define QETH_IDX_ACT_QDIO_DEV_CUA(buffer) (buffer+0x1e)
#define QETH_IDX_ACT_QDIO_DEV_REALADDR(buffer) (buffer+0x20)
#define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08]&3)==2)
enum qeth_card_types {
QETH_CARD_TYPE_UNKNOWN = 0,
QETH_CARD_TYPE_OSAE = 10,
QETH_CARD_TYPE_IQD = 1234,
};
#define QETH_IDX_REPLY_LEVEL(buffer) (buffer+0x12)
#define QETH_MCL_LENGTH 4
#define QETH_MPC_DIFINFO_LEN_INDICATES_LINK_TYPE 0x18
/* only the first two bytes are looked at in qeth_get_cardname_short */
enum qeth_link_types {
QETH_LINK_TYPE_FAST_ETH = 0x01,
QETH_LINK_TYPE_HSTR = 0x02,
QETH_LINK_TYPE_GBIT_ETH = 0x03,
QETH_LINK_TYPE_10GBIT_ETH = 0x10,
QETH_LINK_TYPE_LANE_ETH100 = 0x81,
QETH_LINK_TYPE_LANE_TR = 0x82,
QETH_LINK_TYPE_LANE_ETH1000 = 0x83,
QETH_LINK_TYPE_LANE = 0x88,
QETH_LINK_TYPE_ATM_NATIVE = 0x90,
};
extern unsigned char CM_ENABLE[];
enum qeth_tr_macaddr_modes {
QETH_TR_MACADDR_NONCANONICAL = 0,
QETH_TR_MACADDR_CANONICAL = 1,
};
#define QETH_CM_ENABLE_ISSUER_RM_TOKEN(buffer) (buffer+0x2c)
#define QETH_CM_ENABLE_FILTER_TOKEN(buffer) (buffer+0x53)
#define QETH_CM_ENABLE_USER_DATA(buffer) (buffer+0x5b)
enum qeth_tr_broadcast_modes {
QETH_TR_BROADCAST_ALLRINGS = 0,
QETH_TR_BROADCAST_LOCAL = 1,
};
#define QETH_CM_ENABLE_RESP_FILTER_TOKEN(buffer) (PDU_ENCAPSULATION(buffer)+ \
0x13)
/* these values match CHECKSUM_* in include/linux/skbuff.h */
enum qeth_checksum_types {
SW_CHECKSUMMING = 0, /* TODO: set to bit flag used in IPA Command */
HW_CHECKSUMMING = 1,
NO_CHECKSUMMING = 2,
};
#define QETH_CHECKSUM_DEFAULT SW_CHECKSUMMING
extern unsigned char CM_SETUP[];
/*
* Routing stuff
*/
#define RESET_ROUTING_FLAG 0x10 /* indicate that routing type shall be set */
enum qeth_routing_types {
NO_ROUTER = 0, /* TODO: set to bit flag used in IPA Command */
PRIMARY_ROUTER = 1,
SECONDARY_ROUTER = 2,
MULTICAST_ROUTER = 3,
PRIMARY_CONNECTOR = 4,
SECONDARY_CONNECTOR = 5,
};
#define QETH_CM_SETUP_DEST_ADDR(buffer) (buffer+0x2c)
#define QETH_CM_SETUP_CONNECTION_TOKEN(buffer) (buffer+0x51)
#define QETH_CM_SETUP_FILTER_TOKEN(buffer) (buffer+0x5a)
#define QETH_CM_SETUP_RESP_DEST_ADDR(buffer) (PDU_ENCAPSULATION(buffer)+ \
0x1a)
/* IPA Commands */
enum qeth_ipa_cmds {
IPA_CMD_STARTLAN = 0x01,
IPA_CMD_STOPLAN = 0x02,
IPA_CMD_SETIP = 0xb1,
IPA_CMD_DELIP = 0xb7,
IPA_CMD_QIPASSIST = 0xb2,
IPA_CMD_SETASSPARMS = 0xb3,
IPA_CMD_SETIPM = 0xb4,
IPA_CMD_DELIPM = 0xb5,
IPA_CMD_SETRTG = 0xb6,
IPA_CMD_SETADAPTERPARMS = 0xb8,
IPA_CMD_IPFRAME = 0xb9,
IPA_CMD_ADD_ADDR_ENTRY = 0xc1,
IPA_CMD_DELETE_ADDR_ENTRY = 0xc2,
IPA_CMD_CREATE_ADDR = 0xc3,
IPA_CMD_DESTROY_ADDR = 0xc4,
IPA_CMD_REGISTER_LOCAL_ADDR = 0xd1,
IPA_CMD_UNREGISTER_LOCAL_ADDR = 0xd2,
};
extern unsigned char ULP_ENABLE[];
enum qeth_ip_ass_cmds {
IPA_CMD_ASS_START = 0x0001,
IPA_CMD_ASS_STOP = 0x0002,
IPA_CMD_ASS_CONFIGURE = 0x0003,
IPA_CMD_ASS_ENABLE = 0x0004,
};
#define QETH_ULP_ENABLE_LINKNUM(buffer) (buffer+0x61)
#define QETH_ULP_ENABLE_DEST_ADDR(buffer) (buffer+0x2c)
#define QETH_ULP_ENABLE_FILTER_TOKEN(buffer) (buffer+0x53)
#define QETH_ULP_ENABLE_PORTNAME_AND_LL(buffer) (buffer+0x62)
enum qeth_arp_process_subcmds {
IPA_CMD_ASS_ARP_SET_NO_ENTRIES = 0x0003,
IPA_CMD_ASS_ARP_QUERY_CACHE = 0x0004,
IPA_CMD_ASS_ARP_ADD_ENTRY = 0x0005,
IPA_CMD_ASS_ARP_REMOVE_ENTRY = 0x0006,
IPA_CMD_ASS_ARP_FLUSH_CACHE = 0x0007,
IPA_CMD_ASS_ARP_QUERY_INFO = 0x0104,
IPA_CMD_ASS_ARP_QUERY_STATS = 0x0204,
};
#define QETH_ULP_ENABLE_RESP_FILTER_TOKEN(buffer) (PDU_ENCAPSULATION(buffer)+ \
0x13)
#define QETH_ULP_ENABLE_RESP_MAX_MTU(buffer) (PDU_ENCAPSULATION(buffer)+ 0x1f)
#define QETH_ULP_ENABLE_RESP_DIFINFO_LEN(buffer) (PDU_ENCAPSULATION(buffer)+ \
0x17)
#define QETH_ULP_ENABLE_RESP_LINK_TYPE(buffer) (PDU_ENCAPSULATION(buffer)+ \
0x2b)
/* Return Codes for IPA Commands */
enum qeth_ipa_return_codes {
IPA_RC_SUCCESS = 0x0000,
IPA_RC_NOTSUPP = 0x0001,
IPA_RC_NO_ACCESS = 0x0002,
IPA_RC_FAILED = 0x0003,
IPA_RC_DATA_MISMATCH = 0xe001,
IPA_RC_INVALID_LAN_TYPE = 0xe003,
IPA_RC_INVALID_LAN_NO = 0xe004,
IPA_RC_IPADDR_ALREADY_REG = 0xe005,
IPA_RC_IPADDR_TABLE_FULL = 0xe006,
IPA_RC_IPADDR_ALREADY_USED = 0xe00a,
IPA_RC_ASSNO_NOT_SUPP = 0xe00d,
IPA_RC_ASSCMD_START_FAILED = 0xe00e,
IPA_RC_ASSCMD_PART_SUCCESS = 0xe00f,
IPA_RC_IPADDR_NOT_DEFINED = 0xe010,
IPA_RC_LAN_OFFLINE = 0xe080,
};
extern unsigned char ULP_SETUP[];
/* IPA function flags; each flag marks availability of respective function */
enum qeth_ipa_funcs {
IPA_ARP_PROCESSING = 0x00000001L,
IPA_INBOUND_CHECKSUM = 0x00000002L,
IPA_OUTBOUND_CHECKSUM = 0x00000004L,
IPA_IP_FRAGMENTATION = 0x00000008L,
IPA_FILTERING = 0x00000010L,
IPA_IPV6 = 0x00000020L,
IPA_MULTICASTING = 0x00000040L,
IPA_IP_REASSEMBLY = 0x00000080L,
IPA_QUERY_ARP_COUNTERS = 0x00000100L,
IPA_QUERY_ARP_ADDR_INFO = 0x00000200L,
IPA_SETADAPTERPARMS = 0x00000400L,
IPA_VLAN_PRIO = 0x00000800L,
IPA_PASSTHRU = 0x00001000L,
IPA_FULL_VLAN = 0x00004000L,
IPA_SOURCE_MAC = 0x00010000L,
IPA_OSA_MC_ROUTER = 0x00020000L,
};
#define QETH_ULP_SETUP_DEST_ADDR(buffer) (buffer+0x2c)
#define QETH_ULP_SETUP_CONNECTION_TOKEN(buffer) (buffer+0x51)
#define QETH_ULP_SETUP_FILTER_TOKEN(buffer) (buffer+0x5a)
#define QETH_ULP_SETUP_CUA(buffer) (buffer+0x68)
#define QETH_ULP_SETUP_REAL_DEVADDR(buffer) (buffer+0x6a)
/* SETIP/DELIP IPA Command: ***************************************************/
enum qeth_ipa_setdelip_flags {
QETH_IPA_SETDELIP_DEFAULT = 0x00L, /* default */
QETH_IPA_SETIP_VIPA_FLAG = 0x01L, /* no grat. ARP */
QETH_IPA_SETIP_TAKEOVER_FLAG = 0x02L, /* nofail on grat. ARP */
QETH_IPA_DELIP_ADDR_2_B_TAKEN_OVER = 0x20L,
QETH_IPA_DELIP_VIPA_FLAG = 0x40L,
QETH_IPA_DELIP_ADDR_NEEDS_SETIP = 0x80L,
};
#define QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(buffer) (PDU_ENCAPSULATION \
(buffer)+0x1a)
/* SETADAPTER IPA Command: ****************************************************/
enum qeth_ipa_setadp_cmd {
IPA_SETADP_QUERY_COMMANDS_SUPPORTED = 0x01,
IPA_SETADP_ALTER_MAC_ADDRESS = 0x02,
IPA_SETADP_ADD_DELETE_GROUP_ADDRESS = 0x04,
IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR = 0x08,
IPA_SETADP_SET_ADDRESSING_MODE = 0x10,
IPA_SETADP_SET_CONFIG_PARMS = 0x20,
IPA_SETADP_SET_CONFIG_PARMS_EXTENDED = 0x40,
IPA_SETADP_SET_BROADCAST_MODE = 0x80,
IPA_SETADP_SEND_OSA_MESSAGE = 0x0100,
IPA_SETADP_SET_SNMP_CONTROL = 0x0200,
IPA_SETADP_READ_SNMP_PARMS = 0x0400,
IPA_SETADP_WRITE_SNMP_PARMS = 0x0800,
IPA_SETADP_QUERY_CARD_INFO = 0x1000,
};
enum qeth_ipa_mac_ops {
CHANGE_ADDR_READ_MAC = 0,
CHANGE_ADDR_REPLACE_MAC = 1,
CHANGE_ADDR_ADD_MAC = 2,
CHANGE_ADDR_DEL_MAC = 4,
CHANGE_ADDR_RESET_MAC = 8,
};
enum qeth_ipa_addr_ops {
CHANGE_ADDR_READ_ADDR = 0,
CHANGE_ADDR_ADD_ADDR = 1,
CHANGE_ADDR_DEL_ADDR = 2,
CHANGE_ADDR_FLUSH_ADDR_TABLE = 4,
extern unsigned char DM_ACT[];
#define QETH_DM_ACT_DEST_ADDR(buffer) (buffer+0x2c)
#define QETH_DM_ACT_CONNECTION_TOKEN(buffer) (buffer+0x51)
};
/* (SET)DELIP(M) IPA stuff ***************************************************/
struct qeth_ipacmd_setdelip4 {
__u8 ip_addr[4];
__u8 mask[4];
__u32 flags;
} __attribute__ ((packed));
#define IPA_CMD_STARTLAN 0x01
#define IPA_CMD_STOPLAN 0x02
#define IPA_CMD_SETIP 0xb1
#define IPA_CMD_DELIP 0xb7
#define IPA_CMD_QIPASSIST 0xb2
#define IPA_CMD_SETASSPARMS 0xb3
#define IPA_CMD_SETIPM 0xb4
#define IPA_CMD_DELIPM 0xb5
#define IPA_CMD_SETRTG 0xb6
#define IPA_CMD_SETADAPTERPARMS 0xb8
#define IPA_CMD_ADD_ADDR_ENTRY 0xc1
#define IPA_CMD_DELETE_ADDR_ENTRY 0xc2
#define IPA_CMD_CREATE_ADDR 0xc3
#define IPA_CMD_DESTROY_ADDR 0xc4
#define IPA_CMD_REGISTER_LOCAL_ADDR 0xd1
#define IPA_CMD_UNREGISTER_LOCAL_ADDR 0xd2
#define INITIATOR_HOST 0
#define INITIATOR_HYDRA 1
#define PRIM_VERSION_IPA 1
#define PROT_VERSION_SNA 1 /* hahaha */
#define PROT_VERSION_IPv4 4
#define PROT_VERSION_IPv6 6
struct qeth_ipacmd_setdelip6 {
__u8 ip_addr[16];
__u8 mask[16];
__u32 flags;
} __attribute__ ((packed));
#define OSA_ADDR_LEN 6
#define IPA_SETADAPTERPARMS_IP_VERSION PROT_VERSION_IPv4
#define SR_INFO_LEN 16
struct qeth_ipacmd_setdelipm {
__u8 mac[6];
__u8 padding[2];
__u8 ip6[12];
__u8 ip4[4];
} __attribute__ ((packed));
#define IPA_ARP_PROCESSING 0x00000001L
#define IPA_INBOUND_CHECKSUM 0x00000002L
#define IPA_OUTBOUND_CHECKSUM 0x00000004L
#define IPA_IP_FRAGMENTATION 0x00000008L
#define IPA_FILTERING 0x00000010L
#define IPA_IPv6 0x00000020L
#define IPA_MULTICASTING 0x00000040L
#define IPA_IP_REASSEMBLY 0x00000080L
#define IPA_QUERY_ARP_COUNTERS 0x00000100L
#define IPA_QUERY_ARP_ADDR_INFO 0x00000200L
#define IPA_SETADAPTERPARMS 0x00000400L
#define IPA_VLAN_PRIO 0x00000800L
#define IPA_PASSTHRU 0x00001000L
#define IPA_FULL_VLAN 0x00004000L
#define IPA_SOURCE_MAC_AVAIL 0x00010000L
#define IPA_OSA_MC_ROUTER_AVAIL 0x00020000L
#define IPA_SETADP_QUERY_COMMANDS_SUPPORTED 0x01
#define IPA_SETADP_ALTER_MAC_ADDRESS 0x02
#define IPA_SETADP_ADD_DELETE_GROUP_ADDRESS 0x04
#define IPA_SETADP_ADD_DELETE_FUNCTIONAL_ADDR 0x08
#define IPA_SETADP_SET_ADDRESSING_MODE 0x10
#define IPA_SETADP_SET_CONFIG_PARMS 0x20
#define IPA_SETADP_SET_CONFIG_PARMS_EXTENDED 0x40
#define IPA_SETADP_SET_BROADCAST_MODE 0x80
#define IPA_SETADP_SEND_OSA_MESSAGE 0x0100
#define IPA_SETADP_SET_SNMP_CONTROL 0x0200
#define IPA_SETADP_READ_SNMP_PARMS 0x0400
#define IPA_SETADP_WRITE_SNMP_PARMS 0x0800
#define IPA_SETADP_QUERY_CARD_INFO 0x1000
#define CHANGE_ADDR_READ_MAC 0
#define CHANGE_ADDR_REPLACE_MAC 1
#define CHANGE_ADDR_ADD_MAC 2
#define CHANGE_ADDR_DEL_MAC 4
#define CHANGE_ADDR_RESET_MAC 8
#define CHANGE_ADDR_READ_ADDR 0
#define CHANGE_ADDR_ADD_ADDR 1
#define CHANGE_ADDR_DEL_ADDR 2
#define CHANGE_ADDR_FLUSH_ADDR_TABLE 4
/* we assumed, that the card is named card */
#define qeth_is_supported(str) (card->ipa_supported&str)
#define qeth_is_supported6(str) (card->ipa6_supported&str)
#define qeth_is_adp_supported(str) (card->adp_supported&str)
/* the same for all assist parms: */
#define IPA_CMD_ASS_START 0x0001
#define IPA_CMD_ASS_STOP 0x0002
#define IPA_CMD_ASS_CONFIGURE 0x0003
#define IPA_CMD_ASS_ENABLE 0x0004
#define IPA_CMD_ASS_ARP_SET_NO_ENTRIES 0x0003
#define IPA_CMD_ASS_ARP_QUERY_CACHE 0x0004
#define IPA_CMD_ASS_ARP_ADD_ENTRY 0x0005
#define IPA_CMD_ASS_ARP_REMOVE_ENTRY 0x0006
#define IPA_CMD_ASS_ARP_FLUSH_CACHE 0x0007
#define IPA_CMD_ASS_ARP_QUERY_INFO 0x0104
#define IPA_CMD_ASS_ARP_QUERY_STATS 0x0204
#define IPA_CHECKSUM_DEFAULT_ENABLE_MASK 0x001a
#define IPA_CMD_ASS_FILTER_SET_TYPES 0x0003
#define IPA_CMD_ASS_IPv6_SET_FUNCTIONS 0x0003
#define IPA_REPLY_SUCCESS 0
#define IPA_REPLY_FAILED 1
#define IPA_REPLY_OPNOTSUPP 2
#define IPA_REPLY_OPNOTSUPP2 4
#define IPA_REPLY_NOINFO 8
#define IPA_SETIP_FLAGS 0
#define IPA_SETIP_VIPA_FLAGS 1
#define IPA_SETIP_TAKEOVER_FLAGS 2
#define VIPA_2_B_ADDED 0
#define VIPA_ESTABLISHED 1
#define VIPA_2_B_REMOVED 2
#define IPA_DELIP_FLAGS 0
#define IPA_SETADP_CMDSIZE 40
struct ipa_setadp_cmd {
__u32 supp_hw_cmds;
__u32 reserved1;
__u16 cmdlength;
__u16 reserved2;
__u32 command_code;
struct qeth_ipacmd_setassparms_hdr {
__u32 assist_no;
__u16 length;
__u16 command_code;
__u16 return_code;
__u8 frames_used_total;
__u8 frame_seq_no;
__u32 reserved3;
__u8 number_of_replies;
__u8 seq_no;
} __attribute__((packed));
/* SETASSPARMS IPA Command: */
struct qeth_ipacmd_setassparms {
struct qeth_ipacmd_setassparms_hdr hdr;
union {
struct {
__u32 flags_32bit;
struct qeth_arp_cache_entry add_arp_entry;
__u8 ip[16];
} data;
} __attribute__ ((packed));
/* SETRTG IPA Command: ****************************************************/
struct qeth_set_routing {
__u8 type;
};
/* SETADAPTERPARMS IPA Command: *******************************************/
struct qeth_query_cmds_supp {
__u32 no_lantypes_supp;
__u8 lan_type;
__u8 reserved1[3];
__u32 supported_cmds;
__u8 reserved2[8];
} query_cmds_supp;
struct {
} __attribute__ ((packed));
struct qeth_change_addr {
__u32 cmd;
__u32 addr_size;
__u32 no_macs;
__u8 addr[OSA_ADDR_LEN];
} change_addr;
__u32 mode;
} data;
};
} __attribute__ ((packed));
struct ipa_cmd{
__u8 command;
__u8 initiator;
__u16 seq_no;
__u16 return_code;
__u8 adapter_type;
__u8 rel_adapter_no;
__u8 prim_version_no;
__u8 param_count;
__u16 prot_version;
__u32 ipa_supported;
__u32 ipa_enabled;
union {
struct {
__u8 ip[4];
__u8 netmask[4];
__u32 flags;
} setdelip4;
struct {
__u8 ip[16];
__u8 netmask[16];
__u32 flags;
} setdelip6;
struct {
__u32 assist_no;
__u16 length;
__u16 command_code;
__u16 return_code;
__u8 number_of_replies;
__u8 seq_no;
union {
__u32 flags_32bit;
struct {
__u8 mac[6];
__u8 reserved[2];
__u8 ip[16];
__u8 reserved2[32];
} add_arp_entry;
__u8 ip[16];
} data;
} setassparms;
struct {
__u8 mac[6];
__u8 padding[2];
__u8 ip6[12];
__u8 ip4_6[4];
} setdelipm;
struct {
__u8 type;
} setrtg;
struct ipa_setadp_cmd setadapterparms;
struct {
__u32 command;
#define ADDR_FRAME_TYPE_DIX 1
#define ADDR_FRAME_TYPE_802_3 2
#define ADDR_FRAME_TYPE_TR_WITHOUT_SR 0x10
#define ADDR_FRAME_TYPE_TR_WITH_SR 0x20
__u32 frame_type;
__u32 cmd_flags;
__u8 ip_addr[16];
__u32 tag_field;
__u8 mac_addr[6];
__u8 reserved[10];
__u32 sr_len;
__u8 sr_info[SR_INFO_LEN];
} add_addr_entry;
struct {
__u32 command;
__u32 cmd_flags;
__u8 ip_addr[16];
__u32 tag_field;
} delete_addr_entry;
struct {
__u8 unique_id[8];
} create_destroy_addr;
} data;
}__attribute__ ((packed));
#define QETH_IOC_MAGIC 0x22
/* these don't really have 'unsigned long' arguments but were defined that way */
#define QETH_IOCPROC_OSAEINTERFACES _IOWR(QETH_IOC_MAGIC, 1, unsigned long)
#define QETH_IOCPROC_INTERFACECHANGES _IOWR(QETH_IOC_MAGIC, 2, unsigned long)
#define SNMP_QUERY_CARD_INFO 0x00000002L
#define SNMP_REGISETER_MIB 0x00000004L
#define SNMP_GET_OID 0x00000010L
#define SNMP_SET_OID 0x00000011L
#define SNMP_GET_NEXT_OID 0x00000012L
#define SNMP_QUERY_ALERTS 0x00000020L
#define SNMP_SET_TRAP 0x00000021L
#define ARP_DATA_SIZE 3968
#define ARP_FLUSH -3
#define ARP_RETURNCODE_NOARPDATA -2
#define ARP_RETURNCODE_ERROR -1
#define ARP_RETURNCODE_SUCCESS 0
#define ARP_RETURNCODE_LASTREPLY 1
#define SNMP_BASE_CMDLENGTH 44
#define SNMP_SETADP_CMDLENGTH 16
#define SNMP_REQUEST_DATA_OFFSET 16
struct snmp_ipa_setadp_cmd {
struct qeth_ipacmd_setadpparms {
__u32 supp_hw_cmds;
__u32 reserved1;
__u16 cmdlength;
......@@ -354,24 +287,38 @@ struct snmp_ipa_setadp_cmd {
__u8 frames_used_total;
__u8 frame_seq_no;
__u32 reserved3;
__u8 snmp_token[16];
union {
struct {
__u32 snmp_request;
__u32 snmp_interface;
__u32 snmp_returncode;
__u32 snmp_firmwarelevel;
__u32 snmp_seqno;
__u8 snmp_data[ARP_DATA_SIZE];
} snmp_subcommand;
struct qeth_query_cmds_supp query_cmds_supp;
struct qeth_change_addr change_addr;
__u32 mode;
} data;
}__attribute__ ((packed));
} __attribute__ ((packed));
/* IPFRAME IPA Command: ***************************************************/
/* TODO: define in analogy to commands define above */
/* ADD_ADDR_ENTRY IPA Command: ********************************************/
/* TODO: define in analogy to commands define above */
/* DELETE_ADDR_ENTRY IPA Command: *****************************************/
/* TODO: define in analogy to commands define above */
/* CREATE_ADDR IPA Command: ***********************************************/
struct qeth_create_destroy_address {
__u8 unique_id[8];
} __attribute__ ((packed));
/* REGISTER_LOCAL_ADDR IPA Command: ***************************************/
/* TODO: define in analogy to commands define above */
/* UNREGISTER_LOCAL_ADDR IPA Command: *************************************/
/* TODO: define in analogy to commands define above */
struct arp_cmd {
/* Header for each IPA command */
struct qeth_ipacmd_hdr {
__u8 command;
__u8 initiator;
__u16 seq_no;
__u16 seqno;
__u16 return_code;
__u8 adapter_type;
__u8 rel_adapter_no;
......@@ -380,65 +327,158 @@ struct arp_cmd {
__u16 prot_version;
__u32 ipa_supported;
__u32 ipa_enabled;
} __attribute__ ((packed));
/* The IPA command itself */
struct qeth_ipa_cmd {
struct qeth_ipacmd_hdr hdr;
union {
struct {
__u32 assist_no;
__u16 length;
__u16 command_code;
__u16 return_code;
__u8 number_of_replies;
__u8 seq_no;
union {
struct {
__u16 tcpip_requestbitmask;
__u16 osa_setbitmask;
__u32 number_of_entries;
__u8 arp_data[ARP_DATA_SIZE];
} queryarp_data;
} data;
} setassparms;
struct snmp_ipa_setadp_cmd setadapterparms;
struct qeth_ipacmd_setdelip4 setdelip4;
struct qeth_ipacmd_setdelip6 setdelip6;
struct qeth_ipacmd_setdelipm setdelipm;
struct qeth_ipacmd_setassparms setassparms;
struct qeth_create_destroy_address create_destroy_addr;
struct qeth_ipacmd_setadpparms setadapterparms;
struct qeth_set_routing setrtg;
} data;
}__attribute__ ((packed));
} __attribute__ ((packed));
/*
* special command for ARP processing.
* this is not included in setassparms command before, because we get
* problem with the size of struct qeth_ipacmd_setassparms otherwise
*/
enum qeth_ipa_arp_return_codes {
QETH_IPA_ARP_RC_SUCCESS = 0x0000,
QETH_IPA_ARP_RC_FAILED = 0x0001,
QETH_IPA_ARP_RC_NOTSUPP = 0x0002,
QETH_IPA_ARP_RC_OUT_OF_RANGE = 0x0003,
QETH_IPA_ARP_RC_Q_NOTSUPP = 0x0004,
QETH_IPA_ARP_RC_Q_NO_DATA = 0x0008,
};
#define QETH_QARP_DATA_SIZE 3968
struct qeth_arp_query_data {
__u16 request_bits;
__u16 reply_bits;
__u32 no_entries;
char data[QETH_QARP_DATA_SIZE];
} __attribute__((packed));
/* used as parameter for arp_query reply */
struct qeth_arp_query_info {
__u32 udata_len;
__u32 udata_offset;
__u32 no_entries;
char *udata;
};
#define IPA_PDU_HEADER_SIZE 0x40
#define QETH_IPA_PDU_LEN_TOTAL(buffer) (buffer+0x0e)
#define QETH_IPA_PDU_LEN_PDU1(buffer) (buffer+0x26)
#define QETH_IPA_PDU_LEN_PDU2(buffer) (buffer+0x2a)
#define QETH_IPA_PDU_LEN_PDU3(buffer) (buffer+0x3a)
#define IPA_ARP_CMD_LEN (IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_arp_cmd))
#define QETH_ARP_CMD_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
sizeof(struct qeth_ipacmd_setassparms_hdr))
#define QETH_IPA_ARP_DATA_POS(buffer) (buffer + IPA_PDU_HEADER_SIZE + \
QETH_ARP_CMD_BASE_LEN)
struct qeth_ipa_arp_cmd {
struct qeth_ipacmd_hdr ihdr;
struct qeth_ipacmd_setassparms_hdr shdr;
union {
struct qeth_arp_query_data query_arp;
} data;
} __attribute__((packed));
extern unsigned char IPA_PDU_HEADER[];
#define QETH_IPA_CMD_DEST_ADDR(buffer) (buffer+0x2c)
/* Helper functions */
#define IS_IPA_REPLY(cmd) (cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST)
#define PDU_ENCAPSULATION(buffer) \
(buffer+ \
*(buffer+ (*(buffer+0x0b))+ *(buffer+*(buffer+0x0b)+0x11) +0x07))
/*****************************************************************************/
/* END OF IP Assist related definitions */
/*****************************************************************************/
#define IS_IPA(buffer) ((buffer) && ( *(buffer+ ((*(buffer+0x0b))+4) )==0xc1) )
#define IS_IPA_REPLY(buffer) ( (buffer) && ( (*(PDU_ENCAPSULATION(buffer)+1))==INITIATOR_HOST ) )
extern unsigned char WRITE_CCW[];
extern unsigned char READ_CCW[];
extern unsigned char CM_ENABLE[];
#define CM_ENABLE_SIZE 0x63
#define QETH_CM_ENABLE_ISSUER_RM_TOKEN(buffer) (buffer+0x2c)
#define QETH_CM_ENABLE_FILTER_TOKEN(buffer) (buffer+0x53)
#define QETH_CM_ENABLE_USER_DATA(buffer) (buffer+0x5b)
#define CCW_NOP_CMD 0x03
#define CCW_NOP_COUNT 1
#define QETH_CM_ENABLE_RESP_FILTER_TOKEN(buffer) \
(PDU_ENCAPSULATION(buffer)+ 0x13)
extern unsigned char WRITE_CCW[];
extern unsigned char READ_CCW[];
extern unsigned char CM_SETUP[];
#define CM_SETUP_SIZE 0x64
#define QETH_CM_SETUP_DEST_ADDR(buffer) (buffer+0x2c)
#define QETH_CM_SETUP_CONNECTION_TOKEN(buffer) (buffer+0x51)
#define QETH_CM_SETUP_FILTER_TOKEN(buffer) (buffer+0x5a)
#define QETH_CM_SETUP_RESP_DEST_ADDR(buffer) \
(PDU_ENCAPSULATION(buffer) + 0x1a)
#endif /* __QETH_MPC_H__ */
extern unsigned char ULP_ENABLE[];
#define ULP_ENABLE_SIZE 0x6b
#define QETH_ULP_ENABLE_LINKNUM(buffer) (buffer+0x61)
#define QETH_ULP_ENABLE_DEST_ADDR(buffer) (buffer+0x2c)
#define QETH_ULP_ENABLE_FILTER_TOKEN(buffer) (buffer+0x53)
#define QETH_ULP_ENABLE_PORTNAME_AND_LL(buffer) (buffer+0x62)
#define QETH_ULP_ENABLE_RESP_FILTER_TOKEN(buffer) \
(PDU_ENCAPSULATION(buffer) + 0x13)
#define QETH_ULP_ENABLE_RESP_MAX_MTU(buffer) \
(PDU_ENCAPSULATION(buffer)+ 0x1f)
#define QETH_ULP_ENABLE_RESP_DIFINFO_LEN(buffer) \
(PDU_ENCAPSULATION(buffer) + 0x17)
#define QETH_ULP_ENABLE_RESP_LINK_TYPE(buffer) \
(PDU_ENCAPSULATION(buffer)+ 0x2b)
extern unsigned char ULP_SETUP[];
#define ULP_SETUP_SIZE 0x6c
#define QETH_ULP_SETUP_DEST_ADDR(buffer) (buffer+0x2c)
#define QETH_ULP_SETUP_CONNECTION_TOKEN(buffer) (buffer+0x51)
#define QETH_ULP_SETUP_FILTER_TOKEN(buffer) (buffer+0x5a)
#define QETH_ULP_SETUP_CUA(buffer) (buffer+0x68)
#define QETH_ULP_SETUP_REAL_DEVADDR(buffer) (buffer+0x6a)
#define QETH_ULP_SETUP_RESP_CONNECTION_TOKEN(buffer) \
(PDU_ENCAPSULATION(buffer)+0x1a)
extern unsigned char DM_ACT[];
#define DM_ACT_SIZE 0x55
#define QETH_DM_ACT_DEST_ADDR(buffer) (buffer+0x2c)
#define QETH_DM_ACT_CONNECTION_TOKEN(buffer) (buffer+0x51)
#define QETH_TRANSPORT_HEADER_SEQ_NO(buffer) (buffer+4)
#define QETH_PDU_HEADER_SEQ_NO(buffer) (buffer+0x1c)
#define QETH_PDU_HEADER_ACK_SEQ_NO(buffer) (buffer+0x20)
extern unsigned char IDX_ACTIVATE_READ[];
extern unsigned char IDX_ACTIVATE_WRITE[];
#define IDX_ACTIVATE_SIZE 0x22
#define QETH_IDX_ACT_ISSUER_RM_TOKEN(buffer) (buffer+0x0c)
#define QETH_IDX_NO_PORTNAME_REQUIRED(buffer) ((buffer)[0x0b]&0x80)
#define QETH_IDX_ACT_FUNC_LEVEL(buffer) (buffer+0x10)
#define QETH_IDX_ACT_DATASET_NAME(buffer) (buffer+0x16)
#define QETH_IDX_ACT_QDIO_DEV_CUA(buffer) (buffer+0x1e)
#define QETH_IDX_ACT_QDIO_DEV_REALADDR(buffer) (buffer+0x20)
#define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08]&3)==2)
#define QETH_IDX_REPLY_LEVEL(buffer) (buffer+0x12)
#define PDU_ENCAPSULATION(buffer) \
(buffer + *(buffer + (*(buffer+0x0b)) + \
*(buffer + *(buffer+0x0b)+0x11) +0x07))
#define IS_IPA(buffer) \
((buffer) && \
( *(buffer + ((*(buffer+0x0b))+4) )==0xc1) )
#define ADDR_FRAME_TYPE_DIX 1
#define ADDR_FRAME_TYPE_802_3 2
#define ADDR_FRAME_TYPE_TR_WITHOUT_SR 0x10
#define ADDR_FRAME_TYPE_TR_WITH_SR 0x20
#endif
/*
*
* linux/drivers/s390/net/qeth_fs.c ($Revision: 1.5 $)
*
* Linux on zSeries OSA Express and HiperSockets support
* This file contains code related to procfs.
*
* Copyright 2000,2003 IBM Corporation
*
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/list.h>
#include <linux/rwsem.h>
#include "qeth.h"
#include "qeth_mpc.h"
#include "qeth_fs.h"
/***** /proc/qeth *****/
#define QETH_PROCFILE_NAME "qeth"
static struct proc_dir_entry *qeth_procfile;
static void *
qeth_procfile_seq_start(struct seq_file *s, loff_t *offset)
{
struct list_head *next_card = NULL;
int i = 0;
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
if (*offset == 0)
return SEQ_START_TOKEN;
/* get card at pos *offset */
list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices)
if (++i == *offset)
return next_card;
return NULL;
}
static void
qeth_procfile_seq_stop(struct seq_file *s, void* it)
{
up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
}
static void *
qeth_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
{
struct list_head *next_card = NULL;
struct list_head *current_card;
if (it == SEQ_START_TOKEN) {
next_card = qeth_ccwgroup_driver.driver.devices.next;
if (next_card->next == next_card) /* list empty */
return NULL;
(*offset)++;
} else {
current_card = (struct list_head *)it;
if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
return NULL; /* end of list reached */
next_card = current_card->next;
(*offset)++;
}
return next_card;
}
static inline const char *
qeth_get_router_str(struct qeth_card *card, int ipv)
{
int routing_type = 0;
if (ipv == 4){
routing_type = card->options.route4.type;
} else {
#ifdef CONFIG_QETH_IPV6
routing_type = card->options.route6.type;
#else
return "n/a";
#endif /* CONFIG_QETH_IPV6 */
}
if (routing_type == PRIMARY_ROUTER)
return "pri";
else if (routing_type == SECONDARY_ROUTER)
return "sec";
else if (routing_type == MULTICAST_ROUTER)
return "mc";
else if (routing_type == PRIMARY_CONNECTOR)
return "p.c";
else if (routing_type == SECONDARY_CONNECTOR)
return "s.c";
else if (routing_type == NO_ROUTER)
return "no";
else
return "unk";
}
static int
qeth_procfile_seq_show(struct seq_file *s, void *it)
{
struct device *device;
struct qeth_card *card;
char tmp[12]; /* for qeth_get_prioq_str */
if (it == SEQ_START_TOKEN){
seq_printf(s, "devices CHPID interface "
"cardtype port chksum prio-q'ing rtr4 "
"rtr6 fsz cnt\n");
seq_printf(s, "-------------------------- ----- ---------- "
"-------------- ---- ------ ---------- ---- "
"---- ----- -----\n");
} else {
device = list_entry(it, struct device, driver_list);
card = device->driver_data;
seq_printf(s, "%s/%s/%s x%02X %-10s %-14s %-4i ",
CARD_RDEV_ID(card),
CARD_WDEV_ID(card),
CARD_DDEV_ID(card),
card->info.chpid,
card->info.if_name,
qeth_get_cardname_short(card),
card->info.portno);
if (card->lan_online)
seq_printf(s, "%-6s %-10s %-4s %-4s %-5s %-5i\n",
qeth_get_checksum_str(card),
qeth_get_prioq_str(card, tmp),
qeth_get_router_str(card, 4),
qeth_get_router_str(card, 6),
qeth_get_bufsize_str(card),
card->qdio.in_buf_pool.buf_count);
else
seq_printf(s, " +++ LAN OFFLINE +++\n");
}
return 0;
}
static struct seq_operations qeth_procfile_seq_ops = {
.start = qeth_procfile_seq_start,
.stop = qeth_procfile_seq_stop,
.next = qeth_procfile_seq_next,
.show = qeth_procfile_seq_show,
};
static int
qeth_procfile_open(struct inode *inode, struct file *file)
{
return seq_open(file, &qeth_procfile_seq_ops);
}
static struct file_operations qeth_procfile_fops = {
.owner = THIS_MODULE,
.open = qeth_procfile_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
/***** /proc/qeth_perf *****/
#define QETH_PERF_PROCFILE_NAME "qeth_perf"
static struct proc_dir_entry *qeth_perf_procfile;
#ifdef CONFIG_QETH_PERF_STATS
static void *
qeth_perf_procfile_seq_start(struct seq_file *s, loff_t *offset)
{
struct list_head *next_card = NULL;
int i = 0;
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
/* get card at pos *offset */
list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){
if (i == *offset)
return next_card;
i++;
}
return NULL;
}
static void
qeth_perf_procfile_seq_stop(struct seq_file *s, void* it)
{
up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
}
static void *
qeth_perf_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
{
struct list_head *current_card = (struct list_head *)it;
if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
return NULL; /* end of list reached */
(*offset)++;
return current_card->next;
}
static int
qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
{
struct device *device;
struct qeth_card *card;
device = list_entry(it, struct device, driver_list);
card = device->driver_data;
seq_printf(s, "For card with devnos %s/%s/%s (%s):\n",
CARD_RDEV_ID(card),
CARD_WDEV_ID(card),
CARD_DDEV_ID(card),
card->info.if_name
);
seq_printf(s, " Skb's/buffers received : %li/%i\n"
" Skb's/buffers sent : %li/%i\n\n",
card->stats.rx_packets, card->perf_stats.bufs_rec,
card->stats.tx_packets, card->perf_stats.bufs_sent
);
seq_printf(s, " Skb's/buffers sent without packing : %li/%i\n"
" Skb's/buffers sent with packing : %i/%i\n\n",
card->stats.tx_packets - card->perf_stats.skbs_sent_pack,
card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack,
card->perf_stats.skbs_sent_pack,
card->perf_stats.bufs_sent_pack
);
seq_printf(s, " Packing state changes no pkg.->packing : %i/%i\n"
" Current buffer usage (outbound q's) : "
"%i/%i/%i/%i\n\n",
card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp,
atomic_read(&card->qdio.out_qs[0]->used_buffers),
(card->qdio.no_out_queues > 1)?
atomic_read(&card->qdio.out_qs[1]->used_buffers)
: 0,
(card->qdio.no_out_queues > 2)?
atomic_read(&card->qdio.out_qs[2]->used_buffers)
: 0,
(card->qdio.no_out_queues > 3)?
atomic_read(&card->qdio.out_qs[3]->used_buffers)
: 0
);
seq_printf(s, " Inbound time (in us) : %i\n"
" Inbound cnt : %i\n"
" Outbound time (in us, incl QDIO) : %i\n"
" Outbound cnt : %i\n"
" Watermarks L/H : %i/%i\n\n",
card->perf_stats.inbound_time,
card->perf_stats.inbound_cnt,
card->perf_stats.outbound_time,
card->perf_stats.outbound_cnt,
QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK
);
return 0;
}
static struct seq_operations qeth_perf_procfile_seq_ops = {
.start = qeth_perf_procfile_seq_start,
.stop = qeth_perf_procfile_seq_stop,
.next = qeth_perf_procfile_seq_next,
.show = qeth_perf_procfile_seq_show,
};
static int
qeth_perf_procfile_open(struct inode *inode, struct file *file)
{
return seq_open(file, &qeth_perf_procfile_seq_ops);
}
static struct file_operations qeth_perf_procfile_fops = {
.owner = THIS_MODULE,
.open = qeth_perf_procfile_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
#define qeth_perf_procfile_created qeth_perf_procfile
#else
#define qeth_perf_procfile_created 1
#endif /* CONFIG_QETH_PERF_STATS */
/***** /proc/qeth_ipa_takeover *****/
#define QETH_IPATO_PROCFILE_NAME "qeth_ipa_takeover"
static struct proc_dir_entry *qeth_ipato_procfile;
static void *
qeth_ipato_procfile_seq_start(struct seq_file *s, loff_t *offset)
{
struct list_head *next_card = NULL;
int i = 0;
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
/* TODO: finish this */
/*
* maybe SEQ_SATRT_TOKEN can be returned for offset 0
* output driver settings then;
* else output setting for respective card
*/
/* get card at pos *offset */
list_for_each(next_card, &qeth_ccwgroup_driver.driver.devices){
if (i == *offset)
return next_card;
i++;
}
return NULL;
}
static void
qeth_ipato_procfile_seq_stop(struct seq_file *s, void* it)
{
up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
}
static void *
qeth_ipato_procfile_seq_next(struct seq_file *s, void *it, loff_t *offset)
{
struct list_head *current_card = (struct list_head *)it;
/* TODO: finish this */
/*
* maybe SEQ_SATRT_TOKEN can be returned for offset 0
* output driver settings then;
* else output setting for respective card
*/
if (current_card->next == &qeth_ccwgroup_driver.driver.devices)
return NULL; /* end of list reached */
(*offset)++;
return current_card->next;
}
static int
qeth_ipato_procfile_seq_show(struct seq_file *s, void *it)
{
struct device *device;
struct qeth_card *card;
/* TODO: finish this */
/*
* maybe SEQ_SATRT_TOKEN can be returned for offset 0
* output driver settings then;
* else output setting for respective card
*/
device = list_entry(it, struct device, driver_list);
card = device->driver_data;
return 0;
}
static struct seq_operations qeth_ipato_procfile_seq_ops = {
.start = qeth_ipato_procfile_seq_start,
.stop = qeth_ipato_procfile_seq_stop,
.next = qeth_ipato_procfile_seq_next,
.show = qeth_ipato_procfile_seq_show,
};
static int
qeth_ipato_procfile_open(struct inode *inode, struct file *file)
{
return seq_open(file, &qeth_ipato_procfile_seq_ops);
}
static struct file_operations qeth_ipato_procfile_fops = {
.owner = THIS_MODULE,
.open = qeth_ipato_procfile_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
int __init
qeth_create_procfs_entries(void)
{
qeth_procfile = create_proc_entry(QETH_PROCFILE_NAME,
S_IFREG | 0444, NULL);
if (qeth_procfile)
qeth_procfile->proc_fops = &qeth_procfile_fops;
#ifdef CONFIG_QETH_PERF_STATS
qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME,
S_IFREG | 0444, NULL);
if (qeth_perf_procfile)
qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops;
#endif /* CONFIG_QETH_PERF_STATS */
qeth_ipato_procfile = create_proc_entry(QETH_IPATO_PROCFILE_NAME,
S_IFREG | 0444, NULL);
if (qeth_ipato_procfile)
qeth_ipato_procfile->proc_fops = &qeth_ipato_procfile_fops;
if (qeth_procfile &&
qeth_ipato_procfile &&
qeth_perf_procfile_created)
return 0;
else
return -ENOMEM;
}
void __exit
qeth_remove_procfs_entries(void)
{
if (qeth_procfile)
remove_proc_entry(QETH_PROCFILE_NAME, NULL);
if (qeth_perf_procfile)
remove_proc_entry(QETH_PERF_PROCFILE_NAME, NULL);
if (qeth_ipato_procfile)
remove_proc_entry(QETH_IPATO_PROCFILE_NAME, NULL);
}
/* ONLY FOR DEVELOPMENT! -> make it as module */
/*
static void
qeth_create_sysfs_entries(void)
{
struct device *dev;
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
driver_list)
qeth_create_device_attributes(dev);
up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
}
static void
qeth_remove_sysfs_entries(void)
{
struct device *dev;
down_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
list_for_each_entry(dev, &qeth_ccwgroup_driver.driver.devices,
driver_list)
qeth_remove_device_attributes(dev);
up_read(&qeth_ccwgroup_driver.driver.bus->subsys.rwsem);
}
static int __init
qeth_fs_init(void)
{
printk(KERN_INFO "qeth_fs_init\n");
qeth_create_procfs_entries();
qeth_create_sysfs_entries();
return 0;
}
static void __exit
qeth_fs_exit(void)
{
printk(KERN_INFO "qeth_fs_exit\n");
qeth_remove_procfs_entries();
qeth_remove_sysfs_entries();
}
module_init(qeth_fs_init);
module_exit(qeth_fs_exit);
MODULE_LICENSE("GPL");
*/
/*
*
* linux/drivers/s390/net/qeth_sys.c ($Revision: 1.19 $)
*
* Linux on zSeries OSA Express and HiperSockets support
* This file contains code related to sysfs.
*
* Copyright 2000,2003 IBM Corporation
*
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
* Frank Pavlic <pavlic@de.ibm.com>
*
*/
#include <linux/list.h>
#include <linux/rwsem.h>
#include <asm/ebcdic.h>
#include "qeth.h"
#include "qeth_mpc.h"
#include "qeth_fs.h"
/*****************************************************************************/
/* */
/* /sys-fs stuff UNDER DEVELOPMENT !!! */
/* */
/*****************************************************************************/
//low/high watermark
static ssize_t
qeth_dev_state_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
switch (card->state) {
case CARD_STATE_DOWN:
return sprintf(buf, "DOWN\n");
case CARD_STATE_HARDSETUP:
return sprintf(buf, "HARDSETUP\n");
case CARD_STATE_SOFTSETUP:
return sprintf(buf, "SOFTSETUP\n");
case CARD_STATE_UP_LAN_OFFLINE:
return sprintf(buf, "UP (LAN OFFLINE)\n");
case CARD_STATE_UP_LAN_ONLINE:
return sprintf(buf, "UP (LAN ONLINE)\n");
case CARD_STATE_RECOVER:
return sprintf(buf, "RECOVER\n");
default:
return sprintf(buf, "UNKNOWN\n");
}
}
static DEVICE_ATTR(state, 0444, qeth_dev_state_show, NULL);
static ssize_t
qeth_dev_chpid_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%02X\n", card->info.chpid);
}
static DEVICE_ATTR(chpid, 0444, qeth_dev_chpid_show, NULL);
static ssize_t
qeth_dev_if_name_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%s\n", card->info.if_name);
}
static DEVICE_ATTR(if_name, 0444, qeth_dev_if_name_show, NULL);
static ssize_t
qeth_dev_card_type_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%s\n", qeth_get_cardname_short(card));
}
static DEVICE_ATTR(card_type, 0444, qeth_dev_card_type_show, NULL);
static ssize_t
qeth_dev_portno_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->info.portno);
}
static ssize_t
qeth_dev_portno_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
unsigned int portno;
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
portno = simple_strtoul(buf, &tmp, 16);
if ((portno < 0) || (portno > MAX_PORTNO)){
PRINT_WARN("portno 0x%X is out of range\n", portno);
return -EINVAL;
}
card->info.portno = portno;
return count;
}
static DEVICE_ATTR(portno, 0644, qeth_dev_portno_show, qeth_dev_portno_store);
static ssize_t
qeth_dev_portname_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
char portname[9] = {0, };
if (!card)
return -EINVAL;
if (card->info.portname_required) {
memcpy(portname, card->info.portname + 1, 8);
EBCASC(portname, 8);
return sprintf(buf, "%s\n", portname);
} else
return sprintf(buf, "no portname required\n");
}
static ssize_t
qeth_dev_portname_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
int i;
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
tmp = strsep((char **) &buf, "\n");
if ((strlen(tmp) > 8) || (strlen(tmp) < 2))
return -EINVAL;
card->info.portname[0] = strlen(tmp);
/* for beauty reasons */
for (i = 1; i < 9; i++)
card->info.portname[i] = ' ';
strcpy(card->info.portname + 1, tmp);
ASCEBC(card->info.portname + 1, 8);
return count;
}
static DEVICE_ATTR(portname, 0644, qeth_dev_portname_show,
qeth_dev_portname_store);
static ssize_t
qeth_dev_checksum_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%s checksumming\n", qeth_get_checksum_str(card));
}
static ssize_t
qeth_dev_checksum_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "sw_checksumming"))
card->options.checksum_type = SW_CHECKSUMMING;
else if (!strcmp(tmp, "hw_checksumming"))
card->options.checksum_type = HW_CHECKSUMMING;
else if (!strcmp(tmp, "no_checksumming"))
card->options.checksum_type = NO_CHECKSUMMING;
else {
PRINT_WARN("Unknown checksumming type '%s'\n", tmp);
return -EINVAL;
}
return count;
}
static DEVICE_ATTR(checksumming, 0644, qeth_dev_checksum_show,
qeth_dev_checksum_store);
static ssize_t
qeth_dev_prioqing_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
switch (card->qdio.do_prio_queueing) {
case QETH_PRIO_Q_ING_PREC:
return sprintf(buf, "%s\n", "by precedence");
case QETH_PRIO_Q_ING_TOS:
return sprintf(buf, "%s\n", "by type of service");
default:
return sprintf(buf, "always queue %i\n",
card->qdio.default_out_queue);
}
}
static ssize_t
qeth_dev_prioqing_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "prio_queueing_prec"))
card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_PREC;
else if (!strcmp(tmp, "prio_queueing_tos"))
card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_TOS;
else if (!strcmp(tmp, "no_prio_queueing:0")) {
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = 0;
} else if (!strcmp(tmp, "no_prio_queueing:1")) {
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = 1;
} else if (!strcmp(tmp, "no_prio_queueing:2")) {
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = 2;
} else if (!strcmp(tmp, "no_prio_queueing:3")) {
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = 3;
} else if (!strcmp(tmp, "no_prio_queueing")) {
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
} else {
PRINT_WARN("Unknown queueing type '%s'\n", tmp);
return -EINVAL;
}
return count;
}
static DEVICE_ATTR(priority_queueing, 0644, qeth_dev_prioqing_show,
qeth_dev_prioqing_store);
static ssize_t
qeth_dev_bufcnt_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->qdio.in_buf_pool.buf_count);
}
static ssize_t
qeth_dev_bufcnt_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
unsigned int cnt;
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
cnt = simple_strtoul(buf, &tmp, 16);
cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN :
((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt);
card->qdio.in_buf_pool.buf_count = cnt;
/* TODO: steel/add buffers from/to a running card's buffer pool (?) */
return count;
}
static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show,
qeth_dev_bufcnt_store);
static inline ssize_t
qeth_dev_route_show(struct qeth_routing_info *route, char *buf)
{
switch (route->type) {
case PRIMARY_ROUTER:
return sprintf(buf, "%s\n", "primary router");
case SECONDARY_ROUTER:
return sprintf(buf, "%s\n", "secondary router");
case MULTICAST_ROUTER:
return sprintf(buf, "%s\n", "multicast router");
case PRIMARY_CONNECTOR:
return sprintf(buf, "%s\n", "primary connector");
case SECONDARY_CONNECTOR:
return sprintf(buf, "%s\n", "secondary connector");
default:
return sprintf(buf, "%s\n", "no");
}
}
static ssize_t
qeth_dev_route4_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_route_show(&card->options.route4, buf);
}
static inline ssize_t
qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route,
enum qeth_prot_versions prot, const char *buf, size_t count)
{
enum qeth_routing_types old_route_type = route->type;
char *tmp;
int rc;
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "no_router")){
route->type = NO_ROUTER;
goto check_reset;
}
if (card->info.type == QETH_CARD_TYPE_IQD) {
if (!strcmp(tmp, "primary_connector")) {
route->type = PRIMARY_CONNECTOR;
} else if (!strcmp(tmp, "secondary_connector")) {
route->type = SECONDARY_CONNECTOR;
} else if (!strcmp(tmp, "multicast_router")) {
route->type = MULTICAST_ROUTER;
} else
goto out_inval;
} else {
if (!strcmp(tmp, "primary_router")) {
route->type = PRIMARY_ROUTER;
} else if (!strcmp(tmp, "secondary_router")) {
route->type = SECONDARY_ROUTER;
} else if (!strcmp(tmp, "multicast_router")) {
if (qeth_is_ipafunc_supported(card, prot,
IPA_OSA_MC_ROUTER))
route->type = MULTICAST_ROUTER;
else
goto out_inval;
} else
goto out_inval;
}
check_reset:
if (old_route_type != route->type){
if (prot == QETH_PROT_IPV4)
rc = qeth_setrouting_v4(card);
else if (prot == QETH_PROT_IPV6)
rc = qeth_setrouting_v6(card);
}
return count;
out_inval:
PRINT_WARN("Routing type '%s' not supported for interface %s.\n"
"Router status not changed.\n",
tmp, card->info.if_name);
return -EINVAL;
}
static ssize_t
qeth_dev_route4_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_route_store(card, &card->options.route4,
QETH_PROT_IPV4, buf, count);
}
static DEVICE_ATTR(route4, 0644, qeth_dev_route4_show, qeth_dev_route4_store);
#ifdef CONFIG_QETH_IPV6
static ssize_t
qeth_dev_route6_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
if (!qeth_is_supported(card, IPA_IPV6))
return sprintf(buf, "%s\n", "n/a");
return qeth_dev_route_show(&card->options.route6, buf);
}
static ssize_t
qeth_dev_route6_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
if (!qeth_is_supported(card, IPA_IPV6)){
PRINT_WARN("IPv6 not supported for interface %s.\n"
"Routing status no changed.\n",
card->info.if_name);
return -ENOTSUPP;
}
return qeth_dev_route_store(card, &card->options.route6,
QETH_PROT_IPV6, buf, count);
}
static DEVICE_ATTR(route6, 0644, qeth_dev_route6_show, qeth_dev_route6_store);
#endif
static ssize_t
qeth_dev_add_hhlen_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->options.add_hhlen);
}
static ssize_t
qeth_dev_add_hhlen_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
int i;
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
i = simple_strtoul(buf, &tmp, 16);
if ((i < 0) || (i > MAX_ADD_HHLEN)) {
PRINT_WARN("add_hhlen out of range\n");
return -EINVAL;
}
card->options.add_hhlen = i;
return count;
}
static DEVICE_ATTR(add_hhlen, 0644, qeth_dev_add_hhlen_show,
qeth_dev_add_hhlen_store);
static ssize_t
qeth_dev_fake_ll_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->options.fake_ll? 1:0);
}
static ssize_t
qeth_dev_fake_ll_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
int i;
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
i = simple_strtoul(buf, &tmp, 16);
if ((i == 0) || (i == 1))
card->options.fake_ll = i;
else {
PRINT_WARN("fake_ll: write 0 or 1 to this file!\n");
return -EINVAL;
}
return count;
}
static DEVICE_ATTR(fake_ll, 0644, qeth_dev_fake_ll_show,
qeth_dev_fake_ll_store);
static ssize_t
qeth_dev_fake_broadcast_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->options.fake_broadcast? 1:0);
}
static ssize_t
qeth_dev_fake_broadcast_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
int i;
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
i = simple_strtoul(buf, &tmp, 16);
if ((i == 0) || (i == 1))
card->options.fake_broadcast = i;
else {
PRINT_WARN("fake_broadcast: write 0 or 1 to this file!\n");
return -EINVAL;
}
return count;
}
static DEVICE_ATTR(fake_broadcast, 0644, qeth_dev_fake_broadcast_show,
qeth_dev_fake_broadcast_store);
static ssize_t
qeth_dev_recover_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
int i;
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_UP_LAN_ONLINE) &&
(card->state != CARD_STATE_UP_LAN_OFFLINE))
return -EPERM;
i = simple_strtoul(buf, &tmp, 16);
if (i == 1)
qeth_schedule_recovery(card);
return count;
}
static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store);
/* TODO */
static ssize_t
qeth_dev_broadcast_mode_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
(card->info.link_type == QETH_LINK_TYPE_LANE_TR)))
return sprintf(buf, "n/a\n");
return sprintf(buf, "%s\n", (card->options.broadcast_mode ==
QETH_TR_BROADCAST_ALLRINGS)?
"all rings":"local");
}
/* TODO */
static ssize_t
qeth_dev_broadcast_mode_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
(card->info.link_type == QETH_LINK_TYPE_LANE_TR))){
PRINT_WARN("Device is not a tokenring device!\n");
return -EINVAL;
}
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "local")){
card->options.broadcast_mode = QETH_TR_BROADCAST_LOCAL;
return count;
} else if (!strcmp(tmp, "all_rings")) {
card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS;
return count;
} else {
PRINT_WARN("broadcast_mode: invalid mode %s!\n",
tmp);
return -EINVAL;
}
return count;
}
static DEVICE_ATTR(broadcast_mode, 0644, qeth_dev_broadcast_mode_show,
qeth_dev_broadcast_mode_store);
/* TODO */
static ssize_t
qeth_dev_canonical_macaddr_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
(card->info.link_type == QETH_LINK_TYPE_LANE_TR)))
return sprintf(buf, "n/a\n");
return sprintf(buf, "%i\n", (card->options.macaddr_mode ==
QETH_TR_MACADDR_CANONICAL)? 1:0);
}
/* TODO */
static ssize_t
qeth_dev_canonical_macaddr_store(struct device *dev, const char *buf,
size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
int i;
if (!card)
return -EINVAL;
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) ||
(card->info.link_type == QETH_LINK_TYPE_LANE_TR))){
PRINT_WARN("Device is not a tokenring device!\n");
return -EINVAL;
}
i = simple_strtoul(buf, &tmp, 16);
if ((i == 0) || (i == 1))
card->options.macaddr_mode = i?
QETH_TR_MACADDR_CANONICAL :
QETH_TR_MACADDR_NONCANONICAL;
else {
PRINT_WARN("canonical_macaddr: write 0 or 1 to this file!\n");
return -EINVAL;
}
return count;
}
static DEVICE_ATTR(canonical_macaddr, 0644, qeth_dev_canonical_macaddr_show,
qeth_dev_canonical_macaddr_store);
static struct device_attribute * qeth_device_attrs[] = {
&dev_attr_state,
&dev_attr_chpid,
&dev_attr_if_name,
&dev_attr_card_type,
&dev_attr_portno,
&dev_attr_portname,
&dev_attr_checksumming,
&dev_attr_priority_queueing,
&dev_attr_buffer_count,
&dev_attr_route4,
#ifdef CONFIG_QETH_IPV6
&dev_attr_route6,
#endif
&dev_attr_add_hhlen,
&dev_attr_fake_ll,
&dev_attr_fake_broadcast,
&dev_attr_recover,
&dev_attr_broadcast_mode,
&dev_attr_canonical_macaddr,
NULL,
};
static struct attribute_group qeth_device_attr_group = {
.attrs = (struct attribute **)qeth_device_attrs,
};
#define QETH_DEVICE_ATTR(_id,_name,_mode,_show,_store) \
struct device_attribute dev_attr_##_id = { \
.attr = {.name=__stringify(_name), .mode=_mode, .owner=THIS_MODULE },\
.show = _show, \
.store = _store, \
};
static ssize_t
qeth_dev_ipato_enable_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->ipato.enabled? 1:0);
}
static ssize_t
qeth_dev_ipato_enable_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
if (!card)
return -EINVAL;
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "toggle")){
card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
} else if (!strcmp(tmp, "1")){
card->ipato.enabled = 1;
} else if (!strcmp(tmp, "0")){
card->ipato.enabled = 0;
} else {
PRINT_WARN("ipato_enable: write 0, 1 or 'toggle' to "
"this file\n");
return -EINVAL;
}
return count;
}
static QETH_DEVICE_ATTR(ipato_enable, enable, 0644,
qeth_dev_ipato_enable_show,
qeth_dev_ipato_enable_store);
static ssize_t
qeth_dev_ipato_invert4_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->ipato.invert4? 1:0);
}
static ssize_t
qeth_dev_ipato_invert4_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
if (!card)
return -EINVAL;
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "toggle")){
card->ipato.invert4 = (card->ipato.invert4)? 0 : 1;
} else if (!strcmp(tmp, "1")){
card->ipato.invert4 = 1;
} else if (!strcmp(tmp, "0")){
card->ipato.invert4 = 0;
} else {
PRINT_WARN("ipato_invert4: write 0, 1 or 'toggle' to "
"this file\n");
return -EINVAL;
}
return count;
}
static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
qeth_dev_ipato_invert4_show,
qeth_dev_ipato_invert4_store);
static inline ssize_t
qeth_dev_ipato_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
struct qeth_ipato_entry *ipatoe;
unsigned long flags;
char addr_str[49];
int i = 0;
spin_lock_irqsave(&card->ip_lock, flags);
list_for_each_entry(ipatoe, &card->ipato.entries, entry){
if (ipatoe->proto != proto)
continue;
qeth_ipaddr_to_string(proto, ipatoe->addr, addr_str);
i += sprintf(buf + i, "%s/%i\n", addr_str, ipatoe->mask_bits);
}
spin_unlock_irqrestore(&card->ip_lock, flags);
i += sprintf(buf + i, "\n");
return i;
}
static ssize_t
qeth_dev_ipato_add4_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
}
static inline int
qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
u8 *addr, int *mask_bits)
{
const char *start, *end;
char *tmp;
char buffer[49] = {0, };
start = buf;
/* get address string */
end = strchr(start, '/');
if (!end){
PRINT_WARN("Invalid format for ipato_addx/delx. "
"Use <ip addr>/<mask bits>\n");
return -EINVAL;
}
strncpy(buffer, start, end - start);
if (qeth_string_to_ipaddr(buffer, proto, addr)){
PRINT_WARN("Invalid IP address format!\n");
return -EINVAL;
}
start = end + 1;
*mask_bits = simple_strtoul(start, &tmp, 10);
return 0;
}
static inline ssize_t
qeth_dev_ipato_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
struct qeth_ipato_entry *ipatoe;
u8 addr[16];
int mask_bits;
int rc;
if ((rc = qeth_parse_ipatoe(buf, proto, addr, &mask_bits)))
return rc;
if (!(ipatoe = kmalloc(sizeof(struct qeth_ipato_entry), GFP_KERNEL))){
PRINT_WARN("No memory to allocate ipato entry\n");
return -ENOMEM;
}
memset(ipatoe, 0, sizeof(struct qeth_ipato_entry));
ipatoe->proto = proto;
memcpy(ipatoe->addr, addr, (proto == QETH_PROT_IPV4)? 4:16);
ipatoe->mask_bits = mask_bits;
if ((rc = qeth_add_ipato_entry(card, ipatoe))){
kfree(ipatoe);
return rc;
}
return count;
}
static ssize_t
qeth_dev_ipato_add4_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV4);
}
static QETH_DEVICE_ATTR(ipato_add4, add4, 0644,
qeth_dev_ipato_add4_show,
qeth_dev_ipato_add4_store);
static inline ssize_t
qeth_dev_ipato_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
u8 addr[16];
int mask_bits;
int rc;
if ((rc = qeth_parse_ipatoe(buf, proto, addr, &mask_bits)))
return rc;
qeth_del_ipato_entry(card, proto, addr, mask_bits);
return count;
}
static ssize_t
qeth_dev_ipato_del4_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV4);
}
static QETH_DEVICE_ATTR(ipato_del4, del4, 0200, NULL,
qeth_dev_ipato_del4_store);
#ifdef CONFIG_QETH_IPV6
static ssize_t
qeth_dev_ipato_invert6_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return sprintf(buf, "%i\n", card->ipato.invert6? 1:0);
}
static ssize_t
qeth_dev_ipato_invert6_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
char *tmp;
if (!card)
return -EINVAL;
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "toggle")){
card->ipato.invert6 = (card->ipato.invert6)? 0 : 1;
} else if (!strcmp(tmp, "1")){
card->ipato.invert6 = 1;
} else if (!strcmp(tmp, "0")){
card->ipato.invert6 = 0;
} else {
PRINT_WARN("ipato_invert6: write 0, 1 or 'toggle' to "
"this file\n");
return -EINVAL;
}
return count;
}
static QETH_DEVICE_ATTR(ipato_invert6, invert6, 0644,
qeth_dev_ipato_invert6_show,
qeth_dev_ipato_invert6_store);
static ssize_t
qeth_dev_ipato_add6_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV6);
}
static ssize_t
qeth_dev_ipato_add6_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_ipato_add_store(buf, count, card, QETH_PROT_IPV6);
}
static QETH_DEVICE_ATTR(ipato_add6, add6, 0644,
qeth_dev_ipato_add6_show,
qeth_dev_ipato_add6_store);
static ssize_t
qeth_dev_ipato_del6_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_ipato_del_store(buf, count, card, QETH_PROT_IPV6);
}
static QETH_DEVICE_ATTR(ipato_del6, del6, 0200, NULL,
qeth_dev_ipato_del6_store);
#endif /* CONFIG_QETH_IPV6 */
static struct device_attribute * qeth_ipato_device_attrs[] = {
&dev_attr_ipato_enable,
&dev_attr_ipato_invert4,
&dev_attr_ipato_add4,
&dev_attr_ipato_del4,
#ifdef CONFIG_QETH_IPV6
&dev_attr_ipato_invert6,
&dev_attr_ipato_add6,
&dev_attr_ipato_del6,
#endif
NULL,
};
static struct attribute_group qeth_device_ipato_group = {
.name = "ipa_takeover",
.attrs = (struct attribute **)qeth_ipato_device_attrs,
};
static inline ssize_t
qeth_dev_vipa_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
struct qeth_ipaddr *ipaddr;
char addr_str[49];
unsigned long flags;
int i = 0;
spin_lock_irqsave(&card->ip_lock, flags);
list_for_each_entry(ipaddr, &card->ip_list, entry){
if (ipaddr->proto != proto)
continue;
if (ipaddr->type != QETH_IP_TYPE_VIPA)
continue;
qeth_ipaddr_to_string(proto, (const u8 *)&ipaddr->u, addr_str);
i += sprintf(buf + i, "%s\n", addr_str);
}
spin_unlock_irqrestore(&card->ip_lock, flags);
i += sprintf(buf + i, "\n");
return i;
}
static ssize_t
qeth_dev_vipa_add4_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
}
static inline int
qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto,
u8 *addr)
{
if (qeth_string_to_ipaddr(buf, proto, addr)){
PRINT_WARN("Invalid IP address format!\n");
return -EINVAL;
}
return 0;
}
static inline ssize_t
qeth_dev_vipa_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
u8 addr[16] = {0, };
int rc;
if ((rc = qeth_parse_vipae(buf, proto, addr)))
return rc;
if ((rc = qeth_add_vipa(card, proto, addr)))
return rc;
return count;
}
static ssize_t
qeth_dev_vipa_add4_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV4);
}
static QETH_DEVICE_ATTR(vipa_add4, add4, 0644,
qeth_dev_vipa_add4_show,
qeth_dev_vipa_add4_store);
static inline ssize_t
qeth_dev_vipa_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
u8 addr[16];
int rc;
if ((rc = qeth_parse_vipae(buf, proto, addr)))
return rc;
qeth_del_vipa(card, proto, addr);
return count;
}
static ssize_t
qeth_dev_vipa_del4_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV4);
}
static QETH_DEVICE_ATTR(vipa_del4, del4, 0200, NULL,
qeth_dev_vipa_del4_store);
#ifdef CONFIG_QETH_IPV6
static ssize_t
qeth_dev_vipa_add6_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV6);
}
static ssize_t
qeth_dev_vipa_add6_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_vipa_add_store(buf, count, card, QETH_PROT_IPV6);
}
static QETH_DEVICE_ATTR(vipa_add6, add6, 0644,
qeth_dev_vipa_add6_show,
qeth_dev_vipa_add6_store);
static ssize_t
qeth_dev_vipa_del6_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_vipa_del_store(buf, count, card, QETH_PROT_IPV6);
}
static QETH_DEVICE_ATTR(vipa_del6, del6, 0200, NULL,
qeth_dev_vipa_del6_store);
#endif /* CONFIG_QETH_IPV6 */
static struct device_attribute * qeth_vipa_device_attrs[] = {
&dev_attr_vipa_add4,
&dev_attr_vipa_del4,
#ifdef CONFIG_QETH_IPV6
&dev_attr_vipa_add6,
&dev_attr_vipa_del6,
#endif
NULL,
};
static struct attribute_group qeth_device_vipa_group = {
.name = "vipa",
.attrs = (struct attribute **)qeth_vipa_device_attrs,
};
static inline ssize_t
qeth_dev_rxip_add_show(char *buf, struct qeth_card *card,
enum qeth_prot_versions proto)
{
struct qeth_ipaddr *ipaddr;
char addr_str[49];
unsigned long flags;
int i = 0;
spin_lock_irqsave(&card->ip_lock, flags);
list_for_each_entry(ipaddr, &card->ip_list, entry){
if (ipaddr->proto != proto)
continue;
if (ipaddr->type != QETH_IP_TYPE_RXIP)
continue;
qeth_ipaddr_to_string(proto, (const u8 *)&ipaddr->u, addr_str);
i += sprintf(buf + i, "%s\n", addr_str);
}
spin_unlock_irqrestore(&card->ip_lock, flags);
i += sprintf(buf + i, "\n");
return i;
}
static ssize_t
qeth_dev_rxip_add4_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
}
static inline int
qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto,
u8 *addr)
{
if (qeth_string_to_ipaddr(buf, proto, addr)){
PRINT_WARN("Invalid IP address format!\n");
return -EINVAL;
}
return 0;
}
static inline ssize_t
qeth_dev_rxip_add_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
u8 addr[16] = {0, };
int rc;
if ((rc = qeth_parse_rxipe(buf, proto, addr)))
return rc;
if ((rc = qeth_add_rxip(card, proto, addr)))
return rc;
return count;
}
static ssize_t
qeth_dev_rxip_add4_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV4);
}
static QETH_DEVICE_ATTR(rxip_add4, add4, 0644,
qeth_dev_rxip_add4_show,
qeth_dev_rxip_add4_store);
static inline ssize_t
qeth_dev_rxip_del_store(const char *buf, size_t count,
struct qeth_card *card, enum qeth_prot_versions proto)
{
u8 addr[16];
int rc;
if ((rc = qeth_parse_rxipe(buf, proto, addr)))
return rc;
qeth_del_rxip(card, proto, addr);
return count;
}
static ssize_t
qeth_dev_rxip_del4_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV4);
}
static QETH_DEVICE_ATTR(rxip_del4, del4, 0200, NULL,
qeth_dev_rxip_del4_store);
#ifdef CONFIG_QETH_IPV6
static ssize_t
qeth_dev_rxip_add6_show(struct device *dev, char *buf)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV6);
}
static ssize_t
qeth_dev_rxip_add6_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_rxip_add_store(buf, count, card, QETH_PROT_IPV6);
}
static QETH_DEVICE_ATTR(rxip_add6, add6, 0644,
qeth_dev_rxip_add6_show,
qeth_dev_rxip_add6_store);
static ssize_t
qeth_dev_rxip_del6_store(struct device *dev, const char *buf, size_t count)
{
struct qeth_card *card = dev->driver_data;
if (!card)
return -EINVAL;
return qeth_dev_rxip_del_store(buf, count, card, QETH_PROT_IPV6);
}
static QETH_DEVICE_ATTR(rxip_del6, del6, 0200, NULL,
qeth_dev_rxip_del6_store);
#endif /* CONFIG_QETH_IPV6 */
static struct device_attribute * qeth_rxip_device_attrs[] = {
&dev_attr_rxip_add4,
&dev_attr_rxip_del4,
#ifdef CONFIG_QETH_IPV6
&dev_attr_rxip_add6,
&dev_attr_rxip_del6,
#endif
NULL,
};
static struct attribute_group qeth_device_rxip_group = {
.name = "rxip",
.attrs = (struct attribute **)qeth_rxip_device_attrs,
};
int
qeth_create_device_attributes(struct device *dev)
{
int ret;
if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_attr_group)))
return ret;
if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_ipato_group))){
sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
return ret;
}
if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_vipa_group))){
sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
return ret;
}
if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_rxip_group))){
sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
}
return ret;
}
void
qeth_remove_device_attributes(struct device *dev)
{
sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group);
}
/**********************/
/* DRIVER ATTRIBUTES */
/**********************/
static ssize_t
qeth_driver_group_store(struct device_driver *ddrv, const char *buf,
size_t count)
{
const char *start, *end;
char bus_ids[3][BUS_ID_SIZE], *argv[3];
int i;
int err;
start = buf;
for (i = 0; i < 3; i++) {
static const char delim[] = { ',', ',', '\n' };
int len;
if (!(end = strchr(start, delim[i])))
return -EINVAL;
len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start);
strncpy(bus_ids[i], start, len);
bus_ids[i][len] = '\0';
start = end + 1;
argv[i] = bus_ids[i];
}
err = ccwgroup_create(qeth_root_dev, qeth_ccwgroup_driver.driver_id,
&qeth_ccw_driver, 3, argv);
if (err)
return err;
else
return count;
}
static DRIVER_ATTR(group, 0200, 0, qeth_driver_group_store);
static ssize_t
qeth_driver_snmp_register_show(struct device_driver *ddrv, char *buf)
{
/* TODO */
return 0;
}
static ssize_t
qeth_driver_snmp_register_store(struct device_driver *ddrv, const char *buf,
size_t count)
{
/* TODO */
return count;
}
static DRIVER_ATTR(snmp_register, 0644, qeth_driver_snmp_register_show,
qeth_driver_snmp_register_store);
int
qeth_create_driver_attributes(void)
{
int rc;
if ((rc = driver_create_file(&qeth_ccwgroup_driver.driver,
&driver_attr_group)))
return rc;
return driver_create_file(&qeth_ccwgroup_driver.driver,
&driver_attr_snmp_register);
}
void
qeth_remove_driver_attributes(void)
{
driver_remove_file(&qeth_ccwgroup_driver.driver,
&driver_attr_group);
driver_remove_file(&qeth_ccwgroup_driver.driver,
&driver_attr_snmp_register);
}
/*
* include/asm-s390/qeth.h
*
* ioctl definitions for qeth driver
*
* Copyright (C) 2004 IBM Corporation
*
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
*
*/
#ifndef __ASM_S390_IOCTL_H__
#define __ASM_S390_IOCTL_H__
#include <linux/ioctl.h>
#define QETH_IOCTL_LETTER 'Q'
#define SIOC_QETH_ARP_SET_NO_ENTRIES _IOWR(QETH_IOCTL_LETTER, 1, int)
#define SIOC_QETH_ARP_QUERY_INFO _IOWR(QETH_IOCTL_LETTER, 2, int)
#define SIOC_QETH_ARP_ADD_ENTRY _IOWR(QETH_IOCTL_LETTER, 3, int)
#define SIOC_QETH_ARP_REMOVE_ENTRY _IOWR(QETH_IOCTL_LETTER, 4, int)
#define SIOC_QETH_ARP_FLUSH_CACHE _IOWR(QETH_IOCTL_LETTER, 5, int)
#define SIOC_QETH_ADP_SET_SNMP_CONTROL _IOWR(QETH_IOCTL_LETTER, 6, int)
#define SIOC_QETH_GET_CARD_TYPE _IOWR(QETH_IOCTL_LETTER, 7, int)
struct qeth_arp_cache_entry {
__u8 macaddr[6];
__u8 reserved1[2];
__u8 ipaddr[16]; /* for both IPv4 and IPv6 */
__u8 reserved2[32];
} __attribute__ ((packed));
struct qeth_arp_qi_entry7 {
__u8 media_specific[32];
__u8 macaddr_type;
__u8 ipaddr_type;
__u8 macaddr[6];
__u8 ipaddr[4];
} __attribute__((packed));
struct qeth_arp_qi_entry5 {
__u8 media_specific[32];
__u8 macaddr_type;
__u8 ipaddr_type;
__u8 ipaddr[4];
} __attribute__((packed));
/* data sent to user space as result of query arp ioctl */
#define QETH_QARP_USER_DATA_SIZE 20000
#define QETH_QARP_MASK_OFFSET 4
#define QETH_QARP_ENTRIES_OFFSET 6
struct qeth_arp_query_user_data {
union {
__u32 data_len; /* set by user space program */
__u32 no_entries; /* set by kernel */
} u;
__u16 mask_bits;
char *entries;
} __attribute__((packed));
#endif /* __ASM_S390_IOCTL_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment