📄 ctcmain.c
字号:
ch->ccw[1].count = 0; ch->trans_skb_data = ch->trans_skb->data; ch->flags &= ~CHANNEL_FLAGS_BUFSIZE_CHANGED; } return 0;}/** * Dummy NOP action for statemachines */static void fsm_action_nop(fsm_instance *fi, int event, void *arg){}/** * Actions for channel - statemachines. *****************************************************************************//** * Normal data has been send. Free the corresponding * skb (it's in io_queue), reset dev->tbusy and * revert to idle state. * * @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_txdone(fsm_instance *fi, int event, void *arg){ channel *ch = (channel *)arg; net_device *dev = ch->netdev; ctc_priv *privptr = dev->priv; struct sk_buff *skb; int first = 1; int i; struct timeval done_stamp = xtime; unsigned long duration = (done_stamp.tv_sec - ch->prof.send_stamp.tv_sec) * 1000000 + done_stamp.tv_usec - ch->prof.send_stamp.tv_usec; if (duration > ch->prof.tx_time) ch->prof.tx_time = duration; if (ch->devstat->rescnt != 0) printk(KERN_DEBUG "%s: TX not complete, remaining %d bytes\n", dev->name, ch->devstat->rescnt); fsm_deltimer(&ch->timer); while ((skb = skb_dequeue(&ch->io_queue))) { privptr->stats.tx_packets++; privptr->stats.tx_bytes += skb->len - LL_HEADER_LENGTH; if (first) { privptr->stats.tx_bytes += 2; first = 0; } atomic_dec(&skb->users); dev_kfree_skb_irq(skb); } spin_lock(&ch->collect_lock); clear_normalized_cda(&ch->ccw[4]); if (ch->collect_len > 0) { int rc; if (ctc_checkalloc_buffer(ch, 1)) { spin_unlock(&ch->collect_lock); return; } ch->trans_skb->tail = ch->trans_skb->data = ch->trans_skb_data; ch->trans_skb->len = 0; if (ch->prof.maxmulti < (ch->collect_len + 2)) ch->prof.maxmulti = ch->collect_len + 2; if (ch->prof.maxcqueue < skb_queue_len(&ch->collect_queue)) ch->prof.maxcqueue = skb_queue_len(&ch->collect_queue); *((__u16 *)skb_put(ch->trans_skb, 2)) = ch->collect_len + 2; i = 0; while ((skb = skb_dequeue(&ch->collect_queue))) { memcpy(skb_put(ch->trans_skb, skb->len), skb->data, skb->len); privptr->stats.tx_packets++; privptr->stats.tx_bytes += skb->len - LL_HEADER_LENGTH; atomic_dec(&skb->users); dev_kfree_skb_irq(skb); i++; } ch->collect_len = 0; spin_unlock(&ch->collect_lock); ch->ccw[1].count = ch->trans_skb->len; fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch); ch->prof.send_stamp = xtime; rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0); ch->prof.doios_multi++; if (rc != 0) { privptr->stats.tx_dropped += i; privptr->stats.tx_errors += i; fsm_deltimer(&ch->timer); ccw_check_return_code(ch, rc); } } else { spin_unlock(&ch->collect_lock); fsm_newstate(fi, CH_STATE_TXIDLE); } ctc_clear_busy(dev);}/** * Initial data is sent. * 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 void ch_action_txidle(fsm_instance *fi, int event, void *arg){ channel *ch = (channel *)arg; fsm_deltimer(&ch->timer); fsm_newstate(fi, CH_STATE_TXIDLE); fsm_event(((ctc_priv *)ch->netdev->priv)->fsm, DEV_EVENT_TXUP, ch->netdev);}/** * Got normal data, check for sanity, queue it up, allocate new buffer * trigger bottom half, and initiate next read. * * @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_rx(fsm_instance *fi, int event, void *arg){ channel *ch = (channel *)arg; net_device *dev = ch->netdev; ctc_priv *privptr = dev->priv; int len = ch->max_bufsize - ch->devstat->rescnt; struct sk_buff *skb = ch->trans_skb; __u16 block_len = *((__u16*)skb->data); int check_len; int rc; fsm_deltimer(&ch->timer); if (len < 8) { printk(KERN_WARNING "%s: got packet with length %d < 8\n", dev->name, len); privptr->stats.rx_dropped++; privptr->stats.rx_length_errors++; goto again; } if (len > ch->max_bufsize) { printk(KERN_WARNING "%s: got packet with length %d > %d\n", dev->name, len, ch->max_bufsize); privptr->stats.rx_dropped++; privptr->stats.rx_length_errors++; goto again; } /** * VM TCP seems to have a bug sending 2 trailing bytes of garbage. */ switch (ch->protocol) { case CTC_PROTO_S390: case CTC_PROTO_OS390: check_len = block_len + 2; break; default: check_len = block_len; break; } if ((len < block_len) || (len > check_len)) { printk(KERN_WARNING "%s: got block length %d != rx length %d\n", dev->name, block_len, len);#ifdef DEBUG ctc_dump_skb(skb, 0);#endif *((__u16*)skb->data) = len; privptr->stats.rx_dropped++; privptr->stats.rx_length_errors++; goto again; } block_len -= 2; if (block_len > 0) { *((__u16*)skb->data) = block_len; ctc_unpack_skb(ch, skb); } again: skb->data = skb->tail = ch->trans_skb_data; skb->len = 0; if (ctc_checkalloc_buffer(ch, 1)) return; ch->ccw[1].count = ch->max_bufsize; rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0); if (rc != 0) ccw_check_return_code(ch, rc);}static void ch_action_rxidle(fsm_instance *fi, int event, void *arg);/** * Initialize connection by sending a __u16 of value 0. * * @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_firstio(fsm_instance *fi, int event, void *arg){ channel *ch = (channel *)arg; int rc; if (fsm_getstate(fi) == CH_STATE_TXIDLE) printk(KERN_DEBUG "ch-%04x: remote side issued READ?, " "init ...\n", ch->devno); fsm_deltimer(&ch->timer); if (ctc_checkalloc_buffer(ch, 1)) return; if ((fsm_getstate(fi) == CH_STATE_SETUPWAIT) && (ch->protocol == CTC_PROTO_OS390)) { /* OS/390 resp. z/OS */ if (CHANNEL_DIRECTION(ch->flags) == READ) { *((__u16 *)ch->trans_skb->data) = CTC_INITIAL_BLOCKLEN; fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch); ch_action_rxidle(fi, event, arg); } else { net_device *dev = ch->netdev; fsm_newstate(fi, CH_STATE_TXIDLE); fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXUP, dev); } return; } /** * Don磘 setup a timer for receiving the initial RX frame * if in compatibility mode, since VM TCP delays the initial * frame until it has some data to send. */ 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 = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0); if (rc != 0) { fsm_deltimer(&ch->timer); fsm_newstate(fi, CH_STATE_SETUPWAIT); ccw_check_return_code(ch, rc); } /** * 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)) { net_device *dev = ch->netdev; fsm_event(((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 void ch_action_rxidle(fsm_instance *fi, int event, void *arg){ channel *ch = (channel *)arg; net_device *dev = ch->netdev; __u16 buflen; int rc; fsm_deltimer(&ch->timer); buflen = *((__u16 *)ch->trans_skb->data);#ifdef DEBUG printk(KERN_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 = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0); if (rc != 0) { fsm_newstate(fi, CH_STATE_RXINIT); ccw_check_return_code(ch, rc); } else fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXUP, dev); } else { printk(KERN_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 void ch_action_setmode(fsm_instance *fi, int event, void *arg){ channel *ch = (channel *)arg; int rc; unsigned long saveflags; fsm_deltimer(&ch->timer); fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch); fsm_newstate(fi, CH_STATE_SETUPWAIT); if (event == CH_EVENT_TIMER) s390irq_spin_lock_irqsave(ch->irq, saveflags); rc = do_IO(ch->irq, &ch->ccw[6], (intparm_t)ch, 0xff, 0); if (event == CH_EVENT_TIMER) s390irq_spin_unlock_irqrestore(ch->irq, saveflags); if (rc != 0) { fsm_deltimer(&ch->timer); fsm_newstate(fi, CH_STATE_STARTWAIT); ccw_check_return_code(ch, rc); } 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 void ch_action_start(fsm_instance *fi, int event, void *arg){ channel *ch = (channel *)arg; unsigned long saveflags; int rc; net_device *dev; if (ch == NULL) { printk(KERN_WARNING "ch_action_start ch=NULL\n"); return; } if (ch->netdev == NULL) { printk(KERN_WARNING "ch_action_start dev=NULL, irq=%d\n", ch->irq); return; } dev = ch->netdev;#ifdef DEBUG printk(KERN_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)) 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 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); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -