📄 qeth_main.c
字号:
static intqeth_recover(void *ptr){ struct qeth_card *card; int rc = 0; card = (struct qeth_card *) ptr; daemonize("qeth_recover"); QETH_DBF_TEXT(trace,2,"recover1"); QETH_DBF_HEX(trace, 2, &card, sizeof(void *)); if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD)) return 0; QETH_DBF_TEXT(trace,2,"recover2"); PRINT_WARN("Recovery of device %s started ...\n", CARD_BUS_ID(card)); card->use_hard_stop = 1; __qeth_set_offline(card->gdev,1); rc = __qeth_set_online(card->gdev,1); if (!rc) PRINT_INFO("Device %s successfully recovered!\n", CARD_BUS_ID(card)); else PRINT_INFO("Device %s could not be recovered!\n", CARD_BUS_ID(card)); /* don't run another scheduled recovery */ qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); return 0;}voidqeth_schedule_recovery(struct qeth_card *card){ QETH_DBF_TEXT(trace,2,"startrec"); if (qeth_set_thread_start_bit(card, QETH_RECOVER_THREAD) == 0) schedule_work(&card->kernel_thread_starter);}static intqeth_do_start_thread(struct qeth_card *card, unsigned long thread){ unsigned long flags; int rc = 0; spin_lock_irqsave(&card->thread_mask_lock, flags); QETH_DBF_TEXT_(trace, 4, " %02x%02x%02x", (u8) card->thread_start_mask, (u8) card->thread_allowed_mask, (u8) card->thread_running_mask); rc = (card->thread_start_mask & thread); spin_unlock_irqrestore(&card->thread_mask_lock, flags); return rc;}static voidqeth_start_kernel_thread(struct qeth_card *card){ QETH_DBF_TEXT(trace , 2, "strthrd"); if (card->read.state != CH_STATE_UP && card->write.state != CH_STATE_UP) return; if (qeth_do_start_thread(card, QETH_SET_IP_THREAD)) kernel_thread(qeth_register_ip_addresses, (void *)card,SIGCHLD); if (qeth_do_start_thread(card, QETH_SET_PROMISC_MODE_THREAD)) kernel_thread(qeth_set_promisc_mode, (void *)card, SIGCHLD); if (qeth_do_start_thread(card, QETH_RECOVER_THREAD)) kernel_thread(qeth_recover, (void *) card, SIGCHLD);}static voidqeth_set_intial_options(struct qeth_card *card){ card->options.route4.type = NO_ROUTER;#ifdef CONFIG_QETH_IPV6 card->options.route6.type = NO_ROUTER;#endif /* QETH_IPV6 */ card->options.checksum_type = QETH_CHECKSUM_DEFAULT; card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS; card->options.macaddr_mode = QETH_TR_MACADDR_NONCANONICAL; card->options.fake_broadcast = 0; card->options.add_hhlen = DEFAULT_ADD_HHLEN; card->options.fake_ll = 0; if (card->info.type == QETH_CARD_TYPE_OSN) card->options.layer2 = 1; else card->options.layer2 = 0;}/** * initialize channels ,card and all state machines */static intqeth_setup_card(struct qeth_card *card){ QETH_DBF_TEXT(setup, 2, "setupcrd"); QETH_DBF_HEX(setup, 2, &card, sizeof(void *)); card->read.state = CH_STATE_DOWN; card->write.state = CH_STATE_DOWN; card->data.state = CH_STATE_DOWN; card->state = CARD_STATE_DOWN; card->lan_online = 0; card->use_hard_stop = 0; card->dev = NULL;#ifdef CONFIG_QETH_VLAN spin_lock_init(&card->vlanlock); card->vlangrp = NULL;#endif spin_lock_init(&card->lock); spin_lock_init(&card->ip_lock); spin_lock_init(&card->thread_mask_lock); card->thread_start_mask = 0; card->thread_allowed_mask = 0; card->thread_running_mask = 0; INIT_WORK(&card->kernel_thread_starter, (void *)qeth_start_kernel_thread,card); INIT_LIST_HEAD(&card->ip_list); card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL); if (!card->ip_tbd_list) { QETH_DBF_TEXT(setup, 0, "iptbdnom"); return -ENOMEM; } INIT_LIST_HEAD(card->ip_tbd_list); INIT_LIST_HEAD(&card->cmd_waiter_list); init_waitqueue_head(&card->wait_q); /* intial options */ qeth_set_intial_options(card); /* IP address takeover */ INIT_LIST_HEAD(&card->ipato.entries); card->ipato.enabled = 0; card->ipato.invert4 = 0; card->ipato.invert6 = 0; /* init QDIO stuff */ qeth_init_qdio_info(card); return 0;}static intis_1920_device (struct qeth_card *card){ int single_queue = 0; struct ccw_device *ccwdev; struct channelPath_dsc { u8 flags; u8 lsn; u8 desc; u8 chpid; u8 swla; u8 zeroes; u8 chla; u8 chpp; } *chp_dsc; QETH_DBF_TEXT(setup, 2, "chk_1920"); ccwdev = card->data.ccwdev; chp_dsc = (struct channelPath_dsc *)ccw_device_get_chp_desc(ccwdev, 0); if (chp_dsc != NULL) { /* CHPP field bit 6 == 1 -> single queue */ single_queue = ((chp_dsc->chpp & 0x02) == 0x02); kfree(chp_dsc); } QETH_DBF_TEXT_(setup, 2, "rc:%x", single_queue); return single_queue;}static intqeth_determine_card_type(struct qeth_card *card){ int i = 0; QETH_DBF_TEXT(setup, 2, "detcdtyp"); card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; while (known_devices[i][4]) { if ((CARD_RDEV(card)->id.dev_type == known_devices[i][2]) && (CARD_RDEV(card)->id.dev_model == known_devices[i][3])) { card->info.type = known_devices[i][4]; card->qdio.no_out_queues = known_devices[i][8]; card->info.is_multicast_different = known_devices[i][9]; if (is_1920_device(card)) { PRINT_INFO("Priority Queueing not able " "due to hardware limitations!\n"); card->qdio.no_out_queues = 1; card->qdio.default_out_queue = 0; } return 0; } i++; } card->info.type = QETH_CARD_TYPE_UNKNOWN; PRINT_ERR("unknown card type on device %s\n", CARD_BUS_ID(card)); return -ENOENT;}static intqeth_probe_device(struct ccwgroup_device *gdev){ struct qeth_card *card; struct device *dev; unsigned long flags; int rc; QETH_DBF_TEXT(setup, 2, "probedev"); dev = &gdev->dev; if (!get_device(dev)) return -ENODEV; QETH_DBF_TEXT_(setup, 2, "%s", gdev->dev.bus_id); card = qeth_alloc_card(); if (!card) { put_device(dev); QETH_DBF_TEXT_(setup, 2, "1err%d", -ENOMEM); return -ENOMEM; } card->read.ccwdev = gdev->cdev[0]; card->write.ccwdev = gdev->cdev[1]; card->data.ccwdev = gdev->cdev[2]; gdev->dev.driver_data = card; card->gdev = gdev; gdev->cdev[0]->handler = qeth_irq; gdev->cdev[1]->handler = qeth_irq; gdev->cdev[2]->handler = qeth_irq; if ((rc = qeth_determine_card_type(card))){ PRINT_WARN("%s: not a valid card type\n", __func__); QETH_DBF_TEXT_(setup, 2, "3err%d", rc); put_device(dev); qeth_free_card(card); return rc; } if ((rc = qeth_setup_card(card))){ QETH_DBF_TEXT_(setup, 2, "2err%d", rc); put_device(dev); qeth_free_card(card); return rc; } rc = qeth_create_device_attributes(dev); if (rc) { put_device(dev); qeth_free_card(card); return rc; } /* insert into our internal list */ write_lock_irqsave(&qeth_card_list.rwlock, flags); list_add_tail(&card->list, &qeth_card_list.list); write_unlock_irqrestore(&qeth_card_list.rwlock, flags); return rc;}static intqeth_get_unitaddr(struct qeth_card *card){ int length; char *prcd; int rc; QETH_DBF_TEXT(setup, 2, "getunit"); rc = read_conf_data(CARD_DDEV(card), (void **) &prcd, &length); if (rc) { PRINT_ERR("read_conf_data for device %s returned %i\n", CARD_DDEV_ID(card), rc); return rc; } card->info.chpid = prcd[30]; card->info.unit_addr2 = prcd[31]; card->info.cula = prcd[63]; card->info.guestlan = ((prcd[0x10] == _ascebc['V']) && (prcd[0x11] == _ascebc['M'])); return 0;}static voidqeth_init_tokens(struct qeth_card *card){ card->token.issuer_rm_w = 0x00010103UL; card->token.cm_filter_w = 0x00010108UL; card->token.cm_connection_w = 0x0001010aUL; card->token.ulp_filter_w = 0x0001010bUL; card->token.ulp_connection_w = 0x0001010dUL;}static inline __u16raw_devno_from_bus_id(char *id){ id += (strlen(id) - 4); return (__u16) simple_strtoul(id, &id, 16);}/** * setup channel */static voidqeth_setup_ccw(struct qeth_channel *channel,unsigned char *iob, __u32 len){ struct qeth_card *card; QETH_DBF_TEXT(trace, 4, "setupccw"); card = CARD_FROM_CDEV(channel->ccwdev); if (channel == &card->read) memcpy(&channel->ccw, READ_CCW, sizeof(struct ccw1)); else memcpy(&channel->ccw, WRITE_CCW, sizeof(struct ccw1)); channel->ccw.count = len; channel->ccw.cda = (__u32) __pa(iob);}/** * get free buffer for ccws (IDX activation, lancmds,ipassists...) */static struct qeth_cmd_buffer *__qeth_get_buffer(struct qeth_channel *channel){ __u8 index; QETH_DBF_TEXT(trace, 6, "getbuff"); index = channel->io_buf_no; do { if (channel->iob[index].state == BUF_STATE_FREE) { channel->iob[index].state = BUF_STATE_LOCKED; channel->io_buf_no = (channel->io_buf_no + 1) % QETH_CMD_BUFFER_NO; memset(channel->iob[index].data, 0, QETH_BUFSIZE); return channel->iob + index; } index = (index + 1) % QETH_CMD_BUFFER_NO; } while(index != channel->io_buf_no); return NULL;}/** * release command buffer */static voidqeth_release_buffer(struct qeth_channel *channel, struct qeth_cmd_buffer *iob){ unsigned long flags; QETH_DBF_TEXT(trace, 6, "relbuff"); spin_lock_irqsave(&channel->iob_lock, flags); memset(iob->data, 0, QETH_BUFSIZE); iob->state = BUF_STATE_FREE; iob->callback = qeth_send_control_data_cb; iob->rc = 0; spin_unlock_irqrestore(&channel->iob_lock, flags);}static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *channel){ struct qeth_cmd_buffer *buffer = NULL; unsigned long flags; spin_lock_irqsave(&channel->iob_lock, flags); buffer = __qeth_get_buffer(channel); spin_unlock_irqrestore(&channel->iob_lock, flags); return buffer;}static struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *channel){ struct qeth_cmd_buffer *buffer; wait_event(channel->wait_q, ((buffer = qeth_get_buffer(channel)) != NULL)); return buffer;}static voidqeth_clear_cmd_buffers(struct qeth_channel *channel){ int cnt = 0; for (cnt=0; cnt < QETH_CMD_BUFFER_NO; cnt++) qeth_release_buffer(channel,&channel->iob[cnt]); channel->buf_no = 0; channel->io_buf_no = 0;}/** * start IDX for read and write channel */static intqeth_idx_activate_get_answer(struct qeth_channel *channel, void (*idx_reply_cb)(struct qeth_channel *, struct qeth_cmd_buffer *)){ struct qeth_cmd_buffer *iob; unsigned long flags; int rc; struct qeth_card *card; QETH_DBF_TEXT(setup, 2, "idxanswr"); card = CARD_FROM_CDEV(channel->ccwdev); iob = qeth_get_buffer(channel); iob->callback = idx_reply_cb; memcpy(&channel->ccw, READ_CCW, sizeof(struct ccw1)); channel->ccw.count = QETH_BUFSIZE; channel->ccw.cda = (__u32) __pa(iob->data); wait_event(card->wait_q, atomic_compare_and_swap(0,1,&channel->irq_pending) == 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: Error2 in activating channel rc=%d\n",rc); QETH_DBF_TEXT_(setup, 2, "2err%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_UP, QETH_TIMEOUT); if (rc == -ERESTARTSYS) return rc; if (channel->state != CH_STATE_UP){ rc = -ETIME; QETH_DBF_TEXT_(setup, 2, "3err%d", rc); qeth_clear_cmd_buffers(channel); } else rc = 0; return rc;}static intqeth_idx_activate_channel(struct qeth_channel *channel, void (*idx_reply_cb)(struct qeth_channel *, struct qeth_cmd_buffer *)){ struct qeth_card *card; struct qeth_cmd_buffer *iob; unsigned long flags; __u16 temp; int rc; card = CARD_FROM_CDEV(channel->ccwdev); QETH_DBF_TEXT(setup, 2, "idxactch"); iob = qeth_get_buffer(channel); iob->callback = idx_reply_cb; memcpy(&channel->ccw, WRITE_CCW, sizeof(struct ccw1)); channel->ccw.count = IDX_ACTIVATE_SIZE; channel->ccw.cda = (__u32) __pa(iob->data); if (channel == &card->write) { memcpy(iob->data, IDX_ACTIVATE_WRITE, IDX_ACTIVATE_SIZE); memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); card->seqno.trans_hdr++; } else { memcpy(iob->data, IDX_ACTIVATE_READ, IDX_ACTIVATE_SIZE); memcpy(QETH_TRANSPORT_HEADER_SEQ_NO(iob->data), &card->seqno.trans_hdr, QETH_SEQ_NO_LENGTH); } memcpy(QETH_IDX_ACT_ISSUER_RM_TOKEN(iob->data), &card->token.issuer_rm_w,QETH_MPC_TOKEN_LENGTH); memcpy(QETH_IDX_ACT_FUNC_LEVEL(iob->data), &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_compare_and_swap(0,1,&channel->irq_pending) == 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -