Commit 983f27d3 authored by Jeff Garzik's avatar Jeff Garzik

Merge branch 'upstream-fixes' into upstream

Conflicts:

	drivers/s390/net/ctctty.c
parents de1e938e e82b0f2c
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/err.h> #include <linux/err.h>
...@@ -77,7 +77,7 @@ group_write(struct device_driver *drv, const char *buf, size_t count) ...@@ -77,7 +77,7 @@ group_write(struct device_driver *drv, const char *buf, size_t count)
int len; int len;
if (!(end = strchr(start, delim[i]))) if (!(end = strchr(start, delim[i])))
return count; return -EINVAL;
len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1); len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
strlcpy (bus_ids[i], start, len); strlcpy (bus_ids[i], start, len);
argv[i] = bus_ids[i]; argv[i] = bus_ids[i];
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
*/ */
/* #define DEBUG */ /* #define DEBUG */
#include <linux/module.h> #include <linux/module.h>
...@@ -297,7 +297,7 @@ MODULE_LICENSE("GPL"); ...@@ -297,7 +297,7 @@ MODULE_LICENSE("GPL");
/* /*
* Debugging stuff * Debugging stuff
*******************************************************************************/ *******************************************************************************/
#ifdef DEBUG #ifdef DEBUG
static int debuglevel = 0; static int debuglevel = 0;
...@@ -344,7 +344,7 @@ do { \ ...@@ -344,7 +344,7 @@ do { \
/* /*
* Internal functions * Internal functions
*******************************************************************************/ *******************************************************************************/
/** /**
* print start banner * print start banner
*/ */
......
...@@ -68,6 +68,7 @@ static void lcs_tasklet(unsigned long); ...@@ -68,6 +68,7 @@ static void lcs_tasklet(unsigned long);
static void lcs_start_kernel_thread(struct lcs_card *card); static void lcs_start_kernel_thread(struct lcs_card *card);
static void lcs_get_frames_cb(struct lcs_channel *, struct lcs_buffer *); static void lcs_get_frames_cb(struct lcs_channel *, struct lcs_buffer *);
static int lcs_send_delipm(struct lcs_card *, struct lcs_ipm_list *); static int lcs_send_delipm(struct lcs_card *, struct lcs_ipm_list *);
static int lcs_recovery(void *ptr);
/** /**
* Debug Facility Stuff * Debug Facility Stuff
...@@ -429,12 +430,6 @@ lcs_setup_card(struct lcs_card *card) ...@@ -429,12 +430,6 @@ lcs_setup_card(struct lcs_card *card)
card->tx_buffer = NULL; card->tx_buffer = NULL;
card->tx_emitted = 0; card->tx_emitted = 0;
/* Initialize kernel thread task used for LGW commands. */
INIT_WORK(&card->kernel_thread_starter,
(void *)lcs_start_kernel_thread,card);
card->thread_start_mask = 0;
card->thread_allowed_mask = 0;
card->thread_running_mask = 0;
init_waitqueue_head(&card->wait_q); init_waitqueue_head(&card->wait_q);
spin_lock_init(&card->lock); spin_lock_init(&card->lock);
spin_lock_init(&card->ipm_lock); spin_lock_init(&card->ipm_lock);
...@@ -675,8 +670,9 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) ...@@ -675,8 +670,9 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
int index, rc; int index, rc;
LCS_DBF_TEXT(5, trace, "rdybuff"); LCS_DBF_TEXT(5, trace, "rdybuff");
BUG_ON(buffer->state != BUF_STATE_LOCKED && if (buffer->state != BUF_STATE_LOCKED &&
buffer->state != BUF_STATE_PROCESSED); buffer->state != BUF_STATE_PROCESSED)
BUG();
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
buffer->state = BUF_STATE_READY; buffer->state = BUF_STATE_READY;
index = buffer - channel->iob; index = buffer - channel->iob;
...@@ -700,7 +696,8 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) ...@@ -700,7 +696,8 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
int index, prev, next; int index, prev, next;
LCS_DBF_TEXT(5, trace, "prcsbuff"); LCS_DBF_TEXT(5, trace, "prcsbuff");
BUG_ON(buffer->state != BUF_STATE_READY); if (buffer->state != BUF_STATE_READY)
BUG();
buffer->state = BUF_STATE_PROCESSED; buffer->state = BUF_STATE_PROCESSED;
index = buffer - channel->iob; index = buffer - channel->iob;
prev = (index - 1) & (LCS_NUM_BUFFS - 1); prev = (index - 1) & (LCS_NUM_BUFFS - 1);
...@@ -732,8 +729,9 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) ...@@ -732,8 +729,9 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
unsigned long flags; unsigned long flags;
LCS_DBF_TEXT(5, trace, "relbuff"); LCS_DBF_TEXT(5, trace, "relbuff");
BUG_ON(buffer->state != BUF_STATE_LOCKED && if (buffer->state != BUF_STATE_LOCKED &&
buffer->state != BUF_STATE_PROCESSED); buffer->state != BUF_STATE_PROCESSED)
BUG();
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
buffer->state = BUF_STATE_EMPTY; buffer->state = BUF_STATE_EMPTY;
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
...@@ -1147,8 +1145,6 @@ lcs_fix_multicast_list(struct lcs_card *card) ...@@ -1147,8 +1145,6 @@ lcs_fix_multicast_list(struct lcs_card *card)
list_add_tail(&ipm->list, &card->ipm_list); list_add_tail(&ipm->list, &card->ipm_list);
} }
spin_unlock_irqrestore(&card->ipm_lock, flags); spin_unlock_irqrestore(&card->ipm_lock, flags);
if (card->state == DEV_STATE_UP)
netif_wake_queue(card->dev);
} }
/** /**
...@@ -1231,17 +1227,17 @@ lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) ...@@ -1231,17 +1227,17 @@ lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev)
if (ipm != NULL) if (ipm != NULL)
continue; /* Address already in list. */ continue; /* Address already in list. */
ipm = (struct lcs_ipm_list *) ipm = (struct lcs_ipm_list *)
kmalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC); kzalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC);
if (ipm == NULL) { if (ipm == NULL) {
PRINT_INFO("Not enough memory to add " PRINT_INFO("Not enough memory to add "
"new multicast entry!\n"); "new multicast entry!\n");
break; break;
} }
memset(ipm, 0, sizeof(struct lcs_ipm_list));
memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH); memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH);
ipm->ipm.ip_addr = im4->multiaddr; ipm->ipm.ip_addr = im4->multiaddr;
ipm->ipm_state = LCS_IPM_STATE_SET_REQUIRED; ipm->ipm_state = LCS_IPM_STATE_SET_REQUIRED;
spin_lock_irqsave(&card->ipm_lock, flags); spin_lock_irqsave(&card->ipm_lock, flags);
LCS_DBF_HEX(2,trace,&ipm->ipm.ip_addr,4);
list_add(&ipm->list, &card->ipm_list); list_add(&ipm->list, &card->ipm_list);
spin_unlock_irqrestore(&card->ipm_lock, flags); spin_unlock_irqrestore(&card->ipm_lock, flags);
} }
...@@ -1269,7 +1265,15 @@ lcs_register_mc_addresses(void *data) ...@@ -1269,7 +1265,15 @@ lcs_register_mc_addresses(void *data)
read_unlock(&in4_dev->mc_list_lock); read_unlock(&in4_dev->mc_list_lock);
in_dev_put(in4_dev); in_dev_put(in4_dev);
netif_carrier_off(card->dev);
netif_tx_disable(card->dev);
wait_event(card->write.wait_q,
(card->write.state != CH_STATE_RUNNING));
lcs_fix_multicast_list(card); lcs_fix_multicast_list(card);
if (card->state == DEV_STATE_UP) {
netif_carrier_on(card->dev);
netif_wake_queue(card->dev);
}
out: out:
lcs_clear_thread_running_bit(card, LCS_SET_MC_THREAD); lcs_clear_thread_running_bit(card, LCS_SET_MC_THREAD);
return 0; return 0;
...@@ -1318,6 +1322,53 @@ lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb) ...@@ -1318,6 +1322,53 @@ lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb)
return PTR_ERR(irb); return PTR_ERR(irb);
} }
static int
lcs_get_problem(struct ccw_device *cdev, struct irb *irb)
{
int dstat, cstat;
char *sense;
sense = (char *) irb->ecw;
cstat = irb->scsw.cstat;
dstat = irb->scsw.dstat;
if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK |
SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK |
SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) {
LCS_DBF_TEXT(2, trace, "CGENCHK");
return 1;
}
if (dstat & DEV_STAT_UNIT_CHECK) {
if (sense[LCS_SENSE_BYTE_1] &
LCS_SENSE_RESETTING_EVENT) {
LCS_DBF_TEXT(2, trace, "REVIND");
return 1;
}
if (sense[LCS_SENSE_BYTE_0] &
LCS_SENSE_CMD_REJECT) {
LCS_DBF_TEXT(2, trace, "CMDREJ");
return 0;
}
if ((!sense[LCS_SENSE_BYTE_0]) &&
(!sense[LCS_SENSE_BYTE_1]) &&
(!sense[LCS_SENSE_BYTE_2]) &&
(!sense[LCS_SENSE_BYTE_3])) {
LCS_DBF_TEXT(2, trace, "ZEROSEN");
return 0;
}
LCS_DBF_TEXT(2, trace, "DGENCHK");
return 1;
}
return 0;
}
void
lcs_schedule_recovery(struct lcs_card *card)
{
LCS_DBF_TEXT(2, trace, "startrec");
if (!lcs_set_thread_start_bit(card, LCS_RECOVERY_THREAD))
schedule_work(&card->kernel_thread_starter);
}
/** /**
* IRQ Handler for LCS channels * IRQ Handler for LCS channels
...@@ -1327,7 +1378,8 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) ...@@ -1327,7 +1378,8 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
{ {
struct lcs_card *card; struct lcs_card *card;
struct lcs_channel *channel; struct lcs_channel *channel;
int index; int rc, index;
int cstat, dstat;
if (lcs_check_irb_error(cdev, irb)) if (lcs_check_irb_error(cdev, irb))
return; return;
...@@ -1338,10 +1390,23 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) ...@@ -1338,10 +1390,23 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
else else
channel = &card->write; channel = &card->write;
cstat = irb->scsw.cstat;
dstat = irb->scsw.dstat;
LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id); LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id);
LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat); LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat);
LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.fctl, irb->scsw.actl); LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.fctl, irb->scsw.actl);
/* Check for channel and device errors presented */
rc = lcs_get_problem(cdev, irb);
if (rc || (dstat & DEV_STAT_UNIT_EXCEP)) {
PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n",
cdev->dev.bus_id, dstat, cstat);
if (rc) {
lcs_schedule_recovery(card);
wake_up(&card->wait_q);
return;
}
}
/* How far in the ccw chain have we processed? */ /* How far in the ccw chain have we processed? */
if ((channel->state != CH_STATE_INIT) && if ((channel->state != CH_STATE_INIT) &&
(irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) {
...@@ -1367,7 +1432,6 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) ...@@ -1367,7 +1432,6 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED) else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED)
/* CCW execution stopped on a suspend bit. */ /* CCW execution stopped on a suspend bit. */
channel->state = CH_STATE_SUSPENDED; channel->state = CH_STATE_SUSPENDED;
if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) { if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) {
if (irb->scsw.cc != 0) { if (irb->scsw.cc != 0) {
ccw_device_halt(channel->ccwdev, (addr_t) channel); ccw_device_halt(channel->ccwdev, (addr_t) channel);
...@@ -1376,7 +1440,6 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) ...@@ -1376,7 +1440,6 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
/* The channel has been stopped by halt_IO. */ /* The channel has been stopped by halt_IO. */
channel->state = CH_STATE_HALTED; channel->state = CH_STATE_HALTED;
} }
if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
channel->state = CH_STATE_CLEARED; channel->state = CH_STATE_CLEARED;
} }
...@@ -1452,7 +1515,7 @@ lcs_txbuffer_cb(struct lcs_channel *channel, struct lcs_buffer *buffer) ...@@ -1452,7 +1515,7 @@ lcs_txbuffer_cb(struct lcs_channel *channel, struct lcs_buffer *buffer)
lcs_release_buffer(channel, buffer); lcs_release_buffer(channel, buffer);
card = (struct lcs_card *) card = (struct lcs_card *)
((char *) channel - offsetof(struct lcs_card, write)); ((char *) channel - offsetof(struct lcs_card, write));
if (netif_queue_stopped(card->dev)) if (netif_queue_stopped(card->dev) && netif_carrier_ok(card->dev))
netif_wake_queue(card->dev); netif_wake_queue(card->dev);
spin_lock(&card->lock); spin_lock(&card->lock);
card->tx_emitted--; card->tx_emitted--;
...@@ -1488,6 +1551,10 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb, ...@@ -1488,6 +1551,10 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb,
card->stats.tx_carrier_errors++; card->stats.tx_carrier_errors++;
return 0; return 0;
} }
if (skb->protocol == htons(ETH_P_IPV6)) {
dev_kfree_skb(skb);
return 0;
}
netif_stop_queue(card->dev); netif_stop_queue(card->dev);
spin_lock(&card->lock); spin_lock(&card->lock);
if (card->tx_buffer != NULL && if (card->tx_buffer != NULL &&
...@@ -1632,30 +1699,6 @@ lcs_detect(struct lcs_card *card) ...@@ -1632,30 +1699,6 @@ lcs_detect(struct lcs_card *card)
return rc; return rc;
} }
/**
* reset card
*/
static int
lcs_resetcard(struct lcs_card *card)
{
int retries;
LCS_DBF_TEXT(2, trace, "rescard");
for (retries = 0; retries < 10; retries++) {
if (lcs_detect(card) == 0) {
netif_wake_queue(card->dev);
card->state = DEV_STATE_UP;
PRINT_INFO("LCS device %s successfully restarted!\n",
card->dev->name);
return 0;
}
msleep(3000);
}
PRINT_ERR("Error in Reseting LCS card!\n");
return -EIO;
}
/** /**
* LCS Stop card * LCS Stop card
*/ */
...@@ -1679,111 +1722,6 @@ lcs_stopcard(struct lcs_card *card) ...@@ -1679,111 +1722,6 @@ lcs_stopcard(struct lcs_card *card)
return rc; return rc;
} }
/**
* LGW initiated commands
*/
static int
lcs_lgw_startlan_thread(void *data)
{
struct lcs_card *card;
card = (struct lcs_card *) data;
daemonize("lgwstpln");
if (!lcs_do_run_thread(card, LCS_STARTLAN_THREAD))
return 0;
LCS_DBF_TEXT(4, trace, "lgwstpln");
if (card->dev)
netif_stop_queue(card->dev);
if (lcs_startlan(card) == 0) {
netif_wake_queue(card->dev);
card->state = DEV_STATE_UP;
PRINT_INFO("LCS Startlan for device %s succeeded!\n",
card->dev->name);
} else
PRINT_ERR("LCS Startlan for device %s failed!\n",
card->dev->name);
lcs_clear_thread_running_bit(card, LCS_STARTLAN_THREAD);
return 0;
}
/**
* Send startup command initiated by Lan Gateway
*/
static int
lcs_lgw_startup_thread(void *data)
{
int rc;
struct lcs_card *card;
card = (struct lcs_card *) data;
daemonize("lgwstaln");
if (!lcs_do_run_thread(card, LCS_STARTUP_THREAD))
return 0;
LCS_DBF_TEXT(4, trace, "lgwstaln");
if (card->dev)
netif_stop_queue(card->dev);
rc = lcs_send_startup(card, LCS_INITIATOR_LGW);
if (rc != 0) {
PRINT_ERR("Startup for LCS device %s initiated " \
"by LGW failed!\nReseting card ...\n",
card->dev->name);
/* do a card reset */
rc = lcs_resetcard(card);
if (rc == 0)
goto Done;
}
rc = lcs_startlan(card);
if (rc == 0) {
netif_wake_queue(card->dev);
card->state = DEV_STATE_UP;
}
Done:
if (rc == 0)
PRINT_INFO("LCS Startup for device %s succeeded!\n",
card->dev->name);
else
PRINT_ERR("LCS Startup for device %s failed!\n",
card->dev->name);
lcs_clear_thread_running_bit(card, LCS_STARTUP_THREAD);
return 0;
}
/**
* send stoplan command initiated by Lan Gateway
*/
static int
lcs_lgw_stoplan_thread(void *data)
{
struct lcs_card *card;
int rc;
card = (struct lcs_card *) data;
daemonize("lgwstop");
if (!lcs_do_run_thread(card, LCS_STOPLAN_THREAD))
return 0;
LCS_DBF_TEXT(4, trace, "lgwstop");
if (card->dev)
netif_stop_queue(card->dev);
if (lcs_send_stoplan(card, LCS_INITIATOR_LGW) == 0)
PRINT_INFO("Stoplan for %s initiated by LGW succeeded!\n",
card->dev->name);
else
PRINT_ERR("Stoplan %s initiated by LGW failed!\n",
card->dev->name);
/*Try to reset the card, stop it on failure */
rc = lcs_resetcard(card);
if (rc != 0)
rc = lcs_stopcard(card);
lcs_clear_thread_running_bit(card, LCS_STOPLAN_THREAD);
return rc;
}
/** /**
* Kernel Thread helper functions for LGW initiated commands * Kernel Thread helper functions for LGW initiated commands
*/ */
...@@ -1791,15 +1729,12 @@ static void ...@@ -1791,15 +1729,12 @@ static void
lcs_start_kernel_thread(struct lcs_card *card) lcs_start_kernel_thread(struct lcs_card *card)
{ {
LCS_DBF_TEXT(5, trace, "krnthrd"); LCS_DBF_TEXT(5, trace, "krnthrd");
if (lcs_do_start_thread(card, LCS_STARTUP_THREAD)) if (lcs_do_start_thread(card, LCS_RECOVERY_THREAD))
kernel_thread(lcs_lgw_startup_thread, (void *) card, SIGCHLD); kernel_thread(lcs_recovery, (void *) card, SIGCHLD);
if (lcs_do_start_thread(card, LCS_STARTLAN_THREAD))
kernel_thread(lcs_lgw_startlan_thread, (void *) card, SIGCHLD);
if (lcs_do_start_thread(card, LCS_STOPLAN_THREAD))
kernel_thread(lcs_lgw_stoplan_thread, (void *) card, SIGCHLD);
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
if (lcs_do_start_thread(card, LCS_SET_MC_THREAD)) if (lcs_do_start_thread(card, LCS_SET_MC_THREAD))
kernel_thread(lcs_register_mc_addresses, (void *) card, SIGCHLD); kernel_thread(lcs_register_mc_addresses,
(void *) card, SIGCHLD);
#endif #endif
} }
...@@ -1813,19 +1748,14 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd) ...@@ -1813,19 +1748,14 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd)
if (cmd->initiator == LCS_INITIATOR_LGW) { if (cmd->initiator == LCS_INITIATOR_LGW) {
switch(cmd->cmd_code) { switch(cmd->cmd_code) {
case LCS_CMD_STARTUP: case LCS_CMD_STARTUP:
if (!lcs_set_thread_start_bit(card,
LCS_STARTUP_THREAD))
schedule_work(&card->kernel_thread_starter);
break;
case LCS_CMD_STARTLAN: case LCS_CMD_STARTLAN:
if (!lcs_set_thread_start_bit(card, lcs_schedule_recovery(card);
LCS_STARTLAN_THREAD))
schedule_work(&card->kernel_thread_starter);
break; break;
case LCS_CMD_STOPLAN: case LCS_CMD_STOPLAN:
if (!lcs_set_thread_start_bit(card, PRINT_WARN("Stoplan for %s initiated by LGW.\n",
LCS_STOPLAN_THREAD)) card->dev->name);
schedule_work(&card->kernel_thread_starter); if (card->dev)
netif_carrier_off(card->dev);
break; break;
default: default:
PRINT_INFO("UNRECOGNIZED LGW COMMAND\n"); PRINT_INFO("UNRECOGNIZED LGW COMMAND\n");
...@@ -1941,8 +1871,11 @@ lcs_stop_device(struct net_device *dev) ...@@ -1941,8 +1871,11 @@ lcs_stop_device(struct net_device *dev)
LCS_DBF_TEXT(2, trace, "stopdev"); LCS_DBF_TEXT(2, trace, "stopdev");
card = (struct lcs_card *) dev->priv; card = (struct lcs_card *) dev->priv;
netif_stop_queue(dev); netif_carrier_off(dev);
netif_tx_disable(dev);
dev->flags &= ~IFF_UP; dev->flags &= ~IFF_UP;
wait_event(card->write.wait_q,
(card->write.state != CH_STATE_RUNNING));
rc = lcs_stopcard(card); rc = lcs_stopcard(card);
if (rc) if (rc)
PRINT_ERR("Try it again!\n "); PRINT_ERR("Try it again!\n ");
...@@ -1968,6 +1901,7 @@ lcs_open_device(struct net_device *dev) ...@@ -1968,6 +1901,7 @@ lcs_open_device(struct net_device *dev)
} else { } else {
dev->flags |= IFF_UP; dev->flags |= IFF_UP;
netif_carrier_on(dev);
netif_wake_queue(dev); netif_wake_queue(dev);
card->state = DEV_STATE_UP; card->state = DEV_STATE_UP;
} }
...@@ -2059,10 +1993,31 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char ...@@ -2059,10 +1993,31 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char
DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store); DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
static ssize_t
lcs_dev_recover_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lcs_card *card = dev->driver_data;
char *tmp;
int i;
if (!card)
return -EINVAL;
if (card->state != DEV_STATE_UP)
return -EPERM;
i = simple_strtoul(buf, &tmp, 16);
if (i == 1)
lcs_schedule_recovery(card);
return count;
}
static DEVICE_ATTR(recover, 0200, NULL, lcs_dev_recover_store);
static struct attribute * lcs_attrs[] = { static struct attribute * lcs_attrs[] = {
&dev_attr_portno.attr, &dev_attr_portno.attr,
&dev_attr_type.attr, &dev_attr_type.attr,
&dev_attr_lancmd_timeout.attr, &dev_attr_lancmd_timeout.attr,
&dev_attr_recover.attr,
NULL, NULL,
}; };
...@@ -2099,6 +2054,12 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev) ...@@ -2099,6 +2054,12 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev)
ccwgdev->dev.driver_data = card; ccwgdev->dev.driver_data = card;
ccwgdev->cdev[0]->handler = lcs_irq; ccwgdev->cdev[0]->handler = lcs_irq;
ccwgdev->cdev[1]->handler = lcs_irq; ccwgdev->cdev[1]->handler = lcs_irq;
card->gdev = ccwgdev;
INIT_WORK(&card->kernel_thread_starter,
(void *) lcs_start_kernel_thread, card);
card->thread_start_mask = 0;
card->thread_allowed_mask = 0;
card->thread_running_mask = 0;
return 0; return 0;
} }
...@@ -2200,6 +2161,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) ...@@ -2200,6 +2161,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
if (recover_state == DEV_STATE_RECOVER) { if (recover_state == DEV_STATE_RECOVER) {
lcs_set_multicast_list(card->dev); lcs_set_multicast_list(card->dev);
card->dev->flags |= IFF_UP; card->dev->flags |= IFF_UP;
netif_carrier_on(card->dev);
netif_wake_queue(card->dev); netif_wake_queue(card->dev);
card->state = DEV_STATE_UP; card->state = DEV_STATE_UP;
} else { } else {
...@@ -2229,7 +2191,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) ...@@ -2229,7 +2191,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev)
* lcs_shutdown_device, called when setting the group device offline. * lcs_shutdown_device, called when setting the group device offline.
*/ */
static int static int
lcs_shutdown_device(struct ccwgroup_device *ccwgdev) __lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode)
{ {
struct lcs_card *card; struct lcs_card *card;
enum lcs_dev_states recover_state; enum lcs_dev_states recover_state;
...@@ -2239,9 +2201,11 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev) ...@@ -2239,9 +2201,11 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
card = (struct lcs_card *)ccwgdev->dev.driver_data; card = (struct lcs_card *)ccwgdev->dev.driver_data;
if (!card) if (!card)
return -ENODEV; return -ENODEV;
if (recovery_mode == 0) {
lcs_set_allowed_threads(card, 0); lcs_set_allowed_threads(card, 0);
if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD)) if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD))
return -ERESTARTSYS; return -ERESTARTSYS;
}
LCS_DBF_HEX(3, setup, &card, sizeof(void*)); LCS_DBF_HEX(3, setup, &card, sizeof(void*));
recover_state = card->state; recover_state = card->state;
...@@ -2256,6 +2220,43 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev) ...@@ -2256,6 +2220,43 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
return 0; return 0;
} }
static int
lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
{
return __lcs_shutdown_device(ccwgdev, 0);
}
/**
* drive lcs recovery after startup and startlan initiated by Lan Gateway
*/
static int
lcs_recovery(void *ptr)
{
struct lcs_card *card;
struct ccwgroup_device *gdev;
int rc;
card = (struct lcs_card *) ptr;
daemonize("lcs_recover");
LCS_DBF_TEXT(4, trace, "recover1");
if (!lcs_do_run_thread(card, LCS_RECOVERY_THREAD))
return 0;
LCS_DBF_TEXT(4, trace, "recover2");
gdev = card->gdev;
PRINT_WARN("Recovery of device %s started...\n", gdev->dev.bus_id);
rc = __lcs_shutdown_device(gdev, 1);
rc = lcs_new_device(gdev);
if (!rc)
PRINT_INFO("Device %s successfully recovered!\n",
card->dev->name);
else
PRINT_INFO("Device %s could not be recovered!\n",
card->dev->name);
lcs_clear_thread_running_bit(card, LCS_RECOVERY_THREAD);
return 0;
}
/** /**
* lcs_remove_device, free buffers and card * lcs_remove_device, free buffers and card
*/ */
......
...@@ -73,13 +73,17 @@ do { \ ...@@ -73,13 +73,17 @@ do { \
/** /**
* LCS sense byte definitions * LCS sense byte definitions
*/ */
#define LCS_SENSE_BYTE_0 0
#define LCS_SENSE_BYTE_1 1
#define LCS_SENSE_BYTE_2 2
#define LCS_SENSE_BYTE_3 3
#define LCS_SENSE_INTERFACE_DISCONNECT 0x01 #define LCS_SENSE_INTERFACE_DISCONNECT 0x01
#define LCS_SENSE_EQUIPMENT_CHECK 0x10 #define LCS_SENSE_EQUIPMENT_CHECK 0x10
#define LCS_SENSE_BUS_OUT_CHECK 0x20 #define LCS_SENSE_BUS_OUT_CHECK 0x20
#define LCS_SENSE_INTERVENTION_REQUIRED 0x40 #define LCS_SENSE_INTERVENTION_REQUIRED 0x40
#define LCS_SENSE_CMD_REJECT 0x80 #define LCS_SENSE_CMD_REJECT 0x80
#define LCS_SENSE_RESETTING_EVENT 0x0080 #define LCS_SENSE_RESETTING_EVENT 0x80
#define LCS_SENSE_DEVICE_ONLINE 0x0020 #define LCS_SENSE_DEVICE_ONLINE 0x20
/** /**
* LCS packet type definitions * LCS packet type definitions
...@@ -152,10 +156,9 @@ enum lcs_dev_states { ...@@ -152,10 +156,9 @@ enum lcs_dev_states {
enum lcs_threads { enum lcs_threads {
LCS_SET_MC_THREAD = 1, LCS_SET_MC_THREAD = 1,
LCS_STARTLAN_THREAD = 2, LCS_RECOVERY_THREAD = 2,
LCS_STOPLAN_THREAD = 4,
LCS_STARTUP_THREAD = 8,
}; };
/** /**
* LCS struct declarations * LCS struct declarations
*/ */
...@@ -286,6 +289,7 @@ struct lcs_card { ...@@ -286,6 +289,7 @@ struct lcs_card {
struct net_device_stats stats; struct net_device_stats stats;
unsigned short (*lan_type_trans)(struct sk_buff *skb, unsigned short (*lan_type_trans)(struct sk_buff *skb,
struct net_device *dev); struct net_device *dev);
struct ccwgroup_device *gdev;
struct lcs_channel read; struct lcs_channel read;
struct lcs_channel write; struct lcs_channel write;
struct lcs_buffer *tx_buffer; struct lcs_buffer *tx_buffer;
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *
*/ */
#undef DEBUG #undef DEBUG
#include <linux/module.h> #include <linux/module.h>
...@@ -65,7 +65,7 @@ MODULE_AUTHOR ...@@ -65,7 +65,7 @@ MODULE_AUTHOR
("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)"); ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
#define PRINTK_HEADER " iucv: " /* for debugging */ #define PRINTK_HEADER " iucv: " /* for debugging */
static struct device_driver netiucv_driver = { static struct device_driver netiucv_driver = {
...@@ -202,7 +202,7 @@ netiucv_printname(char *name) ...@@ -202,7 +202,7 @@ netiucv_printname(char *name)
*p = '\0'; *p = '\0';
return tmp; return tmp;
} }
/** /**
* States of the interface statemachine. * States of the interface statemachine.
*/ */
...@@ -244,7 +244,7 @@ static const char *dev_event_names[] = { ...@@ -244,7 +244,7 @@ static const char *dev_event_names[] = {
"Connection up", "Connection up",
"Connection down", "Connection down",
}; };
/** /**
* Events of the connection statemachine * Events of the connection statemachine
*/ */
...@@ -364,7 +364,7 @@ static const char *conn_state_names[] = { ...@@ -364,7 +364,7 @@ static const char *conn_state_names[] = {
"Connect error", "Connect error",
}; };
/** /**
* Debug Facility Stuff * Debug Facility Stuff
*/ */
...@@ -516,7 +516,7 @@ static void ...@@ -516,7 +516,7 @@ static void
fsm_action_nop(fsm_instance *fi, int event, void *arg) fsm_action_nop(fsm_instance *fi, int event, void *arg)
{ {
} }
/** /**
* Actions of the connection statemachine * Actions of the connection statemachine
*****************************************************************************/ *****************************************************************************/
...@@ -993,7 +993,7 @@ static const fsm_node conn_fsm[] = { ...@@ -993,7 +993,7 @@ static const fsm_node conn_fsm[] = {
static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node); static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);
/** /**
* Actions for interface - statemachine. * Actions for interface - statemachine.
*****************************************************************************/ *****************************************************************************/
...@@ -1220,7 +1220,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { ...@@ -1220,7 +1220,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
return rc; return rc;
} }
/** /**
* Interface API for upper network layers * Interface API for upper network layers
*****************************************************************************/ *****************************************************************************/
......
...@@ -1099,7 +1099,7 @@ qeth_string_to_ipaddr4(const char *buf, __u8 *addr) ...@@ -1099,7 +1099,7 @@ qeth_string_to_ipaddr4(const char *buf, __u8 *addr)
rc = sscanf(buf, "%d.%d.%d.%d%n", rc = sscanf(buf, "%d.%d.%d.%d%n",
&in[0], &in[1], &in[2], &in[3], &count); &in[0], &in[1], &in[2], &in[3], &count);
if (rc != 4 || count) if (rc != 4 || count<=0)
return -EINVAL; return -EINVAL;
for (count = 0; count < 4; count++) { for (count = 0; count < 4; count++) {
if (in[count] > 255) if (in[count] > 255)
......
...@@ -3798,10 +3798,10 @@ qeth_open(struct net_device *dev) ...@@ -3798,10 +3798,10 @@ qeth_open(struct net_device *dev)
QETH_DBF_TEXT(trace,4,"nomacadr"); QETH_DBF_TEXT(trace,4,"nomacadr");
return -EPERM; return -EPERM;
} }
card->dev->flags |= IFF_UP;
netif_start_queue(dev);
card->data.state = CH_STATE_UP; card->data.state = CH_STATE_UP;
card->state = CARD_STATE_UP; card->state = CARD_STATE_UP;
card->dev->flags |= IFF_UP;
netif_start_queue(dev);
if (!card->lan_online && netif_carrier_ok(dev)) if (!card->lan_online && netif_carrier_ok(dev))
netif_carrier_off(dev); netif_carrier_off(dev);
...@@ -3817,7 +3817,7 @@ qeth_stop(struct net_device *dev) ...@@ -3817,7 +3817,7 @@ qeth_stop(struct net_device *dev)
card = (struct qeth_card *) dev->priv; card = (struct qeth_card *) dev->priv;
netif_stop_queue(dev); netif_tx_disable(dev);
card->dev->flags &= ~IFF_UP; card->dev->flags &= ~IFF_UP;
if (card->state == CARD_STATE_UP) if (card->state == CARD_STATE_UP)
card->state = CARD_STATE_SOFTSETUP; card->state = CARD_STATE_SOFTSETUP;
...@@ -3958,7 +3958,7 @@ qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, ...@@ -3958,7 +3958,7 @@ qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
#endif #endif
*hdr = (struct qeth_hdr *) *hdr = (struct qeth_hdr *)
qeth_push_skb(card, skb, sizeof(struct qeth_hdr)); qeth_push_skb(card, skb, sizeof(struct qeth_hdr));
if (hdr == NULL) if (*hdr == NULL)
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
...@@ -4416,6 +4416,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) ...@@ -4416,6 +4416,8 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL; struct qeth_eddp_context *ctx = NULL;
int tx_bytes = skb->len; int tx_bytes = skb->len;
unsigned short nr_frags = skb_shinfo(skb)->nr_frags;
unsigned short tso_size = skb_shinfo(skb)->tso_size;
int rc; int rc;
QETH_DBF_TEXT(trace, 6, "sendpkt"); QETH_DBF_TEXT(trace, 6, "sendpkt");
...@@ -4498,16 +4500,16 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) ...@@ -4498,16 +4500,16 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
card->stats.tx_packets++; card->stats.tx_packets++;
card->stats.tx_bytes += tx_bytes; card->stats.tx_bytes += tx_bytes;
#ifdef CONFIG_QETH_PERF_STATS #ifdef CONFIG_QETH_PERF_STATS
if (skb_shinfo(skb)->tso_size && if (tso_size &&
!(large_send == QETH_LARGE_SEND_NO)) { !(large_send == QETH_LARGE_SEND_NO)) {
card->perf_stats.large_send_bytes += skb->len; card->perf_stats.large_send_bytes += tx_bytes;
card->perf_stats.large_send_cnt++; card->perf_stats.large_send_cnt++;
} }
if (skb_shinfo(skb)->nr_frags > 0){ if (nr_frags > 0){
card->perf_stats.sg_skbs_sent++; card->perf_stats.sg_skbs_sent++;
/* nr_frags + skb->data */ /* nr_frags + skb->data */
card->perf_stats.sg_frags_sent += card->perf_stats.sg_frags_sent +=
skb_shinfo(skb)->nr_frags + 1; nr_frags + 1;
} }
#endif /* CONFIG_QETH_PERF_STATS */ #endif /* CONFIG_QETH_PERF_STATS */
} }
...@@ -6359,12 +6361,9 @@ qeth_netdev_init(struct net_device *dev) ...@@ -6359,12 +6361,9 @@ qeth_netdev_init(struct net_device *dev)
dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid; dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid;
dev->vlan_rx_add_vid = qeth_vlan_rx_add_vid; dev->vlan_rx_add_vid = qeth_vlan_rx_add_vid;
#endif #endif
dev->hard_header = card->orig_hard_header;
if (qeth_get_netdev_flags(card) & IFF_NOARP) { if (qeth_get_netdev_flags(card) & IFF_NOARP) {
dev->rebuild_header = NULL; dev->rebuild_header = NULL;
dev->hard_header = NULL; dev->hard_header = NULL;
if (card->options.fake_ll)
dev->hard_header = qeth_fake_header;
dev->header_cache_update = NULL; dev->header_cache_update = NULL;
dev->hard_header_cache = NULL; dev->hard_header_cache = NULL;
} }
...@@ -6373,6 +6372,9 @@ qeth_netdev_init(struct net_device *dev) ...@@ -6373,6 +6372,9 @@ qeth_netdev_init(struct net_device *dev)
if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD)) if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
card->dev->dev_id = card->info.unique_id & 0xffff; card->dev->dev_id = card->info.unique_id & 0xffff;
#endif #endif
if (card->options.fake_ll &&
(qeth_get_netdev_flags(card) & IFF_NOARP))
dev->hard_header = qeth_fake_header;
dev->hard_header_parse = NULL; dev->hard_header_parse = NULL;
dev->set_mac_address = qeth_layer2_set_mac_address; dev->set_mac_address = qeth_layer2_set_mac_address;
dev->flags |= qeth_get_netdev_flags(card); dev->flags |= qeth_get_netdev_flags(card);
...@@ -6477,6 +6479,9 @@ qeth_hardsetup_card(struct qeth_card *card) ...@@ -6477,6 +6479,9 @@ qeth_hardsetup_card(struct qeth_card *card)
/*network device will be recovered*/ /*network device will be recovered*/
if (card->dev) { if (card->dev) {
card->dev->hard_header = card->orig_hard_header; card->dev->hard_header = card->orig_hard_header;
if (card->options.fake_ll &&
(qeth_get_netdev_flags(card) & IFF_NOARP))
card->dev->hard_header = qeth_fake_header;
return 0; return 0;
} }
/* at first set_online allocate netdev */ /* at first set_online allocate netdev */
...@@ -7031,14 +7036,12 @@ qeth_softsetup_ipv6(struct qeth_card *card) ...@@ -7031,14 +7036,12 @@ qeth_softsetup_ipv6(struct qeth_card *card)
QETH_DBF_TEXT(trace,3,"softipv6"); QETH_DBF_TEXT(trace,3,"softipv6");
netif_stop_queue(card->dev);
rc = qeth_send_startlan(card, QETH_PROT_IPV6); rc = qeth_send_startlan(card, QETH_PROT_IPV6);
if (rc) { if (rc) {
PRINT_ERR("IPv6 startlan failed on %s\n", PRINT_ERR("IPv6 startlan failed on %s\n",
QETH_CARD_IFNAME(card)); QETH_CARD_IFNAME(card));
return rc; return rc;
} }
netif_wake_queue(card->dev);
rc = qeth_query_ipassists(card,QETH_PROT_IPV6); rc = qeth_query_ipassists(card,QETH_PROT_IPV6);
if (rc) { if (rc) {
PRINT_ERR("IPv6 query ipassist failed on %s\n", PRINT_ERR("IPv6 query ipassist failed on %s\n",
...@@ -7352,7 +7355,8 @@ qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type) ...@@ -7352,7 +7355,8 @@ qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type)
card->options.large_send = type; card->options.large_send = type;
return 0; return 0;
} }
netif_stop_queue(card->dev); if (card->state == CARD_STATE_UP)
netif_tx_disable(card->dev);
card->options.large_send = type; card->options.large_send = type;
switch (card->options.large_send) { switch (card->options.large_send) {
case QETH_LARGE_SEND_EDDP: case QETH_LARGE_SEND_EDDP:
...@@ -7374,6 +7378,7 @@ qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type) ...@@ -7374,6 +7378,7 @@ qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type)
card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
break; break;
} }
if (card->state == CARD_STATE_UP)
netif_wake_queue(card->dev); netif_wake_queue(card->dev);
return rc; return rc;
} }
...@@ -7427,7 +7432,7 @@ qeth_softsetup_card(struct qeth_card *card) ...@@ -7427,7 +7432,7 @@ qeth_softsetup_card(struct qeth_card *card)
if ((rc = qeth_setrouting_v6(card))) if ((rc = qeth_setrouting_v6(card)))
QETH_DBF_TEXT_(setup, 2, "5err%d", rc); QETH_DBF_TEXT_(setup, 2, "5err%d", rc);
out: out:
netif_stop_queue(card->dev); netif_tx_disable(card->dev);
return 0; return 0;
} }
...@@ -7736,10 +7741,8 @@ static int ...@@ -7736,10 +7741,8 @@ static int
qeth_register_netdev(struct qeth_card *card) qeth_register_netdev(struct qeth_card *card)
{ {
QETH_DBF_TEXT(setup, 3, "regnetd"); QETH_DBF_TEXT(setup, 3, "regnetd");
if (card->dev->reg_state != NETREG_UNINITIALIZED) { if (card->dev->reg_state != NETREG_UNINITIALIZED)
qeth_netdev_init(card->dev);
return 0; return 0;
}
/* sysfs magic */ /* sysfs magic */
SET_NETDEV_DEV(card->dev, &card->gdev->dev); SET_NETDEV_DEV(card->dev, &card->gdev->dev);
return register_netdev(card->dev); return register_netdev(card->dev);
......
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