ipmi_si_intf.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 2,443 行 · 第 1/5 页

C
2,443
字号
			smi_result = smi_info->handlers->event(				smi_info->si_sm, 100);		}		else if (smi_result == SI_SM_CALL_WITHOUT_DELAY)		{			smi_result = smi_info->handlers->event(				smi_info->si_sm, 0);		}		else			break;	}	if (smi_result == SI_SM_HOSED) {		/* We couldn't get the state machine to run, so whatever's at		   the port is probably not an IPMI SMI interface. */		rv = -ENODEV;		goto out;	}	/* Otherwise, we got some data. */	resp_len = smi_info->handlers->get_result(smi_info->si_sm,						  resp, IPMI_MAX_MSG_LENGTH);	if (resp_len < 14) {		/* That's odd, it should be longer. */		rv = -EINVAL;		goto out;	}	if ((resp[1] != IPMI_GET_DEVICE_ID_CMD) || (resp[2] != 0)) {		/* That's odd, it shouldn't be able to fail. */		rv = -EINVAL;		goto out;	}	/* Record info from the get device id, in case we need it. */	ipmi_demangle_device_id(resp+3, resp_len-3, &smi_info->device_id); out:	kfree(resp);	return rv;}static int type_file_read_proc(char *page, char **start, off_t off,			       int count, int *eof, void *data){	char            *out = (char *) page;	struct smi_info *smi = data;	switch (smi->si_type) {	    case SI_KCS:		return sprintf(out, "kcs\n");	    case SI_SMIC:		return sprintf(out, "smic\n");	    case SI_BT:		return sprintf(out, "bt\n");	    default:		return 0;	}}static int stat_file_read_proc(char *page, char **start, off_t off,			       int count, int *eof, void *data){	char            *out = (char *) page;	struct smi_info *smi = data;	out += sprintf(out, "interrupts_enabled:    %d\n",		       smi->irq && !smi->interrupt_disabled);	out += sprintf(out, "short_timeouts:        %ld\n",		       smi->short_timeouts);	out += sprintf(out, "long_timeouts:         %ld\n",		       smi->long_timeouts);	out += sprintf(out, "timeout_restarts:      %ld\n",		       smi->timeout_restarts);	out += sprintf(out, "idles:                 %ld\n",		       smi->idles);	out += sprintf(out, "interrupts:            %ld\n",		       smi->interrupts);	out += sprintf(out, "attentions:            %ld\n",		       smi->attentions);	out += sprintf(out, "flag_fetches:          %ld\n",		       smi->flag_fetches);	out += sprintf(out, "hosed_count:           %ld\n",		       smi->hosed_count);	out += sprintf(out, "complete_transactions: %ld\n",		       smi->complete_transactions);	out += sprintf(out, "events:                %ld\n",		       smi->events);	out += sprintf(out, "watchdog_pretimeouts:  %ld\n",		       smi->watchdog_pretimeouts);	out += sprintf(out, "incoming_messages:     %ld\n",		       smi->incoming_messages);	return (out - ((char *) page));}/* * oem_data_avail_to_receive_msg_avail * @info - smi_info structure with msg_flags set * * Converts flags from OEM_DATA_AVAIL to RECEIVE_MSG_AVAIL * Returns 1 indicating need to re-run handle_flags(). */static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info){	smi_info->msg_flags = ((smi_info->msg_flags & ~OEM_DATA_AVAIL) |			      	RECEIVE_MSG_AVAIL);	return 1;}/* * setup_dell_poweredge_oem_data_handler * @info - smi_info.device_id must be populated * * Systems that match, but have firmware version < 1.40 may assert * OEM0_DATA_AVAIL on their own, without being told via Set Flags that * it's safe to do so.  Such systems will de-assert OEM1_DATA_AVAIL * upon receipt of IPMI_GET_MSG_CMD, so we should treat these flags * as RECEIVE_MSG_AVAIL instead. * * As Dell has no plans to release IPMI 1.5 firmware that *ever* * assert the OEM[012] bits, and if it did, the driver would have to * change to handle that properly, we don't actually check for the * firmware version. * Device ID = 0x20                BMC on PowerEdge 8G servers * Device Revision = 0x80 * Firmware Revision1 = 0x01       BMC version 1.40 * Firmware Revision2 = 0x40       BCD encoded * IPMI Version = 0x51             IPMI 1.5 * Manufacturer ID = A2 02 00      Dell IANA * * Additionally, PowerEdge systems with IPMI < 1.5 may also assert * OEM0_DATA_AVAIL and needs to be treated as RECEIVE_MSG_AVAIL. * */#define DELL_POWEREDGE_8G_BMC_DEVICE_ID  0x20#define DELL_POWEREDGE_8G_BMC_DEVICE_REV 0x80#define DELL_POWEREDGE_8G_BMC_IPMI_VERSION 0x51#define DELL_IANA_MFR_ID 0x0002a2static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info){	struct ipmi_device_id *id = &smi_info->device_id;	if (id->manufacturer_id == DELL_IANA_MFR_ID) {		if (id->device_id       == DELL_POWEREDGE_8G_BMC_DEVICE_ID  &&		    id->device_revision == DELL_POWEREDGE_8G_BMC_DEVICE_REV &&		    id->ipmi_version   == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) {			smi_info->oem_data_avail_handler =				oem_data_avail_to_receive_msg_avail;		}		else if (ipmi_version_major(id) < 1 ||			 (ipmi_version_major(id) == 1 &&			  ipmi_version_minor(id) < 5)) {			smi_info->oem_data_avail_handler =				oem_data_avail_to_receive_msg_avail;		}	}}#define CANNOT_RETURN_REQUESTED_LENGTH 0xCAstatic void return_hosed_msg_badsize(struct smi_info *smi_info){	struct ipmi_smi_msg *msg = smi_info->curr_msg;	/* Make it a reponse */	msg->rsp[0] = msg->data[0] | 4;	msg->rsp[1] = msg->data[1];	msg->rsp[2] = CANNOT_RETURN_REQUESTED_LENGTH;	msg->rsp_size = 3;	smi_info->curr_msg = NULL;	deliver_recv_msg(smi_info, msg);}/* * dell_poweredge_bt_xaction_handler * @info - smi_info.device_id must be populated * * Dell PowerEdge servers with the BT interface (x6xx and 1750) will * not respond to a Get SDR command if the length of the data * requested is exactly 0x3A, which leads to command timeouts and no * data returned.  This intercepts such commands, and causes userspace * callers to try again with a different-sized buffer, which succeeds. */#define STORAGE_NETFN 0x0A#define STORAGE_CMD_GET_SDR 0x23static int dell_poweredge_bt_xaction_handler(struct notifier_block *self,					     unsigned long unused,					     void *in){	struct smi_info *smi_info = in;	unsigned char *data = smi_info->curr_msg->data;	unsigned int size   = smi_info->curr_msg->data_size;	if (size >= 8 &&	    (data[0]>>2) == STORAGE_NETFN &&	    data[1] == STORAGE_CMD_GET_SDR &&	    data[7] == 0x3A) {		return_hosed_msg_badsize(smi_info);		return NOTIFY_STOP;	}	return NOTIFY_DONE;}static struct notifier_block dell_poweredge_bt_xaction_notifier = {	.notifier_call	= dell_poweredge_bt_xaction_handler,};/* * setup_dell_poweredge_bt_xaction_handler * @info - smi_info.device_id must be filled in already * * Fills in smi_info.device_id.start_transaction_pre_hook * when we know what function to use there. */static voidsetup_dell_poweredge_bt_xaction_handler(struct smi_info *smi_info){	struct ipmi_device_id *id = &smi_info->device_id;	if (id->manufacturer_id == DELL_IANA_MFR_ID &&	    smi_info->si_type == SI_BT)		register_xaction_notifier(&dell_poweredge_bt_xaction_notifier);}/* * setup_oem_data_handler * @info - smi_info.device_id must be filled in already * * Fills in smi_info.device_id.oem_data_available_handler * when we know what function to use there. */static void setup_oem_data_handler(struct smi_info *smi_info){	setup_dell_poweredge_oem_data_handler(smi_info);}static void setup_xaction_handlers(struct smi_info *smi_info){	setup_dell_poweredge_bt_xaction_handler(smi_info);}static inline void wait_for_timer_and_thread(struct smi_info *smi_info){	if (smi_info->intf) {		/* The timer and thread are only running if the		   interface has been started up and registered. */		if (smi_info->thread != NULL)			kthread_stop(smi_info->thread);		del_timer_sync(&smi_info->si_timer);	}}static __devinitdata struct ipmi_default_vals{	int type;	int port;} ipmi_defaults[] ={	{ .type = SI_KCS, .port = 0xca2 },	{ .type = SI_SMIC, .port = 0xca9 },	{ .type = SI_BT, .port = 0xe4 },	{ .port = 0 }};static __devinit void default_find_bmc(void){	struct smi_info *info;	int             i;	for (i = 0; ; i++) {		if (!ipmi_defaults[i].port)			break;		info = kzalloc(sizeof(*info), GFP_KERNEL);		if (!info)			return;		info->addr_source = NULL;		info->si_type = ipmi_defaults[i].type;		info->io_setup = port_setup;		info->io.addr_data = ipmi_defaults[i].port;		info->io.addr_type = IPMI_IO_ADDR_SPACE;		info->io.addr = NULL;		info->io.regspacing = DEFAULT_REGSPACING;		info->io.regsize = DEFAULT_REGSPACING;		info->io.regshift = 0;		if (try_smi_init(info) == 0) {			/* Found one... */			printk(KERN_INFO "ipmi_si: Found default %s state"			       " machine at %s address 0x%lx\n",			       si_to_str[info->si_type],			       addr_space_to_str[info->io.addr_type],			       info->io.addr_data);			return;		}	}}static int is_new_interface(struct smi_info *info){	struct smi_info *e;	list_for_each_entry(e, &smi_infos, link) {		if (e->io.addr_type != info->io.addr_type)			continue;		if (e->io.addr_data == info->io.addr_data)			return 0;	}	return 1;}static int try_smi_init(struct smi_info *new_smi){	int rv;	if (new_smi->addr_source) {		printk(KERN_INFO "ipmi_si: Trying %s-specified %s state"		       " machine at %s address 0x%lx, slave address 0x%x,"		       " irq %d\n",		       new_smi->addr_source,		       si_to_str[new_smi->si_type],		       addr_space_to_str[new_smi->io.addr_type],		       new_smi->io.addr_data,		       new_smi->slave_addr, new_smi->irq);	}	mutex_lock(&smi_infos_lock);	if (!is_new_interface(new_smi)) {		printk(KERN_WARNING "ipmi_si: duplicate interface\n");		rv = -EBUSY;		goto out_err;	}	/* So we know not to free it unless we have allocated one. */	new_smi->intf = NULL;	new_smi->si_sm = NULL;	new_smi->handlers = NULL;	switch (new_smi->si_type) {	case SI_KCS:		new_smi->handlers = &kcs_smi_handlers;		break;	case SI_SMIC:		new_smi->handlers = &smic_smi_handlers;		break;	case SI_BT:		new_smi->handlers = &bt_smi_handlers;		break;	default:		/* No support for anything else yet. */		rv = -EIO;		goto out_err;	}	/* Allocate the state machine's data and initialize it. */	new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL);	if (!new_smi->si_sm) {		printk(" Could not allocate state machine memory\n");		rv = -ENOMEM;		goto out_err;	}	new_smi->io_size = new_smi->handlers->init_data(new_smi->si_sm,							&new_smi->io);	/* Now that we know the I/O size, we can set up the I/O. */	rv = new_smi->io_setup(new_smi);	if (rv) {		printk(" Could not set up I/O space\n");		goto out_err;	}	spin_lock_init(&(new_smi->si_lock));	spin_lock_init(&(new_smi->msg_lock));	spin_lock_init(&(new_smi->count_lock));	/* Do low-level detection first. */	if (new_smi->handlers->detect(new_smi->si_sm)) {		if (new_smi->addr_source)			printk(KERN_INFO "ipmi_si: Interface detection"			       " failed\n");		rv = -ENODEV;		goto out_err;	}	/* Attempt a get device id command.  If it fails, we probably           don't have a BMC here. */	rv = try_get_dev_id(new_smi);	if (rv) {		if (new_smi->addr_source)			printk(KERN_INFO "ipmi_si: There appears to be no BMC"			       " at this location\n");		goto out_err;	}	setup_oem_data_handler(new_smi);	setup_xaction_handlers(new_smi);	/* Try to claim any interrupts. */	if (new_smi->irq_setup)		new_smi->irq_setup(new_smi);	INIT_LIST_HEAD(&(new_smi->xmit_msgs));	INIT_LIST_HEAD(&(new_smi->hp_xmit_msgs));	new_smi->curr_msg = NULL;	atomic_set(&new_smi->req_events, 0);	new_smi->run_to_completion = 0;	new_smi->interrupt_disabled = 0;	atomic_set(&new_smi->stop_operation, 0);	new_smi->intf_num = smi_num;	smi_num++;	/* Start clearing the flags before we enable interrupts or the	   timer to avoid racing with the timer. */	start_clear_flags(new_smi);	/* IRQ is defined to be set when non-zero. */	if (new_smi->irq)		new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ;	if (!new_smi->dev) {		/* If we don't already have a device from something		 * else (like PCI), then register a new one. */		new_smi->pdev = platform_device_alloc("ipmi_si",						      new_smi->intf_num);		if (rv) {			printk(KERN_ERR			       "ipmi_si_intf:"			       " Unable to allocate platform device\n");			goto out_err;		}		new_smi->dev = &new_smi->pdev->dev;		new_smi->dev->driver = &ipmi_driver;		rv = platform_device_register(new_smi->pdev);		if (rv) {			printk(KERN_ERR			       "ipmi_si_intf:"			       " Unable to register system interface device:"			       " %d\n",			       rv);			goto out_err;		}		new_smi->dev_registered = 1;	}	rv = ipmi_register_smi(&handlers,			       new_smi,			       &new_smi->device_id,			       new_smi->dev,			       new_smi->slave_addr);	if (rv) {		printk(KERN_ERR		       "ipmi_si: Unable to register device: error %d\n",		       rv);		goto out_err_stop_timer;	}	rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",				     type_file_read_proc, NULL,				     new_smi, THIS_MODULE);	if (rv) {		printk(KERN_ERR		       "ipmi_si: Unable to create proc entry: %d\n",		       rv);		goto out_err_stop_timer;	}	rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",				     stat_file_read_proc, NULL,				     new_smi, THIS_MODULE);	if (rv) {		printk(KERN_ERR		       "ipmi_si: Unable to create proc entry: %d\n",		       rv);		goto out_err_stop_timer;	}	list_add_tail(&new_smi->link, &smi_infos);	mutex_unlock(&smi_infos_lock);	printk(" IPMI %s interface init

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?