diff usr/src/uts/common/io/sata/impl/sata.c @ 1529:4fa3374f2b9d

6386938 sata framework should generate sysevent when device is plugged or unplugged 6387471 sata framework emits duplicate msgs or wrong msgs on certain cfgadm-initiated AP state transitions
author pawelw
date Thu, 02 Mar 2006 14:18:50 -0800
parents 9961d7d3ec8c
children f22bd5bc2aff
line wrap: on
line diff
--- a/usr/src/uts/common/io/sata/impl/sata.c	Thu Mar 02 10:48:56 2006 -0800
+++ b/usr/src/uts/common/io/sata/impl/sata.c	Thu Mar 02 14:18:50 2006 -0800
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -44,6 +44,9 @@
 #include <sys/thread.h>
 #include <sys/kstat.h>
 #include <sys/note.h>
+#include <sys/sysevent.h>
+#include <sys/sysevent/eventdefs.h>
+#include <sys/sysevent/dr.h>
 
 #include <sys/sata/impl/sata.h>
 #include <sys/sata/sata_hba.h>
@@ -192,8 +195,8 @@
     struct mode_cache_scsi3 *, int, int *, int *, int *);
 static	void sata_save_drive_settings(sata_drive_info_t *);
 static	void sata_show_drive_info(sata_hba_inst_t *, sata_drive_info_t *);
-
 static	void sata_log(sata_hba_inst_t *, uint_t, char *fmt, ...);
+static	void sata_gen_sysevent(sata_hba_inst_t *, sata_address_t *, int);
 
 /*
  * SATA Framework will ignore SATA HBA driver cb_ops structure and
@@ -1050,6 +1053,12 @@
 			rv = EIO;
 			break;
 		}
+		/* Sanity check */
+		if (SATA_PORT_DEACTIVATE_FUNC(sata_hba_inst) == NULL) {
+			/* No physical port deactivation supported. */
+			break;
+		}
+
 		/*
 		 * set port's dev_state to not ready - this will disable
 		 * an access to an attached device.
@@ -1105,22 +1114,25 @@
 			}
 			/*
 			 * Note: PMult info requires different handling.
-			 * Put PMult handling code here, when PNult is
+			 * Put PMult handling code here, when PMult is
 			 * supported.
 			 */
+
 		}
 		mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, cport)->cport_mutex);
-		/* Sanity check */
-		if (SATA_PORT_DEACTIVATE_FUNC(sata_hba_inst) == NULL) {
-			/* No physical port deactivation supported. */
-			break;
-		}
-
 		/* Just ask HBA driver to deactivate port */
 		sata_device.satadev_addr.qual = SATA_ADDR_DCPORT;
 
 		rval = (*SATA_PORT_DEACTIVATE_FUNC(sata_hba_inst))
 		    (dip, &sata_device);
+
+		/*
+		 * Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE
+		 * without the hint.
+		 */
+		sata_gen_sysevent(sata_hba_inst,
+		    &sata_device.satadev_addr, SE_NO_HINT);
+
 		mutex_enter(&SATA_CPORT_INFO(sata_hba_inst, cport)->
 		    cport_mutex);
 		sata_update_port_info(sata_hba_inst, &sata_device);
@@ -1135,6 +1147,11 @@
 				cportinfo->cport_state = SATA_PSTATE_FAILED;
 			rv = EIO;
 		} else {
+			/*
+			 * Deactivation succeded. From now on the framework
+			 * will not know what is happening to the device, until
+			 * the port is activated again.
+			 */
 			cportinfo->cport_state |= SATA_PSTATE_SHUTDOWN;
 		}
 		mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, cport)->cport_mutex);
@@ -1243,14 +1260,19 @@
 		if (sata_reprobe_port(sata_hba_inst, &sata_device) ==
 		    SATA_FAILURE)
 			rv = EIO;
-
+		/*
+		 * Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE
+		 * without the hint
+		 */
+		sata_gen_sysevent(sata_hba_inst,
+		    &sata_device.satadev_addr, SE_NO_HINT);
 		/*
 		 * If there is a device attached to the port, emit
 		 * a message.
 		 */
 		if (cportinfo->cport_dev_type != SATA_DTYPE_NONE) {
 			sata_log(sata_hba_inst, CE_WARN,
-			    "SATA device attached at port %d", cport);
+			    "SATA device detected at port %d", cport);
 		}
 		break;
 	}
@@ -1299,7 +1321,7 @@
 			break;
 		}
 		if (cportinfo->cport_state & SATA_PSTATE_SHUTDOWN) {
-			target = TRUE;
+			target = FALSE;
 			mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, cport)->
 			    cport_mutex);
 
@@ -1332,6 +1354,13 @@
 					break;
 				}
 			}
+			/*
+			 * Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE
+			 * without the hint.
+			 */
+			sata_gen_sysevent(sata_hba_inst,
+			    &sata_device.satadev_addr, SE_NO_HINT);
+
 			mutex_enter(&SATA_CPORT_INFO(sata_hba_inst, cport)->
 			    cport_mutex);
 			/* Virgin port state */
@@ -1349,11 +1378,11 @@
 		if (target == FALSE &&
 		    cportinfo->cport_dev_type != SATA_DTYPE_NONE) {
 			/*
-			 * That's the transition from "inactive" port to
-			 * active with device attached.
+			 * That's the transition from "inactive" port
+			 * to active one with device attached.
 			 */
 			sata_log(sata_hba_inst, CE_WARN,
-			    "SATA device attached at port %d",
+			    "SATA device detected at port %d",
 			    cport);
 		}
 
@@ -1847,6 +1876,14 @@
 			/* Just let HBA driver to deactivate port */
 			rval = (*SATA_PORT_DEACTIVATE_FUNC(sata_hba_inst))
 			    (dip, &sata_device);
+			/*
+			 * Generate sysevent -
+			 * EC_DR / ESC_DR_AP_STATE_CHANGE
+			 * without the hint
+			 */
+			sata_gen_sysevent(sata_hba_inst,
+			    &sata_device.satadev_addr, SE_NO_HINT);
+
 			mutex_enter(&SATA_CPORT_INFO(sata_hba_inst, cport)->
 			    cport_mutex);
 			sata_update_port_info(sata_hba_inst, &sata_device);
@@ -1931,6 +1968,14 @@
 			 */
 			(void) sata_reprobe_port(sata_hba_inst, &sata_device);
 
+			/*
+			 * Generate sysevent -
+			 * EC_DR / ESC_DR_AP_STATE_CHANGE
+			 * without the hint.
+			 */
+			sata_gen_sysevent(sata_hba_inst,
+			    &sata_device.satadev_addr, SE_NO_HINT);
+
 			if (dev_existed == FALSE &&
 			    cportinfo->cport_dev_type != SATA_DTYPE_NONE) {
 				/*
@@ -1940,7 +1985,7 @@
 				 * a device attached.
 				 */
 				sata_log(sata_hba_inst, CE_WARN,
-				    "SATA device attached at port %d", cport);
+				    "SATA device detected at port %d", cport);
 			}
 
 			break;
@@ -6633,9 +6678,6 @@
 				sdinfo->satadrv_addr.qual = SATA_ADDR_DCPORT;
 				sdinfo->satadrv_type = SATA_DTYPE_UNKNOWN;
 				sdinfo->satadrv_state = SATA_STATE_UNKNOWN;
-				sata_log(sata_hba_inst, CE_WARN,
-				    "SATA device attached to port %d",
-				    cportinfo->cport_addr.cport);
 			} else {
 				/*
 				 * Port is not in ready state, we
@@ -9466,7 +9508,11 @@
 			    "removed device."));
 		}
 	}
-
+	/*
+	 * Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE
+	 * with the hint: SE_HINT_REMOVE
+	 */
+	sata_gen_sysevent(sata_hba_inst, saddr, SE_HINT_REMOVE);
 }
 
 
@@ -9488,6 +9534,7 @@
 	sata_drive_info_t *sdevinfo;
 	sata_device_t sata_device;
 	dev_info_t *tdip;
+	int rval;
 
 	SATADBG1(SATA_DBG_EVENTS_PROC, sata_hba_inst,
 	    "Processing port %d device attached", saddr->cport);
@@ -9520,7 +9567,57 @@
 		    "Arbitrarily detaching old device info."));
 	}
 	cportinfo->cport_dev_type = SATA_DTYPE_NONE;
+
+	/* For sanity, re-probe the port */
+	sata_device.satadev_rev = SATA_DEVICE_REV;
+	sata_device.satadev_addr = *saddr;
+
+	/*
+	 * We have to exit mutex, because the HBA probe port function may
+	 * block on its own mutex.
+	 */
 	mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)->cport_mutex);
+	rval = (*SATA_PROBE_PORT_FUNC(sata_hba_inst))
+	    (SATA_DIP(sata_hba_inst), &sata_device);
+	mutex_enter(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)->cport_mutex);
+	sata_update_port_info(sata_hba_inst, &sata_device);
+	if (rval != SATA_SUCCESS) {
+		/* Something went wrong? Fail the port */
+		cportinfo->cport_state = SATA_PSTATE_FAILED;
+		mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)->
+		    cport_mutex);
+		SATA_LOG_D((sata_hba_inst, CE_WARN, "Port %d probing failed",
+		    saddr->cport));
+		return;
+	} else {
+		/* port probed successfully */
+		cportinfo->cport_state |= SATA_STATE_PROBED | SATA_STATE_READY;
+	}
+	/*
+	 * Check if a device is still attached. For sanity, check also
+	 * link status - if no link, there is no device.
+	 */
+	if ((sata_device.satadev_scr.sstatus & SATA_PORT_DEVLINK_UP_MASK) !=
+	    SATA_PORT_DEVLINK_UP || sata_device.satadev_type ==
+	    SATA_DTYPE_NONE) {
+		/*
+		 * No device - ignore attach event.
+		 */
+		mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)->
+		    cport_mutex);
+		SATADBG1(SATA_DBG_EVENTS_PROC, sata_hba_inst,
+		    "Ignoring attach - no device connected to port %d",
+		    sata_device.satadev_addr.cport);
+		return;
+	}
+
+	mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)->cport_mutex);
+	/*
+	 * Generate sysevent - EC_DR / ESC_DR_AP_STATE_CHANGE
+	 * with the hint: SE_HINT_INSERT
+	 */
+	sata_gen_sysevent(sata_hba_inst, saddr, SE_HINT_INSERT);
+
 	/*
 	 * Make sure that there is no target node for that device.
 	 * If so, release it. It should not happen, unless we had problem
@@ -9561,9 +9658,8 @@
 	}
 
 	/*
-	 * Reprobing port will take care of detecting device presence,
-	 * creation of the device info structure and determination of the
-	 * device type.
+	 * Reprobing port will take care of the creation of the device info
+	 * structure and determination of the device type.
 	 */
 	sata_device.satadev_addr = *saddr;
 	(void) sata_reprobe_port(sata_hba_inst, &sata_device);
@@ -9573,13 +9669,17 @@
 	 */
 	mutex_enter(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)->cport_mutex);
 	if ((cportinfo->cport_state & SATA_STATE_READY) &&
-	    cportinfo->cport_dev_type != SATA_DTYPE_NONE &&
-	    SATA_CPORTINFO_DRV_INFO(cportinfo) != NULL) {
-		sata_drive_info_t new_sdinfo;
-
-		/* Log device info data */
-		new_sdinfo = *(SATA_CPORTINFO_DRV_INFO(cportinfo));
-		sata_show_drive_info(sata_hba_inst, &new_sdinfo);
+	    cportinfo->cport_dev_type != SATA_DTYPE_NONE) {
+		sata_log(sata_hba_inst, CE_WARN,
+		    "SATA device attached at port %d", saddr->cport);
+
+		if (SATA_CPORTINFO_DRV_INFO(cportinfo) != NULL) {
+			sata_drive_info_t new_sdinfo;
+
+			/* Log device info data */
+			new_sdinfo = *(SATA_CPORTINFO_DRV_INFO(cportinfo));
+			sata_show_drive_info(sata_hba_inst, &new_sdinfo);
+		}
 	}
 	mutex_exit(&SATA_CPORT_INFO(sata_hba_inst, saddr->cport)->cport_mutex);
 }
@@ -9745,3 +9845,60 @@
 
 	return (rval);
 }
+
+
+static void
+sata_gen_sysevent(sata_hba_inst_t *sata_hba_inst, sata_address_t *saddr,
+    int hint)
+{
+	char ap[MAXPATHLEN];
+	nvlist_t *ev_attr_list = NULL;
+	int err;
+
+	/* Allocate and build sysevent attribute list */
+	err = nvlist_alloc(&ev_attr_list, NV_UNIQUE_NAME_TYPE, DDI_NOSLEEP);
+	if (err != 0) {
+		SATA_LOG_D((sata_hba_inst, CE_WARN,
+		    "sata_gen_sysevent: "
+		    "cannot allocate memory for sysevent attributes\n"));
+		return;
+	}
+	/* Add hint attribute */
+	err = nvlist_add_string(ev_attr_list, DR_HINT, SE_HINT2STR(hint));
+	if (err != 0) {
+		SATA_LOG_D((sata_hba_inst, CE_WARN,
+		    "sata_gen_sysevent: "
+		    "failed to add DR_HINT attr for sysevent"));
+		nvlist_free(ev_attr_list);
+		return;
+	}
+	/*
+	 * Add AP attribute.
+	 * Get controller pathname and convert it into AP pathname by adding
+	 * a target number.
+	 */
+	(void) snprintf(ap, MAXPATHLEN, "/devices");
+	(void) ddi_pathname(SATA_DIP(sata_hba_inst), ap + strlen(ap));
+	(void) snprintf(ap + strlen(ap), MAXPATHLEN - strlen(ap), ":%d",
+	    SATA_MAKE_AP_NUMBER(saddr->cport, saddr->pmport, saddr->qual));
+
+	err = nvlist_add_string(ev_attr_list, DR_AP_ID, ap);
+	if (err != 0) {
+		SATA_LOG_D((sata_hba_inst, CE_WARN,
+		    "sata_gen_sysevent: "
+		    "failed to add DR_AP_ID attr for sysevent"));
+		nvlist_free(ev_attr_list);
+		return;
+	}
+
+	/* Generate/log sysevent */
+	err = ddi_log_sysevent(SATA_DIP(sata_hba_inst), DDI_VENDOR_SUNW, EC_DR,
+	    ESC_DR_AP_STATE_CHANGE, ev_attr_list, NULL, DDI_NOSLEEP);
+	if (err != DDI_SUCCESS) {
+		SATA_LOG_D((sata_hba_inst, CE_WARN,
+		    "sata_gen_sysevent: "
+		    "cannot log sysevent, err code %x\n", err));
+	}
+
+	nvlist_free(ev_attr_list);
+}