qeth_main.c

来自「linux 内核源代码」· C语言 代码 · 共 2,480 行 · 第 1/5 页

C
2,480
字号
	       &card->info.func_level,sizeof(__u16));	temp = raw_devno_from_bus_id(CARD_DDEV_ID(card));	memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(iob->data), &temp, 2);	temp = (card->info.cula << 8) + card->info.unit_addr2;	memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(iob->data), &temp, 2);	wait_event(card->wait_q,		   atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);	QETH_DBF_TEXT(setup, 6, "noirqpnd");	spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);	rc = ccw_device_start(channel->ccwdev,			      &channel->ccw,(addr_t) iob, 0, 0);	spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);	if (rc) {		PRINT_ERR("qeth: Error1 in activating channel. rc=%d\n",rc);		QETH_DBF_TEXT_(setup, 2, "1err%d", rc);		atomic_set(&channel->irq_pending, 0);		wake_up(&card->wait_q);		return rc;	}	rc = wait_event_interruptible_timeout(card->wait_q,			channel->state == CH_STATE_ACTIVATING, QETH_TIMEOUT);	if (rc == -ERESTARTSYS)		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))) {		if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)			PRINT_ERR("IDX_ACTIVATE on write channel device %s: "				"adapter exclusively used by another host\n",				CARD_WDEV_ID(card));		else			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))) {		if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19)			PRINT_ERR("IDX_ACTIVATE on read channel device %s: "				"adapter exclusively used by another host\n",				CARD_RDEV_ID(card));		else			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);	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 = kzalloc(sizeof(struct qeth_reply), GFP_ATOMIC);	if (reply){		atomic_set(&reply->refcnt, 1);		atomic_set(&reply->received, 0);		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_issue_ipa_msg(struct qeth_ipa_cmd *cmd, struct qeth_card *card){	int rc;	int com;	char * ipa_name;	com = cmd->hdr.command;	rc  = cmd->hdr.return_code;	ipa_name = qeth_get_ipa_cmd_name(com);	PRINT_ERR("%s(x%X) for %s returned x%X \"%s\"\n", ipa_name, com,		   QETH_CARD_IFNAME(card), rc, qeth_get_ipa_msg(rc));}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)) {			if (cmd->hdr.return_code)				qeth_issue_ipa_msg(cmd, card);			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;				if (card->dev && netif_carrier_ok(card->dev))					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);				netif_carrier_on(card->dev);				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;		atomic_inc(&reply->received);		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 {				atomic_inc(&reply->received);				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 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;	unsigned long timeout;	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_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);	while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ;	qeth_prepare_control_data(card, len, iob);	if (IS_IPA(iob->data))		timeout = jiffies + QETH_IPA_TIMEOUT;	else		timeout = 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;	}	while (!atomic_read(&reply->received)) {		if (time_after(jiffies, timeout)) {			spin_lock_irqsave(&reply->card->lock, flags);			list_del_init(&reply->list);			spin_unlock_irqrestore(&reply->card->lock, flags);			reply->rc = -ETIME;			atomic_inc(&reply->received);			wake_up(&reply->wait_q);		}		cpu_relax();	};	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_cmpxchg(&card->write.irq_pending, 0, 1) == 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;}

⌨️ 快捷键说明

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