ctcmain.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,372 行 · 第 1/5 页
C
2,372 行
static const char *ch_event_names[] = { "ccw_device success", "ccw_device busy", "ccw_device enodev", "ccw_device ioerr", "ccw_device unknown", "Status ATTN & BUSY", "Status ATTN", "Status BUSY", "Unit check remote reset", "Unit check remote system reset", "Unit check TX timeout", "Unit check TX parity", "Unit check Hardware failure", "Unit check RX parity", "Unit check ZERO", "Unit check Unknown", "SubChannel check Unknown", "Machine check failure", "Machine check operational", "IRQ normal", "IRQ final", "Timer", "Start", "Stop",};/** * States of the channel statemachine. */enum ch_states { /** * Channel not assigned to any device, * initial state, direction invalid */ CH_STATE_IDLE, /** * Channel assigned but not operating */ CH_STATE_STOPPED, CH_STATE_STARTWAIT, CH_STATE_STARTRETRY, CH_STATE_SETUPWAIT, CH_STATE_RXINIT, CH_STATE_TXINIT, CH_STATE_RX, CH_STATE_TX, CH_STATE_RXIDLE, CH_STATE_TXIDLE, CH_STATE_RXERR, CH_STATE_TXERR, CH_STATE_TERM, CH_STATE_DTERM, CH_STATE_NOTOP, /** * MUST be always the last element!! */ NR_CH_STATES,};static const char *ch_state_names[] = { "Idle", "Stopped", "StartWait", "StartRetry", "SetupWait", "RX init", "TX init", "RX", "TX", "RX idle", "TX idle", "RX error", "TX error", "Terminating", "Restarting", "Not operational",};#ifdef DEBUG/** * Dump header and first 16 bytes of an sk_buff for debugging purposes. * * @param skb The sk_buff to dump. * @param offset Offset relative to skb-data, where to start the dump. */static voidctc_dump_skb(struct sk_buff *skb, int offset){ unsigned char *p = skb->data; __u16 bl; struct ll_header *header; int i; if (!(loglevel & CTC_LOGLEVEL_DEBUG)) return; p += offset; bl = *((__u16 *) p); p += 2; header = (struct ll_header *) p; p -= 2; printk(KERN_DEBUG "dump:\n"); printk(KERN_DEBUG "blocklen=%d %04x\n", bl, bl); printk(KERN_DEBUG "h->length=%d %04x\n", header->length, header->length); printk(KERN_DEBUG "h->type=%04x\n", header->type); printk(KERN_DEBUG "h->unused=%04x\n", header->unused); if (bl > 16) bl = 16; printk(KERN_DEBUG "data: "); for (i = 0; i < bl; i++) printk("%02x%s", *p++, (i % 16) ? " " : "\n<7>"); printk("\n");}#elsestatic inline voidctc_dump_skb(struct sk_buff *skb, int offset){}#endif/** * Unpack a just received skb and hand it over to * upper layers. * * @param ch The channel where this skb has been received. * @param pskb The received skb. */static __inline__ voidctc_unpack_skb(struct channel *ch, struct sk_buff *pskb){ struct net_device *dev = ch->netdev; struct ctc_priv *privptr = (struct ctc_priv *) dev->priv; __u16 len = *((__u16 *) pskb->data); DBF_TEXT(trace, 4, __FUNCTION__); skb_put(pskb, 2 + LL_HEADER_LENGTH); skb_pull(pskb, 2); pskb->dev = dev; pskb->ip_summed = CHECKSUM_UNNECESSARY; while (len > 0) { struct sk_buff *skb; struct ll_header *header = (struct ll_header *) pskb->data; skb_pull(pskb, LL_HEADER_LENGTH); if ((ch->protocol == CTC_PROTO_S390) && (header->type != ETH_P_IP)) {#ifndef DEBUG if (!(ch->logflags & LOG_FLAG_ILLEGALPKT)) {#endif /** * Check packet type only if we stick strictly * to S/390's protocol of OS390. This only * supports IP. Otherwise allow any packet * type. */ ctc_pr_warn( "%s Illegal packet type 0x%04x received, dropping\n", dev->name, header->type); ch->logflags |= LOG_FLAG_ILLEGALPKT;#ifndef DEBUG }#endif#ifdef DEBUG ctc_dump_skb(pskb, -6);#endif privptr->stats.rx_dropped++; privptr->stats.rx_frame_errors++; return; } pskb->protocol = ntohs(header->type); if (header->length <= LL_HEADER_LENGTH) {#ifndef DEBUG if (!(ch->logflags & LOG_FLAG_ILLEGALSIZE)) {#endif ctc_pr_warn( "%s Illegal packet size %d " "received (MTU=%d blocklen=%d), " "dropping\n", dev->name, header->length, dev->mtu, len); ch->logflags |= LOG_FLAG_ILLEGALSIZE;#ifndef DEBUG }#endif#ifdef DEBUG ctc_dump_skb(pskb, -6);#endif privptr->stats.rx_dropped++; privptr->stats.rx_length_errors++; return; } header->length -= LL_HEADER_LENGTH; len -= LL_HEADER_LENGTH; if ((header->length > skb_tailroom(pskb)) || (header->length > len)) {#ifndef DEBUG if (!(ch->logflags & LOG_FLAG_OVERRUN)) {#endif ctc_pr_warn( "%s Illegal packet size %d " "(beyond the end of received data), " "dropping\n", dev->name, header->length); ch->logflags |= LOG_FLAG_OVERRUN;#ifndef DEBUG }#endif#ifdef DEBUG ctc_dump_skb(pskb, -6);#endif privptr->stats.rx_dropped++; privptr->stats.rx_length_errors++; return; } skb_put(pskb, header->length); pskb->mac.raw = pskb->data; len -= header->length; skb = dev_alloc_skb(pskb->len); if (!skb) {#ifndef DEBUG if (!(ch->logflags & LOG_FLAG_NOMEM)) {#endif ctc_pr_warn( "%s Out of memory in ctc_unpack_skb\n", dev->name); ch->logflags |= LOG_FLAG_NOMEM;#ifndef DEBUG }#endif privptr->stats.rx_dropped++; return; } memcpy(skb_put(skb, pskb->len), pskb->data, pskb->len); skb->mac.raw = skb->data; skb->dev = pskb->dev; skb->protocol = pskb->protocol; pskb->ip_summed = CHECKSUM_UNNECESSARY; if (ch->protocol == CTC_PROTO_LINUX_TTY) ctc_tty_netif_rx(skb); else netif_rx_ni(skb); /** * Successful rx; reset logflags */ ch->logflags = 0; dev->last_rx = jiffies; privptr->stats.rx_packets++; privptr->stats.rx_bytes += skb->len; if (len > 0) { skb_pull(pskb, header->length); if (skb_tailroom(pskb) < LL_HEADER_LENGTH) {#ifndef DEBUG if (!(ch->logflags & LOG_FLAG_OVERRUN)) {#endif ctc_pr_warn( "%s Overrun in ctc_unpack_skb\n", dev->name); ch->logflags |= LOG_FLAG_OVERRUN;#ifndef DEBUG }#endif return; } skb_put(pskb, LL_HEADER_LENGTH); } }}/** * Check return code of a preceeding ccw_device call, halt_IO etc... * * @param ch The channel, the error belongs to. * @param return_code The error code to inspect. */static void inlineccw_check_return_code(struct channel *ch, int return_code, char *msg){ DBF_TEXT(trace, 5, __FUNCTION__); switch (return_code) { case 0: fsm_event(ch->fsm, CH_EVENT_IO_SUCCESS, ch); break; case -EBUSY: ctc_pr_warn("%s (%s): Busy !\n", ch->id, msg); fsm_event(ch->fsm, CH_EVENT_IO_EBUSY, ch); break; case -ENODEV: ctc_pr_emerg("%s (%s): Invalid device called for IO\n", ch->id, msg); fsm_event(ch->fsm, CH_EVENT_IO_ENODEV, ch); break; case -EIO: ctc_pr_emerg("%s (%s): Status pending... \n", ch->id, msg); fsm_event(ch->fsm, CH_EVENT_IO_EIO, ch); break; default: ctc_pr_emerg("%s (%s): Unknown error in do_IO %04x\n", ch->id, msg, return_code); fsm_event(ch->fsm, CH_EVENT_IO_UNKNOWN, ch); }}/** * Check sense of a unit check. * * @param ch The channel, the sense code belongs to. * @param sense The sense code to inspect. */static void inlineccw_unit_check(struct channel *ch, unsigned char sense){ DBF_TEXT(trace, 5, __FUNCTION__); if (sense & SNS0_INTERVENTION_REQ) { if (sense & 0x01) { if (ch->protocol != CTC_PROTO_LINUX_TTY) ctc_pr_debug("%s: Interface disc. or Sel. reset " "(remote)\n", ch->id); fsm_event(ch->fsm, CH_EVENT_UC_RCRESET, ch); } else { ctc_pr_debug("%s: System reset (remote)\n", ch->id); fsm_event(ch->fsm, CH_EVENT_UC_RSRESET, ch); } } else if (sense & SNS0_EQUIPMENT_CHECK) { if (sense & SNS0_BUS_OUT_CHECK) { ctc_pr_warn("%s: Hardware malfunction (remote)\n", ch->id); fsm_event(ch->fsm, CH_EVENT_UC_HWFAIL, ch); } else { ctc_pr_warn("%s: Read-data parity error (remote)\n", ch->id); fsm_event(ch->fsm, CH_EVENT_UC_RXPARITY, ch); } } else if (sense & SNS0_BUS_OUT_CHECK) { if (sense & 0x04) { ctc_pr_warn("%s: Data-streaming timeout)\n", ch->id); fsm_event(ch->fsm, CH_EVENT_UC_TXTIMEOUT, ch); } else { ctc_pr_warn("%s: Data-transfer parity error\n", ch->id); fsm_event(ch->fsm, CH_EVENT_UC_TXPARITY, ch); } } else if (sense & SNS0_CMD_REJECT) { ctc_pr_warn("%s: Command reject\n", ch->id); } else if (sense == 0) { ctc_pr_debug("%s: Unit check ZERO\n", ch->id); fsm_event(ch->fsm, CH_EVENT_UC_ZERO, ch); } else { ctc_pr_warn("%s: Unit Check with sense code: %02x\n", ch->id, sense); fsm_event(ch->fsm, CH_EVENT_UC_UNKNOWN, ch); }}static voidctc_purge_skb_queue(struct sk_buff_head *q){ struct sk_buff *skb; DBF_TEXT(trace, 5, __FUNCTION__); while ((skb = skb_dequeue(q))) { atomic_dec(&skb->users); dev_kfree_skb_irq(skb); }}static __inline__ intctc_checkalloc_buffer(struct channel *ch, int warn){ DBF_TEXT(trace, 5, __FUNCTION__); 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) ctc_pr_warn( "%s: Couldn't alloc %s trans_skb\n", ch->id, (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX"); return -ENOMEM; } ch->ccw[1].count = ch->max_bufsize; if (set_normalized_cda(&ch->ccw[1], ch->trans_skb->data)) { dev_kfree_skb(ch->trans_skb); ch->trans_skb = NULL; if (warn) ctc_pr_warn( "%s: set_normalized_cda for %s " "trans_skb failed, dropping packets\n", ch->id, (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 voidfsm_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 voidch_action_txdone(fsm_instance * fi, int event, void *arg){ struct channel *ch = (struct channel *) arg; struct net_device *dev = ch->netdev; struct ctc_priv *privptr = dev->priv; struct sk_buff *skb; int first = 1; int i; unsigned long duration; struct timespec done_stamp = xtime; DBF_TEXT(trace, 4, __FUNCTION__); duration = (done_stamp.tv_sec - ch->prof.send_stamp.tv_sec) * 1000000 + (done_stamp.tv_nsec - ch->prof.send_stamp.tv_nsec) / 1000; if (duration > ch->prof.tx_time) ch->prof.tx_time = duration; if (ch->irb->scsw.count != 0) ctc_pr_debug("%s: TX not complete, remaining %d bytes\n", dev->name, ch->irb->scsw.count); 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) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?