📄 ctc.c
字号:
} memset(privptr->channel[c].devstat, 0, sizeof(devstat_t)); if (ctc_no_auto == 0) ctc_adapter[m][i].devno[c] = channel_get_next(m); else ctc_adapter[m][i].devno[c] = channel_get(m, ctc_adapter[m][i].devno[c]); if ( ctc_adapter[m][i].devno[c] != -ENODEV){ rc = request_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), (void *)ctc_irq_handler, SA_INTERRUPT, dev->name, privptr->channel[c].devstat); if (rc) { printk(KERN_WARNING "%s: requested device busy %02x\n", dev->name, rc); return -EBUSY; } } else { if (i == WRITE) { free_irq(get_irq_by_devno(ctc_adapter[m][i].devno[c]), privptr->channel[i].devstat); channel_free(m, ctc_adapter[m][i].devno[READ]); kfree(privptr->channel[READ].devstat); } kfree(privptr->channel[i].devstat); return -ENODEV; } } privptr->channel[READ].devno = ctc_adapter[m][i].devno[READ]; privptr->channel[READ].irq = get_irq_by_devno(ctc_adapter[m][i].devno[READ]); privptr->channel[WRITE].devno = ctc_adapter[m][i].devno[WRITE]; privptr->channel[WRITE].irq = get_irq_by_devno(ctc_adapter[m][i].devno[WRITE]); privptr->protocol = ctc_adapter[m][i].protocol; channel[m].left = channel[m].left - 2; printk(KERN_INFO "%s: read dev: %04x irq: %04x - write dev: %04x irq: %04x \n", dev->name, privptr->channel[READ].devno, privptr->channel[READ].irq, privptr->channel[WRITE].devno, privptr->channel[WRITE].irq); dev->mtu = CTC_DEFAULT_MTU_SIZE; dev->hard_start_xmit = ctc_tx; dev->open = ctc_open; dev->stop = ctc_release; dev->get_stats = ctc_stats; dev->change_mtu = ctc_change_mtu; dev->hard_header_len = 0; dev->addr_len = 0; dev->type = ARPHRD_SLIP; dev->tx_queue_len = 100; dev_init_buffers(dev); dev->flags = IFF_POINTOPOINT | IFF_NOARP; return 0;} /* * Interrupt processing * */static void inline ccw_check_return_code (net_device *dev, int return_code){ if (return_code != 0) { switch (return_code) { case -EBUSY: printk(KERN_INFO "%s: Busy !\n", dev->name); break; case -ENODEV: printk(KERN_EMERG "%s: Invalid device called for IO\n", dev->name); break; case -EIO: printk(KERN_EMERG "%s: Status pending... \n", dev->name); break; default: printk(KERN_EMERG "%s: Unknown error in Do_IO %04x\n", dev->name, return_code); } }} static void inline ccw_check_unit_check (net_device *dev, char sense){#ifdef DEBUG printk(KERN_INFO "%s: Unit Check with sense code: %02x\n", dev->name, sense);#endif if (sense & 0x40) {#ifdef DEBUG if (sense & 0x01) printk(KERN_DEBUG "%s: Interface disconnect or Selective reset occurred (remote side)\n", dev->name); else printk(KERN_DEBUG "%s: System reset occured (remote side)\n", dev->name);#endif } else if (sense & 0x20) { if (sense & 0x04) printk(KERN_WARNING "%s: Data-streaming timeout)\n", dev->name); else printk(KERN_WARNING "%s: Data-transfer parity error\n", dev->name); } else if (sense & 0x10) { if (sense & 0x20) printk(KERN_WARNING "%s: Hardware malfunction (remote side)\n", dev->name); else printk(KERN_WARNING "%s: Read-data parity error (remote side)\n", dev->name); }} static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs){ int rc = 0; __u32 parm; __u8 flags = 0x00; struct channel *ctc = NULL; struct ctc_priv *privptr = NULL; net_device *dev = NULL; ccw1_t ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL}, {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; devstat_t *devstat = ((devstat_t *)initparm); /* Bypass all 'unsolited interrupts' */ if (devstat->intparm == 0) {#ifdef DEBUG printk(KERN_DEBUG "ctc: unsolited interrupt for device: %04x received c-%02x d-%02x f-%02x\n", devstat->devno, devstat->cstat, devstat->dstat, devstat->flag);#endif /* FIXME - find the related intparm!!! No IO outstanding!!!! */ return; } ctc = (struct channel *) (devstat->intparm); dev = (net_device *) ctc->dev; privptr = dev->priv;#ifdef DEBUG printk(KERN_DEBUG "%s: interrupt for device: %04x received c-%02x d-%02x f-%02x state-%02x\n", dev->name, ctc->devno, devstat->cstat, devstat->dstat, devstat->flag, ctc->state);#endif /* Check for good subchannel return code, otherwise error message */ if (devstat->cstat) { printk(KERN_WARNING "%s: subchannel check for device: %04x - %02x\n", dev->name, ctc->devno, devstat->cstat); return; } /* Check the reason-code of a unit check */ if (devstat->dstat & DEV_STAT_UNIT_CHECK) ccw_check_unit_check(dev, devstat->ii.sense.data[0]); /* State machine to bring the connection up / down and to restart */ ctc->last_dstat = devstat->dstat; switch (ctc->state) { case CTC_STOP: /* HALT_IO issued by ctc_release (halt sequence) */ if (!devstat->flag & DEVSTAT_FINAL_STATUS) return; wake_up(&ctc->wait); /* wake up ctc_release */ return; case CTC_START_HALT_IO: /* HALT_IO issued by ctc_open (start sequence) */ if (!devstat->flag & DEVSTAT_FINAL_STATUS) return; ctc->state = CTC_START_SET_X_MODE; parm = (__u32) ctc; rc = do_IO (ctc->irq, &ccw_set_x_mode[0], parm, 0xff, flags); if (rc != 0) ccw_check_return_code(dev, rc); return; case CTC_START_SET_X_MODE: if (devstat->dstat & DEV_STAT_UNIT_CHECK) { if ((devstat->ii.sense.data[0] & 0x41) != 0x41 || (devstat->ii.sense.data[0] & 0x40) != 0x40) { wake_up(&ctc->wait); /* wake up ctc_open (READ or WRITE) */ return; } } if (!devstat->flag & DEVSTAT_FINAL_STATUS) return; ctc->state = CTC_START_SELECT; case CTC_START_SELECT: if (!ctc->flag & CTC_WRITE) { ctc->state = CTC_START_READ_TEST; ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); parm = (__u32) ctc; rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); if (rc != 0) ccw_check_return_code(dev, rc); wake_up(&ctc->wait); /* wake up ctc_open (READ) */ } else { ctc->state = CTC_START_WRITE_TEST; /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */ ctc->ccw[1].count = 0; ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); parm = (__u32) ctc; rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags); if (rc != 0) ccw_check_return_code(dev, rc); } return; case CTC_START_READ_TEST: if (devstat->dstat & DEV_STAT_UNIT_CHECK) { if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || (devstat->ii.sense.data[0] & 0x40) == 0x40 || devstat->ii.sense.data[0] == 0 ) { init_timer(&ctc->timer); ctc->timer.function = (void *)ctc_read_retry; ctc->timer.data = (__u32)ctc; ctc->timer.expires = jiffies + 10*HZ; add_timer(&ctc->timer);#ifdef DEBUG printk(KERN_DEBUG "%s: read connection restarted\n",dev->name); #endif } return; } if ((devstat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) != 0x00) { if ((devstat->dstat & DEV_STAT_ATTENTION) && (devstat->dstat & DEV_STAT_BUSY)) { printk(KERN_WARNING "%s: read channel is connected with the remote side read channel\n", dev->name); } wake_up(&privptr->channel[WRITE].wait); /* wake up ctc_open (WRITE) */ return; } ctc->state = CTC_START_READ; set_bit(0, (void *)&ctc->IO_active); /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 2 */ /* wake_up(&privptr->channel[WRITE].wait);*/ /* wake up ctc_open (WRITE) */ case CTC_START_READ: if (devstat->dstat & DEV_STAT_UNIT_CHECK) { if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || (devstat->ii.sense.data[0] & 0x40) == 0x40 || devstat->ii.sense.data[0] == 0 ) { privptr->stats.rx_errors++; /* Need protection here cos we are in the read irq */ /* handler the tbusy is for the write subchannel */ ctc_protect_busy(dev); ctc_setbit_busy(TB_RETRY,dev); ctc_unprotect_busy(dev); init_timer(&ctc->timer); ctc->timer.function = (void *)ctc_read_retry; ctc->timer.data = (__u32)ctc; ctc->timer.expires = jiffies + 30*HZ; add_timer(&ctc->timer); printk(KERN_INFO "%s: connection restarted!! problem on remote side\n",dev->name); } return; } if(!devstat->flag & DEVSTAT_FINAL_STATUS) return; ctc_protect_busy(dev); ctc_clearbit_busy(TB_RETRY,dev); ctc_unprotect_busy(dev); ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor); if (ctc->free_anchor != NULL) { ctc->ccw[1].cda = (char *)virt_to_phys(ctc->free_anchor->block); parm = (__u32) ctc; rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); if (rc != 0) ccw_check_return_code(dev, rc); } else { clear_bit(0, (void *)&ctc->IO_active); #ifdef DEBUG printk(KERN_DEBUG "%s: No HOT READ started in IRQ\n",dev->name);#endif } if (test_and_set_bit(CTC_BH_ACTIVE, (void *)&ctc->flag_a) == 0) { queue_task(&ctc->tq, &tq_immediate); mark_bh(IMMEDIATE_BH); } return; case CTC_START_WRITE_TEST: if (devstat->dstat & DEV_STAT_UNIT_CHECK) { if ((devstat->ii.sense.data[0] & 0x41) == 0x41 || (devstat->ii.sense.data[0] & 0x40) == 0x40 || devstat->ii.sense.data[0] == 0 ) { init_timer(&ctc->timer); ctc->timer.function = (void *)ctc_write_retry; ctc->timer.data = (__u32)ctc; ctc->timer.expires = jiffies + 10*HZ; add_timer(&ctc->timer);#ifdef DEBUG printk(KERN_DEBUG "%s: write connection restarted\n",dev->name);#endif } return; } ctc->state = CTC_START_WRITE; wake_up(&ctc->wait); /* wake up ctc_open (WRITE) */ return; case CTC_START_WRITE: if (devstat->dstat & DEV_STAT_UNIT_CHECK) { privptr->stats.tx_errors += ctc->proc_anchor->packets;#ifdef DEBUG printk(KERN_DEBUG "%s: Unit Check on write channel\n",dev->name);#endif } else { if (!devstat->flag & DEVSTAT_FINAL_STATUS) return; privptr->stats.tx_packets += ctc->proc_anchor->packets; } ctc->proc_anchor->block->length = 0; ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor); ctc_clearbit_busy(TB_NOBUFFER,dev); if (ctc->proc_anchor != NULL) { #ifdef DEBUG printk(KERN_DEBUG "%s: IRQ early swap buffer\n",dev->name); #endif ctc->ccw[1].count = ctc->proc_anchor->block->length; ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block); parm = (__u32) ctc; rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); if (rc != 0) ccw_check_return_code(dev, rc); dev->trans_start = jiffies; return; } if (ctc->free_anchor->block->length != 0) { if (ctc_test_and_setbit_busy(TB_TX,dev) == 0) { /* set transmission to busy */ ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor); ctc_clearbit_busy(TB_TX,dev);#ifdef DEBUG printk(KERN_DEBUG "%s: last buffer move in IRQ\n",dev->name); #endif ctc->ccw[1].count = ctc->proc_anchor->block->length; ctc->ccw[1].cda = (char *)virt_to_phys(ctc->proc_anchor->block); parm = (__u32) ctc; rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags ); if (rc != 0) ccw_check_return_code(dev, rc); dev->trans_start = jiffies; return; } } clear_bit(0, (void *)&ctc->IO_active); /* set by ctc_tx or ctc_bh */ return; default: printk(KERN_WARNING "%s: wrong selection code - irq\n",dev->name); return; }} static void ctc_irq_bh (struct channel *ctc){ int rc = 0; __u16 data_len; __u32 parm; __u8 flags = 0x00; __u32 saveflags; net_device *dev; struct ctc_priv *privptr; struct packet *lp; struct sk_buff *skb; dev = (net_device *) ctc->dev; privptr = (struct ctc_priv *) dev->priv;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -