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

📄 ctcmain.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		ch = ch->next;	}#ifdef DEBUG	ctc_pr_debug("ctc: %s(): ch=0x%pq (id=%s, type=%d\n",		     __func__, ch, ch->id, ch->type);#endif	if (!ch) {		ctc_pr_warn("ctc: %s(): channel with id %s "			    "and type %d not found in channel list\n",			    __func__, id, type);	} else {		if (ch->flags & CHANNEL_FLAGS_INUSE)			ch = NULL;		else {			ch->flags |= CHANNEL_FLAGS_INUSE;			ch->flags &= ~CHANNEL_FLAGS_RWMASK;			ch->flags |= (direction == WRITE)			    ? CHANNEL_FLAGS_WRITE : CHANNEL_FLAGS_READ;			fsm_newstate(ch->fsm, CH_STATE_STOPPED);		}	}	return ch;}/** * Return the channel type by name. * * @param name Name of network interface. * * @return Type class of channel to be used for that interface. */static enum channel_types inlineextract_channel_media(char *name){	enum channel_types ret = channel_type_unknown;	if (name != NULL) {		if (strncmp(name, "ctc", 3) == 0)			ret = channel_type_parallel;		if (strncmp(name, "escon", 5) == 0)			ret = channel_type_escon;	}	return ret;}static long__ctc_check_irb_error(struct ccw_device *cdev, struct irb *irb){	if (!IS_ERR(irb))		return 0;	switch (PTR_ERR(irb)) {	case -EIO:		ctc_pr_warn("i/o-error on device %s\n", cdev->dev.bus_id);//		CTC_DBF_TEXT(trace, 2, "ckirberr");//		CTC_DBF_TEXT_(trace, 2, "  rc%d", -EIO);		break;	case -ETIMEDOUT:		ctc_pr_warn("timeout on device %s\n", cdev->dev.bus_id);//		CTC_DBF_TEXT(trace, 2, "ckirberr");//		CTC_DBF_TEXT_(trace, 2, "  rc%d", -ETIMEDOUT);		break;	default:		ctc_pr_warn("unknown error %ld on device %s\n", PTR_ERR(irb),			   cdev->dev.bus_id);//		CTC_DBF_TEXT(trace, 2, "ckirberr");//		CTC_DBF_TEXT(trace, 2, "  rc???");	}	return PTR_ERR(irb);}/** * Main IRQ handler. * * @param cdev    The ccw_device the interrupt is for. * @param intparm interruption parameter. * @param irb     interruption response block. */static voidctc_irq_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb){	struct channel *ch;	struct net_device *dev;	struct ctc_priv *priv;	DBF_TEXT(trace, 5, __FUNCTION__);	if (__ctc_check_irb_error(cdev, irb))		return;	/* Check for unsolicited interrupts. */	if (!cdev->dev.driver_data) {		ctc_pr_warn("ctc: Got unsolicited irq: %s c-%02x d-%02x\n",			    cdev->dev.bus_id, irb->scsw.cstat,			    irb->scsw.dstat);		return;	}		priv = ((struct ccwgroup_device *)cdev->dev.driver_data)		->dev.driver_data;	/* Try to extract channel from driver data. */	if (priv->channel[READ]->cdev == cdev)		ch = priv->channel[READ];	else if (priv->channel[WRITE]->cdev == cdev)		ch = priv->channel[WRITE];	else {		ctc_pr_err("ctc: Can't determine channel for interrupt, "			   "device %s\n", cdev->dev.bus_id);		return;	}		dev = (struct net_device *) (ch->netdev);	if (dev == NULL) {		ctc_pr_crit("ctc: ctc_irq_handler dev=NULL bus_id=%s, ch=0x%p\n",			    cdev->dev.bus_id, ch);		return;	}#ifdef DEBUG	ctc_pr_debug("%s: interrupt for device: %s received c-%02x d-%02x\n",		     dev->name, ch->id, irb->scsw.cstat, irb->scsw.dstat);#endif	/* Copy interruption response block. */	memcpy(ch->irb, irb, sizeof(struct irb));	/* Check for good subchannel return code, otherwise error message */	if (ch->irb->scsw.cstat) {		fsm_event(ch->fsm, CH_EVENT_SC_UNKNOWN, ch);		ctc_pr_warn("%s: subchannel check for device: %s - %02x %02x\n",			    dev->name, ch->id, ch->irb->scsw.cstat,			    ch->irb->scsw.dstat);		return;	}	/* Check the reason-code of a unit check */	if (ch->irb->scsw.dstat & DEV_STAT_UNIT_CHECK) {		ccw_unit_check(ch, ch->irb->ecw[0]);		return;	}	if (ch->irb->scsw.dstat & DEV_STAT_BUSY) {		if (ch->irb->scsw.dstat & DEV_STAT_ATTENTION)			fsm_event(ch->fsm, CH_EVENT_ATTNBUSY, ch);		else			fsm_event(ch->fsm, CH_EVENT_BUSY, ch);		return;	}	if (ch->irb->scsw.dstat & DEV_STAT_ATTENTION) {		fsm_event(ch->fsm, CH_EVENT_ATTN, ch);		return;	}	if ((ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) ||	    (ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) ||	    (ch->irb->scsw.stctl ==	     (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))		fsm_event(ch->fsm, CH_EVENT_FINSTAT, ch);	else		fsm_event(ch->fsm, CH_EVENT_IRQ, ch);}/** * Actions for interface - statemachine. *****************************************************************************//** * Startup channels by sending CH_EVENT_START to each channel. * * @param fi    An instance of an interface statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from struct net_device * upon call. */static voiddev_action_start(fsm_instance * fi, int event, void *arg){	struct net_device *dev = (struct net_device *) arg;	struct ctc_priv *privptr = dev->priv;	int direction;	DBF_TEXT(setup, 3, __FUNCTION__);	fsm_deltimer(&privptr->restart_timer);	fsm_newstate(fi, DEV_STATE_STARTWAIT_RXTX);	for (direction = READ; direction <= WRITE; direction++) {		struct channel *ch = privptr->channel[direction];		fsm_event(ch->fsm, CH_EVENT_START, ch);	}}/** * Shutdown channels by sending CH_EVENT_STOP to each channel. * * @param fi    An instance of an interface statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from struct net_device * upon call. */static voiddev_action_stop(fsm_instance * fi, int event, void *arg){	struct net_device *dev = (struct net_device *) arg;	struct ctc_priv *privptr = dev->priv;	int direction;	DBF_TEXT(trace, 3, __FUNCTION__);	fsm_newstate(fi, DEV_STATE_STOPWAIT_RXTX);	for (direction = READ; direction <= WRITE; direction++) {		struct channel *ch = privptr->channel[direction];		fsm_event(ch->fsm, CH_EVENT_STOP, ch);	}}static void dev_action_restart(fsm_instance *fi, int event, void *arg){	struct net_device *dev = (struct net_device *)arg;	struct ctc_priv *privptr = dev->priv;		DBF_TEXT(trace, 3, __FUNCTION__);	ctc_pr_debug("%s: Restarting\n", dev->name);	dev_action_stop(fi, event, arg);	fsm_event(privptr->fsm, DEV_EVENT_STOP, dev);	fsm_addtimer(&privptr->restart_timer, CTC_TIMEOUT_5SEC,		     DEV_EVENT_START, dev);}/** * Called from channel statemachine * when a channel is up and running. * * @param fi    An instance of an interface statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from struct net_device * upon call. */static voiddev_action_chup(fsm_instance * fi, int event, void *arg){	struct net_device *dev = (struct net_device *) arg;	struct ctc_priv *privptr = dev->priv;	DBF_TEXT(trace, 3, __FUNCTION__);	switch (fsm_getstate(fi)) {		case DEV_STATE_STARTWAIT_RXTX:			if (event == DEV_EVENT_RXUP)				fsm_newstate(fi, DEV_STATE_STARTWAIT_TX);			else				fsm_newstate(fi, DEV_STATE_STARTWAIT_RX);			break;		case DEV_STATE_STARTWAIT_RX:			if (event == DEV_EVENT_RXUP) {				fsm_newstate(fi, DEV_STATE_RUNNING);				ctc_pr_info("%s: connected with remote side\n",					    dev->name);				if (privptr->protocol == CTC_PROTO_LINUX_TTY)					ctc_tty_setcarrier(dev, 1);				ctc_clear_busy(dev);			}			break;		case DEV_STATE_STARTWAIT_TX:			if (event == DEV_EVENT_TXUP) {				fsm_newstate(fi, DEV_STATE_RUNNING);				ctc_pr_info("%s: connected with remote side\n",					    dev->name);				if (privptr->protocol == CTC_PROTO_LINUX_TTY)					ctc_tty_setcarrier(dev, 1);				ctc_clear_busy(dev);			}			break;		case DEV_STATE_STOPWAIT_TX:			if (event == DEV_EVENT_RXUP)				fsm_newstate(fi, DEV_STATE_STOPWAIT_RXTX);			break;		case DEV_STATE_STOPWAIT_RX:			if (event == DEV_EVENT_TXUP)				fsm_newstate(fi, DEV_STATE_STOPWAIT_RXTX);			break;	}}/** * Called from channel statemachine * when a channel has been shutdown. * * @param fi    An instance of an interface statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from struct net_device * upon call. */static voiddev_action_chdown(fsm_instance * fi, int event, void *arg){	struct net_device *dev = (struct net_device *) arg;	struct ctc_priv *privptr = dev->priv;	DBF_TEXT(trace, 3, __FUNCTION__);	switch (fsm_getstate(fi)) {		case DEV_STATE_RUNNING:			if (privptr->protocol == CTC_PROTO_LINUX_TTY)				ctc_tty_setcarrier(dev, 0);			if (event == DEV_EVENT_TXDOWN)				fsm_newstate(fi, DEV_STATE_STARTWAIT_TX);			else				fsm_newstate(fi, DEV_STATE_STARTWAIT_RX);			break;		case DEV_STATE_STARTWAIT_RX:			if (event == DEV_EVENT_TXDOWN)				fsm_newstate(fi, DEV_STATE_STARTWAIT_RXTX);			break;		case DEV_STATE_STARTWAIT_TX:			if (event == DEV_EVENT_RXDOWN)				fsm_newstate(fi, DEV_STATE_STARTWAIT_RXTX);			break;		case DEV_STATE_STOPWAIT_RXTX:			if (event == DEV_EVENT_TXDOWN)				fsm_newstate(fi, DEV_STATE_STOPWAIT_RX);			else				fsm_newstate(fi, DEV_STATE_STOPWAIT_TX);			break;		case DEV_STATE_STOPWAIT_RX:			if (event == DEV_EVENT_RXDOWN)				fsm_newstate(fi, DEV_STATE_STOPPED);			break;		case DEV_STATE_STOPWAIT_TX:			if (event == DEV_EVENT_TXDOWN)				fsm_newstate(fi, DEV_STATE_STOPPED);			break;	}}static const fsm_node dev_fsm[] = {	{DEV_STATE_STOPPED, DEV_EVENT_START, dev_action_start},	{DEV_STATE_STOPWAIT_RXTX,  DEV_EVENT_START,   dev_action_start   },	{DEV_STATE_STOPWAIT_RXTX,  DEV_EVENT_RXDOWN,  dev_action_chdown  },	{DEV_STATE_STOPWAIT_RXTX,  DEV_EVENT_TXDOWN,  dev_action_chdown  }, 	{DEV_STATE_STOPWAIT_RXTX,  DEV_EVENT_RESTART, dev_action_restart },	{DEV_STATE_STOPWAIT_RX,    DEV_EVENT_START,   dev_action_start   },	{DEV_STATE_STOPWAIT_RX,    DEV_EVENT_RXUP,    dev_action_chup    },	{DEV_STATE_STOPWAIT_RX,    DEV_EVENT_TXUP,    dev_action_chup    },	{DEV_STATE_STOPWAIT_RX,    DEV_EVENT_RXDOWN,  dev_action_chdown  }, 	{DEV_STATE_STOPWAIT_RX,    DEV_EVENT_RESTART, dev_action_restart },	{DEV_STATE_STOPWAIT_TX,    DEV_EVENT_START,   dev_action_start   },	{DEV_STATE_STOPWAIT_TX,    DEV_EVENT_RXUP,    dev_action_chup    },	{DEV_STATE_STOPWAIT_TX,    DEV_EVENT_TXUP,    dev_action_chup    },	{DEV_STATE_STOPWAIT_TX,    DEV_EVENT_TXDOWN,  dev_action_chdown  }, 	{DEV_STATE_STOPWAIT_TX,    DEV_EVENT_RESTART, dev_action_restart },	{DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_STOP,    dev_action_stop    },	{DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_RXUP,    dev_action_chup    },	{DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_TXUP,    dev_action_chup    },	{DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_RXDOWN,  dev_action_chdown  },	{DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_TXDOWN,  dev_action_chdown  }, 	{DEV_STATE_STARTWAIT_RXTX, DEV_EVENT_RESTART, dev_action_restart },	{DEV_STATE_STARTWAIT_TX,   DEV_EVENT_STOP,    dev_action_stop    },	{DEV_STATE_STARTWAIT_TX,   DEV_EVENT_RXUP,    dev_action_chup    },	{DEV_STATE_STARTWAIT_TX,   DEV_EVENT_TXUP,    dev_action_chup    },	{DEV_STATE_STARTWAIT_TX,   DEV_EVENT_RXDOWN,  dev_action_chdown  }, 	{DEV_STATE_STARTWAIT_TX,   DEV_EVENT_RESTART, dev_action_restart },	{DEV_STATE_STARTWAIT_RX,   DEV_EVENT_STOP,    dev_action_stop    },	{DEV_STATE_STARTWAIT_RX,   DEV_EVENT_RXUP,    dev_action_chup    },	{DEV_STATE_STARTWAIT_RX,   DEV_EVENT_TXUP,    dev_action_chup    },	{DEV_STATE_STARTWAIT_RX,   DEV_EVENT_TXDOWN,  dev_action_chdown  }, 	{DEV_STATE_STARTWAIT_RX,   DEV_EVENT_RESTART, dev_action_restart },	{DEV_STATE_RUNNING,        DEV_EVENT_STOP,    dev_action_stop    },	{DEV_STATE_RUNNING,        DEV_EVENT_RXDOWN,  dev_action_chdown  },	{DEV_STATE_RUNNING,        DEV_EVENT_TXDOWN,  dev_action_chdown  },	{DEV_STATE_RUNNING,        DEV_EVENT_TXUP,    fsm_action_nop     },	{DEV_STATE_RUNNING,        DEV_EVENT_RXUP,    fsm_action_nop     }, 	{DEV_STATE_RUNNING,        DEV_EVENT_RESTART, dev_action_restart },};static const int DEV_FSM_LEN = sizeof (dev_fsm) / sizeof (fsm_node);/** * Transmit a packet. * This is a helper function for ctc_tx(). * * @param ch Channel to be used for sending. * @param skb Pointer to struct sk_buff of packet to send. *            The linklevel header has already been set up *            by ctc_tx(). * * @return 0 on success, -ERRNO on failure. (Never fails.) */static inttransmit_skb(struct channel *ch, struct sk_buff *skb){	unsigned long saveflags;	struct ll_header header;	int rc = 0;	DBF_TEXT(trace, 5, __FUNCTION__);	/* we need to acquire the lock for testing the state	 * otherwise we can have an IRQ changing the state to 	 * TXIDLE after the test but before acquiring the lock.	 */	spin_lock_irqsave(&ch->collect_lock, saveflags);	if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) {		int l = skb->len + LL_HEADER_LENGTH;		if (ch->collect_len + l > ch->max_bufsize - 2) {			spin_unlock_irqrestore(&ch->collect_lock, saveflags);			return -EBUSY;		} else {			atomic_inc(&skb->users);			header.length = l;			header.type = skb->protocol;			header.unused = 0;			memcpy(skb_push(skb, LL_HEADER_LENGTH), &header,			       LL_HEADER_LENGTH);			skb_queue_tail(&ch->collect_queue, skb);			ch->collect_len += l;		}		spin_unlock_irqrestore(&ch->collect_lock, saveflags);	} else {		__u16 block_len;		int ccw_idx;		struct sk_buff *nskb;		unsigned long hi;		spin_unlock_irqrestore(&ch->collect_lock, saveflags);		/**		 * Protect skb against beeing free'd by upper		 * layers.		 */		atomic_inc(&skb->users);		ch->prof.txlen += skb->len;		header.length = skb->len + LL_HEADER_LENGTH;		header.type = skb->protocol;		header.unused = 0;		memcpy(skb_push(skb, LL_HEADER_LENGTH), &header,		       LL_HEADER_LENGTH);		block_len = skb->len + 2;		*((__u16 *) skb_push(skb, 2)) = block_len;		/**		 * IDAL support in CTC is broken, so we have to		 * care about skb's above 2G ourselves.		 */		hi = ((unsigned long) skb->tail + LL_HEADER_LENGTH) >> 31;		if (hi) {			nskb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);			if (!nskb) {				atomic_dec(&skb->users);				skb_pull(skb, LL_HEADER_LENGTH + 2);				ctc_clear_busy(ch->netdev);				return -ENOMEM;			} else {				memcpy(skb_put(nskb, skb->len),				       skb->data, skb->len);				atomic_inc(&nskb->users);				atomic_dec(&skb->users);		

⌨️ 快捷键说明

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