📄 qeth_main.c
字号:
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 + -