Commit 1ca06429 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:
 - ctc: Add missing irb error checking.
 - iucv: Add name of net_device to iucvMagic to more than one
         connection between two guests.
 - qeth: Don't send IPA command if card is not in state SOFTSETUP or UP.
 - qeth: Fix number base in simple_strtoul call for buffer_count attribute.
 - qeth: Fix reallocating of buffers when buffer_count attribute is changed.
 - qeth: Correct handling of return codes in qeth_realloc_buffer_pool.
 - qeth: Don't call dev_close/dev_open on STOPLAN/STARTLAN commands.
         Use netif_carrier_off/netif_carrier_on instead.
parent 10281b07
/* /*
* $Id: ctcmain.c,v 1.58 2004/03/24 10:51:56 ptiedem Exp $ * $Id: ctcmain.c,v 1.59 2004/04/21 17:10:13 ptiedem Exp $
* *
* CTC / ESCON network driver * CTC / ESCON network driver
* *
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,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: CTC/ESCON network driver $Revision: 1.58 $ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.59 $
* *
*/ */
...@@ -319,7 +319,7 @@ static void ...@@ -319,7 +319,7 @@ static void
print_banner(void) print_banner(void)
{ {
static int printed = 0; static int printed = 0;
char vbuf[] = "$Revision: 1.58 $"; char vbuf[] = "$Revision: 1.59 $";
char *version = vbuf; char *version = vbuf;
if (printed) if (printed)
...@@ -2045,6 +2045,32 @@ extract_channel_media(char *name) ...@@ -2045,6 +2045,32 @@ extract_channel_media(char *name)
return ret; return ret;
} }
static long
__ctc_check_irb_error(struct ccw_device *cdev, struct irb *irb)
{
if (!IS_ERR(irb))
return 0;
switch (PTR_ERR(irb)) {
case -EIO:
ctc_pr_warn("i/o-error on device %s\n", cdev->dev.bus_id);
// CTC_DBF_TEXT(trace, 2, "ckirberr");
// CTC_DBF_TEXT_(trace, 2, " rc%d", -EIO);
break;
case -ETIMEDOUT:
ctc_pr_warn("timeout on device %s\n", cdev->dev.bus_id);
// CTC_DBF_TEXT(trace, 2, "ckirberr");
// CTC_DBF_TEXT_(trace, 2, " rc%d", -ETIMEDOUT);
break;
default:
ctc_pr_warn("unknown error %ld on device %s\n", PTR_ERR(irb),
cdev->dev.bus_id);
// CTC_DBF_TEXT(trace, 2, "ckirberr");
// CTC_DBF_TEXT(trace, 2, " rc???");
}
return PTR_ERR(irb);
}
/** /**
* Main IRQ handler. * Main IRQ handler.
* *
...@@ -2059,6 +2085,9 @@ ctc_irq_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) ...@@ -2059,6 +2085,9 @@ ctc_irq_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
struct net_device *dev; struct net_device *dev;
struct ctc_priv *priv; struct ctc_priv *priv;
if (__ctc_check_irb_error(cdev, irb))
return;
/* Check for unsolicited interrupts. */ /* Check for unsolicited interrupts. */
if (!cdev->dev.driver_data) { if (!cdev->dev.driver_data) {
ctc_pr_warn("ctc: Got unsolicited irq: %s c-%02x d-%02x\n", ctc_pr_warn("ctc: Got unsolicited irq: %s c-%02x d-%02x\n",
......
/* /*
* $Id: netiucv.c,v 1.49 2004/04/15 06:37:54 braunu Exp $ * $Id: netiucv.c,v 1.51 2004/04/23 08:11:21 mschwide Exp $
* *
* IUCV network driver * IUCV network driver
* *
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,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 network driver $Revision: 1.49 $ * RELEASE-TAG: IUCV network driver $Revision: 1.51 $
* *
*/ */
...@@ -169,10 +169,10 @@ static __inline__ int netiucv_test_and_set_busy(struct net_device *dev) ...@@ -169,10 +169,10 @@ static __inline__ int netiucv_test_and_set_busy(struct net_device *dev)
} }
static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
static __u8 iucvMagic[16] = { //static __u8 iucvMagic[16] = {
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, // 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 // 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
}; //};
/** /**
* This mask means the 16-byte IUCV "magic" and the origin userid must * This mask means the 16-byte IUCV "magic" and the origin userid must
...@@ -693,13 +693,20 @@ static void ...@@ -693,13 +693,20 @@ static void
conn_action_connreject(fsm_instance *fi, int event, void *arg) conn_action_connreject(fsm_instance *fi, int event, void *arg)
{ {
struct iucv_event *ev = (struct iucv_event *)arg; struct iucv_event *ev = (struct iucv_event *)arg;
// struct iucv_connection *conn = ev->conn; struct iucv_connection *conn = ev->conn;
struct net_device *netdev = conn->netdev;
iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data;
__u8 udata[16]; __u8 udata[16];
pr_debug("%s() called\n", __FUNCTION__); pr_debug("%s() called\n", __FUNCTION__);
iucv_sever(eib->ippathid, udata); iucv_sever(eib->ippathid, udata);
if (eib->ippathid != conn->pathid) {
printk(KERN_INFO
"%s: IR pathid %d does not match original pathid %d\n",
netdev->name, eib->ippathid, conn->pathid);
iucv_sever(conn->pathid, udata);
}
} }
static void static void
...@@ -715,7 +722,12 @@ conn_action_connack(fsm_instance *fi, int event, void *arg) ...@@ -715,7 +722,12 @@ conn_action_connack(fsm_instance *fi, int event, void *arg)
fsm_deltimer(&conn->timer); fsm_deltimer(&conn->timer);
fsm_newstate(fi, CONN_STATE_IDLE); fsm_newstate(fi, CONN_STATE_IDLE);
conn->pathid = eib->ippathid; if (eib->ippathid != conn->pathid) {
printk(KERN_INFO
"%s: IR pathid %d does not match original pathid %d\n",
netdev->name, eib->ippathid, conn->pathid);
conn->pathid = eib->ippathid;
}
netdev->tx_queue_len = eib->ipmsglim; netdev->tx_queue_len = eib->ipmsglim;
fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev);
} }
...@@ -759,9 +771,14 @@ conn_action_start(fsm_instance *fi, int event, void *arg) ...@@ -759,9 +771,14 @@ conn_action_start(fsm_instance *fi, int event, void *arg)
struct iucv_connection *conn = ev->conn; struct iucv_connection *conn = ev->conn;
__u16 msglimit; __u16 msglimit;
int rc; int rc;
__u8 iucvMagic[16] = {
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
};
pr_debug("%s() called\n", __FUNCTION__); pr_debug("%s() called\n", __FUNCTION__);
memcpy(iucvMagic, conn->netdev->name, IFNAMSIZ);
if (conn->handle == 0) { if (conn->handle == 0) {
conn->handle = conn->handle =
iucv_register_program(iucvMagic, conn->userid, mask, iucv_register_program(iucvMagic, conn->userid, mask,
...@@ -1882,7 +1899,7 @@ static struct device_driver netiucv_driver = { ...@@ -1882,7 +1899,7 @@ static struct device_driver netiucv_driver = {
static void static void
netiucv_banner(void) netiucv_banner(void)
{ {
char vbuf[] = "$Revision: 1.49 $"; char vbuf[] = "$Revision: 1.51 $";
char *version = vbuf; char *version = vbuf;
if ((version = strchr(version, ':'))) { if ((version = strchr(version, ':'))) {
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "qeth_mpc.h" #include "qeth_mpc.h"
#define VERSION_QETH_H "$Revision: 1.100 $" #define VERSION_QETH_H "$Revision: 1.102 $"
#ifdef CONFIG_QETH_IPV6 #ifdef CONFIG_QETH_IPV6
#define QETH_VERSION_IPV6 ":IPv6" #define QETH_VERSION_IPV6 ":IPv6"
...@@ -397,11 +397,6 @@ struct qeth_qdio_buffer { ...@@ -397,11 +397,6 @@ struct qeth_qdio_buffer {
struct qeth_qdio_q { struct qeth_qdio_q {
struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q]; struct qdio_buffer qdio_bufs[QDIO_MAX_BUFFERS_PER_Q];
struct qeth_qdio_buffer 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 * buf_to_init means "buffer must be initialized by driver and must
* be made available for hardware" -> state is set to EMPTY * be made available for hardware" -> state is set to EMPTY
...@@ -493,8 +488,7 @@ enum qeth_card_states { ...@@ -493,8 +488,7 @@ enum qeth_card_states {
CARD_STATE_DOWN, CARD_STATE_DOWN,
CARD_STATE_HARDSETUP, CARD_STATE_HARDSETUP,
CARD_STATE_SOFTSETUP, CARD_STATE_SOFTSETUP,
CARD_STATE_UP_LAN_OFFLINE, CARD_STATE_UP,
CARD_STATE_UP_LAN_ONLINE,
CARD_STATE_RECOVER, CARD_STATE_RECOVER,
}; };
...@@ -981,24 +975,27 @@ qeth_setrouting_v4(struct qeth_card *); ...@@ -981,24 +975,27 @@ qeth_setrouting_v4(struct qeth_card *);
extern int extern int
qeth_setrouting_v6(struct qeth_card *); qeth_setrouting_v6(struct qeth_card *);
int extern int
qeth_add_ipato_entry(struct qeth_card *, struct qeth_ipato_entry *); qeth_add_ipato_entry(struct qeth_card *, struct qeth_ipato_entry *);
void extern void
qeth_del_ipato_entry(struct qeth_card *, enum qeth_prot_versions, u8 *, int); qeth_del_ipato_entry(struct qeth_card *, enum qeth_prot_versions, u8 *, int);
int extern int
qeth_add_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *); qeth_add_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *);
void extern void
qeth_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *); qeth_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *);
int extern int
qeth_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *); qeth_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *);
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 *);
void extern void
qeth_schedule_recovery(struct qeth_card *); qeth_schedule_recovery(struct qeth_card *);
extern int
qeth_realloc_buffer_pool(struct qeth_card *, int);
#endif /* __QETH_H__ */ #endif /* __QETH_H__ */
/* /*
* *
* linux/drivers/s390/net/qeth_main.c ($Revision: 1.82 $) * linux/drivers/s390/net/qeth_main.c ($Revision: 1.89 $)
* *
* 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.82 $ $Date: 2004/04/21 08:27:21 $ * $Revision: 1.89 $ $Date: 2004/04/27 16:27:26 $
* *
* 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.82 $" #define VERSION_QETH_C "$Revision: 1.89 $"
static const char *version = "qeth S/390 OSA-Express driver (" static const char *version = "qeth S/390 OSA-Express driver ("
VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H VERSION_QETH_C "/" VERSION_QETH_H "/" VERSION_QETH_MPC_H
QETH_VERSION_IPV6 QETH_VERSION_VLAN ")"; QETH_VERSION_IPV6 QETH_VERSION_VLAN ")";
...@@ -457,8 +457,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev) ...@@ -457,8 +457,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev)
ccw_device_set_offline(CARD_DDEV(card)); ccw_device_set_offline(CARD_DDEV(card));
ccw_device_set_offline(CARD_WDEV(card)); ccw_device_set_offline(CARD_WDEV(card));
ccw_device_set_offline(CARD_RDEV(card)); ccw_device_set_offline(CARD_RDEV(card));
if ((recover_flag == CARD_STATE_UP_LAN_ONLINE) || if (recover_flag == CARD_STATE_UP)
(recover_flag == CARD_STATE_UP_LAN_OFFLINE))
card->state = CARD_STATE_RECOVER; card->state = CARD_STATE_RECOVER;
return 0; return 0;
} }
...@@ -485,7 +484,8 @@ qeth_remove_device(struct ccwgroup_device *cgdev) ...@@ -485,7 +484,8 @@ qeth_remove_device(struct ccwgroup_device *cgdev)
write_lock_irqsave(&qeth_card_list.rwlock, flags); write_lock_irqsave(&qeth_card_list.rwlock, flags);
list_del(&card->list); list_del(&card->list);
write_unlock_irqrestore(&qeth_card_list.rwlock, flags); write_unlock_irqrestore(&qeth_card_list.rwlock, flags);
unregister_netdev(card->dev); if (card->dev)
unregister_netdev(card->dev);
qeth_remove_device_attributes(&cgdev->dev); qeth_remove_device_attributes(&cgdev->dev);
qeth_free_card(card); qeth_free_card(card);
cgdev->dev.driver_data = NULL; cgdev->dev.driver_data = NULL;
...@@ -1504,11 +1504,21 @@ qeth_cmd_timeout(unsigned long data) ...@@ -1504,11 +1504,21 @@ qeth_cmd_timeout(unsigned long data)
spin_unlock_irqrestore(&reply->card->lock, flags); spin_unlock_irqrestore(&reply->card->lock, flags);
} }
static void
qeth_reset_ip_addresses(struct qeth_card *card)
{
QETH_DBF_TEXT(trace, 2, "rstipadd");
qeth_clear_ip_list(card, 0, 1);
qeth_set_thread_start_bit(card, QETH_SET_IP_THREAD);
qeth_set_thread_start_bit(card, QETH_SET_MC_THREAD);
schedule_work(&card->kernel_thread_starter);
}
static struct qeth_ipa_cmd * static struct qeth_ipa_cmd *
qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
{ {
struct qeth_ipa_cmd *cmd = NULL; struct qeth_ipa_cmd *cmd = NULL;
enum qeth_card_states old_state;
QETH_DBF_TEXT(trace,5,"chkipad"); QETH_DBF_TEXT(trace,5,"chkipad");
if (IS_IPA(iob->data)){ if (IS_IPA(iob->data)){
...@@ -1521,30 +1531,27 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob) ...@@ -1521,30 +1531,27 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
PRINT_WARN("Link failure on %s (CHPID 0x%X) - " PRINT_WARN("Link failure on %s (CHPID 0x%X) - "
"there is a network problem or " "there is a network problem or "
"someone pulled the cable or " "someone pulled the cable or "
"disabled the port. Setting state " "disabled the port.\n",
"of interface to DOWN.\n",
card->info.if_name, card->info.if_name,
card->info.chpid); card->info.chpid);
card->lan_online = 0; card->lan_online = 0;
old_state = card->state; if (netif_carrier_ok(card->dev)) {
rtnl_lock(); netif_carrier_off(card->dev);
dev_close(card->dev); netif_stop_queue(card->dev);
rtnl_unlock(); }
if ((old_state == CARD_STATE_UP_LAN_ONLINE) ||
(old_state == CARD_STATE_UP_LAN_OFFLINE))
card->state = CARD_STATE_UP_LAN_OFFLINE;
return NULL; return NULL;
case IPA_CMD_STARTLAN: case IPA_CMD_STARTLAN:
PRINT_INFO("Link reestablished on %s " PRINT_INFO("Link reestablished on %s "
"(CHPID 0x%X)\n", "(CHPID 0x%X). Scheduling "
"IP address reset.\n",
card->info.if_name, card->info.if_name,
card->info.chpid); card->info.chpid);
card->lan_online = 1; card->lan_online = 1;
if (card->state == CARD_STATE_UP_LAN_OFFLINE){ if (!netif_carrier_ok(card->dev)) {
rtnl_lock(); netif_carrier_on(card->dev);
dev_open(card->dev); netif_wake_queue(card->dev);
rtnl_unlock();
} }
qeth_reset_ip_addresses(card);
return NULL; return NULL;
case IPA_CMD_REGISTER_LOCAL_ADDR: case IPA_CMD_REGISTER_LOCAL_ADDR:
QETH_DBF_TEXT(trace,3, "irla"); QETH_DBF_TEXT(trace,3, "irla");
...@@ -2674,6 +2681,7 @@ qeth_alloc_buffer_pool(struct qeth_card *card) ...@@ -2674,6 +2681,7 @@ qeth_alloc_buffer_pool(struct qeth_card *card)
void *ptr; void *ptr;
int i, j; int i, j;
QETH_DBF_TEXT(trace,5,"clwkpool");
for (i = 0; i < card->qdio.init_pool.buf_count; ++i){ for (i = 0; i < card->qdio.init_pool.buf_count; ++i){
pool_entry = kmalloc(sizeof(*pool_entry), GFP_KERNEL); pool_entry = kmalloc(sizeof(*pool_entry), GFP_KERNEL);
if (!pool_entry){ if (!pool_entry){
...@@ -2694,12 +2702,27 @@ qeth_alloc_buffer_pool(struct qeth_card *card) ...@@ -2694,12 +2702,27 @@ qeth_alloc_buffer_pool(struct qeth_card *card)
} }
list_add(&pool_entry->init_list, list_add(&pool_entry->init_list,
&card->qdio.init_pool.entry_list); &card->qdio.init_pool.entry_list);
list_add(&pool_entry->list,
&card->qdio.in_buf_pool.entry_list);
} }
return 0; return 0;
} }
int
qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt)
{
QETH_DBF_TEXT(trace, 2, "realcbp");
if ((card->state != CARD_STATE_DOWN) &&
(card->state != CARD_STATE_RECOVER))
return -EPERM;
/* TODO: steel/add buffers from/to a running card's buffer pool (?) */
qeth_clear_working_pool_list(card);
qeth_free_buffer_pool(card);
card->qdio.in_buf_pool.buf_count = bufcnt;
card->qdio.init_pool.buf_count = bufcnt;
return qeth_alloc_buffer_pool(card);
}
static int static int
qeth_alloc_qdio_buffers(struct qeth_card *card) qeth_alloc_qdio_buffers(struct qeth_card *card)
{ {
...@@ -2707,10 +2730,9 @@ qeth_alloc_qdio_buffers(struct qeth_card *card) ...@@ -2707,10 +2730,9 @@ qeth_alloc_qdio_buffers(struct qeth_card *card)
QETH_DBF_TEXT(setup, 2, "allcqdbf"); QETH_DBF_TEXT(setup, 2, "allcqdbf");
if (card->qdio.state == QETH_QDIO_ALLOCATED) { if (card->qdio.state == QETH_QDIO_ALLOCATED)
qeth_initialize_working_pool_list(card);
return 0; return 0;
}
card->qdio.in_q = kmalloc(sizeof(struct qeth_qdio_q), GFP_KERNEL); card->qdio.in_q = kmalloc(sizeof(struct qeth_qdio_q), GFP_KERNEL);
if (!card->qdio.in_q) if (!card->qdio.in_q)
return - ENOMEM; return - ENOMEM;
...@@ -2823,14 +2845,13 @@ qeth_init_qdio_queues(struct qeth_card *card) ...@@ -2823,14 +2845,13 @@ qeth_init_qdio_queues(struct qeth_card *card)
/* inbound queue */ /* inbound queue */
memset(card->qdio.in_q->qdio_bufs, 0, memset(card->qdio.in_q->qdio_bufs, 0,
QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer)); QDIO_MAX_BUFFERS_PER_Q * sizeof(struct qdio_buffer));
card->qdio.in_q->next_buf_to_process = 0; qeth_initialize_working_pool_list(card);
card->qdio.in_q->next_buf_to_init = 0;
/*give only as many buffers to hardware as we have buffer pool entries*/ /*give only as many buffers to hardware as we have buffer pool entries*/
for (i = 0; i < card->qdio.in_buf_pool.buf_count; ++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; card->qdio.in_q->next_buf_to_init = card->qdio.in_buf_pool.buf_count - 1;
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, NULL); card->qdio.in_buf_pool.buf_count - 1, NULL);
if (rc) { if (rc) {
QETH_DBF_TEXT_(setup, 2, "1err%d", rc); QETH_DBF_TEXT_(setup, 2, "1err%d", rc);
return rc; return rc;
...@@ -3168,7 +3189,7 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -3168,7 +3189,7 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->stats.tx_errors++; card->stats.tx_errors++;
return -EIO; return -EIO;
} }
if (card->state != CARD_STATE_UP_LAN_ONLINE) { if ((card->state != CARD_STATE_UP) || !netif_carrier_ok(dev)) {
card->stats.tx_dropped++; card->stats.tx_dropped++;
card->stats.tx_errors++; card->stats.tx_errors++;
card->stats.tx_carrier_errors++; card->stats.tx_carrier_errors++;
...@@ -3271,18 +3292,19 @@ qeth_open(struct net_device *dev) ...@@ -3271,18 +3292,19 @@ qeth_open(struct net_device *dev)
card = (struct qeth_card *) dev->priv; card = (struct qeth_card *) dev->priv;
if ((card->state != CARD_STATE_SOFTSETUP) && if (card->state != CARD_STATE_SOFTSETUP)
(card->state != CARD_STATE_UP_LAN_OFFLINE))
return -ENODEV; return -ENODEV;
if (!card->lan_online){
card->state = CARD_STATE_UP_LAN_OFFLINE;
return -EIO;
}
card->dev->flags |= IFF_UP; card->dev->flags |= IFF_UP;
netif_start_queue(dev); netif_start_queue(dev);
card->data.state = CH_STATE_UP; card->data.state = CH_STATE_UP;
card->state = CARD_STATE_UP_LAN_ONLINE; card->state = CARD_STATE_UP;
if (!card->lan_online){
if (netif_carrier_ok(dev))
netif_carrier_off(dev);
netif_stop_queue(dev);
}
return 0; return 0;
} }
...@@ -3297,8 +3319,7 @@ qeth_stop(struct net_device *dev) ...@@ -3297,8 +3319,7 @@ qeth_stop(struct net_device *dev)
netif_stop_queue(dev); netif_stop_queue(dev);
card->dev->flags &= ~IFF_UP; card->dev->flags &= ~IFF_UP;
if ((card->state == CARD_STATE_UP_LAN_ONLINE) || if (card->state == CARD_STATE_UP)
(card->state == CARD_STATE_UP_LAN_OFFLINE))
card->state = CARD_STATE_SOFTSETUP; card->state = CARD_STATE_SOFTSETUP;
return 0; return 0;
} }
...@@ -3925,13 +3946,17 @@ qeth_get_ipa_arp_cmd_buffer(struct qeth_card *card, u16 cmd_code, ...@@ -3925,13 +3946,17 @@ qeth_get_ipa_arp_cmd_buffer(struct qeth_card *card, u16 cmd_code,
iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, proto); iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETASSPARMS, proto);
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
/* adjust sizes in IPA_PDU_HEADER */
s1 = (u32) IPA_PDU_HEADER_SIZE + QETH_ARP_CMD_BASE_LEN + data_len; if ((IPA_PDU_HEADER_SIZE + QETH_ARP_CMD_BASE_LEN + data_len) > 256) {
s2 = (u32) QETH_ARP_CMD_BASE_LEN + data_len; /* adjust sizes in IPA_PDU_HEADER */
memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2); s1 = (u32) IPA_PDU_HEADER_SIZE + QETH_ARP_CMD_BASE_LEN +
memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2); data_len;
memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2); s2 = (u32) QETH_ARP_CMD_BASE_LEN + data_len;
memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2); memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2);
memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2);
memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2);
memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2);
}
cmd = (struct qeth_ipa_arp_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); cmd = (struct qeth_ipa_arp_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
cmd->shdr.assist_no = IPA_ARP_PROCESSING; cmd->shdr.assist_no = IPA_ARP_PROCESSING;
...@@ -3975,7 +4000,12 @@ qeth_arp_query(struct qeth_card *card, char *udata) ...@@ -3975,7 +4000,12 @@ qeth_arp_query(struct qeth_card *card, char *udata)
QETH_DBF_TEXT(trace,3,"arpquery"); QETH_DBF_TEXT(trace,3,"arpquery");
/* TODO: really not supported by GuestLAN? */ /*
* currently GuestLAN does only deliver all zeros on query arp,
* even though arp processing is supported (according to IPA supp.
* funcs flags); since all zeros is no valueable information,
* we say EOPNOTSUPP for all ARP functions
*/
if (card->info.guestlan) if (card->info.guestlan)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
...@@ -3997,9 +4027,11 @@ qeth_arp_query(struct qeth_card *card, char *udata) ...@@ -3997,9 +4027,11 @@ qeth_arp_query(struct qeth_card *card, char *udata)
return -ENOMEM; return -ENOMEM;
} }
memset(qdata, 0, sizeof(struct qeth_arp_query_data)); memset(qdata, 0, sizeof(struct qeth_arp_query_data));
/* do not give sizeof(struct qeth_arp_query_data) to next command;
* this would cause the IPA PDU size to be set to a value of > 256
* and this is to much for HiperSockets */
iob = qeth_get_ipa_arp_cmd_buffer(card, IPA_CMD_ASS_ARP_QUERY_INFO, iob = qeth_get_ipa_arp_cmd_buffer(card, IPA_CMD_ASS_ARP_QUERY_INFO,
sizeof(struct qeth_arp_query_data), 0, QETH_PROT_IPV4);
QETH_PROT_IPV4);
rc = qeth_send_ipa_arp_cmd(card, iob, rc = qeth_send_ipa_arp_cmd(card, iob,
(char *) qdata, (char *) qdata,
sizeof(struct qeth_arp_query_data), sizeof(struct qeth_arp_query_data),
...@@ -4043,7 +4075,12 @@ qeth_arp_add_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry) ...@@ -4043,7 +4075,12 @@ qeth_arp_add_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry)
QETH_DBF_TEXT(trace,3,"arpadent"); QETH_DBF_TEXT(trace,3,"arpadent");
/* TODO: really not supported by GuestLAN? */ /*
* currently GuestLAN does only deliver all zeros on query arp,
* even though arp processing is supported (according to IPA supp.
* funcs flags); since all zeros is no valueable information,
* we say EOPNOTSUPP for all ARP functions
*/
if (card->info.guestlan) if (card->info.guestlan)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
...@@ -4081,7 +4118,12 @@ qeth_arp_remove_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry ...@@ -4081,7 +4118,12 @@ qeth_arp_remove_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry
QETH_DBF_TEXT(trace,3,"arprment"); QETH_DBF_TEXT(trace,3,"arprment");
/* TODO: really not supported by GuestLAN? */ /*
* currently GuestLAN does only deliver all zeros on query arp,
* even though arp processing is supported (according to IPA supp.
* funcs flags); since all zeros is no valueable information,
* we say EOPNOTSUPP for all ARP functions
*/
if (card->info.guestlan) if (card->info.guestlan)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
...@@ -4117,7 +4159,12 @@ qeth_arp_flush_cache(struct qeth_card *card) ...@@ -4117,7 +4159,12 @@ qeth_arp_flush_cache(struct qeth_card *card)
QETH_DBF_TEXT(trace,3,"arpflush"); QETH_DBF_TEXT(trace,3,"arpflush");
/* TODO: really not supported by GuestLAN? */ /*
* currently GuestLAN does only deliver all zeros on query arp,
* even though arp processing is supported (according to IPA supp.
* funcs flags); since all zeros is no valueable information,
* we say EOPNOTSUPP for all ARP functions
*/
if (card->info.guestlan) if (card->info.guestlan)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) {
...@@ -4147,8 +4194,7 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) ...@@ -4147,8 +4194,7 @@ qeth_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!card) if (!card)
return -ENODEV; return -ENODEV;
if ((card->state != CARD_STATE_UP_LAN_ONLINE) && if (card->state != CARD_STATE_UP)
(card->state != CARD_STATE_UP_LAN_OFFLINE))
return -ENODEV; return -ENODEV;
switch (cmd){ switch (cmd){
...@@ -5551,6 +5597,47 @@ qeth_send_setrouting(struct qeth_card *card, enum qeth_routing_types type, ...@@ -5551,6 +5597,47 @@ qeth_send_setrouting(struct qeth_card *card, enum qeth_routing_types type,
} }
static void
qeth_correct_routing_type(struct qeth_card *card, enum qeth_routing_types *type,
enum qeth_prot_versions prot)
{
if (card->info.type == QETH_CARD_TYPE_IQD) {
switch (*type) {
case NO_ROUTER:
case PRIMARY_CONNECTOR:
case SECONDARY_CONNECTOR:
case MULTICAST_ROUTER:
return;
default:
goto out_inval;
}
} else {
switch (*type) {
case NO_ROUTER:
case PRIMARY_ROUTER:
case SECONDARY_ROUTER:
return;
case MULTICAST_ROUTER:
if (qeth_is_ipafunc_supported(card, prot,
IPA_OSA_MC_ROUTER))
return;
default:
goto out_inval;
}
}
out_inval:
PRINT_WARN("Routing type '%s' not supported for interface %s.\n"
"Router status set to 'no router'.\n",
((*type == PRIMARY_ROUTER)? "primary router" :
(*type == SECONDARY_ROUTER)? "secondary router" :
(*type == PRIMARY_CONNECTOR)? "primary connector" :
(*type == SECONDARY_CONNECTOR)? "secondary connector" :
(*type == MULTICAST_ROUTER)? "multicast router" :
"unknown"),
card->dev->name);
*type = NO_ROUTER;
}
int int
qeth_setrouting_v4(struct qeth_card *card) qeth_setrouting_v4(struct qeth_card *card)
{ {
...@@ -5558,8 +5645,8 @@ qeth_setrouting_v4(struct qeth_card *card) ...@@ -5558,8 +5645,8 @@ qeth_setrouting_v4(struct qeth_card *card)
QETH_DBF_TEXT(trace,3,"setrtg4"); QETH_DBF_TEXT(trace,3,"setrtg4");
if (card->options.route4.type == NO_ROUTER) qeth_correct_routing_type(card, &card->options.route4.type,
return 0; QETH_PROT_IPV4);
rc = qeth_send_setrouting(card, card->options.route4.type, rc = qeth_send_setrouting(card, card->options.route4.type,
QETH_PROT_IPV4); QETH_PROT_IPV4);
...@@ -5580,6 +5667,9 @@ qeth_setrouting_v6(struct qeth_card *card) ...@@ -5580,6 +5667,9 @@ qeth_setrouting_v6(struct qeth_card *card)
QETH_DBF_TEXT(trace,3,"setrtg6"); QETH_DBF_TEXT(trace,3,"setrtg6");
#ifdef CONFIG_QETH_IPV6 #ifdef CONFIG_QETH_IPV6
qeth_correct_routing_type(card, &card->options.route6.type,
QETH_PROT_IPV6);
if ((card->options.route6.type == NO_ROUTER) || if ((card->options.route6.type == NO_ROUTER) ||
((card->info.type == QETH_CARD_TYPE_OSAE) && ((card->info.type == QETH_CARD_TYPE_OSAE) &&
(card->options.route6.type == MULTICAST_ROUTER) && (card->options.route6.type == MULTICAST_ROUTER) &&
...@@ -5775,8 +5865,7 @@ qeth_stop_card(struct qeth_card *card) ...@@ -5775,8 +5865,7 @@ qeth_stop_card(struct qeth_card *card)
return -ERESTARTSYS; return -ERESTARTSYS;
if (card->read.state == CH_STATE_UP && if (card->read.state == CH_STATE_UP &&
card->write.state == CH_STATE_UP && card->write.state == CH_STATE_UP &&
((card->state == CARD_STATE_UP_LAN_ONLINE) || (card->state == CARD_STATE_UP)) {
(card->state == CARD_STATE_UP_LAN_OFFLINE))) {
recover_flag = 1; recover_flag = 1;
rtnl_lock(); rtnl_lock();
dev_close(card->dev); dev_close(card->dev);
......
/* /*
* *
* linux/drivers/s390/net/qeth_sys.c ($Revision: 1.19 $) * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.24 $)
* *
* 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.
...@@ -41,10 +41,11 @@ qeth_dev_state_show(struct device *dev, char *buf) ...@@ -41,10 +41,11 @@ qeth_dev_state_show(struct device *dev, char *buf)
return sprintf(buf, "HARDSETUP\n"); return sprintf(buf, "HARDSETUP\n");
case CARD_STATE_SOFTSETUP: case CARD_STATE_SOFTSETUP:
return sprintf(buf, "SOFTSETUP\n"); return sprintf(buf, "SOFTSETUP\n");
case CARD_STATE_UP_LAN_OFFLINE: case CARD_STATE_UP:
return sprintf(buf, "UP (LAN OFFLINE)\n"); if (card->lan_online)
case CARD_STATE_UP_LAN_ONLINE:
return sprintf(buf, "UP (LAN ONLINE)\n"); return sprintf(buf, "UP (LAN ONLINE)\n");
else
return sprintf(buf, "UP (LAN OFFLINE)\n");
case CARD_STATE_RECOVER: case CARD_STATE_RECOVER:
return sprintf(buf, "RECOVER\n"); return sprintf(buf, "RECOVER\n");
default: default:
...@@ -293,7 +294,8 @@ qeth_dev_bufcnt_store(struct device *dev, const char *buf, size_t count) ...@@ -293,7 +294,8 @@ qeth_dev_bufcnt_store(struct device *dev, const char *buf, size_t count)
{ {
struct qeth_card *card = dev->driver_data; struct qeth_card *card = dev->driver_data;
char *tmp; char *tmp;
unsigned int cnt; int cnt, old_cnt;
int rc;
if (!card) if (!card)
return -EINVAL; return -EINVAL;
...@@ -302,12 +304,15 @@ qeth_dev_bufcnt_store(struct device *dev, const char *buf, size_t count) ...@@ -302,12 +304,15 @@ qeth_dev_bufcnt_store(struct device *dev, const char *buf, size_t count)
(card->state != CARD_STATE_RECOVER)) (card->state != CARD_STATE_RECOVER))
return -EPERM; return -EPERM;
cnt = simple_strtoul(buf, &tmp, 16); old_cnt = card->qdio.in_buf_pool.buf_count;
cnt = simple_strtoul(buf, &tmp, 10);
cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN : cnt = (cnt < QETH_IN_BUF_COUNT_MIN) ? QETH_IN_BUF_COUNT_MIN :
((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt); ((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt);
card->qdio.in_buf_pool.buf_count = cnt; if (old_cnt != cnt) {
/* TODO: steel/add buffers from/to a running card's buffer pool (?) */ if ((rc = qeth_realloc_buffer_pool(card, cnt)))
PRINT_WARN("Error (%d) while setting "
"buffer count.\n", rc);
}
return count; return count;
} }
...@@ -356,45 +361,31 @@ qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route, ...@@ -356,45 +361,31 @@ qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route,
if (!strcmp(tmp, "no_router")){ if (!strcmp(tmp, "no_router")){
route->type = NO_ROUTER; route->type = NO_ROUTER;
goto check_reset; } else if (!strcmp(tmp, "primary_connector")) {
} route->type = PRIMARY_CONNECTOR;
} else if (!strcmp(tmp, "secondary_connector")) {
if (card->info.type == QETH_CARD_TYPE_IQD) { route->type = SECONDARY_CONNECTOR;
if (!strcmp(tmp, "primary_connector")) { } else if (!strcmp(tmp, "multicast_router")) {
route->type = PRIMARY_CONNECTOR; route->type = MULTICAST_ROUTER;
} else if (!strcmp(tmp, "secondary_connector")) { } else if (!strcmp(tmp, "primary_router")) {
route->type = SECONDARY_CONNECTOR; route->type = PRIMARY_ROUTER;
} else if (!strcmp(tmp, "multicast_router")) { } else if (!strcmp(tmp, "secondary_router")) {
route->type = MULTICAST_ROUTER; route->type = SECONDARY_ROUTER;
} else } else if (!strcmp(tmp, "multicast_router")) {
goto out_inval; route->type = MULTICAST_ROUTER;
} else { } else {
if (!strcmp(tmp, "primary_router")) { PRINT_WARN("Invalid routing type '%s'.\n", tmp);
route->type = PRIMARY_ROUTER; return -EINVAL;
} 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 (((card->state == CARD_STATE_SOFTSETUP) ||
if (old_route_type != route->type){ (card->state == CARD_STATE_UP)) &&
(old_route_type != route->type)){
if (prot == QETH_PROT_IPV4) if (prot == QETH_PROT_IPV4)
rc = qeth_setrouting_v4(card); rc = qeth_setrouting_v4(card);
else if (prot == QETH_PROT_IPV6) else if (prot == QETH_PROT_IPV6)
rc = qeth_setrouting_v6(card); rc = qeth_setrouting_v6(card);
} }
return count; 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 static ssize_t
...@@ -572,8 +563,7 @@ qeth_dev_recover_store(struct device *dev, const char *buf, size_t count) ...@@ -572,8 +563,7 @@ qeth_dev_recover_store(struct device *dev, const char *buf, size_t count)
if (!card) if (!card)
return -EINVAL; return -EINVAL;
if ((card->state != CARD_STATE_UP_LAN_ONLINE) && if (card->state != CARD_STATE_UP)
(card->state != CARD_STATE_UP_LAN_OFFLINE))
return -EPERM; return -EPERM;
i = simple_strtoul(buf, &tmp, 16); i = simple_strtoul(buf, &tmp, 16);
...@@ -585,7 +575,6 @@ qeth_dev_recover_store(struct device *dev, const char *buf, size_t count) ...@@ -585,7 +575,6 @@ qeth_dev_recover_store(struct device *dev, const char *buf, size_t count)
static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store); static DEVICE_ATTR(recover, 0200, NULL, qeth_dev_recover_store);
/* TODO */
static ssize_t static ssize_t
qeth_dev_broadcast_mode_show(struct device *dev, char *buf) qeth_dev_broadcast_mode_show(struct device *dev, char *buf)
{ {
...@@ -603,7 +592,6 @@ qeth_dev_broadcast_mode_show(struct device *dev, char *buf) ...@@ -603,7 +592,6 @@ qeth_dev_broadcast_mode_show(struct device *dev, char *buf)
"all rings":"local"); "all rings":"local");
} }
/* TODO */
static ssize_t static ssize_t
qeth_dev_broadcast_mode_store(struct device *dev, const char *buf, size_t count) qeth_dev_broadcast_mode_store(struct device *dev, const char *buf, size_t count)
{ {
...@@ -642,7 +630,6 @@ qeth_dev_broadcast_mode_store(struct device *dev, const char *buf, size_t count) ...@@ -642,7 +630,6 @@ qeth_dev_broadcast_mode_store(struct device *dev, const char *buf, size_t count)
static DEVICE_ATTR(broadcast_mode, 0644, qeth_dev_broadcast_mode_show, static DEVICE_ATTR(broadcast_mode, 0644, qeth_dev_broadcast_mode_show,
qeth_dev_broadcast_mode_store); qeth_dev_broadcast_mode_store);
/* TODO */
static ssize_t static ssize_t
qeth_dev_canonical_macaddr_show(struct device *dev, char *buf) qeth_dev_canonical_macaddr_show(struct device *dev, char *buf)
{ {
...@@ -659,7 +646,6 @@ qeth_dev_canonical_macaddr_show(struct device *dev, char *buf) ...@@ -659,7 +646,6 @@ qeth_dev_canonical_macaddr_show(struct device *dev, char *buf)
QETH_TR_MACADDR_CANONICAL)? 1:0); QETH_TR_MACADDR_CANONICAL)? 1:0);
} }
/* TODO */
static ssize_t static ssize_t
qeth_dev_canonical_macaddr_store(struct device *dev, const char *buf, qeth_dev_canonical_macaddr_store(struct device *dev, const char *buf,
size_t count) size_t count)
......
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