📄 ctcmain.c
字号:
if ((CHANNEL_DIRECTION(ch->flags) == WRITE) || (ch->protocol != CTC_PROTO_S390)) fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch); *((__u16 *) ch->trans_skb->data) = CTC_INITIAL_BLOCKLEN; ch->ccw[1].count = 2; /* Transfer only length */ fsm_newstate(fi, (CHANNEL_DIRECTION(ch->flags) == READ) ? CH_STATE_RXINIT : CH_STATE_TXINIT); rc = ccw_device_start(ch->cdev, &ch->ccw[0], (unsigned long) ch, 0xff, 0); if (rc != 0) { fsm_deltimer(&ch->timer); fsm_newstate(fi, CH_STATE_SETUPWAIT); ccw_check_return_code(ch, rc, "init IO"); } /** * If in compatibility mode since we don磘 setup a timer, we * also signal RX channel up immediately. This enables us * to send packets early which in turn usually triggers some * reply from VM TCP which brings up the RX channel to it磗 * final state. */ if ((CHANNEL_DIRECTION(ch->flags) == READ) && (ch->protocol == CTC_PROTO_S390)) { struct net_device *dev = ch->netdev; fsm_event(((struct ctc_priv *) dev->priv)->fsm, DEV_EVENT_RXUP, dev); }}/** * Got initial data, check it. If OK, * notify device statemachine that we are up and * running. * * @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_rxidle(fsm_instance * fi, int event, void *arg){ struct channel *ch = (struct channel *) arg; struct net_device *dev = ch->netdev; __u16 buflen; int rc; DBF_TEXT(trace, 4, __FUNCTION__); fsm_deltimer(&ch->timer); buflen = *((__u16 *) ch->trans_skb->data);#ifdef DEBUG ctc_pr_debug("%s: Initial RX count %d\n", dev->name, buflen);#endif if (buflen >= CTC_INITIAL_BLOCKLEN) { if (ctc_checkalloc_buffer(ch, 1)) return; ch->ccw[1].count = ch->max_bufsize; fsm_newstate(fi, CH_STATE_RXIDLE); rc = ccw_device_start(ch->cdev, &ch->ccw[0], (unsigned long) ch, 0xff, 0); if (rc != 0) { fsm_newstate(fi, CH_STATE_RXINIT); ccw_check_return_code(ch, rc, "initial RX"); } else fsm_event(((struct ctc_priv *) dev->priv)->fsm, DEV_EVENT_RXUP, dev); } else { ctc_pr_debug("%s: Initial RX count %d not %d\n", dev->name, buflen, CTC_INITIAL_BLOCKLEN); ch_action_firstio(fi, event, arg); }}/** * Set channel into extended mode. * * @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_setmode(fsm_instance * fi, int event, void *arg){ struct channel *ch = (struct channel *) arg; int rc; unsigned long saveflags; DBF_TEXT(trace, 4, __FUNCTION__); fsm_deltimer(&ch->timer); fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch); fsm_newstate(fi, CH_STATE_SETUPWAIT); 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[6], (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); fsm_newstate(fi, CH_STATE_STARTWAIT); ccw_check_return_code(ch, rc, "set Mode"); } else ch->retry = 0;}/** * Setup 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 voidch_action_start(fsm_instance * fi, int event, void *arg){ struct channel *ch = (struct channel *) arg; unsigned long saveflags; int rc; struct net_device *dev; DBF_TEXT(trace, 4, __FUNCTION__); if (ch == NULL) { ctc_pr_warn("ch_action_start ch=NULL\n"); return; } if (ch->netdev == NULL) { ctc_pr_warn("ch_action_start dev=NULL, id=%s\n", ch->id); return; } dev = ch->netdev;#ifdef DEBUG ctc_pr_debug("%s: %s channel start\n", dev->name, (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");#endif 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) { ch->ccw[1].cmd_code = CCW_CMD_READ; ch->ccw[1].flags = CCW_FLAG_SLI; 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)) { ctc_pr_notice( "%s: Could not allocate %s trans_skb, delaying " "allocation until first transfer\n", dev->name, (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX"); } 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 (struct ccw1) * 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); spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags); rc = ccw_device_halt(ch->cdev, (unsigned long) ch); spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags); if (rc != 0) { if (rc != -EBUSY) fsm_deltimer(&ch->timer); ccw_check_return_code(ch, rc, "initial HaltIO"); }#ifdef DEBUG ctc_pr_debug("ctc: %s(): leaving\n", __func__);#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 voidch_action_haltio(fsm_instance * fi, int event, void *arg){ struct channel *ch = (struct channel *) arg; unsigned long saveflags; int rc; int oldstate; DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&ch->timer); fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch); saveflags = 0; /* avoids comp warning with spin_unlock_irqrestore */ if (event == CH_EVENT_STOP) // only for STOP not yet locked spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags); oldstate = fsm_getstate(fi); fsm_newstate(fi, CH_STATE_TERM); rc = ccw_device_halt(ch->cdev, (unsigned long) ch); if (event == CH_EVENT_STOP) spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags); if (rc != 0) { if (rc != -EBUSY) { fsm_deltimer(&ch->timer); fsm_newstate(fi, oldstate); } ccw_check_return_code(ch, rc, "HaltIO in ch_action_haltio"); }}/** * 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 voidch_action_stopped(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); 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(((struct 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(((struct 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 voidch_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 voidch_action_fail(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); fsm_newstate(fi, CH_STATE_NOTOP); if (CHANNEL_DIRECTION(ch->flags) == READ) { skb_queue_purge(&ch->io_queue); fsm_event(((struct 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(((struct 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 voidch_action_setuperr(fsm_instance * fi, int event, void *arg){ struct channel *ch = (struct channel *) arg; struct net_device *dev = ch->netdev; DBF_TEXT(setup, 3, __FUNCTION__); /** * 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 = ccw_device_halt(ch->cdev, (unsigned long) ch); if (rc != 0) ccw_check_return_code( ch, rc, "HaltIO in ch_action_setuperr"); } return; } ctc_pr_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(((struct ctc_priv *) dev->priv)->fsm, DEV_EVENT_RXDOWN, dev); } else { fsm_newstate(fi, CH_STATE_TXERR); fsm_event(((struct 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 voidch_action_restart(fsm_instance * fi, int event, void *arg){ unsigned long saveflags; int oldstate; int rc; struct channel *ch = (struct channel *) arg; struct net_device *dev = ch->netdev; DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&ch->timer); ctc_pr_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); 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_halt(ch->cdev, (unsigned long) ch); if (event == CH_EVENT_TIMER) spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags); if (rc != 0) { if (rc != -EBUSY) { fsm_deltimer(&ch->timer); fsm_newstate(fi, oldstate); } ccw_check_return_code(ch, rc, "HaltIO in ch_action_restart"); }}/** * 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 voidch_action_rxiniterr(fsm_instance * fi, int event, void *arg){ struct channel *ch = (struct channel *) arg; struct net_device *dev = ch->netdev; DBF_TEXT(setup, 3, __FUNCTION__); if (event == CH_EVENT_TIMER) { fsm_deltimer(&ch->timer); ctc_pr_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(((struct ctc_priv *) dev->priv)->fsm, DEV_EVENT_RXDOWN, dev); } } else ctc_pr_warn("%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 voidch_action_rxinitfail(fsm_instance * fi, int event, void *arg){ struct channel *ch = (struct channel *) arg; struct net_device *dev = ch->netdev; DBF_TEXT(setup, 3, __FUNCTION__); fsm_newstate(fi, CH_STATE_RXERR); ctc_pr_warn("%s: RX initialization failed\n", dev->name); ctc_pr_warn("%s: RX <-> RX connection detected\n", dev->name); fsm_event(((struct 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 voidch_action_rxdisc(fsm_instance * fi, int event, void *arg)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -