static void ctcmpc_chx_txdone()

in net/ctcm_fsms.c [1210:1362]


static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
{
	struct channel		*ch = arg;
	struct net_device	*dev = ch->netdev;
	struct ctcm_priv	*priv = dev->ml_priv;
	struct mpc_group	*grp = priv->mpcg;
	struct sk_buff		*skb;
	int		first = 1;
	int		i;
	__u32		data_space;
	unsigned long	duration;
	struct sk_buff	*peekskb;
	int		rc;
	struct th_header *header;
	struct pdu	*p_header;
	unsigned long done_stamp = jiffies;

	CTCM_PR_DEBUG("Enter %s: %s cp:%i\n",
			__func__, dev->name, smp_processor_id());

	duration = done_stamp - ch->prof.send_stamp;
	if (duration > ch->prof.tx_time)
		ch->prof.tx_time = duration;

	if (ch->irb->scsw.cmd.count != 0)
		CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_DEBUG,
			"%s(%s): TX not complete, remaining %d bytes",
			     CTCM_FUNTAIL, dev->name, ch->irb->scsw.cmd.count);
	fsm_deltimer(&ch->timer);
	while ((skb = skb_dequeue(&ch->io_queue))) {
		priv->stats.tx_packets++;
		priv->stats.tx_bytes += skb->len - TH_HEADER_LENGTH;
		if (first) {
			priv->stats.tx_bytes += 2;
			first = 0;
		}
		refcount_dec(&skb->users);
		dev_kfree_skb_irq(skb);
	}
	spin_lock(&ch->collect_lock);
	clear_normalized_cda(&ch->ccw[4]);
	if ((ch->collect_len <= 0) || (grp->in_sweep != 0)) {
		spin_unlock(&ch->collect_lock);
		fsm_newstate(fi, CTC_STATE_TXIDLE);
				goto done;
	}

	if (ctcm_checkalloc_buffer(ch)) {
		spin_unlock(&ch->collect_lock);
				goto done;
	}
	ch->trans_skb->data = ch->trans_skb_data;
	skb_reset_tail_pointer(ch->trans_skb);
	ch->trans_skb->len = 0;
	if (ch->prof.maxmulti < (ch->collect_len + TH_HEADER_LENGTH))
		ch->prof.maxmulti = ch->collect_len + TH_HEADER_LENGTH;
	if (ch->prof.maxcqueue < skb_queue_len(&ch->collect_queue))
		ch->prof.maxcqueue = skb_queue_len(&ch->collect_queue);
	i = 0;
	p_header = NULL;
	data_space = grp->group_max_buflen - TH_HEADER_LENGTH;

	CTCM_PR_DBGDATA("%s: building trans_skb from collect_q"
		       " data_space:%04x\n",
		       __func__, data_space);

	while ((skb = skb_dequeue(&ch->collect_queue))) {
		skb_put_data(ch->trans_skb, skb->data, skb->len);
		p_header = (struct pdu *)
			(skb_tail_pointer(ch->trans_skb) - skb->len);
		p_header->pdu_flag = 0x00;
		if (be16_to_cpu(skb->protocol) == ETH_P_SNAP)
			p_header->pdu_flag |= 0x60;
		else
			p_header->pdu_flag |= 0x20;

		CTCM_PR_DBGDATA("%s: trans_skb len:%04x \n",
				__func__, ch->trans_skb->len);
		CTCM_PR_DBGDATA("%s: pdu header and data for up"
				" to 32 bytes sent to vtam\n", __func__);
		CTCM_D3_DUMP((char *)p_header, min_t(int, skb->len, 32));

		ch->collect_len -= skb->len;
		data_space -= skb->len;
		priv->stats.tx_packets++;
		priv->stats.tx_bytes += skb->len;
		refcount_dec(&skb->users);
		dev_kfree_skb_any(skb);
		peekskb = skb_peek(&ch->collect_queue);
		if (peekskb->len > data_space)
			break;
		i++;
	}
	/* p_header points to the last one we handled */
	if (p_header)
		p_header->pdu_flag |= PDU_LAST;	/*Say it's the last one*/

	header = skb_push(ch->trans_skb, TH_HEADER_LENGTH);
	memset(header, 0, TH_HEADER_LENGTH);

	header->th_ch_flag = TH_HAS_PDU;  /* Normal data */
	ch->th_seq_num++;
	header->th_seq_num = ch->th_seq_num;

	CTCM_PR_DBGDATA("%s: ToVTAM_th_seq= %08x\n" ,
					__func__, ch->th_seq_num);

	CTCM_PR_DBGDATA("%s: trans_skb len:%04x \n",
		       __func__, ch->trans_skb->len);
	CTCM_PR_DBGDATA("%s: up-to-50 bytes of trans_skb "
			"data to vtam from collect_q\n", __func__);
	CTCM_D3_DUMP((char *)ch->trans_skb->data,
				min_t(int, ch->trans_skb->len, 50));

	spin_unlock(&ch->collect_lock);
	clear_normalized_cda(&ch->ccw[1]);

	CTCM_PR_DBGDATA("ccwcda=0x%p data=0x%p\n",
			(void *)(unsigned long)ch->ccw[1].cda,
			ch->trans_skb->data);
	ch->ccw[1].count = ch->max_bufsize;

	if (set_normalized_cda(&ch->ccw[1], ch->trans_skb->data)) {
		dev_kfree_skb_any(ch->trans_skb);
		ch->trans_skb = NULL;
		CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_ERROR,
			"%s: %s: IDAL alloc failed",
				CTCM_FUNTAIL, ch->id);
		fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev);
		return;
	}

	CTCM_PR_DBGDATA("ccwcda=0x%p data=0x%p\n",
			(void *)(unsigned long)ch->ccw[1].cda,
			ch->trans_skb->data);

	ch->ccw[1].count = ch->trans_skb->len;
	fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
	ch->prof.send_stamp = jiffies;
	if (do_debug_ccw)
		ctcmpc_dumpit((char *)&ch->ccw[0], sizeof(struct ccw1) * 3);
	rc = ccw_device_start(ch->cdev, &ch->ccw[0], 0, 0xff, 0);
	ch->prof.doios_multi++;
	if (rc != 0) {
		priv->stats.tx_dropped += i;
		priv->stats.tx_errors += i;
		fsm_deltimer(&ch->timer);
		ctcm_ccw_check_rc(ch, rc, "chained TX");
	}
done:
	ctcm_clear_busy(dev);
	return;
}