⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lcs.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	char buf[MAX_ADDR_LEN];	LCS_DBF_TEXT(4, trace, "remmclst");	spin_lock_irqsave(&card->ipm_lock, flags);	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, card->dev);			if ( (ipm->ipm.ip_addr == im4->multiaddr) &&			     (memcmp(buf, &ipm->ipm.mac_addr,				     LCS_MAC_LENGTH) == 0) )				break;		}		if (im4 == NULL)			ipm->ipm_state = LCS_IPM_STATE_DEL_REQUIRED;	}	spin_unlock_irqrestore(&card->ipm_lock, flags);}static inline struct lcs_ipm_list *lcs_check_addr_entry(struct lcs_card *card, struct ip_mc_list *im4, char *buf){	struct lcs_ipm_list *tmp, *ipm = NULL;	struct list_head *l;	unsigned long flags;	LCS_DBF_TEXT(4, trace, "chkmcent");	spin_lock_irqsave(&card->ipm_lock, flags);	list_for_each(l, &card->ipm_list) {		tmp = list_entry(l, struct lcs_ipm_list, list);		if ( (tmp->ipm.ip_addr == im4->multiaddr) &&		     (memcmp(buf, &tmp->ipm.mac_addr,			     LCS_MAC_LENGTH) == 0) ) {			ipm = tmp;			break;		}	}	spin_unlock_irqrestore(&card->ipm_lock, flags);	return ipm;}static inline voidlcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev){	struct ip_mc_list *im4;	struct lcs_ipm_list *ipm;	char buf[MAX_ADDR_LEN];	unsigned long flags;	LCS_DBF_TEXT(4, trace, "setmclst");	for (im4 = in4_dev->mc_list; im4; im4 = im4->next) {		lcs_get_mac_for_ipm(im4->multiaddr, buf, card->dev);		ipm = lcs_check_addr_entry(card, im4, buf);		if (ipm != NULL)			continue;	/* Address already in list. */		ipm = (struct lcs_ipm_list *)			kzalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC);		if (ipm == NULL) {			PRINT_INFO("Not enough memory to add "				   "new multicast entry!\n");			break;		}		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);	}}static intlcs_register_mc_addresses(void *data){	struct lcs_card *card;	struct in_device *in4_dev;	card = (struct lcs_card *) data;	daemonize("regipm");	if (!lcs_do_run_thread(card, LCS_SET_MC_THREAD))		return 0;	LCS_DBF_TEXT(4, trace, "regmulti");	in4_dev = in_dev_get(card->dev);	if (in4_dev == NULL)		goto out;	read_lock(&in4_dev->mc_list_lock);	lcs_remove_mc_addresses(card,in4_dev);	lcs_set_mc_addresses(card, in4_dev);	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;}/** * function called by net device to * handle multicast address relevant things */static voidlcs_set_multicast_list(struct net_device *dev){        struct lcs_card *card;        LCS_DBF_TEXT(4, trace, "setmulti");        card = (struct lcs_card *) dev->priv;        if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD))		schedule_work(&card->kernel_thread_starter);}#endif /* CONFIG_IP_MULTICAST */static longlcs_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);}static intlcs_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;}voidlcs_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 */static voidlcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb){	struct lcs_card *card;	struct lcs_channel *channel;	int rc, index;	int cstat, dstat;	if (lcs_check_irb_error(cdev, irb))		return;	card = CARD_FROM_DEV(cdev);	if (card->read.ccwdev == cdev)		channel = &card->read;	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)) {		index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa)			- channel->ccws;		if ((irb->scsw.actl & SCSW_ACTL_SUSPENDED) ||		    (irb->scsw.cstat & SCHN_STAT_PCI))			/* Bloody io subsystem tells us lies about cpa... */			index = (index - 1) & (LCS_NUM_BUFFS - 1);		while (channel->io_idx != index) {			__lcs_processed_buffer(channel,					       channel->iob + channel->io_idx);			channel->io_idx =				(channel->io_idx + 1) & (LCS_NUM_BUFFS - 1);		}	}	if ((irb->scsw.dstat & DEV_STAT_DEV_END) ||	    (irb->scsw.dstat & DEV_STAT_CHN_END) ||	    (irb->scsw.dstat & DEV_STAT_UNIT_CHECK))		/* Mark channel as stopped. */		channel->state = CH_STATE_STOPPED;	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);			return;		}		/* 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;	}	/* Do the rest in the tasklet. */	tasklet_schedule(&channel->irq_tasklet);}/** * Tasklet for IRQ handler */static voidlcs_tasklet(unsigned long data){	unsigned long flags;	struct lcs_channel *channel;	struct lcs_buffer *iob;	int buf_idx;	int rc;	channel = (struct lcs_channel *) data;	LCS_DBF_TEXT_(5, trace, "tlet%s",channel->ccwdev->dev.bus_id);	/* Check for processed buffers. */	iob = channel->iob;	buf_idx = channel->buf_idx;	while (iob[buf_idx].state == BUF_STATE_PROCESSED) {		/* Do the callback thing. */		if (iob[buf_idx].callback != NULL)			iob[buf_idx].callback(channel, iob + buf_idx);		buf_idx = (buf_idx + 1) & (LCS_NUM_BUFFS - 1);	}	channel->buf_idx = buf_idx;	if (channel->state == CH_STATE_STOPPED)		// FIXME: what if rc != 0 ??		rc = lcs_start_channel(channel);	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);	if (channel->state == CH_STATE_SUSPENDED &&	    channel->iob[channel->io_idx].state == BUF_STATE_READY) {		// FIXME: what if rc != 0 ??		rc = __lcs_resume_channel(channel);	}	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);	/* Something happened on the channel. Wake up waiters. */	wake_up(&channel->wait_q);}/** * Finish current tx buffer and make it ready for transmit. */static void__lcs_emit_txbuffer(struct lcs_card *card){	LCS_DBF_TEXT(5, trace, "emittx");	*(__u16 *)(card->tx_buffer->data + card->tx_buffer->count) = 0;	card->tx_buffer->count += 2;	lcs_ready_buffer(&card->write, card->tx_buffer);	card->tx_buffer = NULL;	card->tx_emitted++;}/** * Callback for finished tx buffers. */static voidlcs_txbuffer_cb(struct lcs_channel *channel, struct lcs_buffer *buffer){	struct lcs_card *card;	LCS_DBF_TEXT(5, trace, "txbuffcb");	/* Put buffer back to pool. */	lcs_release_buffer(channel, buffer);	card = (struct lcs_card *)		((char *) channel - offsetof(struct lcs_card, write));	if (netif_queue_stopped(card->dev) && netif_carrier_ok(card->dev))		netif_wake_queue(card->dev);	spin_lock(&card->lock);	card->tx_emitted--;	if (card->tx_emitted <= 0 && card->tx_buffer != NULL)		/*		 * Last running tx buffer has finished. Submit partially		 * filled current buffer.		 */		__lcs_emit_txbuffer(card);	spin_unlock(&card->lock);}/** * Packet transmit function called by network stack */static int__lcs_start_xmit(struct lcs_card *card, struct sk_buff *skb,		 struct net_device *dev){	struct lcs_header *header;	int rc = 0;	LCS_DBF_TEXT(5, trace, "hardxmit");	if (skb == NULL) {		card->stats.tx_dropped++;		card->stats.tx_errors++;		return -EIO;	}	if (card->state != DEV_STATE_UP) {		dev_kfree_skb(skb);		card->stats.tx_dropped++;		card->stats.tx_errors++;		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 &&	    card->tx_buffer->count + sizeof(struct lcs_header) +	    skb->len + sizeof(u16) > LCS_IOBUFFERSIZE)		/* skb too big for current tx buffer. */		__lcs_emit_txbuffer(card);	if (card->tx_buffer == NULL) {		/* Get new tx buffer */		card->tx_buffer = lcs_get_buffer(&card->write);		if (card->tx_buffer == NULL) {			card->stats.tx_dropped++;			rc = -EBUSY;			goto out;		}		card->tx_buffer->callback = lcs_txbuffer_cb;		card->tx_buffer->count = 0;	}	header = (struct lcs_header *)		(card->tx_buffer->data + card->tx_buffer->count);	card->tx_buffer->count += skb->len + sizeof(struct lcs_header);	header->offset = card->tx_buffer->count;	header->type = card->lan_type;	header->slot = card->portno;	memcpy(header + 1, skb->data, skb->len);	spin_unlock(&card->lock);	card->stats.tx_bytes += skb->len;	card->stats.tx_packets++;	dev_kfree_skb(skb);	netif_wake_queue(card->dev);	spin_lock(&card->lock);	if (card->tx_emitted <= 0 && card->tx_buffer != NULL)		/* If this is the first tx buffer emit it immediately. */		__lcs_emit_txbuffer(card);out:	spin_unlock(&card->lock);	return rc;}static intlcs_start_xmit(struct sk_buff *skb, struct net_device *dev){	struct lcs_card *card;	int rc;	LCS_DBF_TEXT(5, trace, "pktxmit");	card = (struct lcs_card *) dev->priv;	rc = __lcs_start_xmit(card, skb, dev);	return rc;}/** * send startlan and lanstat command to make LCS device ready */static intlcs_startlan_auto(struct lcs_card *card){	int rc;	LCS_DBF_TEXT(2, trace, "strtauto");#ifdef CONFIG_NET_ETHERNET	card->lan_type = LCS_FRAME_TYPE_ENET;	rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP);	if (rc == 0)		return 0;#endif#ifdef CONFIG_TR	card->lan_type = LCS_FRAME_TYPE_TR;	rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP);	if (rc == 0)		return 0;#endif#ifdef CONFIG_FDDI	card->lan_type = LCS_FRAME_TYPE_FDDI;	rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP);	if (rc == 0)		return 0;#endif	return -EIO;}static intlcs_startlan(struct lcs_card *card){	int rc, i;	LCS_DBF_TEXT(2, trace, "startlan");	rc = 0;	if (card->portno != LCS_INVALID_PORT_NO) {		if (card->lan_type == LCS_FRAME_TYPE_AUTO)			rc = lcs_startlan_auto(card);		else			rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP);	} else {                for (i = 0; i <= 16; i++) {                        card->portno = i;                        if (card->lan_type != LCS_FRAME_TYPE_AUTO)                                rc = lcs_send_startlan(card,                                                       LCS_INITIATOR_TCPIP);                        else                                /* autodetecting lan type */                                rc = lcs_startlan_auto(card);                        if (rc == 0)                                break;                }        }	if (rc == 0)		return lcs_send_lanstat(card);	return rc;}/** * LCS detect function * setup channels and make them I/O ready */static intlcs_detect(struct lcs_card *card){	int rc = 0;	LCS_DBF_TEXT(2, setup, "lcsdetct");	/* start/reset card */	if (card->dev)		netif_stop_queue(card->dev);	rc = lcs_stop_channels(card);	if (rc == 0) {		rc = lcs_start_channels(card);		if (rc == 0) {			rc = lcs_send_startup(card, LCS_INITIATOR_TCPIP);			if (rc == 0)				rc = lcs_startlan(card);		}	}	if (rc == 0) {		card->state = DEV_STATE_UP;	} else {		card->state = DEV_STATE_DOWN;		card->write.state = CH_STATE_INIT;		card->read.state =  CH_STATE_INIT;	}	return rc;}/** * LCS Stop card */static intlcs_stopcard(struct lcs_card *card){	int rc;	LCS_DBF_TEXT(3, setup, "stopcard");	if (card->read.state != CH_STATE_STOPPED &&	    card->write.state != CH_STATE_STOPPED &&	    card->state == DEV_STATE_UP) {		lcs_clear_multicast_list(card);		rc = lcs_send_stoplan(card,LCS_INITIATOR_TCPIP);		rc = lcs_send_shutdown(card);	}	rc = lcs_stop_channels(card);	card->state = DEV_STATE_DOWN;	return rc;}/** * Kernel Thread helper functions for LGW initiated commands */static voidlcs_start_kernel_thread(struct lcs_card *card){	LCS_DBF_TEXT(5, trace, "krnthrd");	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);#endif}/** * Process control frames. */static voidlcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd){	LCS_DBF_TEXT(5, trace, "getctrl");	if (cmd->initiator == LCS_INITIATOR_LGW) {		switch(cmd->cmd_code) {		case LCS_CMD_STARTUP:		case LCS_CMD_STARTLAN:			lcs_schedule_recovery(card);			break;		case LCS_CMD_STOPLAN:			PRINT_WARN("Stoplan for %s initiated by LGW.\n",					card->dev->name);			if (card->dev)				netif_carrier_off(card->dev);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -