ctcmain.c

来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 2,422 行 · 第 1/5 页

C
2,422
字号
		ch->ccw[1].count    = 0;	} else {		ch->ccw[1].cmd_code = CCW_CMD_WRITE;		ch->ccw[1].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;		ch->ccw[1].count    = 0;	}	if (ctc_checkalloc_buffer(ch, 0)) {		if (loglevel & CTC_LOGLEVEL_NOTICE)			printk(KERN_NOTICE			       "%s: Could not allocate %s trans_skb, delaying "			       "allocation until first transfer\n",			       dev->name, 			       (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");	}#if LINUX_VERSION_CODE >= 0x020400	INIT_LIST_HEAD(&ch->tq.list);#else	ch->tq.next = NULL;#endif	ch->tq.sync    = 0;	ch->tq.routine = (void *)(void *)ctc_bh;	ch->tq.data    = ch;	ch->ccw[0].cmd_code = CCW_CMD_PREPARE;	ch->ccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;	ch->ccw[0].count    = 0;	ch->ccw[0].cda	    = 0;	ch->ccw[2].cmd_code = CCW_CMD_NOOP;	 /* jointed CE + DE */	ch->ccw[2].flags    = CCW_FLAG_SLI;	ch->ccw[2].count    = 0;	ch->ccw[2].cda	    = 0;	memcpy(&ch->ccw[3], &ch->ccw[0], sizeof(ccw1_t) * 3);	ch->ccw[4].cda	    = 0;	ch->ccw[4].flags    &= ~CCW_FLAG_IDA;	fsm_newstate(fi, CH_STATE_STARTWAIT);	fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch);	s390irq_spin_lock_irqsave(ch->irq, saveflags);	rc = halt_IO(ch->irq, (intparm_t)ch, 0);	s390irq_spin_unlock_irqrestore(ch->irq, saveflags);	if (rc != 0) {		fsm_deltimer(&ch->timer);		ccw_check_return_code(ch, rc);	}#ifdef DEBUG	if (loglevel & CTC_LOGLEVEL_DEBUG)		printk(KERN_DEBUG "ctc: %s(): leaving\n", __FUNCTION__);#endif}/** * Shutdown a channel. * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static void ch_action_haltio(fsm_instance *fi, int event, void *arg){	channel *ch = (channel *)arg;	unsigned long saveflags;	int     rc;	int     oldstate;	fsm_deltimer(&ch->timer);	fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);	if (event == CH_EVENT_STOP)		s390irq_spin_lock_irqsave(ch->irq, saveflags);	oldstate = fsm_getstate(fi);	fsm_newstate(fi, CH_STATE_TERM);	rc = halt_IO (ch->irq, (intparm_t)ch, 0);	if (event == CH_EVENT_STOP)		s390irq_spin_unlock_irqrestore(ch->irq, saveflags);	if (rc != 0) {		fsm_deltimer(&ch->timer);		fsm_newstate(fi, oldstate);		ccw_check_return_code(ch, rc);	}}/** * A channel has successfully been halted. * Cleanup it's queue and notify interface statemachine. * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static void ch_action_stopped(fsm_instance *fi, int event, void *arg){	channel *ch = (channel *)arg;	net_device *dev = ch->netdev;	fsm_deltimer(&ch->timer);	fsm_newstate(fi, CH_STATE_STOPPED);	if (ch->trans_skb != NULL) {		clear_normalized_cda(&ch->ccw[1]);		dev_kfree_skb(ch->trans_skb);		ch->trans_skb = NULL;	}	if (CHANNEL_DIRECTION(ch->flags) == READ) {		skb_queue_purge(&ch->io_queue);		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);	} else {		ctc_purge_skb_queue(&ch->io_queue);		spin_lock(&ch->collect_lock);		ctc_purge_skb_queue(&ch->collect_queue);		ch->collect_len = 0;		spin_unlock(&ch->collect_lock);		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);	}}/** * A stop command from device statemachine arrived and we are in * not operational mode. Set state to stopped. * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static void ch_action_stop(fsm_instance *fi, int event, void *arg){	fsm_newstate(fi, CH_STATE_STOPPED);}/** * A machine check for no path, not operational status or gone device has * happened. * Cleanup queue and notify interface statemachine. * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static void ch_action_fail(fsm_instance *fi, int event, void *arg){	channel *ch = (channel *)arg;	net_device *dev = ch->netdev;	fsm_deltimer(&ch->timer);	fsm_newstate(fi, CH_STATE_NOTOP);	if (CHANNEL_DIRECTION(ch->flags) == READ) {		skb_queue_purge(&ch->io_queue);		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);	} else {		ctc_purge_skb_queue(&ch->io_queue);		spin_lock(&ch->collect_lock);		ctc_purge_skb_queue(&ch->collect_queue);		ch->collect_len = 0;		spin_unlock(&ch->collect_lock);		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);	}}/** * Handle error during setup of channel. * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static void ch_action_setuperr(fsm_instance *fi, int event, void *arg){	channel *ch = (channel *)arg;	net_device *dev = ch->netdev;	/**	 * Special case: Got UC_RCRESET on setmode.	 * This means that remote side isn't setup. In this case	 * simply retry after some 10 secs...	 */	if ((fsm_getstate(fi) == CH_STATE_SETUPWAIT) &&	    ((event == CH_EVENT_UC_RCRESET) ||	     (event == CH_EVENT_UC_RSRESET)   )         ) {		fsm_newstate(fi, CH_STATE_STARTRETRY);		fsm_deltimer(&ch->timer);		fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);		if (CHANNEL_DIRECTION(ch->flags) == READ) {			int rc = halt_IO (ch->irq, (intparm_t)ch, 0);			if (rc != 0)				ccw_check_return_code(ch, rc);		}		return;	}	if (loglevel & CTC_LOGLEVEL_DEBUG)		printk(KERN_DEBUG "%s: Error %s during %s channel setup state=%s\n",		       dev->name, ch_event_names[event],		       (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX",		       fsm_getstate_str(fi));	if (CHANNEL_DIRECTION(ch->flags) == READ) {		fsm_newstate(fi, CH_STATE_RXERR);		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);	} else {		fsm_newstate(fi, CH_STATE_TXERR);		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);	}}/** * Restart a channel after an error. * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static void ch_action_restart(fsm_instance *fi, int event, void *arg){	unsigned long saveflags;	int   oldstate;	int   rc;	channel *ch = (channel *)arg;	net_device *dev = ch->netdev;	fsm_deltimer(&ch->timer);	if (loglevel & CTC_LOGLEVEL_DEBUG)		printk(KERN_DEBUG "%s: %s channel restart\n", dev->name,		       (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");	fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);	oldstate = fsm_getstate(fi);	fsm_newstate(fi, CH_STATE_STARTWAIT);	if (event == CH_EVENT_TIMER)		s390irq_spin_lock_irqsave(ch->irq, saveflags);	rc = halt_IO (ch->irq, (intparm_t)ch, 0);	if (event == CH_EVENT_TIMER)		s390irq_spin_unlock_irqrestore(ch->irq, saveflags);	if (rc != 0) {		fsm_deltimer(&ch->timer);		fsm_newstate(fi, oldstate);		ccw_check_return_code(ch, rc);	}}/** * Handle error during RX initial handshake (exchange of * 0-length block header) * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static void ch_action_rxiniterr(fsm_instance *fi, int event, void *arg){	channel *ch = (channel *)arg;	net_device *dev = ch->netdev;	if (event == CH_EVENT_TIMER) {		fsm_deltimer(&ch->timer);		if (loglevel & CTC_LOGLEVEL_DEBUG)			printk(KERN_DEBUG "%s: Timeout during RX init handshake\n",			       dev->name);		if (ch->retry++ < 3)			ch_action_restart(fi, event, arg);		else {			fsm_newstate(fi, CH_STATE_RXERR);			fsm_event(((ctc_priv *)dev->priv)->fsm,				  DEV_EVENT_RXDOWN, dev);		}	} else		if (loglevel & CTC_LOGLEVEL_WARN)			printk(KERN_WARNING "%s: Error during RX init handshake\n",			       dev->name);}/** * Notify device statemachine if we gave up initialization * of RX channel. * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static void ch_action_rxinitfail(fsm_instance *fi, int event, void *arg){	channel *ch = (channel *)arg;	net_device *dev = ch->netdev;	fsm_newstate(fi, CH_STATE_RXERR);	if (loglevel & CTC_LOGLEVEL_WARN) {		printk(KERN_WARNING "%s: RX initialization failed\n", dev->name);		printk(KERN_WARNING "%s: RX <-> RX connection detected\n", dev->name);	}	fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);}/** * Handle RX Unit check remote reset (remote disconnected) * * @param fi    An instance of a channel statemachine. * @param event The event, just happened. * @param arg   Generic pointer, casted from channel * upon call. */static void ch_action_rxdisc(fsm_instance *fi, int event, void *arg){	channel    *ch = (channel *)arg;	channel    *ch2;	net_device *dev = ch->netdev;	fsm_deltimer(&ch->timer);	if (loglevel & CTC_LOGLEVEL_DEBUG)		printk(KERN_DEBUG "%s: Got remote disconnect, re-initializing ...\n",		       dev->name);	/**	 * Notify device statemachine	 */	fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);	fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);	fsm_newstate(fi, CH_STATE_DTERM);	ch2 = ((ctc_priv *)dev->priv)->channel[WRITE];	fsm_newstate(ch2->fsm, CH_STATE_DTERM);	halt_IO(ch->irq, (intparm_t)ch, 0);	halt_IO(ch2->irq, (intparm_t)ch2, 0);}/** * 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 void ch_action_txiniterr(fsm_instance *fi, int event, void *arg){	channel *ch = (channel *)arg;	net_device *dev = ch->netdev;	if (event == CH_EVENT_TIMER) {		fsm_deltimer(&ch->timer);		if (loglevel & CTC_LOGLEVEL_DEBUG)			printk(KERN_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(((ctc_priv *)dev->priv)->fsm,				  DEV_EVENT_TXDOWN, dev);		}	} else		if (loglevel & CTC_LOGLEVEL_WARN)			printk(KERN_WARNING "%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 void ch_action_txretry(fsm_instance *fi, int event, void *arg){	channel    *ch = (channel *)arg;	net_device *dev = ch->netdev;	unsigned long saveflags;	fsm_deltimer(&ch->timer);	if (ch->retry++ > 3) {		if (loglevel & CTC_LOGLEVEL_DEBUG)			printk(KERN_DEBUG "%s: TX retry failed, restarting channel\n",			       dev->name);		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);		ch_action_restart(fi, event, arg);	} else {		struct sk_buff *skb;		if (loglevel & CTC_LOGLEVEL_DEBUG)			printk(KERN_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],					       virt_to_phys(skb->data))) {				if (loglevel & CTC_LOGLEVEL_DEBUG)					printk(KERN_DEBUG "%s: IDAL alloc failed, "					       "restarting channel\n", dev->name);				fsm_event(((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);			if (event == CH_EVENT_TIMER)				s390irq_spin_lock_irqsave(ch->irq, saveflags);			rc = do_IO(ch->irq, &ch->ccw[3], (intparm_t)ch, 0xff, 0);			if (event == CH_EVENT_TIMER)				s390irq_spin_unlock_irqrestore(ch->irq,							       saveflags);			if (rc != 0) {				fsm_deltimer(&ch->timer);				ccw_check_return_code(ch, rc);				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 void ch_action_iofatal(fsm_instance *fi, int event, void *arg){	channel *ch = (channel *)arg;	net_device *dev = ch->netdev;	fsm_deltimer(&ch->timer);	if (CHANNEL_DIRECTION(ch->flags) == READ) {		if (loglevel & CTC_LOGLEVEL_DEBUG)			printk(KERN_DEBUG "%s: RX I/O error\n", dev->name);		fsm_newstate(fi, CH_STATE_RXERR);		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);	} else {		if (loglevel & CTC_LOGLEVEL_DEBUG)			printk(KERN_DEBUG "%s: TX I/O error\n", dev->name);		fsm_newstate(fi, CH_STATE_TXERR);		fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);	}}static void ch_action_reinit(fsm_instance *fi, int event, void *arg){	channel *ch = (channel *)arg;	net_device *dev = ch->netdev;	ctc_priv   *privptr = dev->priv;	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  },

⌨️ 快捷键说明

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