]> err.no Git - linux-2.6/commitdiff
lcs: Channel errors drive lcs_recovery which leads to kernel panic.
authorKlaus D. Wacker <kdwacker@de.ibm.com>
Fri, 5 Oct 2007 14:45:47 +0000 (16:45 +0200)
committerDavid S. Miller <davem@sunset.davemloft.net>
Wed, 10 Oct 2007 23:54:41 +0000 (16:54 -0700)
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>
drivers/s390/net/lcs.c
drivers/s390/net/lcs.h

index e4b11afbbc9fcce73a60c75b579e581d7ff14930..0fd663b23d767c9a6e81777d51df467af90631e6 100644 (file)
@@ -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) {
                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)) {
        /* 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 &&
 
        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);
            card->state == DEV_STATE_UP) {
                lcs_clear_multicast_list(card);
                rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP);
index 0e1e4a0a88f04fac497d5d280f7329d47821f824..8976fb0b070a73944b102da520ca4f691461587f 100644 (file)
@@ -138,6 +138,7 @@ enum lcs_channel_states {
        LCS_CH_STATE_RUNNING,
        LCS_CH_STATE_SUSPENDED,
        LCS_CH_STATE_CLEARED,
        LCS_CH_STATE_RUNNING,
        LCS_CH_STATE_SUSPENDED,
        LCS_CH_STATE_CLEARED,
+       LCS_CH_STATE_ERROR,
 };
 
 /**
 };
 
 /**