Merge branch 'upstream-fixes' into upstream
Conflicts: drivers/s390/net/ctctty.c
This commit is contained in:
commit
983f27d37d
@ -20,7 +20,7 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
@ -77,7 +77,7 @@ group_write(struct device_driver *drv, const char *buf, size_t count)
|
||||
int len;
|
||||
|
||||
if (!(end = strchr(start, delim[i])))
|
||||
return count;
|
||||
return -EINVAL;
|
||||
len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
|
||||
strlcpy (bus_ids[i], start, len);
|
||||
argv[i] = bus_ids[i];
|
||||
|
@ -28,7 +28,7 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -297,7 +297,7 @@ MODULE_LICENSE("GPL");
|
||||
/*
|
||||
* Debugging stuff
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
static int debuglevel = 0;
|
||||
@ -344,7 +344,7 @@ do { \
|
||||
/*
|
||||
* Internal functions
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
/**
|
||||
* print start banner
|
||||
*/
|
||||
|
@ -68,6 +68,7 @@ static void lcs_tasklet(unsigned long);
|
||||
static void lcs_start_kernel_thread(struct lcs_card *card);
|
||||
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_recovery(void *ptr);
|
||||
|
||||
/**
|
||||
* Debug Facility Stuff
|
||||
@ -429,12 +430,6 @@ lcs_setup_card(struct lcs_card *card)
|
||||
card->tx_buffer = NULL;
|
||||
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);
|
||||
spin_lock_init(&card->lock);
|
||||
spin_lock_init(&card->ipm_lock);
|
||||
@ -675,8 +670,9 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
|
||||
int index, rc;
|
||||
|
||||
LCS_DBF_TEXT(5, trace, "rdybuff");
|
||||
BUG_ON(buffer->state != BUF_STATE_LOCKED &&
|
||||
buffer->state != BUF_STATE_PROCESSED);
|
||||
if (buffer->state != BUF_STATE_LOCKED &&
|
||||
buffer->state != BUF_STATE_PROCESSED)
|
||||
BUG();
|
||||
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
|
||||
buffer->state = BUF_STATE_READY;
|
||||
index = buffer - channel->iob;
|
||||
@ -700,7 +696,8 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
|
||||
int index, prev, next;
|
||||
|
||||
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;
|
||||
index = buffer - channel->iob;
|
||||
prev = (index - 1) & (LCS_NUM_BUFFS - 1);
|
||||
@ -732,8 +729,9 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
|
||||
unsigned long flags;
|
||||
|
||||
LCS_DBF_TEXT(5, trace, "relbuff");
|
||||
BUG_ON(buffer->state != BUF_STATE_LOCKED &&
|
||||
buffer->state != BUF_STATE_PROCESSED);
|
||||
if (buffer->state != BUF_STATE_LOCKED &&
|
||||
buffer->state != BUF_STATE_PROCESSED)
|
||||
BUG();
|
||||
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
|
||||
buffer->state = BUF_STATE_EMPTY;
|
||||
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
|
||||
@ -1147,8 +1145,6 @@ list_modified:
|
||||
list_add_tail(&ipm->list, &card->ipm_list);
|
||||
}
|
||||
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)
|
||||
if (ipm != NULL)
|
||||
continue; /* Address already in 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) {
|
||||
PRINT_INFO("Not enough memory to add "
|
||||
"new multicast entry!\n");
|
||||
break;
|
||||
}
|
||||
memset(ipm, 0, sizeof(struct lcs_ipm_list));
|
||||
memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH);
|
||||
ipm->ipm.ip_addr = im4->multiaddr;
|
||||
ipm->ipm_state = LCS_IPM_STATE_SET_REQUIRED;
|
||||
spin_lock_irqsave(&card->ipm_lock, flags);
|
||||
LCS_DBF_HEX(2,trace,&ipm->ipm.ip_addr,4);
|
||||
list_add(&ipm->list, &card->ipm_list);
|
||||
spin_unlock_irqrestore(&card->ipm_lock, flags);
|
||||
}
|
||||
@ -1269,7 +1265,15 @@ lcs_register_mc_addresses(void *data)
|
||||
read_unlock(&in4_dev->mc_list_lock);
|
||||
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);
|
||||
if (card->state == DEV_STATE_UP) {
|
||||
netif_carrier_on(card->dev);
|
||||
netif_wake_queue(card->dev);
|
||||
}
|
||||
out:
|
||||
lcs_clear_thread_running_bit(card, LCS_SET_MC_THREAD);
|
||||
return 0;
|
||||
@ -1318,6 +1322,53 @@ lcs_check_irb_error(struct ccw_device *cdev, struct irb *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
|
||||
@ -1327,7 +1378,8 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
|
||||
{
|
||||
struct lcs_card *card;
|
||||
struct lcs_channel *channel;
|
||||
int index;
|
||||
int rc, index;
|
||||
int cstat, dstat;
|
||||
|
||||
if (lcs_check_irb_error(cdev, irb))
|
||||
return;
|
||||
@ -1338,10 +1390,23 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
|
||||
else
|
||||
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, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat);
|
||||
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? */
|
||||
if ((channel->state != CH_STATE_INIT) &&
|
||||
(irb->scsw.fctl & SCSW_FCTL_START_FUNC)) {
|
||||
@ -1367,7 +1432,6 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
|
||||
else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED)
|
||||
/* CCW execution stopped on a suspend bit. */
|
||||
channel->state = CH_STATE_SUSPENDED;
|
||||
|
||||
if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) {
|
||||
if (irb->scsw.cc != 0) {
|
||||
ccw_device_halt(channel->ccwdev, (addr_t) channel);
|
||||
@ -1376,7 +1440,6 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
|
||||
/* The channel has been stopped by halt_IO. */
|
||||
channel->state = CH_STATE_HALTED;
|
||||
}
|
||||
|
||||
if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
|
||||
channel->state = CH_STATE_CLEARED;
|
||||
}
|
||||
@ -1452,7 +1515,7 @@ lcs_txbuffer_cb(struct lcs_channel *channel, struct lcs_buffer *buffer)
|
||||
lcs_release_buffer(channel, buffer);
|
||||
card = (struct lcs_card *)
|
||||
((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);
|
||||
spin_lock(&card->lock);
|
||||
card->tx_emitted--;
|
||||
@ -1488,6 +1551,10 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb,
|
||||
card->stats.tx_carrier_errors++;
|
||||
return 0;
|
||||
}
|
||||
if (skb->protocol == htons(ETH_P_IPV6)) {
|
||||
dev_kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
netif_stop_queue(card->dev);
|
||||
spin_lock(&card->lock);
|
||||
if (card->tx_buffer != NULL &&
|
||||
@ -1632,30 +1699,6 @@ lcs_detect(struct lcs_card *card)
|
||||
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
|
||||
*/
|
||||
@ -1679,111 +1722,6 @@ lcs_stopcard(struct lcs_card *card)
|
||||
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
|
||||
*/
|
||||
@ -1791,15 +1729,12 @@ static void
|
||||
lcs_start_kernel_thread(struct lcs_card *card)
|
||||
{
|
||||
LCS_DBF_TEXT(5, trace, "krnthrd");
|
||||
if (lcs_do_start_thread(card, LCS_STARTUP_THREAD))
|
||||
kernel_thread(lcs_lgw_startup_thread, (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);
|
||||
if (lcs_do_start_thread(card, LCS_RECOVERY_THREAD))
|
||||
kernel_thread(lcs_recovery, (void *) card, SIGCHLD);
|
||||
#ifdef CONFIG_IP_MULTICAST
|
||||
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
|
||||
}
|
||||
|
||||
@ -1813,19 +1748,14 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd)
|
||||
if (cmd->initiator == LCS_INITIATOR_LGW) {
|
||||
switch(cmd->cmd_code) {
|
||||
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:
|
||||
if (!lcs_set_thread_start_bit(card,
|
||||
LCS_STARTLAN_THREAD))
|
||||
schedule_work(&card->kernel_thread_starter);
|
||||
lcs_schedule_recovery(card);
|
||||
break;
|
||||
case LCS_CMD_STOPLAN:
|
||||
if (!lcs_set_thread_start_bit(card,
|
||||
LCS_STOPLAN_THREAD))
|
||||
schedule_work(&card->kernel_thread_starter);
|
||||
PRINT_WARN("Stoplan for %s initiated by LGW.\n",
|
||||
card->dev->name);
|
||||
if (card->dev)
|
||||
netif_carrier_off(card->dev);
|
||||
break;
|
||||
default:
|
||||
PRINT_INFO("UNRECOGNIZED LGW COMMAND\n");
|
||||
@ -1941,8 +1871,11 @@ lcs_stop_device(struct net_device *dev)
|
||||
|
||||
LCS_DBF_TEXT(2, trace, "stopdev");
|
||||
card = (struct lcs_card *) dev->priv;
|
||||
netif_stop_queue(dev);
|
||||
netif_carrier_off(dev);
|
||||
netif_tx_disable(dev);
|
||||
dev->flags &= ~IFF_UP;
|
||||
wait_event(card->write.wait_q,
|
||||
(card->write.state != CH_STATE_RUNNING));
|
||||
rc = lcs_stopcard(card);
|
||||
if (rc)
|
||||
PRINT_ERR("Try it again!\n ");
|
||||
@ -1968,6 +1901,7 @@ lcs_open_device(struct net_device *dev)
|
||||
|
||||
} else {
|
||||
dev->flags |= IFF_UP;
|
||||
netif_carrier_on(dev);
|
||||
netif_wake_queue(dev);
|
||||
card->state = DEV_STATE_UP;
|
||||
}
|
||||
@ -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);
|
||||
|
||||
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[] = {
|
||||
&dev_attr_portno.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_lancmd_timeout.attr,
|
||||
&dev_attr_recover.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ -2099,6 +2054,12 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev)
|
||||
ccwgdev->dev.driver_data = card;
|
||||
ccwgdev->cdev[0]->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;
|
||||
}
|
||||
|
||||
@ -2200,6 +2161,7 @@ netdev_out:
|
||||
if (recover_state == DEV_STATE_RECOVER) {
|
||||
lcs_set_multicast_list(card->dev);
|
||||
card->dev->flags |= IFF_UP;
|
||||
netif_carrier_on(card->dev);
|
||||
netif_wake_queue(card->dev);
|
||||
card->state = DEV_STATE_UP;
|
||||
} else {
|
||||
@ -2229,7 +2191,7 @@ out:
|
||||
* lcs_shutdown_device, called when setting the group device offline.
|
||||
*/
|
||||
static int
|
||||
lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
|
||||
__lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode)
|
||||
{
|
||||
struct lcs_card *card;
|
||||
enum lcs_dev_states recover_state;
|
||||
@ -2239,9 +2201,11 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
|
||||
card = (struct lcs_card *)ccwgdev->dev.driver_data;
|
||||
if (!card)
|
||||
return -ENODEV;
|
||||
if (recovery_mode == 0) {
|
||||
lcs_set_allowed_threads(card, 0);
|
||||
if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD))
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
LCS_DBF_HEX(3, setup, &card, sizeof(void*));
|
||||
recover_state = card->state;
|
||||
|
||||
@ -2256,6 +2220,43 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev)
|
||||
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
|
||||
*/
|
||||
|
@ -73,13 +73,17 @@ do { \
|
||||
/**
|
||||
* 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_EQUIPMENT_CHECK 0x10
|
||||
#define LCS_SENSE_BUS_OUT_CHECK 0x20
|
||||
#define LCS_SENSE_INTERVENTION_REQUIRED 0x40
|
||||
#define LCS_SENSE_CMD_REJECT 0x80
|
||||
#define LCS_SENSE_RESETTING_EVENT 0x0080
|
||||
#define LCS_SENSE_DEVICE_ONLINE 0x0020
|
||||
#define LCS_SENSE_RESETTING_EVENT 0x80
|
||||
#define LCS_SENSE_DEVICE_ONLINE 0x20
|
||||
|
||||
/**
|
||||
* LCS packet type definitions
|
||||
@ -152,10 +156,9 @@ enum lcs_dev_states {
|
||||
|
||||
enum lcs_threads {
|
||||
LCS_SET_MC_THREAD = 1,
|
||||
LCS_STARTLAN_THREAD = 2,
|
||||
LCS_STOPLAN_THREAD = 4,
|
||||
LCS_STARTUP_THREAD = 8,
|
||||
LCS_RECOVERY_THREAD = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* LCS struct declarations
|
||||
*/
|
||||
@ -286,6 +289,7 @@ struct lcs_card {
|
||||
struct net_device_stats stats;
|
||||
unsigned short (*lan_type_trans)(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
struct ccwgroup_device *gdev;
|
||||
struct lcs_channel read;
|
||||
struct lcs_channel write;
|
||||
struct lcs_buffer *tx_buffer;
|
||||
|
@ -30,7 +30,7 @@
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -65,7 +65,7 @@ MODULE_AUTHOR
|
||||
("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)");
|
||||
MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
|
||||
|
||||
|
||||
|
||||
#define PRINTK_HEADER " iucv: " /* for debugging */
|
||||
|
||||
static struct device_driver netiucv_driver = {
|
||||
@ -202,7 +202,7 @@ netiucv_printname(char *name)
|
||||
*p = '\0';
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* States of the interface statemachine.
|
||||
*/
|
||||
@ -244,7 +244,7 @@ static const char *dev_event_names[] = {
|
||||
"Connection up",
|
||||
"Connection down",
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Events of the connection statemachine
|
||||
*/
|
||||
@ -364,7 +364,7 @@ static const char *conn_state_names[] = {
|
||||
"Connect error",
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Debug Facility Stuff
|
||||
*/
|
||||
@ -516,7 +516,7 @@ static void
|
||||
fsm_action_nop(fsm_instance *fi, int event, void *arg)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Actions of the connection statemachine
|
||||
*****************************************************************************/
|
||||
@ -993,7 +993,7 @@ static const fsm_node conn_fsm[] = {
|
||||
|
||||
static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Actions for interface - statemachine.
|
||||
*****************************************************************************/
|
||||
@ -1220,7 +1220,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) {
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Interface API for upper network layers
|
||||
*****************************************************************************/
|
||||
|
@ -1099,7 +1099,7 @@ qeth_string_to_ipaddr4(const char *buf, __u8 *addr)
|
||||
|
||||
rc = sscanf(buf, "%d.%d.%d.%d%n",
|
||||
&in[0], &in[1], &in[2], &in[3], &count);
|
||||
if (rc != 4 || count)
|
||||
if (rc != 4 || count<=0)
|
||||
return -EINVAL;
|
||||
for (count = 0; count < 4; count++) {
|
||||
if (in[count] > 255)
|
||||
|
@ -3798,10 +3798,10 @@ qeth_open(struct net_device *dev)
|
||||
QETH_DBF_TEXT(trace,4,"nomacadr");
|
||||
return -EPERM;
|
||||
}
|
||||
card->dev->flags |= IFF_UP;
|
||||
netif_start_queue(dev);
|
||||
card->data.state = CH_STATE_UP;
|
||||
card->state = CARD_STATE_UP;
|
||||
card->dev->flags |= IFF_UP;
|
||||
netif_start_queue(dev);
|
||||
|
||||
if (!card->lan_online && netif_carrier_ok(dev))
|
||||
netif_carrier_off(dev);
|
||||
@ -3817,7 +3817,7 @@ qeth_stop(struct net_device *dev)
|
||||
|
||||
card = (struct qeth_card *) dev->priv;
|
||||
|
||||
netif_stop_queue(dev);
|
||||
netif_tx_disable(dev);
|
||||
card->dev->flags &= ~IFF_UP;
|
||||
if (card->state == CARD_STATE_UP)
|
||||
card->state = CARD_STATE_SOFTSETUP;
|
||||
@ -3958,7 +3958,7 @@ qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
|
||||
#endif
|
||||
*hdr = (struct qeth_hdr *)
|
||||
qeth_push_skb(card, skb, sizeof(struct qeth_hdr));
|
||||
if (hdr == NULL)
|
||||
if (*hdr == NULL)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
@ -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;
|
||||
struct qeth_eddp_context *ctx = NULL;
|
||||
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;
|
||||
|
||||
QETH_DBF_TEXT(trace, 6, "sendpkt");
|
||||
@ -4498,16 +4500,16 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
|
||||
card->stats.tx_packets++;
|
||||
card->stats.tx_bytes += tx_bytes;
|
||||
#ifdef CONFIG_QETH_PERF_STATS
|
||||
if (skb_shinfo(skb)->tso_size &&
|
||||
if (tso_size &&
|
||||
!(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++;
|
||||
}
|
||||
if (skb_shinfo(skb)->nr_frags > 0){
|
||||
if (nr_frags > 0){
|
||||
card->perf_stats.sg_skbs_sent++;
|
||||
/* nr_frags + skb->data */
|
||||
card->perf_stats.sg_frags_sent +=
|
||||
skb_shinfo(skb)->nr_frags + 1;
|
||||
nr_frags + 1;
|
||||
}
|
||||
#endif /* CONFIG_QETH_PERF_STATS */
|
||||
}
|
||||
@ -6359,12 +6361,9 @@ qeth_netdev_init(struct net_device *dev)
|
||||
dev->vlan_rx_kill_vid = qeth_vlan_rx_kill_vid;
|
||||
dev->vlan_rx_add_vid = qeth_vlan_rx_add_vid;
|
||||
#endif
|
||||
dev->hard_header = card->orig_hard_header;
|
||||
if (qeth_get_netdev_flags(card) & IFF_NOARP) {
|
||||
dev->rebuild_header = NULL;
|
||||
dev->hard_header = NULL;
|
||||
if (card->options.fake_ll)
|
||||
dev->hard_header = qeth_fake_header;
|
||||
dev->header_cache_update = NULL;
|
||||
dev->hard_header_cache = NULL;
|
||||
}
|
||||
@ -6373,6 +6372,9 @@ qeth_netdev_init(struct net_device *dev)
|
||||
if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
|
||||
card->dev->dev_id = card->info.unique_id & 0xffff;
|
||||
#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->set_mac_address = qeth_layer2_set_mac_address;
|
||||
dev->flags |= qeth_get_netdev_flags(card);
|
||||
@ -6477,6 +6479,9 @@ retry:
|
||||
/*network device will be recovered*/
|
||||
if (card->dev) {
|
||||
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;
|
||||
}
|
||||
/* at first set_online allocate netdev */
|
||||
@ -7031,14 +7036,12 @@ qeth_softsetup_ipv6(struct qeth_card *card)
|
||||
|
||||
QETH_DBF_TEXT(trace,3,"softipv6");
|
||||
|
||||
netif_stop_queue(card->dev);
|
||||
rc = qeth_send_startlan(card, QETH_PROT_IPV6);
|
||||
if (rc) {
|
||||
PRINT_ERR("IPv6 startlan failed on %s\n",
|
||||
QETH_CARD_IFNAME(card));
|
||||
return rc;
|
||||
}
|
||||
netif_wake_queue(card->dev);
|
||||
rc = qeth_query_ipassists(card,QETH_PROT_IPV6);
|
||||
if (rc) {
|
||||
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)
|
||||
card->options.large_send = type;
|
||||
return 0;
|
||||
}
|
||||
netif_stop_queue(card->dev);
|
||||
if (card->state == CARD_STATE_UP)
|
||||
netif_tx_disable(card->dev);
|
||||
card->options.large_send = type;
|
||||
switch (card->options.large_send) {
|
||||
case QETH_LARGE_SEND_EDDP:
|
||||
@ -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);
|
||||
break;
|
||||
}
|
||||
if (card->state == CARD_STATE_UP)
|
||||
netif_wake_queue(card->dev);
|
||||
return rc;
|
||||
}
|
||||
@ -7427,7 +7432,7 @@ qeth_softsetup_card(struct qeth_card *card)
|
||||
if ((rc = qeth_setrouting_v6(card)))
|
||||
QETH_DBF_TEXT_(setup, 2, "5err%d", rc);
|
||||
out:
|
||||
netif_stop_queue(card->dev);
|
||||
netif_tx_disable(card->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -7736,10 +7741,8 @@ static int
|
||||
qeth_register_netdev(struct qeth_card *card)
|
||||
{
|
||||
QETH_DBF_TEXT(setup, 3, "regnetd");
|
||||
if (card->dev->reg_state != NETREG_UNINITIALIZED) {
|
||||
qeth_netdev_init(card->dev);
|
||||
if (card->dev->reg_state != NETREG_UNINITIALIZED)
|
||||
return 0;
|
||||
}
|
||||
/* sysfs magic */
|
||||
SET_NETDEV_DEV(card->dev, &card->gdev->dev);
|
||||
return register_netdev(card->dev);
|
||||
|
Loading…
Reference in New Issue
Block a user