📄 ipmi_msghandler.c
字号:
/* We have used up all the sequence numbers, probably, so abort. */ spin_unlock_irqrestore(&(intf->seq_lock), flags); goto out_err; } /* Store the sequence number in the message, so that when the send message response comes back we can start the timer. */ format_lan_msg(smi_msg, msg, lan_addr, STORE_SEQ_IN_MSGID(ipmb_seq, seqid), ipmb_seq, source_lun); /* Copy the message into the recv message data, so we can retransmit it later if necessary. */ memcpy(recv_msg->msg_data, smi_msg->data, smi_msg->data_size); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = smi_msg->data_size; /* We don't unlock until here, because we need to copy the completed message into the recv_msg before we release the lock. Otherwise, race conditions may bite us. I know that's pretty paranoid, but I prefer to be correct. */ spin_unlock_irqrestore(&(intf->seq_lock), flags); } } else { /* Unknown address type. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); rv = -EINVAL; goto out_err; }#ifdef DEBUG_MSGING { int m; for (m = 0; m < smi_msg->data_size; m++) printk(" %2.2x", smi_msg->data[m]); printk("\n"); }#endif intf->handlers->sender(intf->send_info, smi_msg, priority); return 0; out_err: ipmi_free_smi_msg(smi_msg); ipmi_free_recv_msg(recv_msg); return rv;}static int check_addr(ipmi_smi_t intf, struct ipmi_addr *addr, unsigned char *saddr, unsigned char *lun){ if (addr->channel >= IPMI_MAX_CHANNELS) return -EINVAL; *lun = intf->channels[addr->channel].lun; *saddr = intf->channels[addr->channel].address; return 0;}int ipmi_request_settime(ipmi_user_t user, struct ipmi_addr *addr, long msgid, struct kernel_ipmi_msg *msg, void *user_msg_data, int priority, int retries, unsigned int retry_time_ms){ unsigned char saddr, lun; int rv; if (! user) return -EINVAL; rv = check_addr(user->intf, addr, &saddr, &lun); if (rv) return rv; return i_ipmi_request(user, user->intf, addr, msgid, msg, user_msg_data, NULL, NULL, priority, saddr, lun, retries, retry_time_ms);}int ipmi_request_supply_msgs(ipmi_user_t user, struct ipmi_addr *addr, long msgid, struct kernel_ipmi_msg *msg, void *user_msg_data, void *supplied_smi, struct ipmi_recv_msg *supplied_recv, int priority){ unsigned char saddr, lun; int rv; if (! user) return -EINVAL; rv = check_addr(user->intf, addr, &saddr, &lun); if (rv) return rv; return i_ipmi_request(user, user->intf, addr, msgid, msg, user_msg_data, supplied_smi, supplied_recv, priority, saddr, lun, -1, 0);}static int ipmb_file_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ char *out = (char *) page; ipmi_smi_t intf = data; int i; int rv= 0; for (i = 0; i < IPMI_MAX_CHANNELS; i++) rv += sprintf(out+rv, "%x ", intf->channels[i].address); out[rv-1] = '\n'; /* Replace the final space with a newline */ out[rv] = '\0'; rv++; return rv;}static int version_file_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ char *out = (char *) page; ipmi_smi_t intf = data; return sprintf(out, "%d.%d\n", intf->version_major, intf->version_minor);}static int stat_file_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ char *out = (char *) page; ipmi_smi_t intf = data; out += sprintf(out, "sent_invalid_commands: %d\n", intf->sent_invalid_commands); out += sprintf(out, "sent_local_commands: %d\n", 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){ int rv = 0;#ifdef CONFIG_PROC_FS struct proc_dir_entry *file; 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; spin_lock(&smi->proc_entry_lock); /* Stick it on the list. */ entry->next = smi->proc_entries; smi->proc_entries = entry; spin_unlock(&smi->proc_entry_lock); }#endif /* CONFIG_PROC_FS */ return rv;}static int add_proc_entries(ipmi_smi_t smi, int num){ int rv = 0;#ifdef CONFIG_PROC_FS 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);#endif /* CONFIG_PROC_FS */ return rv;}static void remove_proc_entries(ipmi_smi_t smi){#ifdef CONFIG_PROC_FS struct ipmi_proc_entry *entry; spin_lock(&smi->proc_entry_lock); 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); } spin_unlock(&smi->proc_entry_lock); remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);#endif /* CONFIG_PROC_FS */}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, intf, NULL, NULL, 0, intf->channels[0].address, intf->channels[0].lun, -1, 0);}static voidchannel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg){ int rv = 0; int chan; if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) { /* It's the one we want */ if (msg->msg.data[0] != 0) { /* Got an error from the channel, just go on. */ if (msg->msg.data[0] == 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->msg.data_len < 4) { /* Message not big enough, just go on. */ goto next_channel; } chan = intf->curr_channel; intf->channels[chan].medium = msg->msg.data[2] & 0x7f; intf->channels[chan].protocol = msg->msg.data[3] & 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, unsigned char slave_addr, ipmi_smi_t *new_intf){ int i, j; int rv; ipmi_smi_t 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; } intf = kmalloc(sizeof(*intf), GFP_KERNEL); if (!intf) return -ENOMEM; memset(intf, 0, sizeof(*intf)); intf->intf_num = -1; kref_init(&intf->refcount); intf->version_major = version_major; intf->version_minor = version_minor; for (j = 0; j < IPMI_MAX_CHANNELS; j++) { intf->channels[j].address = IPMI_BMC_SLAVE_ADDR; intf->channels[j].lun = 2; } if (slave_addr != 0) intf->channels[0].address = slave_addr; INIT_LIST_HEAD(&intf->users); intf->handlers = handlers; intf->send_info = send_info; spin_lock_init(&intf->seq_lock); for (j = 0; j < IPMI_IPMB_NUM_SEQ; j++) { intf->seq_table[j].inuse = 0; intf->seq_table[j].seqid = 0; } intf->curr_seq = 0;#ifdef CONFIG_PROC_FS spin_lock_init(&intf->proc_entry_lock);#endif spin_lock_init(&intf->waiting_msgs_lock); INIT_LIST_HEAD(&intf->waiting_msgs); spin_lock_init(&intf->events_lock); INIT_LIST_HEAD(&intf->waiting_events); intf->waiting_events_count = 0; init_MUTEX(&intf->cmd_rcvrs_lock); INIT_LIST_HEAD(&intf->cmd_rcvrs); init_waitqueue_head(&intf->waitq); spin_lock_init(&intf->counter_lock); intf->proc_dir = NULL; rv = -ENOMEM; spin_lock_irqsave(&interfaces_lock, flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -