Commit 2c81f2e4 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] s390: network driver

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

Network driver changes:
 - iucv: Make grab_param function SMP safe.
 - lcs: Fix null-pointer dereference after unsuccessful set_online.
 - qeth: Fix kmalloc flags in qeth_alloc_reply.
 - qeth: Show broadcase capability also in route4/6 sysfs attributes.
 - qeth: Remove debug code.
 - qeth: Add option to qetharp user space interface to strip unused
         fields from query arp records.
 - qeth: Add shortcut in outbound path for HiperSockets.
 - qeth: Add more info to qeth_perf_stats.
 - qeth: Add support for direct SNMP interface to OSA express cards.
parent b874ee07
/* /*
* $Id: iucv.c,v 1.30 2004/05/13 09:21:23 braunu Exp $ * $Id: iucv.c,v 1.32 2004/05/18 09:28:43 braunu Exp $
* *
* IUCV network driver * IUCV network driver
* *
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
* RELEASE-TAG: IUCV lowlevel driver $Revision: 1.30 $ * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.32 $
* *
*/ */
...@@ -285,6 +285,7 @@ typedef struct { ...@@ -285,6 +285,7 @@ typedef struct {
iparml_set_mask p_set_mask; iparml_set_mask p_set_mask;
} param; } param;
atomic_t in_use; atomic_t in_use;
__u32 res;
} __attribute__ ((aligned(8))) iucv_param; } __attribute__ ((aligned(8))) iucv_param;
#define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param)) #define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param))
...@@ -351,7 +352,7 @@ do { \ ...@@ -351,7 +352,7 @@ do { \
static void static void
iucv_banner(void) iucv_banner(void)
{ {
char vbuf[] = "$Revision: 1.30 $"; char vbuf[] = "$Revision: 1.32 $";
char *version = vbuf; char *version = vbuf;
if ((version = strchr(version, ':'))) { if ((version = strchr(version, ':'))) {
...@@ -469,17 +470,19 @@ iucv_exit(void) ...@@ -469,17 +470,19 @@ iucv_exit(void)
static __inline__ iucv_param * static __inline__ iucv_param *
grab_param(void) grab_param(void)
{ {
iucv_param *ret; iucv_param *ptr;
static int i = 0; static int hint = 0;
while (atomic_compare_and_swap(0, 1, &iucv_param_pool[i].in_use)) { ptr = iucv_param_pool + hint;
i++; do {
if (i >= PARAM_POOL_SIZE) ptr++;
i = 0; if (ptr >= iucv_param_pool + PARAM_POOL_SIZE)
} ptr = iucv_param_pool;
ret = &iucv_param_pool[i]; } while (atomic_compare_and_swap(0, 1, &ptr->in_use));
memset(&ret->param, 0, sizeof(ret->param)); hint = ptr - iucv_param_pool;
return ret;
memset(&ptr->param, 0, sizeof(ptr->param));
return ptr;
} }
/** /**
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and * Frank Pavlic (pavlic@de.ibm.com) and
* Martin Schwidefsky <schwidefsky@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com>
* *
* $Revision: 1.80 $ $Date: 2004/05/13 08:22:06 $ * $Revision: 1.81 $ $Date: 2004/05/14 13:54:33 $
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
/** /**
* initialization string for output * initialization string for output
*/ */
#define VERSION_LCS_C "$Revision: 1.80 $" #define VERSION_LCS_C "$Revision: 1.81 $"
static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")"; static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
static char debug_buffer[255]; static char debug_buffer[255];
...@@ -1898,8 +1898,10 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) ...@@ -1898,8 +1898,10 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
lcs_setup_card(card); lcs_setup_card(card);
rc = lcs_detect(card); rc = lcs_detect(card);
if (rc) { if (rc) {
LCS_DBF_TEXT(2, setup, "dtctfail");
PRINT_WARN("Detection of LCS card failed with return code "
"%d (0x%x)\n", rc, rc);
lcs_stopcard(card); lcs_stopcard(card);
lcs_cleanup_card(card);
goto out; goto out;
} }
if (card->dev) { if (card->dev) {
...@@ -1962,7 +1964,6 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) ...@@ -1962,7 +1964,6 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
ccw_device_set_offline(card->read.ccwdev); ccw_device_set_offline(card->read.ccwdev);
ccw_device_set_offline(card->write.ccwdev); ccw_device_set_offline(card->write.ccwdev);
lcs_cleanup_card(card);
return -ENODEV; return -ENODEV;
} }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "qeth_mpc.h" #include "qeth_mpc.h"
#define VERSION_QETH_H "$Revision: 1.107 $" #define VERSION_QETH_H "$Revision: 1.108 $"
#ifdef CONFIG_QETH_IPV6 #ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6" #define QETH_VERSION_IPV6 ":IPv6"
...@@ -179,15 +179,26 @@ struct qeth_perf_stats { ...@@ -179,15 +179,26 @@ struct qeth_perf_stats {
unsigned int sc_dp_p; unsigned int sc_dp_p;
unsigned int sc_p_dp; unsigned int sc_p_dp;
/* qdio_input_handler: number of times called, time spent in */
__u64 inbound_start_time; __u64 inbound_start_time;
unsigned int inbound_cnt; unsigned int inbound_cnt;
unsigned int inbound_time; unsigned int inbound_time;
/* qeth_send_packet: number of times called, time spent in */
__u64 outbound_start_time; __u64 outbound_start_time;
unsigned int outbound_cnt; unsigned int outbound_cnt;
unsigned int outbound_time; unsigned int outbound_time;
unsigned int inbound_do_qdio; /* qdio_output_handler: number of times called, time spent in */
unsigned int outbound_do_qdio; __u64 outbound_handler_start_time;
unsigned int outbound_handler_cnt;
unsigned int outbound_handler_time;
/* number of calls to and time spent in do_QDIO for inbound queue */
__u64 inbound_do_qdio_start_time;
unsigned int inbound_do_qdio_cnt;
unsigned int inbound_do_qdio_time;
/* number of calls to and time spent in do_QDIO for outbound queues */
__u64 outbound_do_qdio_start_time;
unsigned int outbound_do_qdio_cnt;
unsigned int outbound_do_qdio_time;
}; };
#endif /* CONFIG_QETH_PERF_STATS */ #endif /* CONFIG_QETH_PERF_STATS */
...@@ -714,6 +725,15 @@ struct qeth_card_list_struct { ...@@ -714,6 +725,15 @@ struct qeth_card_list_struct {
extern struct qeth_card_list_struct qeth_card_list; extern struct qeth_card_list_struct qeth_card_list;
/*notifier list */
struct qeth_notify_list_struct {
struct list_head list;
struct task_struct *task;
int signum;
};
extern spinlock_t qeth_notify_lock;
extern struct list_head qeth_notify_list;
/*some helper functions*/ /*some helper functions*/
inline static __u8 inline static __u8
...@@ -997,6 +1017,12 @@ qeth_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *); ...@@ -997,6 +1017,12 @@ qeth_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *);
extern void extern void
qeth_del_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *); qeth_del_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *);
extern int
qeth_notifier_register(struct task_struct *, int );
extern int
qeth_notifier_unregister(struct task_struct * );
extern void extern void
qeth_schedule_recovery(struct qeth_card *); qeth_schedule_recovery(struct qeth_card *);
......
/* /*
* *
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.107 $) * linux/drivers/s390/net/qeth_main.c ($Revision: 1.112 $)
* *
* Linux on zSeries OSA Express and HiperSockets support * Linux on zSeries OSA Express and HiperSockets support
* *
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and * Frank Pavlic (pavlic@de.ibm.com) and
* Thomas Spatzier <tspat@de.ibm.com> * Thomas Spatzier <tspat@de.ibm.com>
* *
* $Revision: 1.107 $ $Date: 2004/05/13 16:07:59 $ * $Revision: 1.112 $ $Date: 2004/05/19 09:28:21 $
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -78,7 +78,7 @@ qeth_eyecatcher(void) ...@@ -78,7 +78,7 @@ qeth_eyecatcher(void)
#include "qeth_mpc.h" #include "qeth_mpc.h"
#include "qeth_fs.h" #include "qeth_fs.h"
#define VERSION_QETH_C "$Revision: 1.107 $" #define VERSION_QETH_C "$Revision: 1.112 $"
static const char *version = "qeth S/390 OSA-Express driver"; static const char *version = "qeth S/390 OSA-Express driver";
/** /**
...@@ -100,6 +100,9 @@ static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY; ...@@ -100,6 +100,9 @@ static unsigned int known_devices[][10] = QETH_MODELLIST_ARRAY;
/* list of our cards */ /* list of our cards */
struct qeth_card_list_struct qeth_card_list; struct qeth_card_list_struct qeth_card_list;
/*process list want to be notified*/
spinlock_t qeth_notify_lock;
struct list_head qeth_notify_list;
static void qeth_send_control_data_cb(struct qeth_channel *, static void qeth_send_control_data_cb(struct qeth_channel *,
struct qeth_cmd_buffer *); struct qeth_cmd_buffer *);
...@@ -155,6 +158,68 @@ qeth_set_online(struct ccwgroup_device *); ...@@ -155,6 +158,68 @@ qeth_set_online(struct ccwgroup_device *);
static struct qeth_ipaddr * static struct qeth_ipaddr *
qeth_get_addr_buffer(enum qeth_prot_versions); qeth_get_addr_buffer(enum qeth_prot_versions);
static void
qeth_notify_processes(void)
{
/*notify all registered processes */
struct qeth_notify_list_struct *n_entry;
QETH_DBF_TEXT(trace,3,"procnoti");
spin_lock(&qeth_notify_lock);
list_for_each_entry(n_entry, &qeth_notify_list, list) {
send_sig(n_entry->signum, n_entry->task, 1);
}
spin_unlock(&qeth_notify_lock);
}
int
qeth_notifier_unregister(struct task_struct *p)
{
struct qeth_notify_list_struct *n_entry, *tmp;
QETH_DBF_TEXT(trace, 2, "notunreg");
spin_lock(&qeth_notify_lock);
list_for_each_entry_safe(n_entry, tmp, &qeth_notify_list, list) {
if (n_entry->task == p) {
list_del(&n_entry->list);
kfree(n_entry);
goto out;
}
}
out:
spin_unlock(&qeth_notify_lock);
return 0;
}
int
qeth_notifier_register(struct task_struct *p, int signum)
{
struct qeth_notify_list_struct *n_entry;
QETH_DBF_TEXT(trace, 2, "notreg");
/*check first if entry already exists*/
spin_lock(&qeth_notify_lock);
list_for_each_entry(n_entry, &qeth_notify_list, list) {
if (n_entry->task == p) {
n_entry->signum = signum;
spin_unlock(&qeth_notify_lock);
return 0;
}
}
spin_unlock(&qeth_notify_lock);
n_entry = (struct qeth_notify_list_struct *)
kmalloc(sizeof(struct qeth_notify_list_struct),GFP_KERNEL);
if (!n_entry)
return -ENOMEM;
n_entry->task = p;
n_entry->signum = signum;
spin_lock(&qeth_notify_lock);
list_add(&n_entry->list,&qeth_notify_list);
spin_unlock(&qeth_notify_lock);
return 0;
}
/** /**
* free channel command buffers * free channel command buffers
*/ */
...@@ -460,6 +525,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev) ...@@ -460,6 +525,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
ccw_device_set_offline(CARD_RDEV(card)); ccw_device_set_offline(CARD_RDEV(card));
if (recover_flag == CARD_STATE_UP) if (recover_flag == CARD_STATE_UP)
card->state = CARD_STATE_RECOVER; card->state = CARD_STATE_RECOVER;
qeth_notify_processes();
return 0; return 0;
} }
...@@ -1447,7 +1513,7 @@ qeth_alloc_reply(struct qeth_card *card) ...@@ -1447,7 +1513,7 @@ qeth_alloc_reply(struct qeth_card *card)
{ {
struct qeth_reply *reply; struct qeth_reply *reply;
reply = kmalloc(sizeof(struct qeth_reply), GFP_KERNEL|GFP_ATOMIC); reply = kmalloc(sizeof(struct qeth_reply), GFP_ATOMIC);
if (reply){ if (reply){
memset(reply, 0, sizeof(struct qeth_reply)); memset(reply, 0, sizeof(struct qeth_reply));
atomic_set(&reply->refcnt, 1); atomic_set(&reply->refcnt, 1);
...@@ -1631,7 +1697,7 @@ qeth_send_control_data_cb(struct qeth_channel *channel, ...@@ -1631,7 +1697,7 @@ qeth_send_control_data_cb(struct qeth_channel *channel,
(unsigned long)iob); (unsigned long)iob);
} }
if (cmd) if (cmd)
reply->rc = cmd->hdr.return_code; reply->rc = (s16) cmd->hdr.return_code;
else if (iob->rc) else if (iob->rc)
reply->rc = iob->rc; reply->rc = iob->rc;
if (keep_reply) { if (keep_reply) {
...@@ -2222,9 +2288,6 @@ qeth_process_inbound_buffer(struct qeth_card *card, ...@@ -2222,9 +2288,6 @@ qeth_process_inbound_buffer(struct qeth_card *card,
while((skb = qeth_get_next_skb(card, buf->buffer, &element, while((skb = qeth_get_next_skb(card, buf->buffer, &element,
&offset, &hdr))){ &offset, &hdr))){
qeth_rebuild_skb(card, skb, hdr); qeth_rebuild_skb(card, skb, hdr);
if (((*(int *)0xff0)==1) &&
(skb->pkt_type == PACKET_BROADCAST))
qeth_hex_dump(skb->data, 100);
/* is device UP ? */ /* is device UP ? */
if (!(card->dev->flags & IFF_UP)){ if (!(card->dev->flags & IFF_UP)){
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
...@@ -2328,11 +2391,16 @@ qeth_queue_input_buffer(struct qeth_card *card, int index) ...@@ -2328,11 +2391,16 @@ qeth_queue_input_buffer(struct qeth_card *card, int index)
* will be requeued the next time * will be requeued the next time
*/ */
#ifdef CONFIG_QETH_PERF_STATS #ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.inbound_do_qdio++; card->perf_stats.inbound_do_qdio_cnt++;
card->perf_stats.inbound_do_qdio_start_time = qeth_get_micros();
#endif #endif
rc = do_QDIO(CARD_DDEV(card), rc = do_QDIO(CARD_DDEV(card),
QDIO_FLAG_SYNC_INPUT, QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT,
0, queue->next_buf_to_init, count, NULL); 0, queue->next_buf_to_init, count, NULL);
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.inbound_do_qdio_time += qeth_get_micros() -
card->perf_stats.inbound_do_qdio_start_time;
#endif
if (rc){ if (rc){
PRINT_WARN("qeth_queue_input_buffer's do_QDIO " PRINT_WARN("qeth_queue_input_buffer's do_QDIO "
"return %i (device %s).\n", "return %i (device %s).\n",
...@@ -2454,6 +2522,9 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, ...@@ -2454,6 +2522,9 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
buf->buffer->element[buf->next_element_to_fill - 1].flags |= buf->buffer->element[buf->next_element_to_fill - 1].flags |=
SBAL_FLAGS_LAST_ENTRY; SBAL_FLAGS_LAST_ENTRY;
if (queue->card->info.type == QETH_CARD_TYPE_IQD)
continue;
if (!queue->do_pack){ if (!queue->do_pack){
if ((atomic_read(&queue->used_buffers) >= if ((atomic_read(&queue->used_buffers) >=
(QETH_HIGH_WATERMARK_PACK - (QETH_HIGH_WATERMARK_PACK -
...@@ -2485,7 +2556,8 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, ...@@ -2485,7 +2556,8 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
queue->card->dev->trans_start = jiffies; queue->card->dev->trans_start = jiffies;
#ifdef CONFIG_QETH_PERF_STATS #ifdef CONFIG_QETH_PERF_STATS
queue->card->perf_stats.outbound_do_qdio++; queue->card->perf_stats.outbound_do_qdio_cnt++;
queue->card->perf_stats.outbound_do_qdio_start_time = qeth_get_micros();
#endif #endif
if (under_int) if (under_int)
rc = do_QDIO(CARD_DDEV(queue->card), rc = do_QDIO(CARD_DDEV(queue->card),
...@@ -2494,6 +2566,10 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, ...@@ -2494,6 +2566,10 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
else else
rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT, rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT,
queue->queue_no, index, count, NULL); queue->queue_no, index, count, NULL);
#ifdef CONFIG_QETH_PERF_STATS
queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() -
queue->card->perf_stats.outbound_do_qdio_start_time;
#endif
if (rc){ if (rc){
QETH_DBF_SPRINTF(trace, 0, "qeth_flush_buffers: do_QDIO " QETH_DBF_SPRINTF(trace, 0, "qeth_flush_buffers: do_QDIO "
"returned error (%i) on device %s.", "returned error (%i) on device %s.",
...@@ -2598,6 +2674,10 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, ...@@ -2598,6 +2674,10 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
} }
} }
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_handler_cnt++;
card->perf_stats.outbound_handler_start_time = qeth_get_micros();
#endif
for(i = first_element; i < (first_element + count); ++i){ for(i = first_element; i < (first_element + count); ++i){
buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
/*we only handle the KICK_IT error by doing a recovery */ /*we only handle the KICK_IT error by doing a recovery */
...@@ -2616,6 +2696,10 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, ...@@ -2616,6 +2696,10 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
} }
netif_wake_queue(card->dev); netif_wake_queue(card->dev);
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_handler_time += qeth_get_micros() -
card->perf_stats.outbound_handler_start_time;
#endif
} }
static char* static char*
...@@ -2857,9 +2941,6 @@ qeth_init_qdio_queues(struct qeth_card *card) ...@@ -2857,9 +2941,6 @@ qeth_init_qdio_queues(struct qeth_card *card)
for (i = 0; i < card->qdio.in_buf_pool.buf_count - 1; ++i) for (i = 0; i < card->qdio.in_buf_pool.buf_count - 1; ++i)
qeth_init_input_buffer(card, &card->qdio.in_q->bufs[i]); qeth_init_input_buffer(card, &card->qdio.in_q->bufs[i]);
card->qdio.in_q->next_buf_to_init = card->qdio.in_buf_pool.buf_count - 1; card->qdio.in_q->next_buf_to_init = card->qdio.in_buf_pool.buf_count - 1;
#ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.inbound_do_qdio++;
#endif
rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, 0, rc = do_QDIO(CARD_DDEV(card), QDIO_FLAG_SYNC_INPUT, 0, 0,
card->qdio.in_buf_pool.buf_count - 1, NULL); card->qdio.in_buf_pool.buf_count - 1, NULL);
if (rc) { if (rc) {
...@@ -3193,10 +3274,6 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3193,10 +3274,6 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->stats.tx_carrier_errors++; card->stats.tx_carrier_errors++;
return -EIO; return -EIO;
} }
if (netif_queue_stopped(dev) ) {
card->stats.tx_dropped++;
return -EBUSY;
}
#ifdef CONFIG_QETH_PERF_STATS #ifdef CONFIG_QETH_PERF_STATS
card->perf_stats.outbound_cnt++; card->perf_stats.outbound_cnt++;
card->perf_stats.outbound_start_time = qeth_get_micros(); card->perf_stats.outbound_start_time = qeth_get_micros();
...@@ -3612,33 +3689,59 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf ...@@ -3612,33 +3689,59 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf
} }
static inline int static inline int
qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct qeth_qdio_out_q *queue, int ipv, struct sk_buff *skb, struct qeth_hdr *hdr,
int cast_type) int elements_needed)
{
struct qeth_qdio_out_buffer *buffer;
int index;
int rc = 0;
QETH_DBF_TEXT(trace, 6, "dosndpfa");
spin_lock(&queue->lock);
/* do we have empty buffers? */
if (atomic_read(&queue->used_buffers) >= (QDIO_MAX_BUFFERS_PER_Q - 1)){
card->stats.tx_dropped++;
rc = -EBUSY;
spin_unlock(&queue->lock);
goto out;
}
index = queue->next_buf_to_fill;
buffer = &queue->bufs[queue->next_buf_to_fill];
BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED);
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
QDIO_MAX_BUFFERS_PER_Q;
atomic_inc(&queue->used_buffers);
spin_unlock(&queue->lock);
/* go on sending ... */
netif_wake_queue(skb->dev);
qeth_fill_buffer(queue, buffer, (char *)hdr, skb);
qeth_flush_buffers(queue, 0, index, 1);
out:
return rc;
}
static inline int
qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct sk_buff *skb, struct qeth_hdr *hdr,
int elements_needed)
{ {
struct qeth_hdr *hdr;
struct qeth_qdio_out_buffer *buffer; struct qeth_qdio_out_buffer *buffer;
int elements_needed;
int start_index; int start_index;
int flush_count = 0; int flush_count = 0;
int rc; int rc = 0;
QETH_DBF_TEXT(trace, 6, "dosndpkt"); QETH_DBF_TEXT(trace, 6, "dosndpkt");
if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))){
QETH_DBF_TEXT_(trace, 4, "1err%d", rc);
return rc;
}
qeth_fill_header(card, hdr, skb, ipv, cast_type);
elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) + skb->len)
>> PAGE_SHIFT);
if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
PRINT_ERR("qeth_do_send_packet: invalid size of "
"IP packet. Discarded.");
return -EINVAL;
}
spin_lock(&queue->lock); spin_lock(&queue->lock);
/* do we have empty buffers? */
if (atomic_read(&queue->used_buffers) >= (QDIO_MAX_BUFFERS_PER_Q - 2)){
card->stats.tx_dropped++;
rc = -EBUSY;
goto out;
}
start_index = queue->next_buf_to_fill; start_index = queue->next_buf_to_fill;
buffer = &queue->bufs[queue->next_buf_to_fill]; buffer = &queue->bufs[queue->next_buf_to_fill];
BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED); BUG_ON(buffer->state == QETH_QDIO_BUF_PRIMED);
...@@ -3657,12 +3760,8 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, ...@@ -3657,12 +3760,8 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb,
} }
} }
rc = qeth_fill_buffer(queue, buffer, (char *)hdr, skb); qeth_fill_buffer(queue, buffer, (char *)hdr, skb);
if (rc) { if (buffer->state == QETH_QDIO_BUF_PRIMED){
PRINT_WARN("qeth_do_send_packet: error during "
"qeth_fill_buffer.");
card->stats.tx_dropped++;
} else if (buffer->state == QETH_QDIO_BUF_PRIMED){
/* next time fill the next buffer */ /* next time fill the next buffer */
flush_count++; flush_count++;
atomic_inc(&queue->used_buffers); atomic_inc(&queue->used_buffers);
...@@ -3670,7 +3769,6 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, ...@@ -3670,7 +3769,6 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb,
QDIO_MAX_BUFFERS_PER_Q; QDIO_MAX_BUFFERS_PER_Q;
} }
/* check if we need to switch packing state of this queue */ /* check if we need to switch packing state of this queue */
if (card->info.type != QETH_CARD_TYPE_IQD)
flush_count += qeth_switch_packing_state(queue); flush_count += qeth_switch_packing_state(queue);
if (flush_count) if (flush_count)
...@@ -3678,7 +3776,7 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb, ...@@ -3678,7 +3776,7 @@ qeth_do_send_packet(struct qeth_card *card, struct sk_buff *skb,
if (!atomic_read(&queue->set_pci_flags_count)) if (!atomic_read(&queue->set_pci_flags_count))
qeth_flush_buffers_on_no_pci(queue, 0); qeth_flush_buffers_on_no_pci(queue, 0);
out:
spin_unlock(&queue->lock); spin_unlock(&queue->lock);
return rc; return rc;
...@@ -3690,6 +3788,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) ...@@ -3690,6 +3788,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
int ipv; int ipv;
int cast_type; int cast_type;
struct qeth_qdio_out_q *queue; struct qeth_qdio_out_q *queue;
struct qeth_hdr *hdr;
int elements_needed;
int rc; int rc;
QETH_DBF_TEXT(trace, 6, "sendpkt"); QETH_DBF_TEXT(trace, 6, "sendpkt");
...@@ -3698,16 +3798,26 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) ...@@ -3698,16 +3798,26 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
cast_type = qeth_get_cast_type(card, skb); cast_type = qeth_get_cast_type(card, skb);
queue = card->qdio.out_qs queue = card->qdio.out_qs
[qeth_get_priority_queue(card, skb, ipv, cast_type)]; [qeth_get_priority_queue(card, skb, ipv, cast_type)];
/* do we have empty buffers? */
rc = (atomic_read(&queue->used_buffers) >= if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))){
QDIO_MAX_BUFFERS_PER_Q - 1) ? -EBUSY : 0;
if (rc) {
card->stats.tx_dropped++;
QETH_DBF_TEXT_(trace, 4, "1err%d", rc); QETH_DBF_TEXT_(trace, 4, "1err%d", rc);
return rc; return rc;
} }
qeth_fill_header(card, hdr, skb, ipv, cast_type);
elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) + skb->len)
>> PAGE_SHIFT);
if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){
PRINT_ERR("qeth_do_send_packet: invalid size of "
"IP packet. Discarded.");
return -EINVAL;
}
rc = qeth_do_send_packet(card, skb, queue, ipv, cast_type); if (card->info.type != QETH_CARD_TYPE_IQD)
rc = qeth_do_send_packet(card, queue, skb, hdr,
elements_needed);
else
rc = qeth_do_send_packet_fast(card, queue, skb, hdr,
elements_needed);
if (!rc){ if (!rc){
card->stats.tx_packets++; card->stats.tx_packets++;
...@@ -3864,6 +3974,25 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries) ...@@ -3864,6 +3974,25 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries)
return rc; return rc;
} }
static inline void
qeth_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo,
struct qeth_arp_query_data *qdata,
int entry_size, int uentry_size)
{
char *entry_ptr;
char *uentry_ptr;
int i;
entry_ptr = (char *)&qdata->data;
uentry_ptr = (char *)(qinfo->udata + qinfo->udata_offset);
for (i = 0; i < qdata->no_entries; ++i){
/* strip off 32 bytes "media specific information" */
memcpy(uentry_ptr, (entry_ptr + 32), entry_size - 32);
entry_ptr += entry_size;
uentry_ptr += uentry_size;
}
}
static int static int
qeth_arp_query_cb(struct qeth_card *card, struct qeth_reply *reply, qeth_arp_query_cb(struct qeth_card *card, struct qeth_reply *reply,
unsigned long data) unsigned long data)
...@@ -3872,6 +4001,7 @@ qeth_arp_query_cb(struct qeth_card *card, struct qeth_reply *reply, ...@@ -3872,6 +4001,7 @@ qeth_arp_query_cb(struct qeth_card *card, struct qeth_reply *reply,
struct qeth_arp_query_data *qdata; struct qeth_arp_query_data *qdata;
struct qeth_arp_query_info *qinfo; struct qeth_arp_query_info *qinfo;
int entry_size; int entry_size;
int uentry_size;
int i; int i;
QETH_DBF_TEXT(trace,4,"arpquecb"); QETH_DBF_TEXT(trace,4,"arpquecb");
...@@ -3890,37 +4020,54 @@ qeth_arp_query_cb(struct qeth_card *card, struct qeth_reply *reply, ...@@ -3890,37 +4020,54 @@ qeth_arp_query_cb(struct qeth_card *card, struct qeth_reply *reply,
qdata = &cmd->data.setassparms.data.query_arp; qdata = &cmd->data.setassparms.data.query_arp;
switch(qdata->reply_bits){ switch(qdata->reply_bits){
case 5: case 5:
entry_size = sizeof(struct qeth_arp_qi_entry5); uentry_size = entry_size = sizeof(struct qeth_arp_qi_entry5);
if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)
uentry_size = sizeof(struct qeth_arp_qi_entry5_short);
break; break;
case 7: case 7:
entry_size = sizeof(struct qeth_arp_qi_entry7); /* fall through to default */
break;
default: default:
/* tr is the same as eth -> entry7 */ /* tr is the same as eth -> entry7 */
entry_size = sizeof(struct qeth_arp_qi_entry7); uentry_size = entry_size = sizeof(struct qeth_arp_qi_entry7);
if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)
uentry_size = sizeof(struct qeth_arp_qi_entry7_short);
break; break;
} }
/* check if there is enough room in userspace */ /* check if there is enough room in userspace */
if ((qinfo->udata_len - qinfo->udata_offset) < if ((qinfo->udata_len - qinfo->udata_offset) <
qdata->no_entries * entry_size){ qdata->no_entries * uentry_size){
QETH_DBF_TEXT_(trace, 4, "qaer3%i", -ENOMEM); QETH_DBF_TEXT_(trace, 4, "qaer3%i", -ENOMEM);
cmd->hdr.return_code = -ENOMEM; cmd->hdr.return_code = -ENOMEM;
PRINT_WARN("query ARP user space buffer is too small for "
"the returned number of ARP entries. "
"Aborting query!\n");
goto out_error; goto out_error;
} }
QETH_DBF_TEXT_(trace, 4, "anore%i", QETH_DBF_TEXT_(trace, 4, "anore%i",
cmd->data.setassparms.hdr.number_of_replies); cmd->data.setassparms.hdr.number_of_replies);
QETH_DBF_TEXT_(trace, 4, "aseqn%i", cmd->data.setassparms.hdr.seq_no); QETH_DBF_TEXT_(trace, 4, "aseqn%i", cmd->data.setassparms.hdr.seq_no);
QETH_DBF_TEXT_(trace, 4, "anoen%i", qdata->no_entries); QETH_DBF_TEXT_(trace, 4, "anoen%i", qdata->no_entries);
if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES) {
/* strip off "media specific information" */
qeth_copy_arp_entries_stripped(qinfo, qdata, entry_size,
uentry_size);
} else
/*copy entries to user buffer*/ /*copy entries to user buffer*/
memcpy(qinfo->udata + qinfo->udata_offset, memcpy(qinfo->udata + qinfo->udata_offset,
(char *)&qdata->data, qdata->no_entries*entry_size); (char *)&qdata->data, qdata->no_entries*uentry_size);
qinfo->no_entries += qdata->no_entries; qinfo->no_entries += qdata->no_entries;
qinfo->udata_offset += (qdata->no_entries*entry_size); qinfo->udata_offset += (qdata->no_entries*uentry_size);
/* check if all replies received ... */ /* check if all replies received ... */
if (cmd->data.setassparms.hdr.seq_no < if (cmd->data.setassparms.hdr.seq_no <
cmd->data.setassparms.hdr.number_of_replies) cmd->data.setassparms.hdr.number_of_replies)
return 1; return 1;
memcpy(qinfo->udata, &qinfo->no_entries, 4); memcpy(qinfo->udata, &qinfo->no_entries, 4);
/* keep STRIP_ENTRIES flag so the user program can distinguish
* stripped entries from normal ones */
if (qinfo->mask_bits & QETH_QARP_STRIP_ENTRIES)
qdata->reply_bits |= QETH_QARP_STRIP_ENTRIES;
memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET,&qdata->reply_bits,2); memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET,&qdata->reply_bits,2);
return 0; return 0;
out_error: out_error:
...@@ -3975,8 +4122,8 @@ qeth_arp_query(struct qeth_card *card, char *udata) ...@@ -3975,8 +4122,8 @@ qeth_arp_query(struct qeth_card *card, char *udata)
"on %s!\n", card->info.if_name); "on %s!\n", card->info.if_name);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
/* get size of userspace buffer and mask_bits -> 6 bytes */
if (copy_from_user(&qinfo.udata_len, udata, 4)) if (copy_from_user(&qinfo, udata, 6))
return -EFAULT; return -EFAULT;
if (!(qinfo.udata = kmalloc(qinfo.udata_len, GFP_KERNEL))) if (!(qinfo.udata = kmalloc(qinfo.udata_len, GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
...@@ -4004,6 +4151,140 @@ qeth_arp_query(struct qeth_card *card, char *udata) ...@@ -4004,6 +4151,140 @@ qeth_arp_query(struct qeth_card *card, char *udata)
return rc; return rc;
} }
/**
* SNMP command callback
*/
static int
qeth_snmp_command_cb(struct qeth_card *card, struct qeth_reply *reply,
unsigned long sdata)
{
struct qeth_ipa_cmd *cmd;
struct qeth_arp_query_info *qinfo;
struct qeth_snmp_cmd *snmp;
unsigned char *data;
__u16 data_len;
QETH_DBF_TEXT(trace,3,"snpcmdcb");
cmd = (struct qeth_ipa_cmd *) sdata;
data = (unsigned char *)((char *)cmd - reply->offset);
qinfo = (struct qeth_arp_query_info *) reply->param;
snmp = &cmd->data.setadapterparms.data.snmp;
if (cmd->hdr.return_code) {
QETH_DBF_TEXT_(trace,4,"scer1%i", cmd->hdr.return_code);
return 0;
}
if (cmd->data.setadapterparms.hdr.return_code) {
cmd->hdr.return_code = cmd->data.setadapterparms.hdr.return_code;
QETH_DBF_TEXT_(trace,4,"scer2%i", cmd->hdr.return_code);
return 0;
}
data_len = *((__u16*)QETH_IPA_PDU_LEN_PDU1(data));
if (cmd->data.setadapterparms.hdr.seq_no == 1)
data_len -= (__u16)((char*)&snmp->request - (char *)cmd);
else
data_len -= (__u16)((char *)&snmp->data - (char *)cmd);
/* check if there is enough room in userspace */
if ((qinfo->udata_len - qinfo->udata_offset) < data_len) {
QETH_DBF_TEXT_(trace, 4, "scer3%i", -ENOMEM);
cmd->hdr.return_code = -ENOMEM;
return 0;
}
QETH_DBF_TEXT_(trace, 4, "snore%i",
cmd->data.setadapterparms.hdr.used_total);
QETH_DBF_TEXT_(trace, 4, "sseqn%i", cmd->data.setassparms.hdr.seq_no);
/*copy entries to user buffer*/
if (cmd->data.setadapterparms.hdr.seq_no == 1) {
memcpy(qinfo->udata + qinfo->udata_offset,
(char *)snmp,offsetof(struct qeth_snmp_cmd,data));
qinfo->udata_offset += offsetof(struct qeth_snmp_cmd, data);
}
memcpy(qinfo->udata + qinfo->udata_offset,
(char *)&snmp->data, data_len);
qinfo->udata_offset += data_len;
/* check if all replies received ... */
QETH_DBF_TEXT_(trace, 4, "srtot%i",
cmd->data.setadapterparms.hdr.used_total);
QETH_DBF_TEXT_(trace, 4, "srseq%i",
cmd->data.setadapterparms.hdr.seq_no);
if (cmd->data.setadapterparms.hdr.seq_no <
cmd->data.setadapterparms.hdr.used_total)
return 1;
return 0;
}
static struct qeth_cmd_buffer *
qeth_get_ipacmd_buffer(struct qeth_card *, enum qeth_ipa_cmds,
enum qeth_prot_versions );
static struct qeth_cmd_buffer *
qeth_get_adapter_cmd(struct qeth_card *card, __u32 command, __u32 cmdlen)
{
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
iob = qeth_get_ipacmd_buffer(card,IPA_CMD_SETADAPTERPARMS,
QETH_PROT_IPV4);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setadapterparms.hdr.cmdlength = cmdlen;
cmd->data.setadapterparms.hdr.command_code = command;
cmd->data.setadapterparms.hdr.used_total = 1;
cmd->data.setadapterparms.hdr.seq_no = 1;
return iob;
}
/**
* function to send SNMP commands to OSA-E card
*/
static int
qeth_snmp_command(struct qeth_card *card, char *udata)
{
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
struct qeth_snmp_ureq ureq;
struct qeth_arp_query_info qinfo = {0, };
int rc = 0;
QETH_DBF_TEXT(trace,3,"snmpcmd");
if (card->info.guestlan)
return -EOPNOTSUPP;
if (!qeth_adp_supported(card,IPA_SETADP_SET_SNMP_CONTROL)) {
PRINT_WARN("SNMP Query MIBS not supported "
"on %s!\n", card->info.if_name);
return -EOPNOTSUPP;
}
if (copy_from_user(&ureq, udata, sizeof(struct qeth_snmp_ureq)))
return -EFAULT;
qinfo.udata_len = ureq.hdr.data_len;
if (!(qinfo.udata = kmalloc(qinfo.udata_len, GFP_KERNEL)))
return -ENOMEM;
memset(qinfo.udata, 0, qinfo.udata_len);
qinfo.udata_offset = sizeof(struct qeth_snmp_ureq_hdr);
iob = qeth_get_adapter_cmd(card, IPA_SETADP_SET_SNMP_CONTROL,
QETH_SNMP_SETADP_CMDLENGTH+ureq.hdr.req_len);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
memcpy(&cmd->data.setadapterparms.data.snmp, &ureq.cmd,
sizeof(struct qeth_snmp_cmd));
rc = qeth_send_ipa_arp_cmd(card, iob,
QETH_SETADP_BASE_LEN + QETH_ARP_DATA_SIZE +
ureq.hdr.req_len, qeth_snmp_command_cb,
(void *)&qinfo);
if (rc)
PRINT_WARN("SNMP command failed on %s: (0x%x)\n",
card->info.if_name, rc);
else
copy_to_user(udata, qinfo.udata, qinfo.udata_len);
kfree(qinfo.udata);
return rc;
}
static int static int
qeth_default_setassparms_cb(struct qeth_card *, struct qeth_reply *, qeth_default_setassparms_cb(struct qeth_card *, struct qeth_reply *,
unsigned long); unsigned long);
...@@ -4192,6 +4473,7 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -4192,6 +4473,7 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
rc = qeth_arp_flush_cache(card); rc = qeth_arp_flush_cache(card);
break; break;
case SIOC_QETH_ADP_SET_SNMP_CONTROL: case SIOC_QETH_ADP_SET_SNMP_CONTROL:
rc = qeth_snmp_command(card, rq->ifr_ifru.ifru_data);
break; break;
case SIOC_QETH_GET_CARD_TYPE: case SIOC_QETH_GET_CARD_TYPE:
break; break;
...@@ -4955,23 +5237,6 @@ qeth_hardsetup_card(struct qeth_card *card) ...@@ -4955,23 +5237,6 @@ qeth_hardsetup_card(struct qeth_card *card)
return rc; return rc;
} }
static struct qeth_cmd_buffer *
qeth_get_adapter_cmd(struct qeth_card *card, __u32 command, __u32 cmdlen)
{
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
iob = qeth_get_ipacmd_buffer(card,IPA_CMD_SETADAPTERPARMS,
QETH_PROT_IPV4);
cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->data.setadapterparms.hdr.cmdlength = cmdlen;
cmd->data.setadapterparms.hdr.command_code = command;
cmd->data.setadapterparms.hdr.used_total = 1;
cmd->data.setadapterparms.hdr.seq_no = 1;
return iob;
}
static int static int
qeth_default_setassparms_cb(struct qeth_card *card, struct qeth_reply *reply, qeth_default_setassparms_cb(struct qeth_card *card, struct qeth_reply *reply,
unsigned long data) unsigned long data)
...@@ -6174,7 +6439,7 @@ qeth_set_online(struct ccwgroup_device *gdev) ...@@ -6174,7 +6439,7 @@ qeth_set_online(struct ccwgroup_device *gdev)
qeth_set_allowed_threads(card, 0xffffffff, 0); qeth_set_allowed_threads(card, 0xffffffff, 0);
if (recover_flag == CARD_STATE_RECOVER) if (recover_flag == CARD_STATE_RECOVER)
qeth_start_again(card); qeth_start_again(card);
qeth_notify_processes();
return 0; return 0;
out_remove: out_remove:
card->use_hard_stop = 1; card->use_hard_stop = 1;
...@@ -6848,6 +7113,8 @@ qeth_init(void) ...@@ -6848,6 +7113,8 @@ qeth_init(void)
QETH_VERSION_VLAN); QETH_VERSION_VLAN);
INIT_LIST_HEAD(&qeth_card_list.list); INIT_LIST_HEAD(&qeth_card_list.list);
INIT_LIST_HEAD(&qeth_notify_list);
spin_lock_init(&qeth_notify_lock);
rwlock_init(&qeth_card_list.rwlock); rwlock_init(&qeth_card_list.rwlock);
if (qeth_register_dbf_views()) if (qeth_register_dbf_views())
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
#include <asm/qeth.h> #include <asm/qeth.h>
#define VERSION_QETH_MPC_H "$Revision: 1.34 $" #define VERSION_QETH_MPC_H "$Revision: 1.35 $"
extern const char *VERSION_QETH_MPC_C; extern const char *VERSION_QETH_MPC_C;
...@@ -258,6 +258,7 @@ struct qeth_arp_query_data { ...@@ -258,6 +258,7 @@ struct qeth_arp_query_data {
/* used as parameter for arp_query reply */ /* used as parameter for arp_query reply */
struct qeth_arp_query_info { struct qeth_arp_query_info {
__u32 udata_len; __u32 udata_len;
__u16 mask_bits;
__u32 udata_offset; __u32 udata_offset;
__u32 no_entries; __u32 no_entries;
char *udata; char *udata;
...@@ -296,6 +297,29 @@ struct qeth_change_addr { ...@@ -296,6 +297,29 @@ struct qeth_change_addr {
__u8 addr[OSA_ADDR_LEN]; __u8 addr[OSA_ADDR_LEN];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct qeth_snmp_cmd {
__u8 token[16];
__u32 request;
__u32 interface;
__u32 returncode;
__u32 firmwarelevel;
__u32 seqno;
__u8 data;
} __attribute__ ((packed));
struct qeth_snmp_ureq_hdr {
__u32 data_len;
__u32 req_len;
__u32 reserved1;
__u32 reserved2;
} __attribute__ ((packed));
struct qeth_snmp_ureq {
struct qeth_snmp_ureq_hdr hdr;
struct qeth_snmp_cmd cmd;
} __attribute__((packed));
struct qeth_ipacmd_setadpparms_hdr { struct qeth_ipacmd_setadpparms_hdr {
__u32 supp_hw_cmds; __u32 supp_hw_cmds;
__u32 reserved1; __u32 reserved1;
...@@ -313,6 +337,7 @@ struct qeth_ipacmd_setadpparms { ...@@ -313,6 +337,7 @@ struct qeth_ipacmd_setadpparms {
union { union {
struct qeth_query_cmds_supp query_cmds_supp; struct qeth_query_cmds_supp query_cmds_supp;
struct qeth_change_addr change_addr; struct qeth_change_addr change_addr;
struct qeth_snmp_cmd snmp;
__u32 mode; __u32 mode;
} data; } data;
} __attribute__ ((packed)); } __attribute__ ((packed));
......
/* /*
* *
* linux/drivers/s390/net/qeth_fs.c ($Revision: 1.9 $) * linux/drivers/s390/net/qeth_fs.c ($Revision: 1.10 $)
* *
* Linux on zSeries OSA Express and HiperSockets support * Linux on zSeries OSA Express and HiperSockets support
* This file contains code related to procfs. * This file contains code related to procfs.
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include "qeth_mpc.h" #include "qeth_mpc.h"
#include "qeth_fs.h" #include "qeth_fs.h"
const char *VERSION_QETH_PROC_C = "$Revision: 1.9 $"; const char *VERSION_QETH_PROC_C = "$Revision: 1.10 $";
/***** /proc/qeth *****/ /***** /proc/qeth *****/
#define QETH_PROCFILE_NAME "qeth" #define QETH_PROCFILE_NAME "qeth"
...@@ -237,9 +237,11 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it) ...@@ -237,9 +237,11 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
card->perf_stats.bufs_sent_pack card->perf_stats.bufs_sent_pack
); );
seq_printf(s, " Packing state changes no pkg.->packing : %i/%i\n" seq_printf(s, " Packing state changes no pkg.->packing : %i/%i\n"
" Watermarks L/H : %i/%i\n"
" Current buffer usage (outbound q's) : " " Current buffer usage (outbound q's) : "
"%i/%i/%i/%i\n\n", "%i/%i/%i/%i\n\n",
card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp, card->perf_stats.sc_dp_p, card->perf_stats.sc_p_dp,
QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK,
atomic_read(&card->qdio.out_qs[0]->used_buffers), atomic_read(&card->qdio.out_qs[0]->used_buffers),
(card->qdio.no_out_queues > 1)? (card->qdio.no_out_queues > 1)?
atomic_read(&card->qdio.out_qs[1]->used_buffers) atomic_read(&card->qdio.out_qs[1]->used_buffers)
...@@ -251,20 +253,26 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it) ...@@ -251,20 +253,26 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
atomic_read(&card->qdio.out_qs[3]->used_buffers) atomic_read(&card->qdio.out_qs[3]->used_buffers)
: 0 : 0
); );
seq_printf(s, " Inbound time (in us) : %i\n" seq_printf(s, " Inbound handler time (in us) : %i\n"
" Inbound count : %i\n" " Inbound handler count : %i\n"
" Inboud do_QDIO count : %i\n" " Inbound do_QDIO time (in us) : %i\n"
" Inbound do_QDIO count : %i\n\n"
" Outbound handler time (in us) : %i\n"
" Outbound handler count : %i\n\n"
" Outbound time (in us, incl QDIO) : %i\n" " Outbound time (in us, incl QDIO) : %i\n"
" Outbound count : %i\n" " Outbound count : %i\n"
" Outbound do_QDIO count : %i\n" " Outbound do_QDIO time (in us) : %i\n"
" Watermarks L/H : %i/%i\n\n", " Outbound do_QDIO count : %i\n",
card->perf_stats.inbound_time, card->perf_stats.inbound_time,
card->perf_stats.inbound_cnt, card->perf_stats.inbound_cnt,
card->perf_stats.inbound_do_qdio, card->perf_stats.inbound_do_qdio_time,
card->perf_stats.inbound_do_qdio_cnt,
card->perf_stats.outbound_handler_time,
card->perf_stats.outbound_handler_cnt,
card->perf_stats.outbound_time, card->perf_stats.outbound_time,
card->perf_stats.outbound_cnt, card->perf_stats.outbound_cnt,
card->perf_stats.outbound_do_qdio, card->perf_stats.outbound_do_qdio_time,
QETH_LOW_WATERMARK_PACK, QETH_HIGH_WATERMARK_PACK card->perf_stats.outbound_do_qdio_cnt
); );
return 0; return 0;
......
/* /*
* *
* linux/drivers/s390/net/qeth_sys.c ($Revision: 1.29 $) * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.30 $)
* *
* Linux on zSeries OSA Express and HiperSockets support * Linux on zSeries OSA Express and HiperSockets support
* This file contains code related to sysfs. * This file contains code related to sysfs.
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
#include "qeth_mpc.h" #include "qeth_mpc.h"
#include "qeth_fs.h" #include "qeth_fs.h"
const char *VERSION_QETH_SYS_C = "$Revision: 1.29 $"; const char *VERSION_QETH_SYS_C = "$Revision: 1.30 $";
/*****************************************************************************/ /*****************************************************************************/
/* */ /* */
...@@ -322,7 +322,8 @@ static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show, ...@@ -322,7 +322,8 @@ static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show,
qeth_dev_bufcnt_store); qeth_dev_bufcnt_store);
static inline ssize_t static inline ssize_t
qeth_dev_route_show(struct qeth_routing_info *route, char *buf) qeth_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route,
char *buf)
{ {
switch (route->type) { switch (route->type) {
case PRIMARY_ROUTER: case PRIMARY_ROUTER:
...@@ -330,10 +331,19 @@ qeth_dev_route_show(struct qeth_routing_info *route, char *buf) ...@@ -330,10 +331,19 @@ qeth_dev_route_show(struct qeth_routing_info *route, char *buf)
case SECONDARY_ROUTER: case SECONDARY_ROUTER:
return sprintf(buf, "%s\n", "secondary router"); return sprintf(buf, "%s\n", "secondary router");
case MULTICAST_ROUTER: case MULTICAST_ROUTER:
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
return sprintf(buf, "%s\n", "multicast router+");
else
return sprintf(buf, "%s\n", "multicast router"); return sprintf(buf, "%s\n", "multicast router");
case PRIMARY_CONNECTOR: case PRIMARY_CONNECTOR:
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
return sprintf(buf, "%s\n", "primary connector+");
else
return sprintf(buf, "%s\n", "primary connector"); return sprintf(buf, "%s\n", "primary connector");
case SECONDARY_CONNECTOR: case SECONDARY_CONNECTOR:
if (card->info.broadcast_capable == QETH_BROADCAST_WITHOUT_ECHO)
return sprintf(buf, "%s\n", "secondary connector+");
else
return sprintf(buf, "%s\n", "secondary connector"); return sprintf(buf, "%s\n", "secondary connector");
default: default:
return sprintf(buf, "%s\n", "no"); return sprintf(buf, "%s\n", "no");
...@@ -348,7 +358,7 @@ qeth_dev_route4_show(struct device *dev, char *buf) ...@@ -348,7 +358,7 @@ qeth_dev_route4_show(struct device *dev, char *buf)
if (!card) if (!card)
return -EINVAL; return -EINVAL;
return qeth_dev_route_show(&card->options.route4, buf); return qeth_dev_route_show(card, &card->options.route4, buf);
} }
static inline ssize_t static inline ssize_t
...@@ -416,7 +426,7 @@ qeth_dev_route6_show(struct device *dev, char *buf) ...@@ -416,7 +426,7 @@ qeth_dev_route6_show(struct device *dev, char *buf)
if (!qeth_is_supported(card, IPA_IPV6)) if (!qeth_is_supported(card, IPA_IPV6))
return sprintf(buf, "%s\n", "n/a"); return sprintf(buf, "%s\n", "n/a");
return qeth_dev_route_show(&card->options.route6, buf); return qeth_dev_route_show(card, &card->options.route6, buf);
} }
static ssize_t static ssize_t
...@@ -1432,22 +1442,31 @@ qeth_driver_group_store(struct device_driver *ddrv, const char *buf, ...@@ -1432,22 +1442,31 @@ qeth_driver_group_store(struct device_driver *ddrv, const char *buf,
static DRIVER_ATTR(group, 0200, 0, qeth_driver_group_store); static DRIVER_ATTR(group, 0200, 0, qeth_driver_group_store);
static ssize_t static ssize_t
qeth_driver_snmp_register_show(struct device_driver *ddrv, char *buf) qeth_driver_notifier_register_store(struct device_driver *ddrv, const char *buf,
{
/* TODO */
return 0;
}
static ssize_t
qeth_driver_snmp_register_store(struct device_driver *ddrv, const char *buf,
size_t count) size_t count)
{ {
/* TODO */ int rc;
int signum;
char *tmp;
tmp = strsep((char **) &buf, "\n");
if (!strcmp(tmp, "unregister")){
return qeth_notifier_unregister(current);
}
signum = simple_strtoul(buf, &tmp, 10);
if ((signum < 0) || (signum > 32)){
PRINT_WARN("Signal number %d is out of range\n", signum);
return -EINVAL;
}
if ((rc = qeth_notifier_register(current, signum)))
return rc;
return count; return count;
} }
static DRIVER_ATTR(snmp_register, 0644, qeth_driver_snmp_register_show, static DRIVER_ATTR(notifier_register, 0644, 0,
qeth_driver_snmp_register_store); qeth_driver_notifier_register_store);
int int
qeth_create_driver_attributes(void) qeth_create_driver_attributes(void)
...@@ -1458,7 +1477,7 @@ qeth_create_driver_attributes(void) ...@@ -1458,7 +1477,7 @@ qeth_create_driver_attributes(void)
&driver_attr_group))) &driver_attr_group)))
return rc; return rc;
return driver_create_file(&qeth_ccwgroup_driver.driver, return driver_create_file(&qeth_ccwgroup_driver.driver,
&driver_attr_snmp_register); &driver_attr_notifier_register);
} }
void void
...@@ -1467,5 +1486,5 @@ qeth_remove_driver_attributes(void) ...@@ -1467,5 +1486,5 @@ qeth_remove_driver_attributes(void)
driver_remove_file(&qeth_ccwgroup_driver.driver, driver_remove_file(&qeth_ccwgroup_driver.driver,
&driver_attr_group); &driver_attr_group);
driver_remove_file(&qeth_ccwgroup_driver.driver, driver_remove_file(&qeth_ccwgroup_driver.driver,
&driver_attr_snmp_register); &driver_attr_notifier_register);
} }
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
* Author(s): Thomas Spatzier <tspat@de.ibm.com> * Author(s): Thomas Spatzier <tspat@de.ibm.com>
* *
*/ */
#ifndef __ASM_S390_IOCTL_H__ #ifndef __ASM_S390_QETH_IOCTL_H__
#define __ASM_S390_IOCTL_H__ #define __ASM_S390_QETH_IOCTL_H__
#include <linux/ioctl.h> #include <linux/ioctl.h>
#define SIOC_QETH_ARP_SET_NO_ENTRIES (SIOCDEVPRIVATE) #define SIOC_QETH_ARP_SET_NO_ENTRIES (SIOCDEVPRIVATE)
...@@ -35,6 +35,13 @@ struct qeth_arp_qi_entry7 { ...@@ -35,6 +35,13 @@ struct qeth_arp_qi_entry7 {
__u8 ipaddr[4]; __u8 ipaddr[4];
} __attribute__((packed)); } __attribute__((packed));
struct qeth_arp_qi_entry7_short {
__u8 macaddr_type;
__u8 ipaddr_type;
__u8 macaddr[6];
__u8 ipaddr[4];
} __attribute__((packed));
struct qeth_arp_qi_entry5 { struct qeth_arp_qi_entry5 {
__u8 media_specific[32]; __u8 media_specific[32];
__u8 macaddr_type; __u8 macaddr_type;
...@@ -42,6 +49,19 @@ struct qeth_arp_qi_entry5 { ...@@ -42,6 +49,19 @@ struct qeth_arp_qi_entry5 {
__u8 ipaddr[4]; __u8 ipaddr[4];
} __attribute__((packed)); } __attribute__((packed));
struct qeth_arp_qi_entry5_short {
__u8 macaddr_type;
__u8 ipaddr_type;
__u8 ipaddr[4];
} __attribute__((packed));
/*
* can be set by user if no "media specific information" is wanted
* -> saves a lot of space in user space buffer
*/
#define QETH_QARP_STRIP_ENTRIES 0x8000
#define QETH_QARP_REQUEST_MASK 0x00ff
/* data sent to user space as result of query arp ioctl */ /* data sent to user space as result of query arp ioctl */
#define QETH_QARP_USER_DATA_SIZE 20000 #define QETH_QARP_USER_DATA_SIZE 20000
#define QETH_QARP_MASK_OFFSET 4 #define QETH_QARP_MASK_OFFSET 4
...@@ -55,4 +75,4 @@ struct qeth_arp_query_user_data { ...@@ -55,4 +75,4 @@ struct qeth_arp_query_user_data {
char *entries; char *entries;
} __attribute__((packed)); } __attribute__((packed));
#endif /* __ASM_S390_IOCTL_H__ */ #endif /* __ASM_S390_QETH_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