All of lore.kernel.org
 help / color / mirror / Atom feed
* IPMI fixes for 2.6.0-test7
@ 2003-10-09 13:35 Corey Minyard
  0 siblings, 0 replies; only message in thread
From: Corey Minyard @ 2003-10-09 13:35 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: lkml

[-- Attachment #1: Type: text/plain, Size: 315 bytes --]

Linus,

The following patch fixes some problems with timing calculations 
(primarily for ia64) and adds an operation to send panic strings to the 
IPMI event log on a panic.  I've sent this several times, and I've had 
several requests to get this in before 2.6 goes out.  Could you please 
apply?

Thanks,

-Corey

[-- Attachment #2: ipmi-2.6.0-test7.diff --]
[-- Type: text/plain, Size: 10720 bytes --]

Index: include/linux/ipmi_msgdefs.h
===================================================================
RCS file: /home/cvs/linux-2.5/include/linux/ipmi_msgdefs.h,v
retrieving revision 1.2
diff -u -r1.2 ipmi_msgdefs.h
--- linux.old/include/linux/ipmi_msgdefs.h	13 Jan 2003 21:20:22 -0000	1.2
+++ linux/include/linux/ipmi_msgdefs.h	9 Oct 2003 11:33:46 -0000
@@ -37,22 +37,32 @@
 /* Various definitions for IPMI messages used by almost everything in
    the IPMI stack. */
 
-#define IPMI_NETFN_APP_REQUEST	0x06
-#define IPMI_NETFN_APP_RESPONSE	0x07
+/* NetFNs and commands used inside the IPMI stack. */
 
-#define IPMI_BMC_SLAVE_ADDR	0x20
+#define IPMI_NETFN_SENSOR_EVENT_REQUEST		0x04
+#define IPMI_NETFN_SENSOR_EVENT_RESPONSE	0x05
+#define IPMI_GET_EVENT_RECEIVER_CMD	0x01
 
+#define IPMI_NETFN_APP_REQUEST			0x06
+#define IPMI_NETFN_APP_RESPONSE			0x07
 #define IPMI_GET_DEVICE_ID_CMD		0x01
-
 #define IPMI_CLEAR_MSG_FLAGS_CMD	0x30
 #define IPMI_GET_MSG_FLAGS_CMD		0x31
 #define IPMI_SEND_MSG_CMD		0x34
 #define IPMI_GET_MSG_CMD		0x33
-
 #define IPMI_SET_BMC_GLOBAL_ENABLES_CMD	0x2e
 #define IPMI_GET_BMC_GLOBAL_ENABLES_CMD	0x2f
 #define IPMI_READ_EVENT_MSG_BUFFER_CMD	0x35
 
+#define IPMI_NETFN_STORAGE_REQUEST		0x0a
+#define IPMI_NETFN_STORAGE_RESPONSE		0x0b
+#define IPMI_ADD_SEL_ENTRY_CMD		0x44
+
+/* The default slave address */
+#define IPMI_BMC_SLAVE_ADDR	0x20
+
 #define IPMI_MAX_MSG_LENGTH	80
+
+#define IPMI_CC_NO_ERROR	0
 
 #endif /* __LINUX_IPMI_MSGDEFS_H */
Index: drivers/char/ipmi/Kconfig
===================================================================
RCS file: /home/cvs/linux-2.5/drivers/char/ipmi/Kconfig,v
retrieving revision 1.3
diff -u -r1.3 Kconfig
--- linux.old/drivers/char/ipmi/Kconfig	28 Mar 2003 05:14:18 -0000	1.3
+++ linux/drivers/char/ipmi/Kconfig	9 Oct 2003 11:33:46 -0000
@@ -24,6 +24,18 @@
 	 generate an IPMI event describing the panic to each interface
 	 registered with the message handler.
 
+config IPMI_PANIC_STRING
+	bool 'Generate OEM events containing the panic string'
+	depends on IPMI_PANIC_EVENT
+	help
+	  When a panic occurs, this will cause the IPMI message handler to
+	  generate IPMI OEM type f0 events holding the IPMB address of the
+	  panic generator (byte 4 of the event), a sequence number for the
+	  string (byte 5 of the event) and part of the string (the rest of the
+	  event).  Bytes 1, 2, and 3 are the normal usage for an OEM event.
+	  You can fetch these events and use the sequence numbers to piece the
+	  string together.
+
 config IPMI_DEVICE_INTERFACE
        tristate 'Device interface for IPMI'
        depends on IPMI_HANDLER
Index: drivers/char/ipmi/ipmi_msghandler.c
===================================================================
RCS file: /home/cvs/linux-2.5/drivers/char/ipmi/ipmi_msghandler.c,v
retrieving revision 1.7
diff -u -r1.7 ipmi_msghandler.c
--- linux.old/drivers/char/ipmi/ipmi_msghandler.c	24 May 2003 17:02:51 -0000	1.7
+++ linux/drivers/char/ipmi/ipmi_msghandler.c	9 Oct 2003 11:33:48 -0000
@@ -169,6 +169,19 @@
 	/* My LUN.  This should generally stay the SMS LUN, but just in
 	   case... */
 	unsigned char my_lun;
+
+	/* The event receiver for my BMC, only really used at panic
+	   shutdown as a place to store this. */
+	unsigned char event_receiver;
+	unsigned char event_receiver_lun;
+	unsigned char local_sel_device;
+	unsigned char local_event_generator;
+
+	/* A cheap hack, if this is non-null and a message to an
+	   interface comes in with a NULL user, call this routine with
+	   it.  Note that the message will still be freed by the
+	   caller.  This only works on the system interface. */
+	void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_smi_msg *msg);
 };
 
 int
@@ -1465,6 +1478,9 @@
 	}
 
 	if (!found) {
+		/* Special handling for NULL users. */
+		if (!recv_msg->user && intf->null_user_handler)
+			intf->null_user_handler(intf, msg);
 		/* The user for the message went away, so give up. */
 		ipmi_free_recv_msg(recv_msg);
 	} else {
@@ -1733,7 +1749,7 @@
 
 /* Call every 100 ms. */
 #define IPMI_TIMEOUT_TIME	100
-#define IPMI_TIMEOUT_JIFFIES	(IPMI_TIMEOUT_TIME/(1000/HZ))
+#define IPMI_TIMEOUT_JIFFIES	((IPMI_TIMEOUT_TIME * HZ)/1000)
 
 /* Request events from the queue every second.  Hopefully, in the
    future, IPMI will add a way to know immediately if an event is
@@ -1813,18 +1829,48 @@
 {
 }
 
-static void send_panic_events(void)
+#ifdef CONFIG_IPMI_PANIC_STRING
+static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+{
+	if ((msg->rsp[0] == (IPMI_NETFN_SENSOR_EVENT_RESPONSE << 2))
+	    && (msg->rsp[1] == IPMI_GET_EVENT_RECEIVER_CMD)
+	    && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+	{
+		/* A get event receiver command, save it. */
+		intf->event_receiver = msg->rsp[3];
+		intf->event_receiver_lun = msg->rsp[4] & 0x3;
+	}
+}
+
+static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_smi_msg *msg)
+{
+	if ((msg->rsp[0] == (IPMI_NETFN_APP_RESPONSE << 2))
+	    && (msg->rsp[1] == IPMI_GET_DEVICE_ID_CMD)
+	    && (msg->rsp[2] == IPMI_CC_NO_ERROR))
+	{
+		/* A get device id command, save if we are an event
+		   receiver or generator. */
+		intf->local_sel_device = (msg->rsp[8] >> 2) & 1;
+		intf->local_event_generator = (msg->rsp[8] >> 5) & 1;
+	}
+}
+#endif
+
+static void send_panic_events(char *str)
 {
 	struct ipmi_msg                   msg;
 	ipmi_smi_t                        intf;
-	unsigned char                     data[8];
+	unsigned char                     data[16];
 	int                               i;
-	struct ipmi_system_interface_addr addr;
+	struct ipmi_system_interface_addr *si;
+	struct ipmi_addr                  addr;
 	struct ipmi_smi_msg               smi_msg;
 	struct ipmi_recv_msg              recv_msg;
 
-	addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
-	addr.channel = IPMI_BMC_CHANNEL;
+	si = (struct ipmi_system_interface_addr *) &addr;
+	si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	si->channel = IPMI_BMC_CHANNEL;
+	si->lun = 0;
 
 	/* Fill in an event telling that we have failed. */
 	msg.netfn = 0x04; /* Sensor or Event. */
@@ -1837,12 +1883,13 @@
 	data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
 	data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
 
-	/* These used to have the first three bytes of the panic string,
-	   but not only is that not terribly useful, it's not available
-	   any more. */
-	data[3] = 0;
-	data[6] = 0;
-	data[7] = 0;
+	/* Put a few breadcrumbs in.  Hopefully later we can add more things
+	   to make the panic events more useful. */
+	if (str) {
+		data[3] = str[0];
+		data[6] = str[1];
+		data[7] = str[2];
+	}
 
 	smi_msg.done = dummy_smi_done_handler;
 	recv_msg.done = dummy_recv_done_handler;
@@ -1853,10 +1900,11 @@
 		if (intf == NULL)
 			continue;
 
+		/* Send the event announcing the panic. */
 		intf->handlers->set_run_to_completion(intf->send_info, 1);
 		i_ipmi_request(NULL,
 			       intf,
-			       (struct ipmi_addr *) &addr,
+			       &addr,
 			       0,
 			       &msg,
 			       &smi_msg,
@@ -1865,6 +1913,130 @@
 			       intf->my_address,
 			       intf->my_lun);
 	}
