📄 ipmi_msghandler.c
字号:
intf->sent_local_commands); out += sprintf(out, "handled_local_responses: %d\n", intf->handled_local_responses); out += sprintf(out, "unhandled_local_responses: %d\n", intf->unhandled_local_responses); out += sprintf(out, "sent_ipmb_commands: %d\n", intf->sent_ipmb_commands); out += sprintf(out, "sent_ipmb_command_errs: %d\n", intf->sent_ipmb_command_errs); out += sprintf(out, "retransmitted_ipmb_commands: %d\n", intf->retransmitted_ipmb_commands); out += sprintf(out, "timed_out_ipmb_commands: %d\n", intf->timed_out_ipmb_commands); out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n", intf->timed_out_ipmb_broadcasts); out += sprintf(out, "sent_ipmb_responses: %d\n", intf->sent_ipmb_responses); out += sprintf(out, "handled_ipmb_responses: %d\n", intf->handled_ipmb_responses); out += sprintf(out, "invalid_ipmb_responses: %d\n", intf->invalid_ipmb_responses); out += sprintf(out, "unhandled_ipmb_responses: %d\n", intf->unhandled_ipmb_responses); out += sprintf(out, "sent_lan_commands: %d\n", intf->sent_lan_commands); out += sprintf(out, "sent_lan_command_errs: %d\n", intf->sent_lan_command_errs); out += sprintf(out, "retransmitted_lan_commands: %d\n", intf->retransmitted_lan_commands); out += sprintf(out, "timed_out_lan_commands: %d\n", intf->timed_out_lan_commands); out += sprintf(out, "sent_lan_responses: %d\n", intf->sent_lan_responses); out += sprintf(out, "handled_lan_responses: %d\n", intf->handled_lan_responses); out += sprintf(out, "invalid_lan_responses: %d\n", intf->invalid_lan_responses); out += sprintf(out, "unhandled_lan_responses: %d\n", intf->unhandled_lan_responses); out += sprintf(out, "handled_commands: %d\n", intf->handled_commands); out += sprintf(out, "invalid_commands: %d\n", intf->invalid_commands); out += sprintf(out, "unhandled_commands: %d\n", intf->unhandled_commands); out += sprintf(out, "invalid_events: %d\n", intf->invalid_events); out += sprintf(out, "events: %d\n", intf->events); return (out - ((char *) page));}int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, read_proc_t *read_proc, write_proc_t *write_proc, void *data, struct module *owner){ struct proc_dir_entry *file; int rv = 0; struct ipmi_proc_entry *entry; /* Create a list element. */ entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; entry->name = kmalloc(strlen(name)+1, GFP_KERNEL); if (!entry->name) { kfree(entry); return -ENOMEM; } strcpy(entry->name, name); file = create_proc_entry(name, 0, smi->proc_dir); if (!file) { kfree(entry->name); kfree(entry); rv = -ENOMEM; } else { file->nlink = 1; file->data = data; file->read_proc = read_proc; file->write_proc = write_proc; file->owner = owner; /* Stick it on the list. */ entry->next = smi->proc_entries; smi->proc_entries = entry; } return rv;}static int add_proc_entries(ipmi_smi_t smi, int num){ int rv = 0; sprintf(smi->proc_dir_name, "%d", num); smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root); if (!smi->proc_dir) rv = -ENOMEM; else { smi->proc_dir->owner = THIS_MODULE; } if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "stats", stat_file_read_proc, NULL, smi, THIS_MODULE); if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "ipmb", ipmb_file_read_proc, NULL, smi, THIS_MODULE); if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "version", version_file_read_proc, NULL, smi, THIS_MODULE); return rv;}static void remove_proc_entries(ipmi_smi_t smi){ struct ipmi_proc_entry *entry; while (smi->proc_entries) { entry = smi->proc_entries; smi->proc_entries = entry->next; remove_proc_entry(entry->name, smi->proc_dir); kfree(entry->name); kfree(entry); } remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);}static intsend_channel_info_cmd(ipmi_smi_t intf, int chan){ struct kernel_ipmi_msg msg; unsigned char data[1]; struct ipmi_system_interface_addr si; si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si.channel = IPMI_BMC_CHANNEL; si.lun = 0; msg.netfn = IPMI_NETFN_APP_REQUEST; msg.cmd = IPMI_GET_CHANNEL_INFO_CMD; msg.data = data; msg.data_len = 1; data[0] = chan; return i_ipmi_request(NULL, intf, (struct ipmi_addr *) &si, 0, &msg, NULL, NULL, NULL, 0, intf->my_address, intf->my_lun, -1, 0);}static voidchannel_handler(ipmi_smi_t intf, struct ipmi_smi_msg *msg){ int rv = 0; int chan; if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2)) && (msg->rsp[1] == IPMI_GET_CHANNEL_INFO_CMD)) { /* It's the one we want */ if (msg->rsp[2] != 0) { /* Got an error from the channel, just go on. */ if (msg->rsp[2] == IPMI_INVALID_COMMAND_ERR) { /* If the MC does not support this command, that is legal. We just assume it has one IPMB at channel zero. */ intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB; rv = -ENOSYS; intf->curr_channel = IPMI_MAX_CHANNELS; wake_up(&intf->waitq); goto out; } goto next_channel; } if (msg->rsp_size < 6) { /* Message not big enough, just go on. */ goto next_channel; } chan = intf->curr_channel; intf->channels[chan].medium = msg->rsp[4] & 0x7f; intf->channels[chan].protocol = msg->rsp[5] & 0x1f; next_channel: intf->curr_channel++; if (intf->curr_channel >= IPMI_MAX_CHANNELS) wake_up(&intf->waitq); else rv = send_channel_info_cmd(intf, intf->curr_channel); if (rv) { /* Got an error somehow, just give up. */ intf->curr_channel = IPMI_MAX_CHANNELS; wake_up(&intf->waitq); printk(KERN_WARNING PFX "Error sending channel information: %d\n", rv); } } out: return;}int ipmi_register_smi(struct ipmi_smi_handlers *handlers, void *send_info, unsigned char version_major, unsigned char version_minor, ipmi_smi_t *intf){ int i, j; int rv; ipmi_smi_t new_intf; unsigned long flags; /* Make sure the driver is actually initialized, this handles problems with initialization order. */ if (!initialized) { rv = ipmi_init_msghandler(); if (rv) return rv; /* The init code doesn't return an error if it was turned off, but it won't initialize. Check that. */ if (!initialized) return -ENODEV; } new_intf = kmalloc(sizeof(*new_intf), GFP_KERNEL); if (!new_intf) return -ENOMEM; memset(new_intf, 0, sizeof(*new_intf)); new_intf->proc_dir = NULL; rv = -ENOMEM; down_write(&interfaces_sem); for (i=0; i<MAX_IPMI_INTERFACES; i++) { if (ipmi_interfaces[i] == NULL) { new_intf->intf_num = i; new_intf->version_major = version_major; new_intf->version_minor = version_minor; new_intf->my_address = IPMI_BMC_SLAVE_ADDR; new_intf->my_lun = 2; /* the SMS LUN. */ rwlock_init(&(new_intf->users_lock)); INIT_LIST_HEAD(&(new_intf->users)); new_intf->handlers = handlers; new_intf->send_info = send_info; spin_lock_init(&(new_intf->seq_lock)); for (j=0; j<IPMI_IPMB_NUM_SEQ; j++) { new_intf->seq_table[j].inuse = 0; new_intf->seq_table[j].seqid = 0; } new_intf->curr_seq = 0; spin_lock_init(&(new_intf->waiting_msgs_lock)); INIT_LIST_HEAD(&(new_intf->waiting_msgs)); spin_lock_init(&(new_intf->events_lock)); INIT_LIST_HEAD(&(new_intf->waiting_events)); new_intf->waiting_events_count = 0; rwlock_init(&(new_intf->cmd_rcvr_lock)); init_waitqueue_head(&new_intf->waitq); INIT_LIST_HEAD(&(new_intf->cmd_rcvrs)); new_intf->all_cmd_rcvr = NULL; spin_lock_init(&(new_intf->counter_lock)); spin_lock_irqsave(&interfaces_lock, flags); ipmi_interfaces[i] = new_intf; spin_unlock_irqrestore(&interfaces_lock, flags); rv = 0; *intf = new_intf; break; } } downgrade_write(&interfaces_sem); if (rv == 0) rv = add_proc_entries(*intf, i); if (rv == 0) { if ((version_major > 1) || ((version_major == 1) && (version_minor >= 5))) { /* Start scanning the channels to see what is available. */ (*intf)->null_user_handler = channel_handler; (*intf)->curr_channel = 0; rv = send_channel_info_cmd(*intf, 0); if (rv) goto out; /* Wait for the channel info to be read. */ up_read(&interfaces_sem); wait_event((*intf)->waitq, ((*intf)->curr_channel>=IPMI_MAX_CHANNELS)); down_read(&interfaces_sem); if (ipmi_interfaces[i] != new_intf) /* Well, it went away. Just return. */ goto out; } else { /* Assume a single IPMB channel at zero. */ (*intf)->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; (*intf)->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB; } /* Call all the watcher interfaces to tell them that a new interface is available. */ call_smi_watchers(i); } out: up_read(&interfaces_sem); if (rv) { if (new_intf->proc_dir) remove_proc_entries(new_intf); kfree(new_intf); } return rv;}static void free_recv_msg_list(struct list_head *q){ struct ipmi_recv_msg *msg, *msg2; list_for_each_entry_safe(msg, msg2, q, link) { list_del(&msg->link); ipmi_free_recv_msg(msg); }}static void free_cmd_rcvr_list(struct list_head *q){ struct cmd_rcvr *rcvr, *rcvr2; list_for_each_entry_safe(rcvr, rcvr2, q, link) { list_del(&rcvr->link); kfree(rcvr); }}static void clean_up_interface_data(ipmi_smi_t intf){ int i; free_recv_msg_list(&(intf->waiting_msgs)); free_recv_msg_list(&(intf->waiting_events)); free_cmd_rcvr_list(&(intf->cmd_rcvrs)); for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) { if ((intf->seq_table[i].inuse) && (intf->seq_table[i].recv_msg)) { ipmi_free_recv_msg(intf->seq_table[i].recv_msg); } }}int ipmi_unregister_smi(ipmi_smi_t intf){ int rv = -ENODEV; int i; struct ipmi_smi_watcher *w; unsigned long flags; down_write(&interfaces_sem); if (list_empty(&(intf->users))) { for (i=0; i<MAX_IPMI_INTERFACES; i++) { if (ipmi_interfaces[i] == intf) { remove_proc_entries(intf); spin_lock_irqsave(&interfaces_lock, flags); ipmi_interfaces[i] = NULL; clean_up_interface_data(intf); spin_unlock_irqrestore(&interfaces_lock,flags); kfree(intf); rv = 0; goto out_call_watcher; } } } else { rv = -EBUSY; } up_write(&interfaces_sem); return rv; out_call_watcher: downgrade_write(&interfaces_sem); /* Call all the watcher interfaces to tell them that an interface is gone. */ down_read(&smi_watchers_sem); list_for_each_entry(w, &smi_watchers, link) { w->smi_gone(i); } up_read(&smi_watchers_sem); up_read(&interfaces_sem); return 0;}static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg){ struct ipmi_ipmb_addr ipmb_addr; struct ipmi_recv_msg *recv_msg; unsigned long flags; /* This is 11, not 10, because the response must contain a * completion code. */ if (msg->rsp_size < 11) { /* Message not big enough, just ignore it. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->invalid_ipmb_responses++; spin_unlock_irqrestore(&intf->counter_lock, flags); return 0; } if (msg->rsp[2] != 0) { /* An error getting the response, just ignore it. */ return 0; } ipmb_addr.addr_type = IPMI_IPMB_ADDR_TYPE; ipmb_addr.slave_addr = msg->rsp[6]; ipmb_addr.channel = msg->rsp[3] & 0x0f; ipmb_addr.lun = msg->rsp[7] & 3; /* It's a response from a remote entity. Look up the sequence number and handle the response. */ if (intf_find_seq(intf, msg->rsp[7] >> 2, msg->rsp[3] & 0x0f, msg->rsp[8], (msg->rsp[4] >> 2) & (~1), (struct ipmi_addr *) &(ipmb_addr), &recv_msg)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -