summaryrefslogtreecommitdiffstats
path: root/drivers/s390/net/lcs.c
diff options
context:
space:
mode:
authorKlaus D. Wacker <kdwacker@de.ibm.com>2007-10-05 16:45:47 +0200
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 16:54:41 -0700
commit59579da329b22bcddc5da0c22c61d6dc1f9eb96a (patch)
tree117eb93c9d50643a633018481ed68fc84063519d /drivers/s390/net/lcs.c
parentd8fae9c2f2642ffe411424ed2e4677f959168152 (diff)
downloadlinux-59579da329b22bcddc5da0c22c61d6dc1f9eb96a.tar.gz
linux-59579da329b22bcddc5da0c22c61d6dc1f9eb96a.tar.bz2
linux-59579da329b22bcddc5da0c22c61d6dc1f9eb96a.zip
lcs: Channel errors drive lcs_recovery which leads to kernel panic.
When the lcs irq routine detects channel failures it drives device recovery. After this event the device is no longer usable for shutdown requests, because the lcs_irq routine may get wrong channel status information. In such a case the lcs_irq routine marks the channel in 'error' state. The channel state comes back to 'running' after restarting the channels. Signed-off-by: Klaus D. Wacker <kdwacker@de.ibm.com> Signed-off-by: Ursula Braun <braunu@de.ibm.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/s390/net/lcs.c')
-rw-r--r--drivers/s390/net/lcs.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index e4b11afbbc9f..0fd663b23d76 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1400,11 +1400,14 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
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;
+ channel->state = LCS_CH_STATE_ERROR;
}
}
+ if (channel->state == LCS_CH_STATE_ERROR) {
+ lcs_schedule_recovery(card);
+ wake_up(&card->wait_q);
+ return;
+ }
/* How far in the ccw chain have we processed? */
if ((channel->state != LCS_CH_STATE_INIT) &&
(irb->scsw.fctl & SCSW_FCTL_START_FUNC)) {
@@ -1708,6 +1711,8 @@ lcs_stopcard(struct lcs_card *card)
if (card->read.state != LCS_CH_STATE_STOPPED &&
card->write.state != LCS_CH_STATE_STOPPED &&
+ card->read.state != LCS_CH_STATE_ERROR &&
+ card->write.state != LCS_CH_STATE_ERROR &&
card->state == DEV_STATE_UP) {
lcs_clear_multicast_list(card);
rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP);