⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ctcmain.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		    (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) {		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 = ccw_device_start(ch->cdev, &ch->ccw[0],				      (unsigned long) 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, "chained TX");		}	} 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 voidch_action_txidle(fsm_instance * fi, int event, void *arg){	struct channel *ch = (struct channel *) arg;	DBF_TEXT(trace, 4, __FUNCTION__);	fsm_deltimer(&ch->timer);	fsm_newstate(fi, CH_STATE_TXIDLE);	fsm_event(((struct 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 voidch_action_rx(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;	int len = ch->max_bufsize - ch->irb->scsw.count;	struct sk_buff *skb = ch->trans_skb;	__u16 block_len = *((__u16 *) skb->data);	int check_len;	int rc;	DBF_TEXT(trace, 4, __FUNCTION__);	fsm_deltimer(&ch->timer);	if (len < 8) {		ctc_pr_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) {		ctc_pr_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)) {		ctc_pr_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 = ccw_device_start(ch->cdev, &ch->ccw[0], (unsigned long) ch, 0xff, 0);	if (rc != 0)		ccw_check_return_code(ch, rc, "normal RX");}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 voidch_action_firstio(fsm_instance * fi, int event, void *arg){	struct channel *ch = (struct channel *) arg;	int rc;	DBF_TEXT(trace, 4, __FUNCTION__);	if (fsm_getstate(fi) == CH_STATE_TXIDLE)		ctc_pr_debug("%s: remote side issued READ?, init ...\n", ch->id);	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 {			struct net_device *dev = ch->netdev;			fsm_newstate(fi, CH_STATE_TXIDLE);			fsm_event(((struct 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.	 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -