ipmi_msghandler.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,371 行 · 第 1/5 页
C
2,371 行
}static voidcleanup_bmc_device(struct kref *ref){ struct bmc_device *bmc; bmc = container_of(ref, struct bmc_device, refcount); device_remove_file(&bmc->dev->dev, &bmc->device_id_attr); device_remove_file(&bmc->dev->dev, &bmc->provides_dev_sdrs_attr); device_remove_file(&bmc->dev->dev, &bmc->revision_attr); device_remove_file(&bmc->dev->dev, &bmc->firmware_rev_attr); device_remove_file(&bmc->dev->dev, &bmc->version_attr); device_remove_file(&bmc->dev->dev, &bmc->add_dev_support_attr); device_remove_file(&bmc->dev->dev, &bmc->manufacturer_id_attr); device_remove_file(&bmc->dev->dev, &bmc->product_id_attr); if (bmc->id.aux_firmware_revision_set) device_remove_file(&bmc->dev->dev, &bmc->aux_firmware_rev_attr); if (bmc->guid_set) device_remove_file(&bmc->dev->dev, &bmc->guid_attr); platform_device_unregister(bmc->dev); kfree(bmc);}static void ipmi_bmc_unregister(ipmi_smi_t intf){ struct bmc_device *bmc = intf->bmc; sysfs_remove_link(&intf->si_dev->kobj, "bmc"); if (intf->my_dev_name) { sysfs_remove_link(&bmc->dev->dev.kobj, intf->my_dev_name); kfree(intf->my_dev_name); intf->my_dev_name = NULL; } mutex_lock(&ipmidriver_mutex); kref_put(&bmc->refcount, cleanup_bmc_device); mutex_unlock(&ipmidriver_mutex);}static int ipmi_bmc_register(ipmi_smi_t intf){ int rv; struct bmc_device *bmc = intf->bmc; struct bmc_device *old_bmc; int size; char dummy[1]; mutex_lock(&ipmidriver_mutex); /* * Try to find if there is an bmc_device struct * representing the interfaced BMC already */ if (bmc->guid_set) old_bmc = ipmi_find_bmc_guid(&ipmidriver, bmc->guid); else old_bmc = ipmi_find_bmc_prod_dev_id(&ipmidriver, bmc->id.product_id, bmc->id.device_id); /* * If there is already an bmc_device, free the new one, * otherwise register the new BMC device */ if (old_bmc) { kfree(bmc); intf->bmc = old_bmc; bmc = old_bmc; kref_get(&bmc->refcount); mutex_unlock(&ipmidriver_mutex); printk(KERN_INFO "ipmi: interfacing existing BMC (man_id: 0x%6.6x," " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", bmc->id.manufacturer_id, bmc->id.product_id, bmc->id.device_id); } else { bmc->dev = platform_device_alloc("ipmi_bmc", bmc->id.device_id); if (!bmc->dev) { printk(KERN_ERR "ipmi_msghandler:" " Unable to allocate platform device\n"); return -ENOMEM; } bmc->dev->dev.driver = &ipmidriver; dev_set_drvdata(&bmc->dev->dev, bmc); kref_init(&bmc->refcount); rv = platform_device_register(bmc->dev); mutex_unlock(&ipmidriver_mutex); if (rv) { printk(KERN_ERR "ipmi_msghandler:" " Unable to register bmc device: %d\n", rv); /* Don't go to out_err, you can only do that if the device is registered already. */ return rv; } bmc->device_id_attr.attr.name = "device_id"; bmc->device_id_attr.attr.owner = THIS_MODULE; bmc->device_id_attr.attr.mode = S_IRUGO; bmc->device_id_attr.show = device_id_show; bmc->provides_dev_sdrs_attr.attr.name = "provides_device_sdrs"; bmc->provides_dev_sdrs_attr.attr.owner = THIS_MODULE; bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO; bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show; bmc->revision_attr.attr.name = "revision"; bmc->revision_attr.attr.owner = THIS_MODULE; bmc->revision_attr.attr.mode = S_IRUGO; bmc->revision_attr.show = revision_show; bmc->firmware_rev_attr.attr.name = "firmware_revision"; bmc->firmware_rev_attr.attr.owner = THIS_MODULE; bmc->firmware_rev_attr.attr.mode = S_IRUGO; bmc->firmware_rev_attr.show = firmware_rev_show; bmc->version_attr.attr.name = "ipmi_version"; bmc->version_attr.attr.owner = THIS_MODULE; bmc->version_attr.attr.mode = S_IRUGO; bmc->version_attr.show = ipmi_version_show; bmc->add_dev_support_attr.attr.name = "additional_device_support"; bmc->add_dev_support_attr.attr.owner = THIS_MODULE; bmc->add_dev_support_attr.attr.mode = S_IRUGO; bmc->add_dev_support_attr.show = add_dev_support_show; bmc->manufacturer_id_attr.attr.name = "manufacturer_id"; bmc->manufacturer_id_attr.attr.owner = THIS_MODULE; bmc->manufacturer_id_attr.attr.mode = S_IRUGO; bmc->manufacturer_id_attr.show = manufacturer_id_show; bmc->product_id_attr.attr.name = "product_id"; bmc->product_id_attr.attr.owner = THIS_MODULE; bmc->product_id_attr.attr.mode = S_IRUGO; bmc->product_id_attr.show = product_id_show; bmc->guid_attr.attr.name = "guid"; bmc->guid_attr.attr.owner = THIS_MODULE; bmc->guid_attr.attr.mode = S_IRUGO; bmc->guid_attr.show = guid_show; bmc->aux_firmware_rev_attr.attr.name = "aux_firmware_revision"; bmc->aux_firmware_rev_attr.attr.owner = THIS_MODULE; bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO; bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show; device_create_file(&bmc->dev->dev, &bmc->device_id_attr); device_create_file(&bmc->dev->dev, &bmc->provides_dev_sdrs_attr); device_create_file(&bmc->dev->dev, &bmc->revision_attr); device_create_file(&bmc->dev->dev, &bmc->firmware_rev_attr); device_create_file(&bmc->dev->dev, &bmc->version_attr); device_create_file(&bmc->dev->dev, &bmc->add_dev_support_attr); device_create_file(&bmc->dev->dev, &bmc->manufacturer_id_attr); device_create_file(&bmc->dev->dev, &bmc->product_id_attr); if (bmc->id.aux_firmware_revision_set) device_create_file(&bmc->dev->dev, &bmc->aux_firmware_rev_attr); if (bmc->guid_set) device_create_file(&bmc->dev->dev, &bmc->guid_attr); printk(KERN_INFO "ipmi: Found new BMC (man_id: 0x%6.6x, " " prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n", bmc->id.manufacturer_id, bmc->id.product_id, bmc->id.device_id); } /* * create symlink from system interface device to bmc device * and back. */ rv = sysfs_create_link(&intf->si_dev->kobj, &bmc->dev->dev.kobj, "bmc"); if (rv) { printk(KERN_ERR "ipmi_msghandler: Unable to create bmc symlink: %d\n", rv); goto out_err; } size = snprintf(dummy, 0, "ipmi%d", intf->intf_num); intf->my_dev_name = kmalloc(size+1, GFP_KERNEL); if (!intf->my_dev_name) { rv = -ENOMEM; printk(KERN_ERR "ipmi_msghandler: allocate link from BMC: %d\n", rv); goto out_err; } snprintf(intf->my_dev_name, size+1, "ipmi%d", intf->intf_num); rv = sysfs_create_link(&bmc->dev->dev.kobj, &intf->si_dev->kobj, intf->my_dev_name); if (rv) { kfree(intf->my_dev_name); intf->my_dev_name = NULL; printk(KERN_ERR "ipmi_msghandler:" " Unable to create symlink to bmc: %d\n", rv); goto out_err; } return 0;out_err: ipmi_bmc_unregister(intf); return rv;}static intsend_guid_cmd(ipmi_smi_t intf, int chan){ struct kernel_ipmi_msg msg; 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_DEVICE_GUID_CMD; msg.data = NULL; msg.data_len = 0; 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 voidguid_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg){ if ((msg->addr.addr_type != IPMI_SYSTEM_INTERFACE_ADDR_TYPE) || (msg->msg.netfn != IPMI_NETFN_APP_RESPONSE) || (msg->msg.cmd != IPMI_GET_DEVICE_GUID_CMD)) /* Not for me */ return; if (msg->msg.data[0] != 0) { /* Error from getting the GUID, the BMC doesn't have one. */ intf->bmc->guid_set = 0; goto out; } if (msg->msg.data_len < 17) { intf->bmc->guid_set = 0; printk(KERN_WARNING PFX "guid_handler: The GUID response from the BMC was too" " short, it was %d but should have been 17. Assuming" " GUID is not available.\n", msg->msg.data_len); goto out; } memcpy(intf->bmc->guid, msg->msg.data, 16); intf->bmc->guid_set = 1; out: wake_up(&intf->waitq);}static voidget_guid(ipmi_smi_t intf){ int rv; intf->bmc->guid_set = 0x2; intf->null_user_handler = guid_handler; rv = send_guid_cmd(intf, 0); if (rv) /* Send failed, no GUID available. */ intf->bmc->guid_set = 0; wait_event(intf->waitq, intf->bmc->guid_set != 2); intf->null_user_handler = NULL;}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, struct ipmi_device_id *device_id, struct device *si_dev, unsigned char slave_addr){ int i, j; int rv; ipmi_smi_t intf; unsigned long flags; int version_major; int version_minor; version_major = ipmi_version_major(device_id); version_minor = ipmi_version_minor(device_id); /* 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->bmc = kzalloc(sizeof(*intf->bmc), GFP_KERNEL); if (!intf->bmc) { kfree(intf); return -ENOMEM; } intf->intf_num = -1; kref_init(&intf->refcount); intf->bmc->id = *device_id; intf->si_dev = si_dev; 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; mutex_init(&intf->cmd_rcvrs_mutex); INIT_LIST_HEAD(&intf->cmd_rcvrs);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?