ipmi_msghandler.c
来自「linux 内核源代码」· C语言 代码 · 共 2,407 行 · 第 1/5 页
C
2,407 行
int ipmi_get_my_address(ipmi_user_t user, unsigned int channel, unsigned char *address){ if (channel >= IPMI_MAX_CHANNELS) return -EINVAL; *address = user->intf->channels[channel].address; return 0;}int ipmi_set_my_LUN(ipmi_user_t user, unsigned int channel, unsigned char LUN){ if (channel >= IPMI_MAX_CHANNELS) return -EINVAL; user->intf->channels[channel].lun = LUN & 0x3; return 0;}int ipmi_get_my_LUN(ipmi_user_t user, unsigned int channel, unsigned char *address){ if (channel >= IPMI_MAX_CHANNELS) return -EINVAL; *address = user->intf->channels[channel].lun; return 0;}int ipmi_get_maintenance_mode(ipmi_user_t user){ int mode; unsigned long flags; spin_lock_irqsave(&user->intf->maintenance_mode_lock, flags); mode = user->intf->maintenance_mode; spin_unlock_irqrestore(&user->intf->maintenance_mode_lock, flags); return mode;}EXPORT_SYMBOL(ipmi_get_maintenance_mode);static void maintenance_mode_update(ipmi_smi_t intf){ if (intf->handlers->set_maintenance_mode) intf->handlers->set_maintenance_mode( intf->send_info, intf->maintenance_mode_enable);}int ipmi_set_maintenance_mode(ipmi_user_t user, int mode){ int rv = 0; unsigned long flags; ipmi_smi_t intf = user->intf; spin_lock_irqsave(&intf->maintenance_mode_lock, flags); if (intf->maintenance_mode != mode) { switch (mode) { case IPMI_MAINTENANCE_MODE_AUTO: intf->maintenance_mode = mode; intf->maintenance_mode_enable = (intf->auto_maintenance_timeout > 0); break; case IPMI_MAINTENANCE_MODE_OFF: intf->maintenance_mode = mode; intf->maintenance_mode_enable = 0; break; case IPMI_MAINTENANCE_MODE_ON: intf->maintenance_mode = mode; intf->maintenance_mode_enable = 1; break; default: rv = -EINVAL; goto out_unlock; } maintenance_mode_update(intf); } out_unlock: spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags); return rv;}EXPORT_SYMBOL(ipmi_set_maintenance_mode);int ipmi_set_gets_events(ipmi_user_t user, int val){ unsigned long flags; ipmi_smi_t intf = user->intf; struct ipmi_recv_msg *msg, *msg2; struct list_head msgs; INIT_LIST_HEAD(&msgs); spin_lock_irqsave(&intf->events_lock, flags); user->gets_events = val; if (intf->delivering_events) /* * Another thread is delivering events for this, so * let it handle any new events. */ goto out; /* Deliver any queued events. */ while (user->gets_events && !list_empty(&intf->waiting_events)) { list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) list_move_tail(&msg->link, &msgs); intf->waiting_events_count = 0; intf->delivering_events = 1; spin_unlock_irqrestore(&intf->events_lock, flags); list_for_each_entry_safe(msg, msg2, &msgs, link) { msg->user = user; kref_get(&user->refcount); deliver_response(msg); } spin_lock_irqsave(&intf->events_lock, flags); intf->delivering_events = 0; } out: spin_unlock_irqrestore(&intf->events_lock, flags); return 0;}static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf, unsigned char netfn, unsigned char cmd, unsigned char chan){ struct cmd_rcvr *rcvr; list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd) && (rcvr->chans & (1 << chan))) return rcvr; } return NULL;}static int is_cmd_rcvr_exclusive(ipmi_smi_t intf, unsigned char netfn, unsigned char cmd, unsigned int chans){ struct cmd_rcvr *rcvr; list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd) && (rcvr->chans & chans)) return 0; } return 1;}int ipmi_register_for_cmd(ipmi_user_t user, unsigned char netfn, unsigned char cmd, unsigned int chans){ ipmi_smi_t intf = user->intf; struct cmd_rcvr *rcvr; int rv = 0; rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL); if (!rcvr) return -ENOMEM; rcvr->cmd = cmd; rcvr->netfn = netfn; rcvr->chans = chans; rcvr->user = user; mutex_lock(&intf->cmd_rcvrs_mutex); /* Make sure the command/netfn is not already registered. */ if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) { rv = -EBUSY; goto out_unlock; } list_add_rcu(&rcvr->link, &intf->cmd_rcvrs); out_unlock: mutex_unlock(&intf->cmd_rcvrs_mutex); if (rv) kfree(rcvr); return rv;}int ipmi_unregister_for_cmd(ipmi_user_t user, unsigned char netfn, unsigned char cmd, unsigned int chans){ ipmi_smi_t intf = user->intf; struct cmd_rcvr *rcvr; struct cmd_rcvr *rcvrs = NULL; int i, rv = -ENOENT; mutex_lock(&intf->cmd_rcvrs_mutex); for (i = 0; i < IPMI_NUM_CHANNELS; i++) { if (((1 << i) & chans) == 0) continue; rcvr = find_cmd_rcvr(intf, netfn, cmd, i); if (rcvr == NULL) continue; if (rcvr->user == user) { rv = 0; rcvr->chans &= ~chans; if (rcvr->chans == 0) { list_del_rcu(&rcvr->link); rcvr->next = rcvrs; rcvrs = rcvr; } } } mutex_unlock(&intf->cmd_rcvrs_mutex); synchronize_rcu(); while (rcvrs) { rcvr = rcvrs; rcvrs = rcvr->next; kfree(rcvr); } return rv;}void ipmi_user_set_run_to_completion(ipmi_user_t user, int val){ ipmi_smi_t intf = user->intf; if (intf->handlers) intf->handlers->set_run_to_completion(intf->send_info, val);}static unsigned charipmb_checksum(unsigned char *data, int size){ unsigned char csum = 0; for (; size > 0; size--, data++) csum += *data; return -csum;}static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg, struct kernel_ipmi_msg *msg, struct ipmi_ipmb_addr *ipmb_addr, long msgid, unsigned char ipmb_seq, int broadcast, unsigned char source_address, unsigned char source_lun){ int i = broadcast; /* Format the IPMB header data. */ smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); smi_msg->data[1] = IPMI_SEND_MSG_CMD; smi_msg->data[2] = ipmb_addr->channel; if (broadcast) smi_msg->data[3] = 0; smi_msg->data[i+3] = ipmb_addr->slave_addr; smi_msg->data[i+4] = (msg->netfn << 2) | (ipmb_addr->lun & 0x3); smi_msg->data[i+5] = ipmb_checksum(&(smi_msg->data[i+3]), 2); smi_msg->data[i+6] = source_address; smi_msg->data[i+7] = (ipmb_seq << 2) | source_lun; smi_msg->data[i+8] = msg->cmd; /* Now tack on the data to the message. */ if (msg->data_len > 0) memcpy(&(smi_msg->data[i+9]), msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 9; /* Now calculate the checksum and tack it on. */ smi_msg->data[i+smi_msg->data_size] = ipmb_checksum(&(smi_msg->data[i+6]), smi_msg->data_size-6); /* Add on the checksum size and the offset from the broadcast. */ smi_msg->data_size += 1 + i; smi_msg->msgid = msgid;}static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg, struct kernel_ipmi_msg *msg, struct ipmi_lan_addr *lan_addr, long msgid, unsigned char ipmb_seq, unsigned char source_lun){ /* Format the IPMB header data. */ smi_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); smi_msg->data[1] = IPMI_SEND_MSG_CMD; smi_msg->data[2] = lan_addr->channel; smi_msg->data[3] = lan_addr->session_handle; smi_msg->data[4] = lan_addr->remote_SWID; smi_msg->data[5] = (msg->netfn << 2) | (lan_addr->lun & 0x3); smi_msg->data[6] = ipmb_checksum(&(smi_msg->data[4]), 2); smi_msg->data[7] = lan_addr->local_SWID; smi_msg->data[8] = (ipmb_seq << 2) | source_lun; smi_msg->data[9] = msg->cmd; /* Now tack on the data to the message. */ if (msg->data_len > 0) memcpy(&(smi_msg->data[10]), msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 10; /* Now calculate the checksum and tack it on. */ smi_msg->data[smi_msg->data_size] = ipmb_checksum(&(smi_msg->data[7]), smi_msg->data_size-7); /* Add on the checksum size and the offset from the broadcast. */ smi_msg->data_size += 1; smi_msg->msgid = msgid;}/* Separate from ipmi_request so that the user does not have to be supplied in certain circumstances (mainly at panic time). If messages are supplied, they will be freed, even if an error occurs. */static int i_ipmi_request(ipmi_user_t user, ipmi_smi_t intf, 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 source_address, unsigned char source_lun, int retries, unsigned int retry_time_ms){ int rv = 0; struct ipmi_smi_msg *smi_msg; struct ipmi_recv_msg *recv_msg; unsigned long flags; struct ipmi_smi_handlers *handlers; if (supplied_recv) { recv_msg = supplied_recv; } else { recv_msg = ipmi_alloc_recv_msg(); if (recv_msg == NULL) { return -ENOMEM; } } recv_msg->user_msg_data = user_msg_data; if (supplied_smi) { smi_msg = (struct ipmi_smi_msg *) supplied_smi; } else { smi_msg = ipmi_alloc_smi_msg(); if (smi_msg == NULL) { ipmi_free_recv_msg(recv_msg); return -ENOMEM; } } rcu_read_lock(); handlers = intf->handlers; if (!handlers) { rv = -ENODEV; goto out_err; } recv_msg->user = user; if (user) kref_get(&user->refcount); recv_msg->msgid = msgid; /* Store the message to send in the receive message so timeout responses can get the proper response data. */ recv_msg->msg = *msg; if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { struct ipmi_system_interface_addr *smi_addr; if (msg->netfn & 1) { /* Responses are not allowed to the SMI. */ rv = -EINVAL; goto out_err; } smi_addr = (struct ipmi_system_interface_addr *) addr; if (smi_addr->lun > 3) { spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); rv = -EINVAL; goto out_err; } memcpy(&recv_msg->addr, smi_addr, sizeof(*smi_addr)); if ((msg->netfn == IPMI_NETFN_APP_REQUEST) && ((msg->cmd == IPMI_SEND_MSG_CMD) || (msg->cmd == IPMI_GET_MSG_CMD) || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) { /* We don't let the user do these, since we manage the sequence numbers. */ spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); rv = -EINVAL; goto out_err; } if (((msg->netfn == IPMI_NETFN_APP_REQUEST) && ((msg->cmd == IPMI_COLD_RESET_CMD) || (msg->cmd == IPMI_WARM_RESET_CMD))) || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) { spin_lock_irqsave(&intf->maintenance_mode_lock, flags); intf->auto_maintenance_timeout = IPMI_MAINTENANCE_MODE_TIMEOUT; if (!intf->maintenance_mode && !intf->maintenance_mode_enable) { intf->maintenance_mode_enable = 1; maintenance_mode_update(intf); } spin_unlock_irqrestore(&intf->maintenance_mode_lock, flags); } if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) { spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); rv = -EMSGSIZE; goto out_err; } smi_msg->data[0] = (msg->netfn << 2) | (smi_addr->lun & 0x3); smi_msg->data[1] = msg->cmd; smi_msg->msgid = msgid; smi_msg->user_data = recv_msg; if (msg->data_len > 0) memcpy(&(smi_msg->data[2]), msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 2; spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_local_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE) || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) { struct ipmi_ipmb_addr *ipmb_addr; unsigned char ipmb_seq; long seqid; int broadcast = 0; if (addr->channel >= IPMI_MAX_CHANNELS) { spin_lock_irqsave(&intf->counter_lock, flags); intf->sent_invalid_commands++; spin_unlock_irqrestore(&intf->counter_lock, flags); rv = -EINVAL; goto out_err; } if (intf->channels[addr->channel].medium != IPMI_CHANNEL_MEDIUM_IPMB) { spin_lock_irqsave(&intf->counter_lock, flags);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?