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 + -
显示快捷键?