* Frank Pavlic (pavlic@de.ibm.com) and
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*
- * $Revision: 1.74 $ $Date: 2004/04/05 00:01:04 $
+ * $Revision: 1.81 $ $Date: 2004/05/14 13:54:33 $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
/**
* initialization string for output
*/
-#define VERSION_LCS_C "$Revision: 1.74 $"
+#define VERSION_LCS_C "$Revision: 1.81 $"
static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
static char debug_buffer[255];
return -ENOMEM;
}
debug_register_view(lcs_dbf_setup, &debug_hex_ascii_view);
- debug_set_level(lcs_dbf_setup, 5);
+ debug_set_level(lcs_dbf_setup, 2);
debug_register_view(lcs_dbf_trace, &debug_hex_ascii_view);
- debug_set_level(lcs_dbf_trace, 5);
+ debug_set_level(lcs_dbf_trace, 2);
return 0;
}
(void *)lcs_start_kernel_thread,card);
card->thread_mask = 0;
spin_lock_init(&card->lock);
+ spin_lock_init(&card->ipm_lock);
#ifdef CONFIG_IP_MULTICAST
INIT_LIST_HEAD(&card->ipm_list);
#endif
/**
* set or del multicast address on LCS card
*/
-static int
-lcs_fix_multicast_list(void *data)
+static void
+lcs_fix_multicast_list(struct lcs_card *card)
{
struct list_head *l, *n;
struct lcs_ipm_list *ipm;
- struct lcs_card *card;
- card = (struct lcs_card *) data;
-
- daemonize("fixipm");
LCS_DBF_TEXT(4,trace, "fixipm");
- spin_lock(&card->lock);
+ spin_lock(&card->ipm_lock);
list_for_each_safe(l, n, &card->ipm_list) {
ipm = list_entry(l, struct lcs_ipm_list, list);
switch (ipm->ipm_state) {
}
if (card->state == DEV_STATE_UP)
netif_wake_queue(card->dev);
- spin_unlock(&card->lock);
- return 0;
+ spin_unlock(&card->ipm_lock);
}
/**
/**
* function called by net device to handle multicast address relevant things
*/
-static void
-lcs_set_multicast_list(struct net_device *dev)
+static int
+lcs_register_mc_addresses(void *data)
{
+ struct lcs_card *card;
char buf[MAX_ADDR_LEN];
struct list_head *l;
struct ip_mc_list *im4;
struct in_device *in4_dev;
struct lcs_ipm_list *ipm, *tmp;
- struct lcs_card *card;
- LCS_DBF_TEXT(4, trace, "setmulti");
- in4_dev = in_dev_get(dev);
+ daemonize("regipm");
+ LCS_DBF_TEXT(4, trace, "regmulti");
+
+ card = (struct lcs_card *) data;
+ in4_dev = in_dev_get(card->dev);
if (in4_dev == NULL)
- return;
+ return 0;
read_lock(&in4_dev->lock);
- card = (struct lcs_card *) dev->priv;
- spin_lock(&card->lock);
+ spin_lock(&card->ipm_lock);
/* Check for multicast addresses to be removed. */
list_for_each(l, &card->ipm_list) {
ipm = list_entry(l, struct lcs_ipm_list, list);
for (im4 = in4_dev->mc_list; im4 != NULL; im4 = im4->next) {
- lcs_get_mac_for_ipm(im4->multiaddr, buf, dev);
+ lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev);
if (memcmp(buf, &ipm->ipm.mac_addr,
LCS_MAC_LENGTH) == 0 &&
ipm->ipm.ip_addr == im4->multiaddr)
}
/* Check for multicast addresses to be added. */
for (im4 = in4_dev->mc_list; im4; im4 = im4->next) {
- lcs_get_mac_for_ipm(im4->multiaddr, buf, dev);
+ lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev);
ipm = NULL;
list_for_each(l, &card->ipm_list) {
tmp = list_entry(l, struct lcs_ipm_list, list);
ipm->ipm_state = LCS_IPM_STATE_SET_REQUIRED;
list_add(&ipm->list, &card->ipm_list);
}
- spin_unlock(&card->lock);
+ spin_unlock(&card->ipm_lock);
read_unlock(&in4_dev->lock);
- set_bit(3, &card->thread_mask);
- schedule_work(&card->kernel_thread_starter);
+ lcs_fix_multicast_list(card);
+ in_dev_put(in4_dev);
+ return 0;
+}
+/**
+ * function called by net device to
+ * handle multicast address relevant things
+ */
+static void
+lcs_set_multicast_list(struct net_device *dev)
+{
+ struct lcs_card *card;
+
+ LCS_DBF_TEXT(4, trace, "setmulti");
+ card = (struct lcs_card *) dev->priv;
+ set_bit(3, &card->thread_mask);
+ schedule_work(&card->kernel_thread_starter);
}
#endif /* CONFIG_IP_MULTICAST */
+static long
+lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb)
+{
+ if (!IS_ERR(irb))
+ return 0;
+
+ switch (PTR_ERR(irb)) {
+ case -EIO:
+ PRINT_WARN("i/o-error on device %s\n", cdev->dev.bus_id);
+ LCS_DBF_TEXT(2, trace, "ckirberr");
+ LCS_DBF_TEXT_(2, trace, " rc%d", -EIO);
+ break;
+ case -ETIMEDOUT:
+ PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
+ LCS_DBF_TEXT(2, trace, "ckirberr");
+ LCS_DBF_TEXT_(2, trace, " rc%d", -ETIMEDOUT);
+ break;
+ default:
+ PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
+ cdev->dev.bus_id);
+ LCS_DBF_TEXT(2, trace, "ckirberr");
+ LCS_DBF_TEXT(2, trace, " rc???");
+ }
+ return PTR_ERR(irb);
+}
+
+
/**
* IRQ Handler for LCS channels
*/
struct lcs_channel *channel;
int index;
+ if (lcs_check_irb_error(cdev, irb))
+ return;
+
card = CARD_FROM_DEV(cdev);
if (card->read.ccwdev == cdev)
channel = &card->read;
kernel_thread(lcs_lgw_stoplan_thread, (void *) card, SIGCHLD);
#ifdef CONFIG_IP_MULTICAST
if (test_and_clear_bit(3, &card->thread_mask))
- kernel_thread(lcs_fix_multicast_list, (void *) card, SIGCHLD);
+ kernel_thread(lcs_register_mc_addresses, (void *) card, SIGCHLD);
#endif
}
lcs_setup_card(card);
rc = lcs_detect(card);
if (rc) {
+ LCS_DBF_TEXT(2, setup, "dtctfail");
+ PRINT_WARN("Detection of LCS card failed with return code "
+ "%d (0x%x)\n", rc, rc);
lcs_stopcard(card);
- lcs_cleanup_card(card);
goto out;
}
if (card->dev) {
goto out;
memcpy(card->dev->dev_addr, card->mac, LCS_MAC_LENGTH);
#ifdef CONFIG_IP_MULTICAST
- if (lcs_check_multicast_support(card))
+ if (!lcs_check_multicast_support(card))
card->dev->set_multicast_list = lcs_set_multicast_list;
#endif
netif_stop_queue(card->dev);
ccw_device_set_offline(card->read.ccwdev);
ccw_device_set_offline(card->write.ccwdev);
- lcs_cleanup_card(card);
return -ENODEV;
}