-static int __find_bmc_guid(struct device *dev, void *data)
-{
- unsigned char *id = data;
- struct bmc_device *bmc = dev_get_drvdata(dev);
- return memcmp(bmc->guid, id, 16) == 0;
-}
-
-static struct bmc_device *ipmi_find_bmc_guid(struct device_driver *drv,
- unsigned char *guid)
-{
- struct device *dev;
-
- dev = driver_find_device(drv, NULL, guid, __find_bmc_guid);
- if (dev)
- return dev_get_drvdata(dev);
- else
- return NULL;
-}
-
-struct prod_dev_id {
- unsigned int product_id;
- unsigned char device_id;
-};
-
-static int __find_bmc_prod_dev_id(struct device *dev, void *data)
-{
- struct prod_dev_id *id = data;
- struct bmc_device *bmc = dev_get_drvdata(dev);
-
- return (bmc->id.product_id == id->product_id
- && bmc->id.product_id == id->product_id
- && bmc->id.device_id == id->device_id);
-}
-
-static struct bmc_device *ipmi_find_bmc_prod_dev_id(
- struct device_driver *drv,
- unsigned char product_id, unsigned char device_id)
-{
- struct prod_dev_id id = {
- .product_id = product_id,
- .device_id = device_id,
- };
- struct device *dev;
-
- dev = driver_find_device(drv, NULL, &id, __find_bmc_prod_dev_id);
- if (dev)
- return dev_get_drvdata(dev);
- else
- return NULL;
-}
-
-static ssize_t device_id_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bmc_device *bmc = dev_get_drvdata(dev);
-
- return snprintf(buf, 10, "%u\n", bmc->id.device_id);
-}
-
-static ssize_t provides_dev_sdrs_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bmc_device *bmc = dev_get_drvdata(dev);
-
- return snprintf(buf, 10, "%u\n",
- bmc->id.device_revision && 0x80 >> 7);
-}
-
-static ssize_t revision_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct bmc_device *bmc = dev_get_drvdata(dev);
-
- return snprintf(buf, 20, "%u\n",
- bmc->id.device_revision && 0x0F);
-}
-
-static ssize_t firmware_rev_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bmc_device *bmc = dev_get_drvdata(dev);
-
- return snprintf(buf, 20, "%u.%x\n", bmc->id.firmware_revision_1,
- bmc->id.firmware_revision_2);
-}
-
-static ssize_t ipmi_version_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bmc_device *bmc = dev_get_drvdata(dev);
-
- return snprintf(buf, 20, "%u.%u\n",
- ipmi_version_major(&bmc->id),
- ipmi_version_minor(&bmc->id));
-}
-
-static ssize_t add_dev_support_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bmc_device *bmc = dev_get_drvdata(dev);
-
- return snprintf(buf, 10, "0x%02x\n",
- bmc->id.additional_device_support);
-}
-
-static ssize_t manufacturer_id_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bmc_device *bmc = dev_get_drvdata(dev);
-
- return snprintf(buf, 20, "0x%6.6x\n", bmc->id.manufacturer_id);
-}
-
-static ssize_t product_id_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bmc_device *bmc = dev_get_drvdata(dev);
-
- return snprintf(buf, 10, "0x%4.4x\n", bmc->id.product_id);
-}
-
-static ssize_t aux_firmware_rev_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct bmc_device *bmc = dev_get_drvdata(dev);
-
- return snprintf(buf, 21, "0x%02x 0x%02x 0x%02x 0x%02x\n",
- bmc->id.aux_firmware_revision[3],
- bmc->id.aux_firmware_revision[2],
- bmc->id.aux_firmware_revision[1],
- bmc->id.aux_firmware_revision[0]);
-}
-
-static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct bmc_device *bmc = dev_get_drvdata(dev);
-
- return snprintf(buf, 100, "%Lx%Lx\n",
- (long long) bmc->guid[0],
- (long long) bmc->guid[8]);
-}
-
-static void
-cleanup_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 int
-send_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 void
-guid_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 void
-get_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;
-}
-