changeset 14035:9992f781c89a

3770 ipmi drivers hangs due to attach/detach/attach cycle Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com> Reviewed by: Albert Lee <trisk@nexenta.com> Reviewed by: Saso Kiselkov <skiselkov.ml@gmail.com> Approved by: Richard Lowe <richlowe@richlowe.net>
author Alek Pinchuk <alek@nexenta.com>
date Fri, 24 May 2013 12:35:17 -0500
parents e4eb37f33d60
children 9f368de5660f 10b779d783d1
files usr/src/uts/intel/io/ipmi/ipmi.c usr/src/uts/intel/io/ipmi/ipmi_main.c usr/src/uts/intel/io/ipmi/ipmivars.h
diffstat 3 files changed, 50 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/intel/io/ipmi/ipmi.c	Thu May 23 13:07:25 2013 -0400
+++ b/usr/src/uts/intel/io/ipmi/ipmi.c	Fri May 24 12:35:17 2013 -0500
@@ -28,6 +28,7 @@
 
 /*
  * Copyright 2012, Joyent, Inc.  All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/devops.h>
@@ -178,6 +179,18 @@
 }
 
 void
+ipmi_shutdown(struct ipmi_softc *sc)
+{
+	taskq_destroy(sc->ipmi_kthread);
+
+	cv_destroy(&sc->ipmi_request_added);
+	mutex_destroy(&sc->ipmi_lock);
+
+	cv_destroy(&slplock);
+	mutex_destroy(&slpmutex);
+}
+
+boolean_t
 ipmi_startup(struct ipmi_softc *sc)
 {
 	struct ipmi_request *req;
@@ -195,7 +208,7 @@
 	error = sc->ipmi_startup(sc);
 	if (error) {
 		cmn_err(CE_WARN, "Failed to initialize interface: %d", error);
-		return;
+		return (B_FALSE);
 	}
 
 	/* Send a GET_DEVICE_ID request. */
@@ -206,22 +219,22 @@
 	if (error == EWOULDBLOCK) {
 		cmn_err(CE_WARN, "Timed out waiting for GET_DEVICE_ID");
 		ipmi_free_request(req);
-		return;
+		return (B_FALSE);
 	} else if (error) {
 		cmn_err(CE_WARN, "Failed GET_DEVICE_ID: %d", error);
 		ipmi_free_request(req);
-		return;
+		return (B_FALSE);
 	} else if (req->ir_compcode != 0) {
 		cmn_err(CE_WARN,
 		    "Bad completion code for GET_DEVICE_ID: %d",
 		    req->ir_compcode);
 		ipmi_free_request(req);
-		return;
+		return (B_FALSE);
 	} else if (req->ir_replylen < 5) {
 		cmn_err(CE_WARN, "Short reply for GET_DEVICE_ID: %d",
 		    req->ir_replylen);
 		ipmi_free_request(req);
-		return;
+		return (B_FALSE);
 	}
 
 	cmn_err(CE_CONT, "!device rev. %d, firmware rev. %d.%d%d, "
@@ -235,8 +248,11 @@
 	req = ipmi_alloc_driver_request(IPMI_ADDR(IPMI_APP_REQUEST, 0),
 	    IPMI_CLEAR_FLAGS, 1, 0);
 
-	if ((error = ipmi_submit_driver_request(sc, req, 0)) != 0)
+	if ((error = ipmi_submit_driver_request(sc, req, 0)) != 0) {
 		cmn_err(CE_WARN, "Failed to clear IPMI flags: %d\n", error);
+		ipmi_free_request(req);
+		return (B_FALSE);
+	}
 
 	/* Magic numbers */
 	if (req->ir_compcode == 0xc0) {
@@ -272,7 +288,7 @@
 	if ((error = ipmi_submit_driver_request(sc, req, 0)) != 0) {
 		cmn_err(CE_WARN, "Failed to check IPMI watchdog: %d\n", error);
 		ipmi_free_request(req);
-		return;
+		return (B_FALSE);
 	}
 
 	if (req->ir_compcode == 0x00) {
@@ -284,4 +300,6 @@
 		 */
 	}
 	ipmi_free_request(req);
+
+	return (B_TRUE);
 }
--- a/usr/src/uts/intel/io/ipmi/ipmi_main.c	Thu May 23 13:07:25 2013 -0400
+++ b/usr/src/uts/intel/io/ipmi/ipmi_main.c	Fri May 24 12:35:17 2013 -0500
@@ -21,6 +21,7 @@
 
 /*
  * Copyright 2012, Joyent, Inc.  All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
@@ -487,6 +488,14 @@
 	if (cmd != DDI_ATTACH)
 		return (DDI_FAILURE);
 
+	/* this driver only supports one device instance */
+	if (ddi_get_instance(dip) != 0) {
+		cmn_err(CE_WARN,
+		    "!not attaching to non-zero device instance %d",
+		    ddi_get_instance(dip));
+		return (DDI_FAILURE);
+	}
+
 	if (get_smbios_ipmi_info() == DDI_FAILURE)
 		return (DDI_FAILURE);
 
@@ -518,7 +527,11 @@
 	/* Create ID space for open devs.  ID 0 is reserved. */
 	minor_ids = id_space_create("ipmi_id_space", 1, 128);
 
-	ipmi_startup(sc);
+	if (ipmi_startup(sc) != B_TRUE) {
+		ipmi_shutdown(sc);
+		return (DDI_FAILURE);
+	}
+
 	ipmi_attached = B_TRUE;
 
 	return (DDI_SUCCESS);
@@ -540,13 +553,14 @@
 	sc->ipmi_detaching = 1;
 	cv_signal(&sc->ipmi_request_added);
 
+	ipmi_shutdown(sc);
 	ddi_remove_minor_node(dip, NULL);
 	ipmi_dip = NULL;
 
-	taskq_destroy(sc->ipmi_kthread);
 	list_destroy(&dev_list);
 	id_space_destroy(minor_ids);
 
+	sc->ipmi_detaching = 0;
 	ipmi_attached = B_FALSE;
 	return (DDI_SUCCESS);
 }
@@ -566,7 +580,10 @@
 	ipmi_poll,
 	ddi_prop_op,
 	NULL,			/* streamtab */
-	D_NEW | D_MP		/* flags */
+	D_NEW | D_MP,		/* flags */
+	CB_REV,
+	nodev,			/* awread */
+	nodev			/* awrite */
 };
 
 static struct dev_ops ipmi_ops = {
--- a/usr/src/uts/intel/io/ipmi/ipmivars.h	Thu May 23 13:07:25 2013 -0400
+++ b/usr/src/uts/intel/io/ipmi/ipmivars.h	Fri May 24 12:35:17 2013 -0500
@@ -28,6 +28,7 @@
 
 /*
  * Copyright 2012, Joyent, Inc.  All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc.  All rights reserved.
  */
 
 #ifndef _IPMIVARS_H_
@@ -179,9 +180,12 @@
 void	ipmi_free_request(struct ipmi_request *);
 
 /* Interface attach routines. */
-void	ipmi_startup(struct ipmi_softc *sc);
+boolean_t ipmi_startup(struct ipmi_softc *sc);
 int	ipmi_kcs_attach(struct ipmi_softc *);
 
+/* Interface detach cleanup */
+void	ipmi_shutdown(struct ipmi_softc *sc);
+
 #ifdef	__cplusplus
 }
 #endif