diff options
Diffstat (limited to 'drivers/s390/net/lcs.c')
-rw-r--r-- | drivers/s390/net/lcs.c | 345 |
1 files changed, 173 insertions, 172 deletions
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index e65da921a827..f94419b334f7 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -68,6 +68,7 @@ static void lcs_tasklet(unsigned long); | |||
68 | static void lcs_start_kernel_thread(struct lcs_card *card); | 68 | static void lcs_start_kernel_thread(struct lcs_card *card); |
69 | static void lcs_get_frames_cb(struct lcs_channel *, struct lcs_buffer *); | 69 | static void lcs_get_frames_cb(struct lcs_channel *, struct lcs_buffer *); |
70 | static int lcs_send_delipm(struct lcs_card *, struct lcs_ipm_list *); | 70 | static int lcs_send_delipm(struct lcs_card *, struct lcs_ipm_list *); |
71 | static int lcs_recovery(void *ptr); | ||
71 | 72 | ||
72 | /** | 73 | /** |
73 | * Debug Facility Stuff | 74 | * Debug Facility Stuff |
@@ -429,12 +430,6 @@ lcs_setup_card(struct lcs_card *card) | |||
429 | card->tx_buffer = NULL; | 430 | card->tx_buffer = NULL; |
430 | card->tx_emitted = 0; | 431 | card->tx_emitted = 0; |
431 | 432 | ||
432 | /* Initialize kernel thread task used for LGW commands. */ | ||
433 | INIT_WORK(&card->kernel_thread_starter, | ||
434 | (void *)lcs_start_kernel_thread,card); | ||
435 | card->thread_start_mask = 0; | ||
436 | card->thread_allowed_mask = 0; | ||
437 | card->thread_running_mask = 0; | ||
438 | init_waitqueue_head(&card->wait_q); | 433 | init_waitqueue_head(&card->wait_q); |
439 | spin_lock_init(&card->lock); | 434 | spin_lock_init(&card->lock); |
440 | spin_lock_init(&card->ipm_lock); | 435 | spin_lock_init(&card->ipm_lock); |
@@ -675,8 +670,9 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | |||
675 | int index, rc; | 670 | int index, rc; |
676 | 671 | ||
677 | LCS_DBF_TEXT(5, trace, "rdybuff"); | 672 | LCS_DBF_TEXT(5, trace, "rdybuff"); |
678 | BUG_ON(buffer->state != BUF_STATE_LOCKED && | 673 | if (buffer->state != BUF_STATE_LOCKED && |
679 | buffer->state != BUF_STATE_PROCESSED); | 674 | buffer->state != BUF_STATE_PROCESSED) |
675 | BUG(); | ||
680 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | 676 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); |
681 | buffer->state = BUF_STATE_READY; | 677 | buffer->state = BUF_STATE_READY; |
682 | index = buffer - channel->iob; | 678 | index = buffer - channel->iob; |
@@ -700,7 +696,8 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | |||
700 | int index, prev, next; | 696 | int index, prev, next; |
701 | 697 | ||
702 | LCS_DBF_TEXT(5, trace, "prcsbuff"); | 698 | LCS_DBF_TEXT(5, trace, "prcsbuff"); |
703 | BUG_ON(buffer->state != BUF_STATE_READY); | 699 | if (buffer->state != BUF_STATE_READY) |
700 | BUG(); | ||
704 | buffer->state = BUF_STATE_PROCESSED; | 701 | buffer->state = BUF_STATE_PROCESSED; |
705 | index = buffer - channel->iob; | 702 | index = buffer - channel->iob; |
706 | prev = (index - 1) & (LCS_NUM_BUFFS - 1); | 703 | prev = (index - 1) & (LCS_NUM_BUFFS - 1); |
@@ -732,8 +729,9 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer) | |||
732 | unsigned long flags; | 729 | unsigned long flags; |
733 | 730 | ||
734 | LCS_DBF_TEXT(5, trace, "relbuff"); | 731 | LCS_DBF_TEXT(5, trace, "relbuff"); |
735 | BUG_ON(buffer->state != BUF_STATE_LOCKED && | 732 | if (buffer->state != BUF_STATE_LOCKED && |
736 | buffer->state != BUF_STATE_PROCESSED); | 733 | buffer->state != BUF_STATE_PROCESSED) |
734 | BUG(); | ||
737 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); | 735 | spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); |
738 | buffer->state = BUF_STATE_EMPTY; | 736 | buffer->state = BUF_STATE_EMPTY; |
739 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); | 737 | spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); |
@@ -1147,8 +1145,6 @@ list_modified: | |||
1147 | list_add_tail(&ipm->list, &card->ipm_list); | 1145 | list_add_tail(&ipm->list, &card->ipm_list); |
1148 | } | 1146 | } |
1149 | spin_unlock_irqrestore(&card->ipm_lock, flags); | 1147 | spin_unlock_irqrestore(&card->ipm_lock, flags); |
1150 | if (card->state == DEV_STATE_UP) | ||
1151 | netif_wake_queue(card->dev); | ||
1152 | } | 1148 | } |
1153 | 1149 | ||
1154 | /** | 1150 | /** |
@@ -1231,17 +1227,17 @@ lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) | |||
1231 | if (ipm != NULL) | 1227 | if (ipm != NULL) |
1232 | continue; /* Address already in list. */ | 1228 | continue; /* Address already in list. */ |
1233 | ipm = (struct lcs_ipm_list *) | 1229 | ipm = (struct lcs_ipm_list *) |
1234 | kmalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC); | 1230 | kzalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC); |
1235 | if (ipm == NULL) { | 1231 | if (ipm == NULL) { |
1236 | PRINT_INFO("Not enough memory to add " | 1232 | PRINT_INFO("Not enough memory to add " |
1237 | "new multicast entry!\n"); | 1233 | "new multicast entry!\n"); |
1238 | break; | 1234 | break; |
1239 | } | 1235 | } |
1240 | memset(ipm, 0, sizeof(struct lcs_ipm_list)); | ||
1241 | memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH); | 1236 | memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH); |
1242 | ipm->ipm.ip_addr = im4->multiaddr; | 1237 | ipm->ipm.ip_addr = im4->multiaddr; |
1243 | ipm->ipm_state = LCS_IPM_STATE_SET_REQUIRED; | 1238 | ipm->ipm_state = LCS_IPM_STATE_SET_REQUIRED; |
1244 | spin_lock_irqsave(&card->ipm_lock, flags); | 1239 | spin_lock_irqsave(&card->ipm_lock, flags); |
1240 | LCS_DBF_HEX(2,trace,&ipm->ipm.ip_addr,4); | ||
1245 | list_add(&ipm->list, &card->ipm_list); | 1241 | list_add(&ipm->list, &card->ipm_list); |
1246 | spin_unlock_irqrestore(&card->ipm_lock, flags); | 1242 | spin_unlock_irqrestore(&card->ipm_lock, flags); |
1247 | } | 1243 | } |
@@ -1269,7 +1265,15 @@ lcs_register_mc_addresses(void *data) | |||
1269 | read_unlock(&in4_dev->mc_list_lock); | 1265 | read_unlock(&in4_dev->mc_list_lock); |
1270 | in_dev_put(in4_dev); | 1266 | in_dev_put(in4_dev); |
1271 | 1267 | ||
1268 | netif_carrier_off(card->dev); | ||
1269 | netif_tx_disable(card->dev); | ||
1270 | wait_event(card->write.wait_q, | ||
1271 | (card->write.state != CH_STATE_RUNNING)); | ||
1272 | lcs_fix_multicast_list(card); | 1272 | lcs_fix_multicast_list(card); |
1273 | if (card->state == DEV_STATE_UP) { | ||
1274 | netif_carrier_on(card->dev); | ||
1275 | netif_wake_queue(card->dev); | ||
1276 | } | ||
1273 | out: | 1277 | out: |
1274 | lcs_clear_thread_running_bit(card, LCS_SET_MC_THREAD); | 1278 | lcs_clear_thread_running_bit(card, LCS_SET_MC_THREAD); |
1275 | return 0; | 1279 | return 0; |
@@ -1286,7 +1290,7 @@ lcs_set_multicast_list(struct net_device *dev) | |||
1286 | LCS_DBF_TEXT(4, trace, "setmulti"); | 1290 | LCS_DBF_TEXT(4, trace, "setmulti"); |
1287 | card = (struct lcs_card *) dev->priv; | 1291 | card = (struct lcs_card *) dev->priv; |
1288 | 1292 | ||
1289 | if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD)) | 1293 | if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD)) |
1290 | schedule_work(&card->kernel_thread_starter); | 1294 | schedule_work(&card->kernel_thread_starter); |
1291 | } | 1295 | } |
1292 | 1296 | ||
@@ -1318,6 +1322,53 @@ lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb) | |||
1318 | return PTR_ERR(irb); | 1322 | return PTR_ERR(irb); |
1319 | } | 1323 | } |
1320 | 1324 | ||
1325 | static int | ||
1326 | lcs_get_problem(struct ccw_device *cdev, struct irb *irb) | ||
1327 | { | ||
1328 | int dstat, cstat; | ||
1329 | char *sense; | ||
1330 | |||
1331 | sense = (char *) irb->ecw; | ||
1332 | cstat = irb->scsw.cstat; | ||
1333 | dstat = irb->scsw.dstat; | ||
1334 | |||
1335 | if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK | | ||
1336 | SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK | | ||
1337 | SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) { | ||
1338 | LCS_DBF_TEXT(2, trace, "CGENCHK"); | ||
1339 | return 1; | ||
1340 | } | ||
1341 | if (dstat & DEV_STAT_UNIT_CHECK) { | ||
1342 | if (sense[LCS_SENSE_BYTE_1] & | ||
1343 | LCS_SENSE_RESETTING_EVENT) { | ||
1344 | LCS_DBF_TEXT(2, trace, "REVIND"); | ||
1345 | return 1; | ||
1346 | } | ||
1347 | if (sense[LCS_SENSE_BYTE_0] & | ||
1348 | LCS_SENSE_CMD_REJECT) { | ||
1349 | LCS_DBF_TEXT(2, trace, "CMDREJ"); | ||
1350 | return 0; | ||
1351 | } | ||
1352 | if ((!sense[LCS_SENSE_BYTE_0]) && | ||
1353 | (!sense[LCS_SENSE_BYTE_1]) && | ||
1354 | (!sense[LCS_SENSE_BYTE_2]) && | ||
1355 | (!sense[LCS_SENSE_BYTE_3])) { | ||
1356 | LCS_DBF_TEXT(2, trace, "ZEROSEN"); | ||
1357 | return 0; | ||
1358 | } | ||
1359 | LCS_DBF_TEXT(2, trace, "DGENCHK"); | ||
1360 | return 1; | ||
1361 | } | ||
1362 | return 0; | ||
1363 | } | ||
1364 | |||
1365 | void | ||
1366 | lcs_schedule_recovery(struct lcs_card *card) | ||
1367 | { | ||
1368 | LCS_DBF_TEXT(2, trace, "startrec"); | ||
1369 | if (!lcs_set_thread_start_bit(card, LCS_RECOVERY_THREAD)) | ||
1370 | schedule_work(&card->kernel_thread_starter); | ||
1371 | } | ||
1321 | 1372 | ||
1322 | /** | 1373 | /** |
1323 | * IRQ Handler for LCS channels | 1374 | * IRQ Handler for LCS channels |
@@ -1327,7 +1378,8 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
1327 | { | 1378 | { |
1328 | struct lcs_card *card; | 1379 | struct lcs_card *card; |
1329 | struct lcs_channel *channel; | 1380 | struct lcs_channel *channel; |
1330 | int index; | 1381 | int rc, index; |
1382 | int cstat, dstat; | ||
1331 | 1383 | ||
1332 | if (lcs_check_irb_error(cdev, irb)) | 1384 | if (lcs_check_irb_error(cdev, irb)) |
1333 | return; | 1385 | return; |
@@ -1338,14 +1390,27 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
1338 | else | 1390 | else |
1339 | channel = &card->write; | 1391 | channel = &card->write; |
1340 | 1392 | ||
1393 | cstat = irb->scsw.cstat; | ||
1394 | dstat = irb->scsw.dstat; | ||
1341 | LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id); | 1395 | LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id); |
1342 | LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat); | 1396 | LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat); |
1343 | LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.fctl, irb->scsw.actl); | 1397 | LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.fctl, irb->scsw.actl); |
1344 | 1398 | ||
1399 | /* Check for channel and device errors presented */ | ||
1400 | rc = lcs_get_problem(cdev, irb); | ||
1401 | if (rc || (dstat & DEV_STAT_UNIT_EXCEP)) { | ||
1402 | PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n", | ||
1403 | cdev->dev.bus_id, dstat, cstat); | ||
1404 | if (rc) { | ||
1405 | lcs_schedule_recovery(card); | ||
1406 | wake_up(&card->wait_q); | ||
1407 | return; | ||
1408 | } | ||
1409 | } | ||
1345 | /* How far in the ccw chain have we processed? */ | 1410 | /* How far in the ccw chain have we processed? */ |
1346 | if ((channel->state != CH_STATE_INIT) && | 1411 | if ((channel->state != CH_STATE_INIT) && |
1347 | (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { | 1412 | (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { |
1348 | index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa) | 1413 | index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa) |
1349 | - channel->ccws; | 1414 | - channel->ccws; |
1350 | if ((irb->scsw.actl & SCSW_ACTL_SUSPENDED) || | 1415 | if ((irb->scsw.actl & SCSW_ACTL_SUSPENDED) || |
1351 | (irb->scsw.cstat & SCHN_STAT_PCI)) | 1416 | (irb->scsw.cstat & SCHN_STAT_PCI)) |
@@ -1367,7 +1432,6 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
1367 | else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED) | 1432 | else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED) |
1368 | /* CCW execution stopped on a suspend bit. */ | 1433 | /* CCW execution stopped on a suspend bit. */ |
1369 | channel->state = CH_STATE_SUSPENDED; | 1434 | channel->state = CH_STATE_SUSPENDED; |
1370 | |||
1371 | if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) { | 1435 | if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) { |
1372 | if (irb->scsw.cc != 0) { | 1436 | if (irb->scsw.cc != 0) { |
1373 | ccw_device_halt(channel->ccwdev, (addr_t) channel); | 1437 | 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 | /* The channel has been stopped by halt_IO. */ | 1440 | /* The channel has been stopped by halt_IO. */ |
1377 | channel->state = CH_STATE_HALTED; | 1441 | channel->state = CH_STATE_HALTED; |
1378 | } | 1442 | } |
1379 | |||
1380 | if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { | 1443 | if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { |
1381 | channel->state = CH_STATE_CLEARED; | 1444 | channel->state = CH_STATE_CLEARED; |
1382 | } | 1445 | } |
@@ -1452,7 +1515,7 @@ lcs_txbuffer_cb(struct lcs_channel *channel, struct lcs_buffer *buffer) | |||
1452 | lcs_release_buffer(channel, buffer); | 1515 | lcs_release_buffer(channel, buffer); |
1453 | card = (struct lcs_card *) | 1516 | card = (struct lcs_card *) |
1454 | ((char *) channel - offsetof(struct lcs_card, write)); | 1517 | ((char *) channel - offsetof(struct lcs_card, write)); |
1455 | if (netif_queue_stopped(card->dev)) | 1518 | if (netif_queue_stopped(card->dev) && netif_carrier_ok(card->dev)) |
1456 | netif_wake_queue(card->dev); | 1519 | netif_wake_queue(card->dev); |
1457 | spin_lock(&card->lock); | 1520 | spin_lock(&card->lock); |
1458 | card->tx_emitted--; | 1521 | card->tx_emitted--; |
@@ -1488,6 +1551,10 @@ __lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb, | |||
1488 | card->stats.tx_carrier_errors++; | 1551 | card->stats.tx_carrier_errors++; |
1489 | return 0; | 1552 | return 0; |
1490 | } | 1553 | } |
1554 | if (skb->protocol == htons(ETH_P_IPV6)) { | ||
1555 | dev_kfree_skb(skb); | ||
1556 | return 0; | ||
1557 | } | ||
1491 | netif_stop_queue(card->dev); | 1558 | netif_stop_queue(card->dev); |
1492 | spin_lock(&card->lock); | 1559 | spin_lock(&card->lock); |
1493 | if (card->tx_buffer != NULL && | 1560 | if (card->tx_buffer != NULL && |
@@ -1633,30 +1700,6 @@ lcs_detect(struct lcs_card *card) | |||
1633 | } | 1700 | } |
1634 | 1701 | ||
1635 | /** | 1702 | /** |
1636 | * reset card | ||
1637 | */ | ||
1638 | static int | ||
1639 | lcs_resetcard(struct lcs_card *card) | ||
1640 | { | ||
1641 | int retries; | ||
1642 | |||
1643 | LCS_DBF_TEXT(2, trace, "rescard"); | ||
1644 | for (retries = 0; retries < 10; retries++) { | ||
1645 | if (lcs_detect(card) == 0) { | ||
1646 | netif_wake_queue(card->dev); | ||
1647 | card->state = DEV_STATE_UP; | ||
1648 | PRINT_INFO("LCS device %s successfully restarted!\n", | ||
1649 | card->dev->name); | ||
1650 | return 0; | ||
1651 | } | ||
1652 | msleep(3000); | ||
1653 | } | ||
1654 | PRINT_ERR("Error in Reseting LCS card!\n"); | ||
1655 | return -EIO; | ||
1656 | } | ||
1657 | |||
1658 | |||
1659 | /** | ||
1660 | * LCS Stop card | 1703 | * LCS Stop card |
1661 | */ | 1704 | */ |
1662 | static int | 1705 | static int |
@@ -1680,126 +1723,18 @@ lcs_stopcard(struct lcs_card *card) | |||
1680 | } | 1723 | } |
1681 | 1724 | ||
1682 | /** | 1725 | /** |
1683 | * LGW initiated commands | ||
1684 | */ | ||
1685 | static int | ||
1686 | lcs_lgw_startlan_thread(void *data) | ||
1687 | { | ||
1688 | struct lcs_card *card; | ||
1689 | |||
1690 | card = (struct lcs_card *) data; | ||
1691 | daemonize("lgwstpln"); | ||
1692 | |||
1693 | if (!lcs_do_run_thread(card, LCS_STARTLAN_THREAD)) | ||
1694 | return 0; | ||
1695 | LCS_DBF_TEXT(4, trace, "lgwstpln"); | ||
1696 | if (card->dev) | ||
1697 | netif_stop_queue(card->dev); | ||
1698 | if (lcs_startlan(card) == 0) { | ||
1699 | netif_wake_queue(card->dev); | ||
1700 | card->state = DEV_STATE_UP; | ||
1701 | PRINT_INFO("LCS Startlan for device %s succeeded!\n", | ||
1702 | card->dev->name); | ||
1703 | |||
1704 | } else | ||
1705 | PRINT_ERR("LCS Startlan for device %s failed!\n", | ||
1706 | card->dev->name); | ||
1707 | lcs_clear_thread_running_bit(card, LCS_STARTLAN_THREAD); | ||
1708 | return 0; | ||
1709 | } | ||
1710 | |||
1711 | /** | ||
1712 | * Send startup command initiated by Lan Gateway | ||
1713 | */ | ||
1714 | static int | ||
1715 | lcs_lgw_startup_thread(void *data) | ||
1716 | { | ||
1717 | int rc; | ||
1718 | |||
1719 | struct lcs_card *card; | ||
1720 | |||
1721 | card = (struct lcs_card *) data; | ||
1722 | daemonize("lgwstaln"); | ||
1723 | |||
1724 | if (!lcs_do_run_thread(card, LCS_STARTUP_THREAD)) | ||
1725 | return 0; | ||
1726 | LCS_DBF_TEXT(4, trace, "lgwstaln"); | ||
1727 | if (card->dev) | ||
1728 | netif_stop_queue(card->dev); | ||
1729 | rc = lcs_send_startup(card, LCS_INITIATOR_LGW); | ||
1730 | if (rc != 0) { | ||
1731 | PRINT_ERR("Startup for LCS device %s initiated " \ | ||
1732 | "by LGW failed!\nReseting card ...\n", | ||
1733 | card->dev->name); | ||
1734 | /* do a card reset */ | ||
1735 | rc = lcs_resetcard(card); | ||
1736 | if (rc == 0) | ||
1737 | goto Done; | ||
1738 | } | ||
1739 | rc = lcs_startlan(card); | ||
1740 | if (rc == 0) { | ||
1741 | netif_wake_queue(card->dev); | ||
1742 | card->state = DEV_STATE_UP; | ||
1743 | } | ||
1744 | Done: | ||
1745 | if (rc == 0) | ||
1746 | PRINT_INFO("LCS Startup for device %s succeeded!\n", | ||
1747 | card->dev->name); | ||
1748 | else | ||
1749 | PRINT_ERR("LCS Startup for device %s failed!\n", | ||
1750 | card->dev->name); | ||
1751 | lcs_clear_thread_running_bit(card, LCS_STARTUP_THREAD); | ||
1752 | return 0; | ||
1753 | } | ||
1754 | |||
1755 | |||
1756 | /** | ||
1757 | * send stoplan command initiated by Lan Gateway | ||
1758 | */ | ||
1759 | static int | ||
1760 | lcs_lgw_stoplan_thread(void *data) | ||
1761 | { | ||
1762 | struct lcs_card *card; | ||
1763 | int rc; | ||
1764 | |||
1765 | card = (struct lcs_card *) data; | ||
1766 | daemonize("lgwstop"); | ||
1767 | |||
1768 | if (!lcs_do_run_thread(card, LCS_STOPLAN_THREAD)) | ||
1769 | return 0; | ||
1770 | LCS_DBF_TEXT(4, trace, "lgwstop"); | ||
1771 | if (card->dev) | ||
1772 | netif_stop_queue(card->dev); | ||
1773 | if (lcs_send_stoplan(card, LCS_INITIATOR_LGW) == 0) | ||
1774 | PRINT_INFO("Stoplan for %s initiated by LGW succeeded!\n", | ||
1775 | card->dev->name); | ||
1776 | else | ||
1777 | PRINT_ERR("Stoplan %s initiated by LGW failed!\n", | ||
1778 | card->dev->name); | ||
1779 | /*Try to reset the card, stop it on failure */ | ||
1780 | rc = lcs_resetcard(card); | ||
1781 | if (rc != 0) | ||
1782 | rc = lcs_stopcard(card); | ||
1783 | lcs_clear_thread_running_bit(card, LCS_STOPLAN_THREAD); | ||
1784 | return rc; | ||
1785 | } | ||
1786 | |||
1787 | /** | ||
1788 | * Kernel Thread helper functions for LGW initiated commands | 1726 | * Kernel Thread helper functions for LGW initiated commands |
1789 | */ | 1727 | */ |
1790 | static void | 1728 | static void |
1791 | lcs_start_kernel_thread(struct lcs_card *card) | 1729 | lcs_start_kernel_thread(struct lcs_card *card) |
1792 | { | 1730 | { |
1793 | LCS_DBF_TEXT(5, trace, "krnthrd"); | 1731 | LCS_DBF_TEXT(5, trace, "krnthrd"); |
1794 | if (lcs_do_start_thread(card, LCS_STARTUP_THREAD)) | 1732 | if (lcs_do_start_thread(card, LCS_RECOVERY_THREAD)) |
1795 | kernel_thread(lcs_lgw_startup_thread, (void *) card, SIGCHLD); | 1733 | kernel_thread(lcs_recovery, (void *) card, SIGCHLD); |
1796 | if (lcs_do_start_thread(card, LCS_STARTLAN_THREAD)) | ||
1797 | kernel_thread(lcs_lgw_startlan_thread, (void *) card, SIGCHLD); | ||
1798 | if (lcs_do_start_thread(card, LCS_STOPLAN_THREAD)) | ||
1799 | kernel_thread(lcs_lgw_stoplan_thread, (void *) card, SIGCHLD); | ||
1800 | #ifdef CONFIG_IP_MULTICAST | 1734 | #ifdef CONFIG_IP_MULTICAST |
1801 | if (lcs_do_start_thread(card, LCS_SET_MC_THREAD)) | 1735 | if (lcs_do_start_thread(card, LCS_SET_MC_THREAD)) |
1802 | kernel_thread(lcs_register_mc_addresses, (void *) card, SIGCHLD); | 1736 | kernel_thread(lcs_register_mc_addresses, |
1737 | (void *) card, SIGCHLD); | ||
1803 | #endif | 1738 | #endif |
1804 | } | 1739 | } |
1805 | 1740 | ||
@@ -1813,19 +1748,14 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd) | |||
1813 | if (cmd->initiator == LCS_INITIATOR_LGW) { | 1748 | if (cmd->initiator == LCS_INITIATOR_LGW) { |
1814 | switch(cmd->cmd_code) { | 1749 | switch(cmd->cmd_code) { |
1815 | case LCS_CMD_STARTUP: | 1750 | case LCS_CMD_STARTUP: |
1816 | if (!lcs_set_thread_start_bit(card, | ||
1817 | LCS_STARTUP_THREAD)) | ||
1818 | schedule_work(&card->kernel_thread_starter); | ||
1819 | break; | ||
1820 | case LCS_CMD_STARTLAN: | 1751 | case LCS_CMD_STARTLAN: |
1821 | if (!lcs_set_thread_start_bit(card, | 1752 | lcs_schedule_recovery(card); |
1822 | LCS_STARTLAN_THREAD)) | ||
1823 | schedule_work(&card->kernel_thread_starter); | ||
1824 | break; | 1753 | break; |
1825 | case LCS_CMD_STOPLAN: | 1754 | case LCS_CMD_STOPLAN: |
1826 | if (!lcs_set_thread_start_bit(card, | 1755 | PRINT_WARN("Stoplan for %s initiated by LGW.\n", |
1827 | LCS_STOPLAN_THREAD)) | 1756 | card->dev->name); |
1828 | schedule_work(&card->kernel_thread_starter); | 1757 | if (card->dev) |
1758 | netif_carrier_off(card->dev); | ||
1829 | break; | 1759 | break; |
1830 | default: | 1760 | default: |
1831 | PRINT_INFO("UNRECOGNIZED LGW COMMAND\n"); | 1761 | PRINT_INFO("UNRECOGNIZED LGW COMMAND\n"); |
@@ -1941,8 +1871,11 @@ lcs_stop_device(struct net_device *dev) | |||
1941 | 1871 | ||
1942 | LCS_DBF_TEXT(2, trace, "stopdev"); | 1872 | LCS_DBF_TEXT(2, trace, "stopdev"); |
1943 | card = (struct lcs_card *) dev->priv; | 1873 | card = (struct lcs_card *) dev->priv; |
1944 | netif_stop_queue(dev); | 1874 | netif_carrier_off(dev); |
1875 | netif_tx_disable(dev); | ||
1945 | dev->flags &= ~IFF_UP; | 1876 | dev->flags &= ~IFF_UP; |
1877 | wait_event(card->write.wait_q, | ||
1878 | (card->write.state != CH_STATE_RUNNING)); | ||
1946 | rc = lcs_stopcard(card); | 1879 | rc = lcs_stopcard(card); |
1947 | if (rc) | 1880 | if (rc) |
1948 | PRINT_ERR("Try it again!\n "); | 1881 | PRINT_ERR("Try it again!\n "); |
@@ -1968,6 +1901,7 @@ lcs_open_device(struct net_device *dev) | |||
1968 | 1901 | ||
1969 | } else { | 1902 | } else { |
1970 | dev->flags |= IFF_UP; | 1903 | dev->flags |= IFF_UP; |
1904 | netif_carrier_on(dev); | ||
1971 | netif_wake_queue(dev); | 1905 | netif_wake_queue(dev); |
1972 | card->state = DEV_STATE_UP; | 1906 | card->state = DEV_STATE_UP; |
1973 | } | 1907 | } |
@@ -2059,10 +1993,31 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char | |||
2059 | 1993 | ||
2060 | DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store); | 1994 | DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store); |
2061 | 1995 | ||
1996 | static ssize_t | ||
1997 | lcs_dev_recover_store(struct device *dev, struct device_attribute *attr, | ||
1998 | const char *buf, size_t count) | ||
1999 | { | ||
2000 | struct lcs_card *card = dev->driver_data; | ||
2001 | char *tmp; | ||
2002 | int i; | ||
2003 | |||
2004 | if (!card) | ||
2005 | return -EINVAL; | ||
2006 | if (card->state != DEV_STATE_UP) | ||
2007 | return -EPERM; | ||
2008 | i = simple_strtoul(buf, &tmp, 16); | ||
2009 | if (i == 1) | ||
2010 | lcs_schedule_recovery(card); | ||
2011 | return count; | ||
2012 | } | ||
2013 | |||
2014 | static DEVICE_ATTR(recover, 0200, NULL, lcs_dev_recover_store); | ||
2015 | |||
2062 | static struct attribute * lcs_attrs[] = { | 2016 | static struct attribute * lcs_attrs[] = { |
2063 | &dev_attr_portno.attr, | 2017 | &dev_attr_portno.attr, |
2064 | &dev_attr_type.attr, | 2018 | &dev_attr_type.attr, |
2065 | &dev_attr_lancmd_timeout.attr, | 2019 | &dev_attr_lancmd_timeout.attr, |
2020 | &dev_attr_recover.attr, | ||
2066 | NULL, | 2021 | NULL, |
2067 | }; | 2022 | }; |
2068 | 2023 | ||
@@ -2099,6 +2054,12 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev) | |||
2099 | ccwgdev->dev.driver_data = card; | 2054 | ccwgdev->dev.driver_data = card; |
2100 | ccwgdev->cdev[0]->handler = lcs_irq; | 2055 | ccwgdev->cdev[0]->handler = lcs_irq; |
2101 | ccwgdev->cdev[1]->handler = lcs_irq; | 2056 | ccwgdev->cdev[1]->handler = lcs_irq; |
2057 | card->gdev = ccwgdev; | ||
2058 | INIT_WORK(&card->kernel_thread_starter, | ||
2059 | (void *) lcs_start_kernel_thread, card); | ||
2060 | card->thread_start_mask = 0; | ||
2061 | card->thread_allowed_mask = 0; | ||
2062 | card->thread_running_mask = 0; | ||
2102 | return 0; | 2063 | return 0; |
2103 | } | 2064 | } |
2104 | 2065 | ||
@@ -2200,6 +2161,7 @@ netdev_out: | |||
2200 | if (recover_state == DEV_STATE_RECOVER) { | 2161 | if (recover_state == DEV_STATE_RECOVER) { |
2201 | lcs_set_multicast_list(card->dev); | 2162 | lcs_set_multicast_list(card->dev); |
2202 | card->dev->flags |= IFF_UP; | 2163 | card->dev->flags |= IFF_UP; |
2164 | netif_carrier_on(card->dev); | ||
2203 | netif_wake_queue(card->dev); | 2165 | netif_wake_queue(card->dev); |
2204 | card->state = DEV_STATE_UP; | 2166 | card->state = DEV_STATE_UP; |
2205 | } else { | 2167 | } else { |
@@ -2229,7 +2191,7 @@ out: | |||
2229 | * lcs_shutdown_device, called when setting the group device offline. | 2191 | * lcs_shutdown_device, called when setting the group device offline. |
2230 | */ | 2192 | */ |
2231 | static int | 2193 | static int |
2232 | lcs_shutdown_device(struct ccwgroup_device *ccwgdev) | 2194 | __lcs_shutdown_device(struct ccwgroup_device *ccwgdev, int recovery_mode) |
2233 | { | 2195 | { |
2234 | struct lcs_card *card; | 2196 | struct lcs_card *card; |
2235 | enum lcs_dev_states recover_state; | 2197 | enum lcs_dev_states recover_state; |
@@ -2239,9 +2201,11 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev) | |||
2239 | card = (struct lcs_card *)ccwgdev->dev.driver_data; | 2201 | card = (struct lcs_card *)ccwgdev->dev.driver_data; |
2240 | if (!card) | 2202 | if (!card) |
2241 | return -ENODEV; | 2203 | return -ENODEV; |
2242 | lcs_set_allowed_threads(card, 0); | 2204 | if (recovery_mode == 0) { |
2243 | if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD)) | 2205 | lcs_set_allowed_threads(card, 0); |
2244 | return -ERESTARTSYS; | 2206 | if (lcs_wait_for_threads(card, LCS_SET_MC_THREAD)) |
2207 | return -ERESTARTSYS; | ||
2208 | } | ||
2245 | LCS_DBF_HEX(3, setup, &card, sizeof(void*)); | 2209 | LCS_DBF_HEX(3, setup, &card, sizeof(void*)); |
2246 | recover_state = card->state; | 2210 | recover_state = card->state; |
2247 | 2211 | ||
@@ -2256,6 +2220,43 @@ lcs_shutdown_device(struct ccwgroup_device *ccwgdev) | |||
2256 | return 0; | 2220 | return 0; |
2257 | } | 2221 | } |
2258 | 2222 | ||
2223 | static int | ||
2224 | lcs_shutdown_device(struct ccwgroup_device *ccwgdev) | ||
2225 | { | ||
2226 | return __lcs_shutdown_device(ccwgdev, 0); | ||
2227 | } | ||
2228 | |||
2229 | /** | ||
2230 | * drive lcs recovery after startup and startlan initiated by Lan Gateway | ||
2231 | */ | ||
2232 | static int | ||
2233 | lcs_recovery(void *ptr) | ||
2234 | { | ||
2235 | struct lcs_card *card; | ||
2236 | struct ccwgroup_device *gdev; | ||
2237 | int rc; | ||
2238 | |||
2239 | card = (struct lcs_card *) ptr; | ||
2240 | daemonize("lcs_recover"); | ||
2241 | |||
2242 | LCS_DBF_TEXT(4, trace, "recover1"); | ||
2243 | if (!lcs_do_run_thread(card, LCS_RECOVERY_THREAD)) | ||
2244 | return 0; | ||
2245 | LCS_DBF_TEXT(4, trace, "recover2"); | ||
2246 | gdev = card->gdev; | ||
2247 | PRINT_WARN("Recovery of device %s started...\n", gdev->dev.bus_id); | ||
2248 | rc = __lcs_shutdown_device(gdev, 1); | ||
2249 | rc = lcs_new_device(gdev); | ||
2250 | if (!rc) | ||
2251 | PRINT_INFO("Device %s successfully recovered!\n", | ||
2252 | card->dev->name); | ||
2253 | else | ||
2254 | PRINT_INFO("Device %s could not be recovered!\n", | ||
2255 | card->dev->name); | ||
2256 | lcs_clear_thread_running_bit(card, LCS_RECOVERY_THREAD); | ||
2257 | return 0; | ||
2258 | } | ||
2259 | |||
2259 | /** | 2260 | /** |
2260 | * lcs_remove_device, free buffers and card | 2261 | * lcs_remove_device, free buffers and card |
2261 | */ | 2262 | */ |