+
+#ifdef CONFIG_IPMI_PANIC_STRING
+	/* On every interface, dump a bunch of OEM event holding the
+	   string. */
+	if (!str) 
+		return;
+
+	for (i=0; i<MAX_IPMI_INTERFACES; i++) {
+		char                  *p = str;
+		struct ipmi_ipmb_addr *ipmb;
+		int                   j;
+
+		intf = ipmi_interfaces[i];
+		if (intf == NULL)
+			continue;
+
+		/* First job here is to figure out where to send the
+		   OEM events.  There's no way in IPMI to send OEM
+		   events using an event send command, so we have to
+		   find the SEL to put them in and stick them in
+		   there. */
+
+		/* Get capabilities from the get device id. */
+		intf->local_sel_device = 0;
+		intf->local_event_generator = 0;
+		intf->event_receiver = 0;
+
+		/* Request the device info from the local MC. */
+		msg.netfn = IPMI_NETFN_APP_REQUEST;
+		msg.cmd = IPMI_GET_DEVICE_ID_CMD;
+		msg.data = NULL;
+		msg.data_len = 0;
+		intf->null_user_handler = device_id_fetcher;
+		i_ipmi_request(NULL,
+			       intf,
+			       &addr,
+			       0,
+			       &msg,
+			       &smi_msg,
+			       &recv_msg,
+			       0,
+			       intf->my_address,
+			       intf->my_lun);
+
+		if (intf->local_event_generator) {
+			/* Request the event receiver from the local MC. */
+			msg.netfn = IPMI_NETFN_SENSOR_EVENT_REQUEST;
+			msg.cmd = IPMI_GET_EVENT_RECEIVER_CMD;
+			msg.data = NULL;
+			msg.data_len = 0;
+			intf->null_user_handler = event_receiver_fetcher;
+			i_ipmi_request(NULL,
+				       intf,
+				       &addr,
+				       0,
+				       &msg,
+				       &smi_msg,
+				       &recv_msg,
+				       0,
+				       intf->my_address,
+				       intf->my_lun);
+		}
+		intf->null_user_handler = NULL;
+
+		/* Validate the event receiver.  The low bit must not
+		   be 1 (it must be a valid IPMB address), it cannot
+		   be zero, and it must not be my address. */
+                if (((intf->event_receiver & 1) == 0)
+		    && (intf->event_receiver != 0)
+		    && (intf->event_receiver != intf->my_address))
+		{
+			/* The event receiver is valid, send an IPMB
+			   message. */
+			ipmb = (struct ipmi_ipmb_addr *) &addr;
+			ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
+			ipmb->channel = 0; /* FIXME - is this right? */
+			ipmb->lun = intf->event_receiver_lun;
+			ipmb->slave_addr = intf->event_receiver;
+		} else if (intf->local_sel_device) {
+			/* The event receiver was not valid (or was
+			   me), but I am an SEL device, just dump it
+			   in my SEL. */
+			si = (struct ipmi_system_interface_addr *) &addr;
+			si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+			si->channel = IPMI_BMC_CHANNEL;
+			si->lun = 0;
+		} else
+			continue; /* No where to send the event. */
+
+		
+		msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
+		msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
+		msg.data = data;
+		msg.data_len = 16;
+
+		j = 0;
+		while (*p) {
+			int size = strlen(p);
+
+			if (size > 11)
+				size = 11;
+			data[0] = 0;
+			data[1] = 0;
+			data[2] = 0xf0; /* OEM event without timestamp. */
+			data[3] = intf->my_address;
+			data[4] = j++; /* sequence # */
+			/* Always give 11 bytes, so strncpy will fill
+			   it with zeroes for me. */
+			strncpy(data+5, p, 11);
+			p += size;
+
+			i_ipmi_request(NULL,
+				       intf,
+				       &addr,
+				       0,
+				       &msg,
+				       &smi_msg,
+				       &recv_msg,
+				       0,
+				       intf->my_address,
+				       intf->my_lun);
+		}
+	}	
+#endif /* CONFIG_IPMI_PANIC_STRING */
 }
 #endif /* CONFIG_IPMI_PANIC_EVENT */
 
@@ -1891,7 +2063,7 @@
 	}
 
 #ifdef CONFIG_IPMI_PANIC_EVENT
-	send_panic_events();
+	send_panic_events(ptr);
 #endif
 
 	return NOTIFY_DONE;

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2003-10-09 13:36 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-10-09 13:35 IPMI fixes for 2.6.0-test7 Corey Minyard

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.