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

📄 ctcmain.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
{	struct channel *ch = (struct channel *) arg;	struct channel *ch2;	struct net_device *dev = ch->netdev;	DBF_TEXT(trace, 3, __FUNCTION__);	fsm_deltimer(&ch->timer);	ctc_pr_debug("%s: Got remote disconnect, re-initializing ...\n",		     dev->name);	/**	 * Notify device statemachine	 */	fsm_event(((struct ctc_priv *) dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);	fsm_event(((struct ctc_priv *) dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);	fsm_newstate(fi, CH_STATE_DTERM);	ch2 = ((struct ctc_priv *) dev->priv)->channel[WRITE];	fsm_newstate(ch2->fsm, CH_STATE_DTERM);	ccw_device_halt(ch->cdev, (unsigned long) ch);	ccw_device_halt(ch2->cdev, (unsigned long) ch2);}/** * Handle error during TX channel initialization. * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static voidch_action_txiniterr(fsm_instance * fi, int event, void *arg){	struct channel *ch = (struct channel *) arg;	struct net_device *dev = ch->netdev;	DBF_TEXT(setup, 2, __FUNCTION__);	if (event == CH_EVENT_TIMER) {		fsm_deltimer(&ch->timer);		ctc_pr_debug("%s: Timeout during TX init handshake\n", dev->name);		if (ch->retry++ < 3)			ch_action_restart(fi, event, arg);		else {			fsm_newstate(fi, CH_STATE_TXERR);			fsm_event(((struct ctc_priv *) dev->priv)->fsm,				  DEV_EVENT_TXDOWN, dev);		}	} else		ctc_pr_warn("%s: Error during TX init handshake\n", dev->name);}/** * Handle TX timeout by retrying operation. * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static voidch_action_txretry(fsm_instance * fi, int event, void *arg){	struct channel *ch = (struct channel *) arg;	struct net_device *dev = ch->netdev;	unsigned long saveflags;	DBF_TEXT(trace, 4, __FUNCTION__);	fsm_deltimer(&ch->timer);	if (ch->retry++ > 3) {		ctc_pr_debug("%s: TX retry failed, restarting channel\n",			     dev->name);		fsm_event(((struct ctc_priv *) dev->priv)->fsm,			  DEV_EVENT_TXDOWN, dev);		ch_action_restart(fi, event, arg);	} else {		struct sk_buff *skb;		ctc_pr_debug("%s: TX retry %d\n", dev->name, ch->retry);		if ((skb = skb_peek(&ch->io_queue))) {			int rc = 0;			clear_normalized_cda(&ch->ccw[4]);			ch->ccw[4].count = skb->len;			if (set_normalized_cda(&ch->ccw[4], skb->data)) {				ctc_pr_debug(					"%s: IDAL alloc failed, chan restart\n",					dev->name);				fsm_event(((struct ctc_priv *) dev->priv)->fsm,					  DEV_EVENT_TXDOWN, dev);				ch_action_restart(fi, event, arg);				return;			}			fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch);			saveflags = 0;	/* avoids compiler warning with					   spin_unlock_irqrestore */			if (event == CH_EVENT_TIMER) // only for TIMER not yet locked				spin_lock_irqsave(get_ccwdev_lock(ch->cdev),						  saveflags);			rc = ccw_device_start(ch->cdev, &ch->ccw[3],					      (unsigned long) ch, 0xff, 0);			if (event == CH_EVENT_TIMER)				spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev),						       saveflags);			if (rc != 0) {				fsm_deltimer(&ch->timer);				ccw_check_return_code(ch, rc, "TX in ch_action_txretry");				ctc_purge_skb_queue(&ch->io_queue);			}		}	}}/** * Handle fatal errors during an I/O command. * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static voidch_action_iofatal(fsm_instance * fi, int event, void *arg){	struct channel *ch = (struct channel *) arg;	struct net_device *dev = ch->netdev;	DBF_TEXT(trace, 3, __FUNCTION__);	fsm_deltimer(&ch->timer);	if (CHANNEL_DIRECTION(ch->flags) == READ) {		ctc_pr_debug("%s: RX I/O error\n", dev->name);		fsm_newstate(fi, CH_STATE_RXERR);		fsm_event(((struct ctc_priv *) dev->priv)->fsm,			  DEV_EVENT_RXDOWN, dev);	} else {		ctc_pr_debug("%s: TX I/O error\n", dev->name);		fsm_newstate(fi, CH_STATE_TXERR);		fsm_event(((struct ctc_priv *) dev->priv)->fsm,			  DEV_EVENT_TXDOWN, dev);	}}static void ch_action_reinit(fsm_instance *fi, int event, void *arg){ 	struct channel *ch = (struct channel *)arg; 	struct net_device *dev = ch->netdev; 	struct ctc_priv *privptr = dev->priv; 	DBF_TEXT(trace, 4, __FUNCTION__); 	ch_action_iofatal(fi, event, arg); 	fsm_addtimer(&privptr->restart_timer, 1000, DEV_EVENT_RESTART, dev);}/** * The statemachine for a channel. */static const fsm_node ch_fsm[] = {	{CH_STATE_STOPPED,    CH_EVENT_STOP,       fsm_action_nop       },	{CH_STATE_STOPPED,    CH_EVENT_START,      ch_action_start      },	{CH_STATE_STOPPED,    CH_EVENT_FINSTAT,    fsm_action_nop       },	{CH_STATE_STOPPED,    CH_EVENT_MC_FAIL,    fsm_action_nop       },	{CH_STATE_NOTOP,      CH_EVENT_STOP,       ch_action_stop       },	{CH_STATE_NOTOP,      CH_EVENT_START,      fsm_action_nop       },	{CH_STATE_NOTOP,      CH_EVENT_FINSTAT,    fsm_action_nop       },	{CH_STATE_NOTOP,      CH_EVENT_MC_FAIL,    fsm_action_nop       },	{CH_STATE_NOTOP,      CH_EVENT_MC_GOOD,    ch_action_start      },	{CH_STATE_STARTWAIT,  CH_EVENT_STOP,       ch_action_haltio     },	{CH_STATE_STARTWAIT,  CH_EVENT_START,      fsm_action_nop       },	{CH_STATE_STARTWAIT,  CH_EVENT_FINSTAT,    ch_action_setmode    },	{CH_STATE_STARTWAIT,  CH_EVENT_TIMER,      ch_action_setuperr   },	{CH_STATE_STARTWAIT,  CH_EVENT_IO_ENODEV,  ch_action_iofatal    },	{CH_STATE_STARTWAIT,  CH_EVENT_IO_EIO,     ch_action_reinit     },	{CH_STATE_STARTWAIT,  CH_EVENT_MC_FAIL,    ch_action_fail       },	{CH_STATE_STARTRETRY, CH_EVENT_STOP,       ch_action_haltio     },	{CH_STATE_STARTRETRY, CH_EVENT_TIMER,      ch_action_setmode    },	{CH_STATE_STARTRETRY, CH_EVENT_FINSTAT,    fsm_action_nop       },	{CH_STATE_STARTRETRY, CH_EVENT_MC_FAIL,    ch_action_fail       },	{CH_STATE_SETUPWAIT,  CH_EVENT_STOP,       ch_action_haltio     },	{CH_STATE_SETUPWAIT,  CH_EVENT_START,      fsm_action_nop       },	{CH_STATE_SETUPWAIT,  CH_EVENT_FINSTAT,    ch_action_firstio    },	{CH_STATE_SETUPWAIT,  CH_EVENT_UC_RCRESET, ch_action_setuperr   },	{CH_STATE_SETUPWAIT,  CH_EVENT_UC_RSRESET, ch_action_setuperr   },	{CH_STATE_SETUPWAIT,  CH_EVENT_TIMER,      ch_action_setmode    },	{CH_STATE_SETUPWAIT,  CH_EVENT_IO_ENODEV,  ch_action_iofatal    },	{CH_STATE_SETUPWAIT,  CH_EVENT_IO_EIO,     ch_action_reinit     },	{CH_STATE_SETUPWAIT,  CH_EVENT_MC_FAIL,    ch_action_fail       },	{CH_STATE_RXINIT,     CH_EVENT_STOP,       ch_action_haltio     },	{CH_STATE_RXINIT,     CH_EVENT_START,      fsm_action_nop       },	{CH_STATE_RXINIT,     CH_EVENT_FINSTAT,    ch_action_rxidle     },	{CH_STATE_RXINIT,     CH_EVENT_UC_RCRESET, ch_action_rxiniterr  },	{CH_STATE_RXINIT,     CH_EVENT_UC_RSRESET, ch_action_rxiniterr  },	{CH_STATE_RXINIT,     CH_EVENT_TIMER,      ch_action_rxiniterr  },	{CH_STATE_RXINIT,     CH_EVENT_ATTNBUSY,   ch_action_rxinitfail },	{CH_STATE_RXINIT,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },	{CH_STATE_RXINIT,     CH_EVENT_IO_EIO,     ch_action_reinit     },	{CH_STATE_RXINIT,     CH_EVENT_UC_ZERO,    ch_action_firstio    },	{CH_STATE_RXINIT,     CH_EVENT_MC_FAIL,    ch_action_fail       },	{CH_STATE_RXIDLE,     CH_EVENT_STOP,       ch_action_haltio     },	{CH_STATE_RXIDLE,     CH_EVENT_START,      fsm_action_nop       },	{CH_STATE_RXIDLE,     CH_EVENT_FINSTAT,    ch_action_rx         },	{CH_STATE_RXIDLE,     CH_EVENT_UC_RCRESET, ch_action_rxdisc     },//      {CH_STATE_RXIDLE,     CH_EVENT_UC_RSRESET, ch_action_rxretry    },	{CH_STATE_RXIDLE,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },	{CH_STATE_RXIDLE,     CH_EVENT_IO_EIO,     ch_action_reinit     },	{CH_STATE_RXIDLE,     CH_EVENT_MC_FAIL,    ch_action_fail       },	{CH_STATE_RXIDLE,     CH_EVENT_UC_ZERO,    ch_action_rx         },	{CH_STATE_TXINIT,     CH_EVENT_STOP,       ch_action_haltio     },	{CH_STATE_TXINIT,     CH_EVENT_START,      fsm_action_nop       },	{CH_STATE_TXINIT,     CH_EVENT_FINSTAT,    ch_action_txidle     },	{CH_STATE_TXINIT,     CH_EVENT_UC_RCRESET, ch_action_txiniterr  },	{CH_STATE_TXINIT,     CH_EVENT_UC_RSRESET, ch_action_txiniterr  },	{CH_STATE_TXINIT,     CH_EVENT_TIMER,      ch_action_txiniterr  },	{CH_STATE_TXINIT,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },	{CH_STATE_TXINIT,     CH_EVENT_IO_EIO,     ch_action_reinit     },	{CH_STATE_TXINIT,     CH_EVENT_MC_FAIL,    ch_action_fail       },	{CH_STATE_TXIDLE,     CH_EVENT_STOP,       ch_action_haltio     },	{CH_STATE_TXIDLE,     CH_EVENT_START,      fsm_action_nop       },	{CH_STATE_TXIDLE,     CH_EVENT_FINSTAT,    ch_action_firstio    },	{CH_STATE_TXIDLE,     CH_EVENT_UC_RCRESET, fsm_action_nop       },	{CH_STATE_TXIDLE,     CH_EVENT_UC_RSRESET, fsm_action_nop       },	{CH_STATE_TXIDLE,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },	{CH_STATE_TXIDLE,     CH_EVENT_IO_EIO,     ch_action_reinit     },	{CH_STATE_TXIDLE,     CH_EVENT_MC_FAIL,    ch_action_fail       },	{CH_STATE_TERM,       CH_EVENT_STOP,       fsm_action_nop       },	{CH_STATE_TERM,       CH_EVENT_START,      ch_action_restart    },	{CH_STATE_TERM,       CH_EVENT_FINSTAT,    ch_action_stopped    },	{CH_STATE_TERM,       CH_EVENT_UC_RCRESET, fsm_action_nop       },	{CH_STATE_TERM,       CH_EVENT_UC_RSRESET, fsm_action_nop       },	{CH_STATE_TERM,       CH_EVENT_MC_FAIL,    ch_action_fail       },	{CH_STATE_DTERM,      CH_EVENT_STOP,       ch_action_haltio     },	{CH_STATE_DTERM,      CH_EVENT_START,      ch_action_restart    },	{CH_STATE_DTERM,      CH_EVENT_FINSTAT,    ch_action_setmode    },	{CH_STATE_DTERM,      CH_EVENT_UC_RCRESET, fsm_action_nop       },	{CH_STATE_DTERM,      CH_EVENT_UC_RSRESET, fsm_action_nop       },	{CH_STATE_DTERM,      CH_EVENT_MC_FAIL,    ch_action_fail       },	{CH_STATE_TX,         CH_EVENT_STOP,       ch_action_haltio     },	{CH_STATE_TX,         CH_EVENT_START,      fsm_action_nop       },	{CH_STATE_TX,         CH_EVENT_FINSTAT,    ch_action_txdone     },	{CH_STATE_TX,         CH_EVENT_UC_RCRESET, ch_action_txretry    },	{CH_STATE_TX,         CH_EVENT_UC_RSRESET, ch_action_txretry    },	{CH_STATE_TX,         CH_EVENT_TIMER,      ch_action_txretry    },	{CH_STATE_TX,         CH_EVENT_IO_ENODEV,  ch_action_iofatal    },	{CH_STATE_TX,         CH_EVENT_IO_EIO,     ch_action_reinit     },	{CH_STATE_TX,         CH_EVENT_MC_FAIL,    ch_action_fail       },	{CH_STATE_RXERR,      CH_EVENT_STOP,       ch_action_haltio     },	{CH_STATE_TXERR,      CH_EVENT_STOP,       ch_action_haltio     },	{CH_STATE_TXERR,      CH_EVENT_MC_FAIL,    ch_action_fail       },	{CH_STATE_RXERR,      CH_EVENT_MC_FAIL,    ch_action_fail       },};static const int CH_FSM_LEN = sizeof (ch_fsm) / sizeof (fsm_node);/** * Functions related to setup and device detection. *****************************************************************************/static inline intless_than(char *id1, char *id2){	int dev1, dev2, i;	for (i = 0; i < 5; i++) {		id1++;		id2++;	}	dev1 = simple_strtoul(id1, &id1, 16);	dev2 = simple_strtoul(id2, &id2, 16);		return (dev1 < dev2);}/** * Add a new channel to the list of channels. * Keeps the channel list sorted. * * @param cdev  The ccw_device to be added. * @param type  The type class of the new channel. * * @return 0 on success, !0 on error. */static intadd_channel(struct ccw_device *cdev, enum channel_types type){	struct channel **c = &channels;	struct channel *ch;	DBF_TEXT(trace, 2, __FUNCTION__);	if ((ch =	     (struct channel *) kmalloc(sizeof (struct channel),					GFP_KERNEL)) == NULL) {		ctc_pr_warn("ctc: Out of memory in add_channel\n");		return -1;	}	memset(ch, 0, sizeof (struct channel));	if ((ch->ccw = (struct ccw1 *) kmalloc(8*sizeof(struct ccw1),					       GFP_KERNEL | GFP_DMA)) == NULL) {		kfree(ch);		ctc_pr_warn("ctc: Out of memory in add_channel\n");		return -1;	}	memset(ch->ccw, 0, 8*sizeof(struct ccw1));	// assure all flags and counters are reset	/**	 * "static" ccws are used in the following way:	 *	 * ccw[0..2] (Channel program for generic I/O):	 *           0: prepare	 *           1: read or write (depending on direction) with fixed	 *              buffer (idal allocated once when buffer is allocated)	 *           2: nop	 * ccw[3..5] (Channel program for direct write of packets)	 *           3: prepare	 *           4: write (idal allocated on every write).	 *           5: nop	 * ccw[6..7] (Channel program for initial channel setup):	 *           6: set extended mode	 *           7: nop	 *	 * ch->ccw[0..5] are initialized in ch_action_start because	 * the channel's direction is yet unknown here.	 */	ch->ccw[6].cmd_code = CCW_CMD_SET_EXTENDED;	ch->ccw[6].flags = CCW_FLAG_SLI;	ch->ccw[7].cmd_code = CCW_CMD_NOOP;	ch->ccw[7].flags = CCW_FLAG_SLI;	ch->cdev = cdev;	snprintf(ch->id, CTC_ID_SIZE, "ch-%s", cdev->dev.bus_id);	ch->type = type;	ch->fsm = init_fsm(ch->id, ch_state_names,			   ch_event_names, NR_CH_STATES, NR_CH_EVENTS,			   ch_fsm, CH_FSM_LEN, GFP_KERNEL);	if (ch->fsm == NULL) {		ctc_pr_warn("ctc: Could not create FSM in add_channel\n");		kfree(ch->ccw);		kfree(ch);		return -1;	}	fsm_newstate(ch->fsm, CH_STATE_IDLE);	if ((ch->irb = (struct irb *) kmalloc(sizeof (struct irb),					      GFP_KERNEL)) == NULL) {		ctc_pr_warn("ctc: Out of memory in add_channel\n");		kfree_fsm(ch->fsm);		kfree(ch->ccw);		kfree(ch);		return -1;	}	memset(ch->irb, 0, sizeof (struct irb));	while (*c && less_than((*c)->id, ch->id))		c = &(*c)->next;	if (*c && (!strncmp((*c)->id, ch->id, CTC_ID_SIZE))) {		ctc_pr_debug(			"ctc: add_channel: device %s already in list, "			"using old entry\n", (*c)->id);		kfree(ch->irb);		kfree_fsm(ch->fsm);		kfree(ch->ccw);		kfree(ch);		return 0;	}	fsm_settimer(ch->fsm, &ch->timer);	skb_queue_head_init(&ch->io_queue);	skb_queue_head_init(&ch->collect_queue);	ch->next = *c;	*c = ch;	return 0;}/** * Release a specific channel in the channel list. * * @param ch Pointer to channel struct to be released. */static voidchannel_free(struct channel *ch){	ch->flags &= ~CHANNEL_FLAGS_INUSE;	fsm_newstate(ch->fsm, CH_STATE_IDLE);}/** * Remove a specific channel in the channel list. * * @param ch Pointer to channel struct to be released. */static voidchannel_remove(struct channel *ch){	struct channel **c = &channels;	DBF_TEXT(trace, 2, __FUNCTION__);	if (ch == NULL)		return;	channel_free(ch);	while (*c) {		if (*c == ch) {			*c = ch->next;			fsm_deltimer(&ch->timer);			kfree_fsm(ch->fsm);			clear_normalized_cda(&ch->ccw[4]);			if (ch->trans_skb != NULL) {				clear_normalized_cda(&ch->ccw[1]);				dev_kfree_skb(ch->trans_skb);			}			kfree(ch->ccw);			kfree(ch->irb);			kfree(ch);			return;		}		c = &((*c)->next);	}}/** * Get a specific channel from the channel list. * * @param type Type of channel we are interested in. * @param id Id of channel we are interested in. * @param direction Direction we want to use this channel for. * * @return Pointer to a channel or NULL if no matching channel available. */static struct channel*channel_get(enum channel_types type, char *id, int direction){	struct channel *ch = channels;	DBF_TEXT(trace, 3, __FUNCTION__);#ifdef DEBUG	ctc_pr_debug("ctc: %s(): searching for ch with id %s and type %d\n",		     __func__, id, type);#endif	while (ch && ((strncmp(ch->id, id, CTC_ID_SIZE)) || (ch->type != type))) {#ifdef DEBUG		ctc_pr_debug("ctc: %s(): ch=0x%p (id=%s, type=%d\n",			     __func__, ch, ch->id, ch->type);#endif

⌨️ 快捷键说明

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