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 + -
显示快捷键?