📄 ipmi_msghandler.c
字号:
int rv = 0; unsigned int i; for (i=intf->curr_seq; (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; i=(i+1)%IPMI_IPMB_NUM_SEQ) { if (! intf->seq_table[i].inuse) break; } if (! intf->seq_table[i].inuse) { intf->seq_table[i].recv_msg = recv_msg; /* Start with the maximum timeout, when the send response comes in we will start the real timer. */ intf->seq_table[i].timeout = MAX_MSG_TIMEOUT; intf->seq_table[i].orig_timeout = timeout; intf->seq_table[i].retries_left = retries; intf->seq_table[i].broadcast = broadcast; intf->seq_table[i].inuse = 1; intf->seq_table[i].seqid = NEXT_SEQID(intf->seq_table[i].seqid); *seq = i; *seqid = intf->seq_table[i].seqid; intf->curr_seq = (i+1)%IPMI_IPMB_NUM_SEQ; } else { rv = -EAGAIN; } return rv;}/* Return the receive message for the given sequence number and release the sequence number so it can be reused. Some other data is passed in to be sure the message matches up correctly (to help guard against message coming in after their timeout and the sequence number being reused). */static int intf_find_seq(ipmi_smi_t intf, unsigned char seq, short channel, unsigned char cmd, unsigned char netfn, struct ipmi_addr *addr, struct ipmi_recv_msg **recv_msg){ int rv = -ENODEV; unsigned long flags; if (seq >= IPMI_IPMB_NUM_SEQ) return -EINVAL; spin_lock_irqsave(&(intf->seq_lock), flags); if (intf->seq_table[seq].inuse) { struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg; if ((msg->addr.channel == channel) && (msg->msg.cmd == cmd) && (msg->msg.netfn == netfn) && (ipmi_addr_equal(addr, &(msg->addr)))) { *recv_msg = msg; intf->seq_table[seq].inuse = 0; rv = 0; } } spin_unlock_irqrestore(&(intf->seq_lock), flags); return rv;}/* Start the timer for a specific sequence table entry. */static int intf_start_seq_timer(ipmi_smi_t intf, long msgid){ int rv = -ENODEV; unsigned long flags; unsigned char seq; unsigned long seqid; GET_SEQ_FROM_MSGID(msgid, seq, seqid); spin_lock_irqsave(&(intf->seq_lock), flags); /* We do this verification because the user can be deleted while a message is outstanding. */ if ((intf->seq_table[seq].inuse) && (intf->seq_table[seq].seqid == seqid)) { struct seq_table *ent = &(intf->seq_table[seq]); ent->timeout = ent->orig_timeout; rv = 0; } spin_unlock_irqrestore(&(intf->seq_lock), flags); return rv;}/* Got an error for the send message for a specific sequence number. */static int intf_err_seq(ipmi_smi_t intf, long msgid, unsigned int err){ int rv = -ENODEV; unsigned long flags; unsigned char seq; unsigned long seqid; struct ipmi_recv_msg *msg = NULL; GET_SEQ_FROM_MSGID(msgid, seq, seqid); spin_lock_irqsave(&(intf->seq_lock), flags); /* We do this verification because the user can be deleted while a message is outstanding. */ if ((intf->seq_table[seq].inuse) && (intf->seq_table[seq].seqid == seqid)) { struct seq_table *ent = &(intf->seq_table[seq]); ent->inuse = 0; msg = ent->recv_msg; rv = 0; } spin_unlock_irqrestore(&(intf->seq_lock), flags); if (msg) { msg->recv_type = IPMI_RESPONSE_RECV_TYPE; msg->msg_data[0] = err; msg->msg.netfn |= 1; /* Convert to a response. */ msg->msg.data_len = 1; msg->msg.data = msg->msg_data; deliver_response(msg); } return rv;}int ipmi_create_user(unsigned int if_num, struct ipmi_user_hndl *handler, void *handler_data, ipmi_user_t *user){ unsigned long flags; ipmi_user_t new_user; int rv = 0; /* There is no module usecount here, because it's not required. Since this can only be used by and called from other modules, they will implicitly use this module, and thus this can't be removed unless the other modules are removed. */ if (handler == NULL) return -EINVAL; /* 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_user = kmalloc(sizeof(*new_user), GFP_KERNEL); if (! new_user) return -ENOMEM; down_read(&interfaces_sem); if ((if_num > MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL) { rv = -EINVAL; goto out_unlock; } new_user->handler = handler; new_user->handler_data = handler_data; new_user->intf = ipmi_interfaces[if_num]; new_user->gets_events = 0; if (!try_module_get(new_user->intf->handlers->owner)) { rv = -ENODEV; goto out_unlock; } write_lock_irqsave(&new_user->intf->users_lock, flags); list_add_tail(&new_user->link, &new_user->intf->users); write_unlock_irqrestore(&new_user->intf->users_lock, flags); out_unlock: if (rv) { kfree(new_user); } else { *user = new_user; } up_read(&interfaces_sem); return rv;}static int ipmi_destroy_user_nolock(ipmi_user_t user){ int rv = -ENODEV; ipmi_user_t t_user; struct cmd_rcvr *rcvr, *rcvr2; int i; unsigned long flags; /* Find the user and delete them from the list. */ list_for_each_entry(t_user, &(user->intf->users), link) { if (t_user == user) { list_del(&t_user->link); rv = 0; break; } } if (rv) { goto out_unlock; } /* Remove the user from the interfaces sequence table. */ spin_lock_irqsave(&(user->intf->seq_lock), flags); for (i=0; i<IPMI_IPMB_NUM_SEQ; i++) { if (user->intf->seq_table[i].inuse && (user->intf->seq_table[i].recv_msg->user == user)) { user->intf->seq_table[i].inuse = 0; } } spin_unlock_irqrestore(&(user->intf->seq_lock), flags); /* Remove the user from the command receiver's table. */ write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags); list_for_each_entry_safe(rcvr, rcvr2, &(user->intf->cmd_rcvrs), link) { if (rcvr->user == user) { list_del(&rcvr->link); kfree(rcvr); } } write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags); kfree(user); out_unlock: return rv;}int ipmi_destroy_user(ipmi_user_t user){ int rv; ipmi_smi_t intf = user->intf; unsigned long flags; down_read(&interfaces_sem); write_lock_irqsave(&intf->users_lock, flags); rv = ipmi_destroy_user_nolock(user); if (!rv) module_put(intf->handlers->owner); write_unlock_irqrestore(&intf->users_lock, flags); up_read(&interfaces_sem); return rv;}void ipmi_get_version(ipmi_user_t user, unsigned char *major, unsigned char *minor){ *major = user->intf->version_major; *minor = user->intf->version_minor;}void ipmi_set_my_address(ipmi_user_t user, unsigned char address){ user->intf->my_address = address;}unsigned char ipmi_get_my_address(ipmi_user_t user){ return user->intf->my_address;}void ipmi_set_my_LUN(ipmi_user_t user, unsigned char LUN){ user->intf->my_lun = LUN & 0x3;}unsigned char ipmi_get_my_LUN(ipmi_user_t user){ return user->intf->my_lun;}int ipmi_set_gets_events(ipmi_user_t user, int val){ unsigned long flags; struct ipmi_recv_msg *msg, *msg2; read_lock(&(user->intf->users_lock)); spin_lock_irqsave(&(user->intf->events_lock), flags); user->gets_events = val; if (val) { /* Deliver any queued events. */ list_for_each_entry_safe(msg, msg2, &(user->intf->waiting_events), link) { list_del(&msg->link); msg->user = user; deliver_response(msg); } } spin_unlock_irqrestore(&(user->intf->events_lock), flags); read_unlock(&(user->intf->users_lock)); return 0;}int ipmi_register_for_cmd(ipmi_user_t user, unsigned char netfn, unsigned char cmd){ struct cmd_rcvr *cmp; unsigned long flags; struct cmd_rcvr *rcvr; int rv = 0; rcvr = kmalloc(sizeof(*rcvr), GFP_KERNEL); if (! rcvr) return -ENOMEM; read_lock(&(user->intf->users_lock)); write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags); if (user->intf->all_cmd_rcvr != NULL) { rv = -EBUSY; goto out_unlock; } /* Make sure the command/netfn is not already registered. */ list_for_each_entry(cmp, &(user->intf->cmd_rcvrs), link) { if ((cmp->netfn == netfn) && (cmp->cmd == cmd)) { rv = -EBUSY; break; } } if (! rv) { rcvr->cmd = cmd; rcvr->netfn = netfn; rcvr->user = user; list_add_tail(&(rcvr->link), &(user->intf->cmd_rcvrs)); } out_unlock: write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags); read_unlock(&(user->intf->users_lock)); if (rv) kfree(rcvr); return rv;}int ipmi_unregister_for_cmd(ipmi_user_t user, unsigned char netfn, unsigned char cmd){ unsigned long flags; struct cmd_rcvr *rcvr; int rv = -ENOENT; read_lock(&(user->intf->users_lock)); write_lock_irqsave(&(user->intf->cmd_rcvr_lock), flags); /* Make sure the command/netfn is not already registered. */ list_for_each_entry(rcvr, &(user->intf->cmd_rcvrs), link) { if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)) { rv = 0; list_del(&rcvr->link); kfree(rcvr); break; } } write_unlock_irqrestore(&(user->intf->cmd_rcvr_lock), flags); read_unlock(&(user->intf->users_lock)); return rv;}void ipmi_user_set_run_to_completion(ipmi_user_t user, int val){ user->intf->handlers->set_run_to_completion(user->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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -