ctcmain.c
来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 2,422 行 · 第 1/5 页
C
2,422 行
if (sense & SNS0_INTERVENTION_REQ) { if (sense & 0x01) { if (ch->protocol != CTC_PROTO_LINUX_TTY) if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG "ch-%04x: Interface disc. or Sel. reset " "(remote)\n", ch->devno); fsm_event(ch->fsm, CH_EVENT_UC_RCRESET, ch); } else { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG "ch-%04x: System reset (remote)\n", ch->devno); fsm_event(ch->fsm, CH_EVENT_UC_RSRESET, ch); } } else if (sense & SNS0_EQUIPMENT_CHECK) { if (sense & SNS0_BUS_OUT_CHECK) { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING "ch-%04x: Hardware malfunction (remote)\n", ch->devno); fsm_event(ch->fsm, CH_EVENT_UC_HWFAIL, ch); } else { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING "ch-%04x: Read-data parity error (remote)\n", ch->devno); fsm_event(ch->fsm, CH_EVENT_UC_RXPARITY, ch); } } else if (sense & SNS0_BUS_OUT_CHECK) { if (sense & 0x04) { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING "ch-%04x: Data-streaming timeout)\n", ch->devno); fsm_event(ch->fsm, CH_EVENT_UC_TXTIMEOUT, ch); } else { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING "ch-%04x: Data-transfer parity error\n", ch->devno); fsm_event(ch->fsm, CH_EVENT_UC_TXPARITY, ch); } } else if (sense & SNS0_CMD_REJECT) { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING "ch-%04x: Command reject\n", ch->devno); } else if (sense == 0) { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG "ch-%04x: Unit check ZERO\n", ch->devno); fsm_event(ch->fsm, CH_EVENT_UC_ZERO, ch); } else { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING "ch-%04x: Unit Check with sense code: %02x\n", ch->devno, sense); fsm_event(ch->fsm, CH_EVENT_UC_UNKNOWN, ch); }}static void ctc_purge_skb_queue(struct sk_buff_head *q){ struct sk_buff *skb; while ((skb = skb_dequeue(q))) { atomic_dec(&skb->users); dev_kfree_skb_irq(skb); }}static __inline__ int ctc_checkalloc_buffer(channel *ch, int warn) { if ((ch->trans_skb == NULL) || (ch->flags & CHANNEL_FLAGS_BUFSIZE_CHANGED)) { if (ch->trans_skb != NULL) dev_kfree_skb(ch->trans_skb); clear_normalized_cda(&ch->ccw[1]); ch->trans_skb = __dev_alloc_skb(ch->max_bufsize, GFP_ATOMIC|GFP_DMA); if (ch->trans_skb == NULL) { if (warn && (loglevel & CTC_LOGLEVEL_WARN)) printk(KERN_WARNING "ch-%04x: Couldn't alloc %s trans_skb\n", ch->devno, (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX"); return -ENOMEM; } ch->ccw[1].count = ch->max_bufsize; if (set_normalized_cda(&ch->ccw[1], virt_to_phys(ch->trans_skb->data))) { dev_kfree_skb(ch->trans_skb); ch->trans_skb = NULL; if (warn && (loglevel & CTC_LOGLEVEL_WARN)) printk(KERN_WARNING "ch-%04x: set_normalized_cda for %s " "trans_skb failed, dropping packets\n", ch->devno, (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX"); return -ENOMEM; } 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) && (loglevel & CTC_LOGLEVEL_DEBUG)) 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) { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG "%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) { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG "%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)) { if (loglevel & CTC_LOGLEVEL_DEBUG) printk(KERN_DEBUG "%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) { if (loglevel & CTC_LOGLEVEL_DEBUG) 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 if (loglevel & CTC_LOGLEVEL_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 { if (loglevel & CTC_LOGLEVEL_DEBUG) 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) { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING "ch_action_start ch=NULL\n"); return; } if (ch->netdev == NULL) { if (loglevel & CTC_LOGLEVEL_WARN) printk(KERN_WARNING "ch_action_start dev=NULL, irq=%d\n", ch->irq); return; } dev = ch->netdev;#ifdef DEBUG if (loglevel & CTC_LOGLEVEL_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;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?