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

📄 qeth_main.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
		return rc;	if (channel->state != CH_STATE_ACTIVATING) {		PRINT_WARN("qeth: IDX activate timed out!\n");		QETH_DBF_TEXT_(setup, 2, "2err%d", -ETIME);		qeth_clear_cmd_buffers(channel);		return -ETIME;	}	return qeth_idx_activate_get_answer(channel,idx_reply_cb);}static intqeth_peer_func_level(int level){	if ((level & 0xff) == 8)		return (level & 0xff) + 0x400;	if (((level >> 8) & 3) == 1)		return (level & 0xff) + 0x200;	return level;}static voidqeth_idx_write_cb(struct qeth_channel *channel, struct qeth_cmd_buffer *iob){	struct qeth_card *card;	__u16 temp;	QETH_DBF_TEXT(setup ,2, "idxwrcb");	if (channel->state == CH_STATE_DOWN) {		channel->state = CH_STATE_ACTIVATING;		goto out;	}	card = CARD_FROM_CDEV(channel->ccwdev);	if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {		PRINT_ERR("IDX_ACTIVATE on write channel device %s: negative "			  "reply\n", CARD_WDEV_ID(card));		goto out;	}	memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);	if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) {		PRINT_WARN("IDX_ACTIVATE on write channel device %s: "			   "function level mismatch "			   "(sent: 0x%x, received: 0x%x)\n",			   CARD_WDEV_ID(card), card->info.func_level, temp);		goto out;	}	channel->state = CH_STATE_UP;out:	qeth_release_buffer(channel, iob);}static intqeth_check_idx_response(unsigned char *buffer){	if (!buffer)		return 0;	QETH_DBF_HEX(control, 2, buffer, QETH_DBF_CONTROL_LEN);	if ((buffer[2] & 0xc0) == 0xc0) {		PRINT_WARN("received an IDX TERMINATE "			   "with cause code 0x%02x%s\n",			   buffer[4],			   ((buffer[4] == 0x22) ?			    " -- try another portname" : ""));		QETH_DBF_TEXT(trace, 2, "ckidxres");		QETH_DBF_TEXT(trace, 2, " idxterm");		QETH_DBF_TEXT_(trace, 2, "  rc%d", -EIO);		return -EIO;	}	return 0;}static voidqeth_idx_read_cb(struct qeth_channel *channel, struct qeth_cmd_buffer *iob){	struct qeth_card *card;	__u16 temp;	QETH_DBF_TEXT(setup , 2, "idxrdcb");	if (channel->state == CH_STATE_DOWN) {		channel->state = CH_STATE_ACTIVATING;		goto out;	}	card = CARD_FROM_CDEV(channel->ccwdev);	if (qeth_check_idx_response(iob->data)) {			goto out;	}	if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) {		PRINT_ERR("IDX_ACTIVATE on read channel device %s: negative "			  "reply\n", CARD_RDEV_ID(card));		goto out;	}/** * temporary fix for microcode bug * to revert it,replace OR by AND */	if ( (!QETH_IDX_NO_PORTNAME_REQUIRED(iob->data)) ||	     (card->info.type == QETH_CARD_TYPE_OSAE) )		card->info.portname_required = 1;	memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2);	if (temp != qeth_peer_func_level(card->info.func_level)) {		PRINT_WARN("IDX_ACTIVATE on read channel device %s: function "			   "level mismatch (sent: 0x%x, received: 0x%x)\n",			   CARD_RDEV_ID(card), card->info.func_level, temp);		goto out;	}	memcpy(&card->token.issuer_rm_r,	       QETH_IDX_ACT_ISSUER_RM_TOKEN(iob->data),	       QETH_MPC_TOKEN_LENGTH);	memcpy(&card->info.mcl_level[0],	       QETH_IDX_REPLY_LEVEL(iob->data), QETH_MCL_LENGTH);	channel->state = CH_STATE_UP;out:	qeth_release_buffer(channel,iob);}static intqeth_issue_next_read(struct qeth_card *card){	int rc;	struct qeth_cmd_buffer *iob;	QETH_DBF_TEXT(trace,5,"issnxrd");	if (card->read.state != CH_STATE_UP)		return -EIO;	iob = qeth_get_buffer(&card->read);	if (!iob) {		PRINT_WARN("issue_next_read failed: no iob available!\n");		return -ENOMEM;	}	qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE);	wait_event(card->wait_q,		   atomic_compare_and_swap(0,1,&card->read.irq_pending) == 0);	QETH_DBF_TEXT(trace, 6, "noirqpnd");	rc = ccw_device_start(card->read.ccwdev, &card->read.ccw,			      (addr_t) iob, 0, 0);	if (rc) {		PRINT_ERR("Error in starting next read ccw! rc=%i\n", rc);		atomic_set(&card->read.irq_pending, 0);		qeth_schedule_recovery(card);		wake_up(&card->wait_q);	}	return rc;}static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card){	struct qeth_reply *reply;	reply = kmalloc(sizeof(struct qeth_reply), GFP_ATOMIC);	if (reply){		memset(reply, 0, sizeof(struct qeth_reply));		atomic_set(&reply->refcnt, 1);		reply->card = card;	};	return reply;}static voidqeth_get_reply(struct qeth_reply *reply){	WARN_ON(atomic_read(&reply->refcnt) <= 0);	atomic_inc(&reply->refcnt);}static voidqeth_put_reply(struct qeth_reply *reply){	WARN_ON(atomic_read(&reply->refcnt) <= 0);	if (atomic_dec_and_test(&reply->refcnt))		kfree(reply);}static voidqeth_cmd_timeout(unsigned long data){	struct qeth_reply *reply, *list_reply, *r;	unsigned long flags;	reply = (struct qeth_reply *) data;	spin_lock_irqsave(&reply->card->lock, flags);	list_for_each_entry_safe(list_reply, r,				 &reply->card->cmd_waiter_list, list) {		if (reply == list_reply){			qeth_get_reply(reply);			list_del_init(&reply->list);			spin_unlock_irqrestore(&reply->card->lock, flags);			reply->rc = -ETIME;			reply->received = 1;			wake_up(&reply->wait_q);			qeth_put_reply(reply);			return;		}	}	spin_unlock_irqrestore(&reply->card->lock, flags);}static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob){	struct qeth_ipa_cmd *cmd = NULL;	QETH_DBF_TEXT(trace,5,"chkipad");	if (IS_IPA(iob->data)){		cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);		if (IS_IPA_REPLY(cmd))			return cmd;		else {			switch (cmd->hdr.command) {			case IPA_CMD_STOPLAN:				PRINT_WARN("Link failure on %s (CHPID 0x%X) - "					   "there is a network problem or "					   "someone pulled the cable or "					   "disabled the port.\n",					   QETH_CARD_IFNAME(card),					   card->info.chpid);				card->lan_online = 0;				netif_carrier_off(card->dev);				return NULL;			case IPA_CMD_STARTLAN:				PRINT_INFO("Link reestablished on %s "					   "(CHPID 0x%X). Scheduling "					   "IP address reset.\n",					   QETH_CARD_IFNAME(card),					   card->info.chpid);				qeth_schedule_recovery(card);				return NULL;			case IPA_CMD_MODCCID:				return cmd;			case IPA_CMD_REGISTER_LOCAL_ADDR:				QETH_DBF_TEXT(trace,3, "irla");				break;			case IPA_CMD_UNREGISTER_LOCAL_ADDR:				QETH_DBF_TEXT(trace,3, "urla");				break;			default:				PRINT_WARN("Received data is IPA "					   "but not a reply!\n");				break;			}		}	}	return cmd;}/** * wake all waiting ipa commands */static voidqeth_clear_ipacmd_list(struct qeth_card *card){	struct qeth_reply *reply, *r;	unsigned long flags;	QETH_DBF_TEXT(trace, 4, "clipalst");	spin_lock_irqsave(&card->lock, flags);	list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) {		qeth_get_reply(reply);		reply->rc = -EIO;		reply->received = 1;		list_del_init(&reply->list);		wake_up(&reply->wait_q);		qeth_put_reply(reply);	}	spin_unlock_irqrestore(&card->lock, flags);}static voidqeth_send_control_data_cb(struct qeth_channel *channel,			  struct qeth_cmd_buffer *iob){	struct qeth_card *card;	struct qeth_reply *reply, *r;	struct qeth_ipa_cmd *cmd;	unsigned long flags;	int keep_reply;	QETH_DBF_TEXT(trace,4,"sndctlcb");	card = CARD_FROM_CDEV(channel->ccwdev);	if (qeth_check_idx_response(iob->data)) {		qeth_clear_ipacmd_list(card);		qeth_schedule_recovery(card);		goto out;	}	cmd = qeth_check_ipa_data(card, iob);	if ((cmd == NULL) && (card->state != CARD_STATE_DOWN))		goto out;	/*in case of OSN : check if cmd is set */	if (card->info.type == QETH_CARD_TYPE_OSN &&	    cmd &&	    cmd->hdr.command != IPA_CMD_STARTLAN &&	    card->osn_info.assist_cb != NULL) {		card->osn_info.assist_cb(card->dev, cmd);		goto out;	}	spin_lock_irqsave(&card->lock, flags);	list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) {		if ((reply->seqno == QETH_IDX_COMMAND_SEQNO) ||		    ((cmd) && (reply->seqno == cmd->hdr.seqno))) {			qeth_get_reply(reply);			list_del_init(&reply->list);			spin_unlock_irqrestore(&card->lock, flags);			keep_reply = 0;			if (reply->callback != NULL) {				if (cmd) {					reply->offset = (__u16)((char*)cmd -								(char *)iob->data);					keep_reply = reply->callback(card,							reply,							(unsigned long)cmd);				} else					keep_reply = reply->callback(card,							reply,							(unsigned long)iob);			}			if (cmd)				reply->rc = (u16) cmd->hdr.return_code;			else if (iob->rc)				reply->rc = iob->rc;			if (keep_reply) {				spin_lock_irqsave(&card->lock, flags);				list_add_tail(&reply->list,					      &card->cmd_waiter_list);				spin_unlock_irqrestore(&card->lock, flags);			} else {				reply->received = 1;				wake_up(&reply->wait_q);			}			qeth_put_reply(reply);			goto out;		}	}	spin_unlock_irqrestore(&card->lock, flags);out:	memcpy(&card->seqno.pdu_hdr_ack,		QETH_PDU_HEADER_SEQ_NO(iob->data),		QETH_SEQ_NO_LENGTH);	qeth_release_buffer(channel,iob);}static inline voidqeth_prepare_control_data(struct qeth_card *card, int len,struct qeth_cmd_buffer *iob){	qeth_setup_ccw(&card->write,iob->data,len);	iob->callback = qeth_release_buffer;	memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data),	       &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH);	card->seqno.trans_hdr++;	memcpy(QETH_PDU_HEADER_SEQ_NO(iob->data),	       &card->seqno.pdu_hdr, QETH_SEQ_NO_LENGTH);	card->seqno.pdu_hdr++;	memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data),	       &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH);	QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN);}						    static intqeth_send_control_data(struct qeth_card *card, int len,		       struct qeth_cmd_buffer *iob,		       int (*reply_cb)		       (struct qeth_card *, struct qeth_reply*, unsigned long),		       void *reply_param){	int rc;	unsigned long flags;	struct qeth_reply *reply = NULL;	struct timer_list timer;	QETH_DBF_TEXT(trace, 2, "sendctl");	reply = qeth_alloc_reply(card);	if (!reply) {		PRINT_WARN("Could no alloc qeth_reply!\n");		return -ENOMEM;	}	reply->callback = reply_cb;	reply->param = reply_param;	if (card->state == CARD_STATE_DOWN)		reply->seqno = QETH_IDX_COMMAND_SEQNO;	else		reply->seqno = card->seqno.ipa++;	init_timer(&timer);	timer.function = qeth_cmd_timeout;	timer.data = (unsigned long) reply;	init_waitqueue_head(&reply->wait_q);	spin_lock_irqsave(&card->lock, flags);	list_add_tail(&reply->list, &card->cmd_waiter_list);	spin_unlock_irqrestore(&card->lock, flags);	QETH_DBF_HEX(control, 2, iob->data, QETH_DBF_CONTROL_LEN);	wait_event(card->wait_q,		   atomic_compare_and_swap(0,1,&card->write.irq_pending) == 0);	qeth_prepare_control_data(card, len, iob);	if (IS_IPA(iob->data))		timer.expires = jiffies + QETH_IPA_TIMEOUT;	else		timer.expires = jiffies + QETH_TIMEOUT;	QETH_DBF_TEXT(trace, 6, "noirqpnd");	spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);	rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,			      (addr_t) iob, 0, 0);	spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);	if (rc){		PRINT_WARN("qeth_send_control_data: "			   "ccw_device_start rc = %i\n", rc);		QETH_DBF_TEXT_(trace, 2, " err%d", rc);		spin_lock_irqsave(&card->lock, flags);		list_del_init(&reply->list);		qeth_put_reply(reply);		spin_unlock_irqrestore(&card->lock, flags);		qeth_release_buffer(iob->channel, iob);		atomic_set(&card->write.irq_pending, 0);		wake_up(&card->wait_q);		return rc;	}	add_timer(&timer);	wait_event(reply->wait_q, reply->received);	del_timer_sync(&timer);	rc = reply->rc;	qeth_put_reply(reply);	return rc;}static intqeth_osn_send_control_data(struct qeth_card *card, int len,			   struct qeth_cmd_buffer *iob){	unsigned long flags;	int rc = 0;	QETH_DBF_TEXT(trace, 5, "osndctrd");	wait_event(card->wait_q,		   atomic_compare_and_swap(0,1,&card->write.irq_pending) == 0);	qeth_prepare_control_data(card, len, iob);	QETH_DBF_TEXT(trace, 6, "osnoirqp");	spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);	rc = ccw_device_start(card->write.ccwdev, &card->write.ccw,			      (addr_t) iob, 0, 0);	spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);	if (rc){		PRINT_WARN("qeth_osn_send_control_data: "			   "ccw_device_start rc = %i\n", rc);		QETH_DBF_TEXT_(trace, 2, " err%d", rc);		qeth_release_buffer(iob->channel, iob);		atomic_set(&card->write.irq_pending, 0);		wake_up(&card->wait_q);	}	return rc;}					static inline voidqeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,		     char prot_type){	memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);	memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data),&prot_type,1);	memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data),	       &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);}static intqeth_osn_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,		      int data_len){	u16 s1, s2;	QETH_DBF_TEXT(trace,4,"osndipa");	qeth_prepare_ipa_cmd(card, iob, QETH_PROT_OSN2);	s1 = (u16)(IPA_PDU_HEADER_SIZE + data_len);	s2 = (u16)data_len;	memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2);	memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2);	memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2);	memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2);	return qeth_osn_send_control_data(card, s1, iob);}							    static intqeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,		  int (*reply_cb)		  (struct qeth_card *,struct qeth_reply*, unsigned long),

⌨️ 快捷键说明

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