PSARC/2009/058 physical eject button
authorArtem Kachitchkine <Artem.Kachitchkin@Sun.COM>
Sat, 05 Sep 2009 09:21:22 -0700
changeset 10459 38bef17cedbb
parent 10458 6e451acbaeaf
child 10460 fd9eef1634c5
PSARC/2009/058 physical eject button 6795138 Solaris ignores eject button on optical drives
usr/src/cmd/hal/addons/storage/Makefile
usr/src/cmd/hal/addons/storage/addon-storage.c
usr/src/cmd/rmmount/rmmount.c
usr/src/cmd/rmvolmgr/rmm_common.c
usr/src/cmd/rmvolmgr/rmm_common.h
usr/src/cmd/rmvolmgr/rmvolmgr.c
usr/src/cmd/rmvolmgr/vold.c
usr/src/cmd/volcheck/volcheck.c
usr/src/cmd/volrmmount/volrmmount.c
usr/src/uts/common/io/scsi/impl/scsi_watch.c
usr/src/uts/common/io/scsi/targets/sd.c
usr/src/uts/common/sys/scsi/generic/commands.h
usr/src/uts/common/sys/scsi/scsi_watch.h
usr/src/uts/common/sys/scsi/targets/sddef.h
usr/src/uts/common/sys/sysevent/eventdefs.h
--- a/usr/src/cmd/hal/addons/storage/Makefile	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/cmd/hal/addons/storage/Makefile	Sat Sep 05 09:21:22 2009 -0700
@@ -19,11 +19,9 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-# ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 PROG =		hald-addon-storage
 OBJS =		addon-storage.o logger.o
@@ -34,7 +32,7 @@
 
 ROOTCMDDIR =	$(ROOTLIB_HAL)
 
-LDLIBS +=	-lc -ldbus-1 -lhal
+LDLIBS +=	-lc -ldbus-1 -lhal -lnvpair -lsysevent
 
 CPPFLAGS +=	$(HAL_DBUS_CPPFLAGS) $(HAL_CONFIG_CPPFLAGS)
 CPPFLAGS +=	-I$(ROOT)/usr/include/hal -I../../hald
--- a/usr/src/cmd/hal/addons/storage/addon-storage.c	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/cmd/hal/addons/storage/addon-storage.c	Sat Sep 05 09:21:22 2009 -0700
@@ -2,15 +2,13 @@
  *
  * addon-storage.c : watch removable media state changes
  *
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
  * Licensed under the Academic Free License version 2.1
  *
  **************************************************************************/
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
@@ -30,6 +28,8 @@
 #include <sys/mnttab.h>
 #include <sys/dkio.h>
 #include <priv.h>
+#include <libsysevent.h>
+#include <sys/sysevent/dev.h>
 
 #include <libhal.h>
 
@@ -37,6 +37,13 @@
 
 #define	SLEEP_PERIOD	5
 
+static char			*udi;
+static char			*devfs_path;
+LibHalContext			*ctx = NULL;
+static sysevent_handle_t	*shp = NULL;
+
+static void	sysevent_dev_handler(sysevent_t *);
+
 static void
 my_dbus_error_free(DBusError *error)
 {
@@ -46,6 +53,85 @@
 }
 
 static void
+sysevent_init ()
+{
+	const char	*subcl[1];
+
+	shp = sysevent_bind_handle (sysevent_dev_handler);
+	if (shp == NULL) {
+		HAL_DEBUG (("sysevent_bind_handle failed %d", errno));
+		return;
+	}
+
+	subcl[0] = ESC_DEV_EJECT_REQUEST;
+	if (sysevent_subscribe_event (shp, EC_DEV_STATUS, subcl, 1) != 0) {
+		HAL_INFO (("subscribe(dev_status) failed %d", errno));
+		sysevent_unbind_handle (shp);
+		return;
+	}
+}
+
+static void
+sysevent_fini ()
+{
+	if (shp != NULL) {
+		sysevent_unbind_handle (shp);
+		shp = NULL;
+	}
+}
+
+static void
+sysevent_dev_handler (sysevent_t *ev)
+{
+	char		*class;
+	char		*subclass;
+	nvlist_t	*attr_list;
+	char		*phys_path, *path;
+	char		*p;
+	int		len;
+	DBusError	error;
+
+	if ((class = sysevent_get_class_name (ev)) == NULL)
+		return;
+
+	if ((subclass = sysevent_get_subclass_name (ev)) == NULL)
+		return;
+
+	if ((strcmp (class, EC_DEV_STATUS) != 0) ||
+	    (strcmp (subclass, ESC_DEV_EJECT_REQUEST) != 0))
+		return;
+
+	if (sysevent_get_attr_list (ev, &attr_list) != 0)
+		return;
+
+	if (nvlist_lookup_string (attr_list, DEV_PHYS_PATH, &phys_path) != 0) {
+		goto out;
+	}
+
+	/* see if event belongs to our LUN (ignore slice and "/devices" ) */
+	if (strncmp (phys_path, "/devices", sizeof ("/devices") - 1) == 0)
+		path = phys_path + sizeof ("/devices") - 1;
+	else
+		path = phys_path;
+
+	if ((p = strrchr (path, ':')) == NULL)
+		goto out;
+	len = (uintptr_t)p - (uintptr_t)path;
+	if (strncmp (path, devfs_path, len) != 0)
+		goto out;
+
+	HAL_DEBUG (("sysevent_dev_handler %s %s", subclass, phys_path));
+
+	/* we got it, tell the world */
+	dbus_error_init (&error);
+	libhal_device_emit_condition (ctx, udi, "EjectPressed", "", &error);
+	dbus_error_free (&error);
+
+out:
+	nvlist_free(attr_list);
+}
+
+static void
 force_unmount (LibHalContext *ctx, const char *udi)
 {
 	DBusError error;
@@ -202,6 +288,9 @@
 	/* to open logindevperm'd devices */
 	(void) priv_addset(pPrivSet, PRIV_FILE_DAC_READ);
 
+	/* to receive sysevents */
+	(void) priv_addset(pPrivSet, PRIV_SYS_CONFIG);
+
 	/* Set the permitted privilege set. */
 	if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
 		return;
@@ -224,9 +313,7 @@
 int 
 main (int argc, char *argv[])
 {
-	char *udi;
 	char *device_file, *raw_device_file;
-	LibHalContext *ctx = NULL;
 	DBusError error;
 	char *bus;
 	char *drive_type;
@@ -245,11 +332,15 @@
 		goto out;
 	if ((drive_type = getenv ("HAL_PROP_STORAGE_DRIVE_TYPE")) == NULL)
 		goto out;
+	if ((devfs_path = getenv ("HAL_PROP_SOLARIS_DEVFS_PATH")) == NULL)
+		goto out;
 
 	drop_privileges ();
 
 	setup_logger ();
 
+	sysevent_init ();
+
 	support_media_changed_str = getenv ("HAL_PROP_STORAGE_CDROM_SUPPORT_MEDIA_CHANGED");
 	if (support_media_changed_str != NULL && strcmp (support_media_changed_str, "true") == 0)
 		support_media_changed = TRUE;
@@ -347,6 +438,7 @@
 	}
 
 out:
+	sysevent_fini ();
 	if (ctx != NULL) {
 		my_dbus_error_free (&error);
 		libhal_ctx_shutdown (ctx, &error);
--- a/usr/src/cmd/rmmount/rmmount.c	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/cmd/rmmount/rmmount.c	Sat Sep 05 09:21:22 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/types.h>
@@ -134,7 +132,7 @@
 		action = INSERT;
 	}
 
-	if ((hal_ctx = rmm_hal_init(0, 0, 0, &error, &rmm_error)) == NULL) {
+	if ((hal_ctx = rmm_hal_init(0, 0, 0, 0, &error, &rmm_error)) == NULL) {
 		(void) fprintf(stderr, gettext("warning: %s\n"),
 		    rmm_strerror(&error, rmm_error));
 		rmm_dbus_error_free(&error);
--- a/usr/src/cmd/rmvolmgr/rmm_common.c	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/cmd/rmvolmgr/rmm_common.c	Sat Sep 05 09:21:22 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <errno.h>
 #include <string.h>
@@ -64,7 +62,7 @@
 
 LibHalContext *
 rmm_hal_init(LibHalDeviceAdded devadd_cb, LibHalDeviceRemoved devrem_cb,
-    LibHalDevicePropertyModified propmod_cb,
+    LibHalDevicePropertyModified propmod_cb, LibHalDeviceCondition cond_cb,
     DBusError *error, rmm_error_t *rmm_error)
 {
 	DBusConnection	*dbus_conn;
@@ -114,6 +112,9 @@
 			return (NULL);
 		}
 	}
+	if (cond_cb != NULL) {
+		libhal_ctx_set_device_condition(ctx, cond_cb);
+	}
 
 	if (!libhal_ctx_init(ctx, error)) {
 		dprintf("libhal_ctx_init failed: %s", rmm_strerror(error, -1));
--- a/usr/src/cmd/rmvolmgr/rmm_common.h	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/cmd/rmvolmgr/rmm_common.h	Sat Sep 05 09:21:22 2009 -0700
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_COMMON_H
 #define	_COMMON_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -68,7 +66,8 @@
 extern char *progname;
 
 LibHalContext	*rmm_hal_init(LibHalDeviceAdded, LibHalDeviceRemoved,
-		LibHalDevicePropertyModified, DBusError *, rmm_error_t *);
+		LibHalDevicePropertyModified, LibHalDeviceCondition,
+		DBusError *, rmm_error_t *);
 void		rmm_hal_fini(LibHalContext *hal_ctx);
 
 LibHalDrive	*rmm_hal_volume_find(LibHalContext *, const char *,
--- a/usr/src/cmd/rmvolmgr/rmvolmgr.c	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/cmd/rmvolmgr/rmvolmgr.c	Sat Sep 05 09:21:22 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * rmvolmgr daemon
  */
@@ -72,12 +70,17 @@
 static boolean_t	opt_n;	/* disable legacy mountpoint symlinks */
 static boolean_t	opt_s;	/* system instance */
 
+/* SMF property "eject_button" */
+static boolean_t	rmm_prop_eject_button = B_TRUE;
+
 static void	get_smf_properties();
 static int	daemon(int nochdir, int noclose);
 static void	rmm_device_added(LibHalContext *ctx, const char *udi);
 static void	rmm_device_removed(LibHalContext *ctx, const char *udi);
 static void	rmm_property_modified(LibHalContext *ctx, const char *udi,
 		const char *key, dbus_bool_t is_removed, dbus_bool_t is_added);
+static void	rmm_device_condition(LibHalContext *ctx, const char *udi,
+		const char *name, const char *detail);
 static void	rmm_mount_all();
 static void	rmm_unmount_all();
 static void	sigexit(int signo);
@@ -200,7 +203,8 @@
 	signal(SIGUSR2, SIG_IGN);
 
 	if ((hal_ctx = rmm_hal_init(rmm_device_added, rmm_device_removed,
-	    rmm_property_modified, &error, &rmm_error)) == NULL) {
+	    rmm_property_modified, rmm_device_condition,
+	    &error, &rmm_error)) == NULL) {
 		dbus_error_free(&error);
 		return (1);
 	}
@@ -247,6 +251,14 @@
 		}
 		scf_simple_prop_free(prop);
 	}
+
+	if ((prop = scf_simple_prop_get(NULL, RMVOLMGR_FMRI,
+	    "rmvolmgr", "eject_button")) != NULL) {
+		if ((val = scf_simple_prop_next_boolean(prop)) != NULL) {
+			rmm_prop_eject_button = (*val != 0);
+		}
+		scf_simple_prop_free(prop);
+	}
 }
 
 /* ARGSUSED */
@@ -482,6 +494,34 @@
 	}
 }
 
+static void
+storage_eject_pressed(const char *udi)
+{
+	DBusError	error;
+
+	/* ignore if disabled via SMF or claimed by another volume manager */
+	if (!rmm_prop_eject_button ||
+	    libhal_device_get_property_bool(hal_ctx, udi, "info.claimed",
+	    NULL)) {
+		return;
+	}
+
+	dbus_error_init(&error);
+	(void) rmm_hal_eject(hal_ctx, udi, &error);
+	rmm_dbus_error_free(&error);
+}
+
+/* ARGSUSED */
+static void
+rmm_device_condition(LibHalContext *ctx, const char *udi,
+    const char *name, const char *detail)
+{
+	if ((strcmp(name, "EjectPressed") == 0) &&
+	    libhal_device_query_capability(hal_ctx, udi, "storage", NULL)) {
+		storage_eject_pressed(udi);
+	}
+}
+
 /*
  * Mount all mountable volumes
  */
--- a/usr/src/cmd/rmvolmgr/vold.c	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/cmd/rmvolmgr/vold.c	Sat Sep 05 09:21:22 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * Vold compatibility for rmvolmgr: emulate old commands as well as
  * action_filemgr.so to notify legacy apps via /tmp/.removable pipes.
@@ -277,7 +275,7 @@
 		rmm_vold_actions_enabled = B_TRUE;
 	}
 
-	if ((hal_ctx = rmm_hal_init(0, 0, 0, &error, &rmm_error)) == NULL) {
+	if ((hal_ctx = rmm_hal_init(0, 0, 0, 0, &error, &rmm_error)) == NULL) {
 		rmm_dbus_error_free(&error);
 
 		/* if HAL's not running, must be root */
@@ -534,8 +532,7 @@
 				    prog_name, prog_pid, errno);
 				return (1);
 			}
-		    }
-
+		}
 	}
 
 	/* only support one action at a time XXX */
@@ -585,7 +582,7 @@
 		}
 	} else {
 		dprintf("%s[%d]: action(): invalid action: %s\n",
-			__FILE__, __LINE__, action);
+		    __FILE__, __LINE__, action);
 		result = FALSE;
 	}
 
@@ -594,7 +591,7 @@
 	}
 
 	dprintf("%s[%d]: leaving action(), result = %s\n",
-		__FILE__, __LINE__, result_strings[result]);
+	    __FILE__, __LINE__, result_strings[result]);
 
 	if (mnt_zoneid > GLOBAL_ZONEID) {
 		/* exit forked local zone process */
@@ -666,7 +663,7 @@
 				 * file name conflicts.
 				 */
 				sprintf(notify_file, "%s-%s", symdev,
-						aa[ai]->aa_partname);
+				    aa[ai]->aa_partname);
 			} else {
 				sprintf(notify_file, "%s-0", symdev);
 			}
@@ -699,13 +696,13 @@
 					 * file name conflicts.
 					 */
 					sprintf(notify_file, "%s-%s", symdev,
-							aa[0]->aa_partname);
+					    aa[0]->aa_partname);
 				} else {
 					sprintf(notify_file, "%s-0", symdev);
 				}
 				if ((aa[0]->aa_type != NULL) &&
-					(strcmp(aa[0]->aa_type, "backup_slice")
-						== 0)) {
+				    (strcmp(aa[0]->aa_type, "backup_slice")
+				    == 0)) {
 					reason = "backup_slice";
 				} else {
 					reason = "unformatted_media";
@@ -723,15 +720,15 @@
 		}
 		raw_partitionp = aa[0]->aa_rawpath;
 		result = create_one_notify_file(fstype,
-				mount_point,
-				notify_file,
-				raw_partitionp,
-				reason,
-				symdev);
+		    mount_point,
+		    notify_file,
+		    raw_partitionp,
+		    reason,
+		    symdev);
 		ai++;
 	}
 	dprintf("%s[%d]: leaving create_notify_files(), result = %s\n",
-		__FILE__, __LINE__, result_strings[result]);
+	    __FILE__, __LINE__, result_strings[result]);
 	return (result);
 }
 
@@ -765,12 +762,12 @@
 	int	result;
 
 	dprintf("%s[%d]:Entering create_one_notify_file()\n",
-		__FILE__, __LINE__);
+	    __FILE__, __LINE__);
 	dprintf("\tcreate_one_notify_file(): fstype = %s\n", fstype);
 	dprintf("\tcreate_one_notify_file(): mount_point = %s\n", mount_point);
 	dprintf("\tcreate_one_notify_file(): notify_file = %s\n", notify_file);
 	dprintf("\tcreate_one_notify_file(): raw_partitionp = %s\n",
-		raw_partitionp);
+	    raw_partitionp);
 	if (reason != NULL) {
 		dprintf("\tcreate_one_notify_file(): reason = %s\n", reason);
 	} else {
@@ -819,42 +816,42 @@
 		 */
 		(void) remove(notify_file);
 		file_descriptor =
-			open(notify_file, O_CREAT|O_EXCL|O_WRONLY, 0644);
+		    open(notify_file, O_CREAT|O_EXCL|O_WRONLY, 0644);
 		if (file_descriptor < 0) {
 			dprintf("%s[%d]: can't create %s/%s; %m\n",
-				__FILE__, __LINE__, NOTIFY_DIR, notify_file);
+			    __FILE__, __LINE__, NOTIFY_DIR, notify_file);
 			result = FALSE;
 		} else {
 			filep = fdopen(file_descriptor, "w");
 			if (filep != NULL) {
 				if (reason == NULL) {
 					(void) fprintf(filep, "%s %s %s",
-						mount_point,
-						raw_partitionp,
-						fstype);
+					    mount_point,
+					    raw_partitionp,
+					    fstype);
 					(void) fclose(filep);
 				dprintf("%s[%d]: Just wrote %s %s %s to %s\n",
-						__FILE__,
-						__LINE__,
-						mount_point,
-						raw_partitionp,
-						fstype,
-						notify_file);
+				    __FILE__,
+				    __LINE__,
+				    mount_point,
+				    raw_partitionp,
+				    fstype,
+				    notify_file);
 				} else {
 					(void) fprintf(filep, "%s %s",
-						reason, raw_partitionp);
+					    reason, raw_partitionp);
 					(void) fclose(filep);
 				dprintf("%s[%d]: Just wrote %s %s to %s\n",
-						__FILE__,
-						__LINE__,
-						reason,
-						raw_partitionp,
-						notify_file);
+				    __FILE__,
+				    __LINE__,
+				    reason,
+				    raw_partitionp,
+				    notify_file);
 				}
 			} else {
 				dprintf("%s[%d]: can't write %s/%s; %m\n",
-					__FILE__, __LINE__,
-					NOTIFY_DIR, notify_file);
+				    __FILE__, __LINE__,
+				    NOTIFY_DIR, notify_file);
 				(void) close(file_descriptor);
 				result = FALSE;
 			}
@@ -862,7 +859,7 @@
 		popdir(current_working_dir_fd);
 	}
 	dprintf("%s[%d]: leaving create_one_notify_file, result = %s\n",
-		__FILE__, __LINE__, result_strings[result]);
+	    __FILE__, __LINE__, result_strings[result]);
 	return (result);
 }
 
@@ -910,7 +907,7 @@
 		dirp = opendir(".");
 		if (dirp == NULL) {
 			dprintf("%s[%d]:opendir failed on '.'; %m\n",
-				__FILE__, __LINE__);
+			    __FILE__, __LINE__);
 			popdir(current_working_dir_fd);
 			result = FALSE;
 		}
@@ -933,7 +930,7 @@
 				continue;
 			}
 			(void) sprintf(namebuf, "%s/%s",
-				NOTIFY_DIR, dir_entryp->d_name);
+			    NOTIFY_DIR, dir_entryp->d_name);
 			if ((fd = open(namebuf, O_WRONLY|O_NDELAY)) < 0) {
 				dprintf("%s[%d]: open failed for %s; %m\n",
 				    __FILE__, __LINE__, namebuf);
@@ -946,7 +943,7 @@
 			 */
 			if ((fstat(fd, &sb) < 0) || (!S_ISFIFO(sb.st_mode))) {
 				dprintf("%s[%d]: %s isn't a named pipe\n",
-					__FILE__, __LINE__, namebuf);
+				    __FILE__, __LINE__, namebuf);
 
 				(void) close(fd);
 				continue;
@@ -965,7 +962,7 @@
 		popdir(current_working_dir_fd);
 	}
 	dprintf("%s[%d]: leaving notify_clients(), result = %s\n",
-		__FILE__, __LINE__, result_strings[result]);
+	    __FILE__, __LINE__, result_strings[result]);
 	return (result);
 }
 
@@ -1010,25 +1007,25 @@
 
 	if (lstat(dir, &stat_buf) < 0) {
 		dprintf("%s[%d]: push_dir_and_check(): %s does not exist\n",
-			__FILE__, __LINE__, dir);
+		    __FILE__, __LINE__, dir);
 		return (-1);
 	}
 
 	if (!(S_ISDIR(stat_buf.st_mode))) {
 		dprintf("%s[%d]: push_dir_and_check(): %s not a directory.\n",
-			__FILE__, __LINE__, dir);
+		    __FILE__, __LINE__, dir);
 		(void) remove(dir);
 		return (-1);
 	}
 	if ((current_working_dir_fd = open(".", O_RDONLY)) < 0) {
 		dprintf("%s[%d]: push_dir_and_check(): can't open %s.\n",
-			__FILE__, __LINE__, dir);
+		    __FILE__, __LINE__, dir);
 		return (-1);
 	}
 	if (chdir(dir) < 0) {
 		(void) close(current_working_dir_fd);
 		dprintf("%s[%d]: push_dir_and_check(): can't chdir() to %s.\n",
-			__FILE__, __LINE__, dir);
+		    __FILE__, __LINE__, dir);
 		return (-1);
 	}
 	return (current_working_dir_fd);
@@ -1049,8 +1046,8 @@
 	result = TRUE;
 	symdev = aa[ai]->aa_symdev;
 	while ((result == TRUE) &&
-		(aa[ai] != NULL) &&
-		(aa[ai]->aa_path != NULL)) {
+	    (aa[ai] != NULL) &&
+	    (aa[ai]->aa_path != NULL)) {
 
 		if (not_mountable(aa[ai])) {
 			sprintf(notify_file, "%s-0", symdev);
@@ -1063,7 +1060,7 @@
 			 * file name conflicts.
 			 */
 			sprintf(notify_file, "%s-%s",
-				symdev, aa[0]->aa_partname);
+			    symdev, aa[0]->aa_partname);
 		} else {
 			sprintf(notify_file, "%s-0", symdev);
 		}
@@ -1074,7 +1071,7 @@
 		}
 		if ((result == TRUE) && (remove(notify_file) < 0)) {
 			dprintf("%s[%d]: remove %s/%s; %m\n",
-				__FILE__, __LINE__, NOTIFY_DIR, notify_file);
+			    __FILE__, __LINE__, NOTIFY_DIR, notify_file);
 			result = FALSE;
 		}
 		if (current_working_dir_fd != -1) {
@@ -1083,7 +1080,7 @@
 		ai++;
 	}
 	dprintf("%s[%d]: leaving remove_notify_files(), result = %s\n",
-		__FILE__, __LINE__, result_strings[result]);
+	    __FILE__, __LINE__, result_strings[result]);
 
 	return (result);
 }
--- a/usr/src/cmd/volcheck/volcheck.c	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/cmd/volcheck/volcheck.c	Sat Sep 05 09:21:22 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -83,7 +81,7 @@
 		}
 	}
 
-	if ((hal_ctx = rmm_hal_init(0, 0, 0, &error, &rmm_error)) == NULL) {
+	if ((hal_ctx = rmm_hal_init(0, 0, 0, 0, &error, &rmm_error)) == NULL) {
 		(void) fprintf(stderr,
 		    gettext("HAL initialization failed: %s\n"),
 		    rmm_strerror(&error, rmm_error));
--- a/usr/src/cmd/volrmmount/volrmmount.c	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/cmd/volrmmount/volrmmount.c	Sat Sep 05 09:21:22 2009 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -105,7 +103,7 @@
 		return (1);
 	}
 
-	if ((hal_ctx = rmm_hal_init(0, 0, 0, &error, &rmm_error)) == NULL) {
+	if ((hal_ctx = rmm_hal_init(0, 0, 0, 0, &error, &rmm_error)) == NULL) {
 		(void) fprintf(stderr,
 		    gettext("HAL initialization failed: %s\n"),
 		    rmm_strerror(&error, rmm_error));
--- a/usr/src/uts/common/io/scsi/impl/scsi_watch.c	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/uts/common/io/scsi/impl/scsi_watch.c	Sat Sep 05 09:21:22 2009 -0700
@@ -122,6 +122,7 @@
 	struct scsi_pkt		*swr_pkt;	/* TUR pkt itself	*/
 	struct scsi_pkt		*swr_rqpkt;	/* request sense pkt	*/
 	struct buf		*swr_rqbp;	/* bp for request sense data */
+	struct buf		*swr_mmcbp;	/* bp for MMC command data */
 	int			(*swr_callback)(); /* callback to driver */
 	caddr_t			swr_callback_arg;
 	kcondvar_t		swr_terminate_cv; /* cv to wait on to cleanup */
@@ -147,6 +148,9 @@
 #define	SWR_SUSPEND_REQUESTED	2	/* req. pending suspend */
 #define	SWR_SUSPENDED		3	/* req. is suspended */
 
+static opaque_t scsi_watch_request_submit_impl(struct scsi_device *devp,
+    int interval, int sense_length, int (*callback)(), caddr_t cb_arg,
+    boolean_t mmc);
 static void scsi_watch_request_destroy(struct scsi_watch_request *swr);
 static void scsi_watch_thread(void);
 static void scsi_watch_request_intr(struct scsi_pkt *pkt);
@@ -195,9 +199,35 @@
 	int			(*callback)(),	/* callback function */
 	caddr_t			cb_arg)		/* device number */
 {
+	return (scsi_watch_request_submit_impl(devp, interval, sense_length,
+	    callback, cb_arg, B_FALSE));
+}
+
+opaque_t
+scsi_mmc_watch_request_submit(
+	struct scsi_device	*devp,
+	int			interval,
+	int			sense_length,
+	int			(*callback)(),	/* callback function */
+	caddr_t			cb_arg)		/* device number */
+{
+	return (scsi_watch_request_submit_impl(devp, interval, sense_length,
+	    callback, cb_arg, B_TRUE));
+}
+
+static opaque_t
+scsi_watch_request_submit_impl(
+	struct scsi_device	*devp,
+	int			interval,
+	int			sense_length,
+	int			(*callback)(),	/* callback function */
+	caddr_t			cb_arg,		/* device number */
+	boolean_t		mmc)
+{
 	register struct scsi_watch_request	*swr = NULL;
 	register struct scsi_watch_request	*sswr, *p;
 	struct buf				*bp = NULL;
+	struct buf				*mmcbp = NULL;
 	struct scsi_pkt				*rqpkt = NULL;
 	struct scsi_pkt				*pkt = NULL;
 	uchar_t					dtype;
@@ -259,15 +289,27 @@
 	rqpkt->pkt_flags |= FLAG_HEAD;
 
 	/*
-	 * Create TUR pkt or a zero byte WRITE(10) based on the
-	 * disk-type for reservation state.
+	 * Create TUR pkt or GET STATUS EVENT NOTIFICATION for MMC requests or
+	 * a zero byte WRITE(10) based on the disk-type for reservation state.
 	 * For inq_dtype of SBC (DIRECT, dtype == 0)
 	 * OR for RBC devices (dtype is 0xE) AND for
 	 * ANSI version of SPC/SPC-2/SPC-3 (inq_ansi == 3-5).
 	 */
 
 	dtype = devp->sd_inq->inq_dtype & DTYPE_MASK;
-	if (((dtype == 0) || (dtype == 0xE)) &&
+	if (mmc) {
+		mmcbp = scsi_alloc_consistent_buf(ROUTE, NULL,
+		    8, B_READ, SLEEP_FUNC, NULL);
+
+		pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, mmcbp,
+		    CDB_GROUP1, sizeof (struct scsi_arq_status),
+		    0, 0, SLEEP_FUNC, NULL);
+
+		(void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp,
+		    SCMD_GET_EVENT_STATUS_NOTIFICATION, 0, 8, 0);
+		pkt->pkt_cdbp[1] = 1; /* polled */
+		pkt->pkt_cdbp[4] = 1 << SD_GESN_MEDIA_CLASS;
+	} else if (((dtype == 0) || (dtype == 0xE)) &&
 	    (devp->sd_inq->inq_ansi > 2)) {
 		pkt = scsi_init_pkt(ROUTE, (struct scsi_pkt *)NULL, NULL,
 		    CDB_GROUP1, sizeof (struct scsi_arq_status),
@@ -297,6 +339,7 @@
 	 */
 	swr->swr_rqbp = bp;
 	swr->swr_rqpkt = rqpkt;
+	swr->swr_mmcbp = mmcbp;
 	swr->swr_pkt = pkt;
 	swr->swr_timeout = swr->swr_interval = drv_usectohz(interval);
 	swr->swr_callback = callback;
@@ -465,6 +508,9 @@
 
 	scsi_destroy_pkt(swr->swr_rqpkt);
 	scsi_free_consistent_buf(swr->swr_rqbp);
+	if (swr->swr_mmcbp != NULL) {
+		scsi_free_consistent_buf(swr->swr_mmcbp);
+	}
 	scsi_destroy_pkt(swr->swr_pkt);
 	cv_signal(&swr->swr_terminate_cv);
 }
@@ -945,6 +991,9 @@
 	result.sensep = rqsensep;
 	result.actual_sense_length = (uchar_t)amt;
 	result.pkt = swr->swr_pkt;
+	if (swr->swr_mmcbp != NULL) {
+		bcopy(swr->swr_mmcbp->b_un.b_addr, result.mmc_data, 8);
+	}
 
 	if ((*swr->swr_callback)(swr->swr_callback_arg, &result)) {
 		swr->swr_what = SWR_STOP;
--- a/usr/src/uts/common/io/scsi/targets/sd.c	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/uts/common/io/scsi/targets/sd.c	Sat Sep 05 09:21:22 2009 -0700
@@ -1018,7 +1018,9 @@
 #define	sd_taskq_create			ssd_taskq_create
 #define	sd_taskq_delete			ssd_taskq_delete
 #define	sd_target_change_task		ssd_target_change_task
+#define	sd_log_dev_status_event		ssd_log_dev_status_event
 #define	sd_log_lun_expansion_event	ssd_log_lun_expansion_event
+#define	sd_log_eject_request_event	ssd_log_eject_request_event
 #define	sd_media_change_task		ssd_media_change_task
 #define	sd_handle_mchange		ssd_handle_mchange
 #define	sd_send_scsi_DOORLOCK		ssd_send_scsi_DOORLOCK
@@ -1041,6 +1043,9 @@
 #define	sd_send_scsi_MODE_SELECT	ssd_send_scsi_MODE_SELECT
 #define	sd_send_scsi_RDWR		ssd_send_scsi_RDWR
 #define	sd_send_scsi_LOG_SENSE		ssd_send_scsi_LOG_SENSE
+#define	sd_send_scsi_GET_EVENT_STATUS_NOTIFICATION	\
+				ssd_send_scsi_GET_EVENT_STATUS_NOTIFICATION
+#define	sd_gesn_media_data_valid	ssd_gesn_media_data_valid
 #define	sd_alloc_rqs			ssd_alloc_rqs
 #define	sd_free_rqs			ssd_free_rqs
 #define	sd_dump_memory			ssd_dump_memory
@@ -1092,6 +1097,7 @@
 #define	sr_eject			ssr_eject
 #define	sr_ejected			ssr_ejected
 #define	sr_check_wp			ssr_check_wp
+#define	sd_watch_request_submit		ssd_watch_request_submit
 #define	sd_check_media			ssd_check_media
 #define	sd_media_watch_cb		ssd_media_watch_cb
 #define	sd_delayed_cv_broadcast		ssd_delayed_cv_broadcast
@@ -1485,7 +1491,9 @@
 static void sd_taskq_create(void);
 static void sd_taskq_delete(void);
 static void sd_target_change_task(void *arg);
+static void sd_log_dev_status_event(struct sd_lun *un, char *esc, int km_flag);
 static void sd_log_lun_expansion_event(struct sd_lun *un, int km_flag);
+static void sd_log_eject_request_event(struct sd_lun *un, int km_flag);
 static void sd_media_change_task(void *arg);
 
 static int sd_handle_mchange(struct sd_lun *un);
@@ -1528,6 +1536,9 @@
 static int sd_send_scsi_LOG_SENSE(sd_ssc_t *ssc, uchar_t *bufaddr,
 	uint16_t buflen, uchar_t page_code, uchar_t page_control,
 	uint16_t param_ptr, int path_flag);
+static int sd_send_scsi_GET_EVENT_STATUS_NOTIFICATION(sd_ssc_t *ssc,
+	uchar_t *bufaddr, size_t buflen, uchar_t class_req);
+static boolean_t sd_gesn_media_data_valid(uchar_t *data);
 
 static int  sd_alloc_rqs(struct scsi_device *devp, struct sd_lun *un);
 static void sd_free_rqs(struct sd_lun *un);
@@ -1590,6 +1601,7 @@
 static int sr_eject(dev_t dev);
 static void sr_ejected(register struct sd_lun *un);
 static int sr_check_wp(dev_t dev);
+static opaque_t sd_watch_request_submit(struct sd_lun *un);
 static int sd_check_media(dev_t dev, enum dkio_state state);
 static int sd_media_watch_cb(caddr_t arg, struct scsi_watch_result *resultp);
 static void sd_delayed_cv_broadcast(void *arg);
@@ -3405,6 +3417,8 @@
 	int				rtn;
 	uchar_t				*out_data_rw, *out_data_hd;
 	uchar_t				*rqbuf_rw, *rqbuf_hd;
+	uchar_t				*out_data_gesn;
+	int				gesn_len;
 	struct sd_lun			*un;
 
 	ASSERT(ssc != NULL);
@@ -3437,6 +3451,28 @@
 	 */
 	un->un_f_mmc_cap = TRUE;
 
+	/* See if GET STATUS EVENT NOTIFICATION is supported */
+	if (un->un_f_mmc_gesn_polling) {
+		gesn_len = SD_GESN_HEADER_LEN + SD_GESN_MEDIA_DATA_LEN;
+		out_data_gesn = kmem_zalloc(gesn_len, KM_SLEEP);
+
+		rtn = sd_send_scsi_GET_EVENT_STATUS_NOTIFICATION(ssc,
+		    out_data_gesn, gesn_len, 1 << SD_GESN_MEDIA_CLASS);
+
+		sd_ssc_assessment(ssc, SD_FMT_IGNORE);
+
+		if ((rtn != 0) || !sd_gesn_media_data_valid(out_data_gesn)) {
+			un->un_f_mmc_gesn_polling = FALSE;
+			SD_INFO(SD_LOG_ATTACH_DETACH, un,
+			    "sd_set_mmc_caps: gesn not supported "
+			    "%d %x %x %x %x\n", rtn,
+			    out_data_gesn[0], out_data_gesn[1],
+			    out_data_gesn[2], out_data_gesn[3]);
+		}
+
+		kmem_free(out_data_gesn, gesn_len);
+	}
+
 	/* Get to the page data */
 	sense_mhp = (struct mode_header_grp2 *)buf;
 	bd_len = (sense_mhp->bdesc_length_hi << 8) |
@@ -4177,6 +4213,20 @@
 		un->un_saved_throttle = un->un_throttle = sd_max_throttle;
 		un->un_min_throttle = sd_min_throttle;
 	}
+
+	if (strcasecmp(name, "mmc-gesn-polling") == 0) {
+		if (strcasecmp(value, "true") == 0) {
+			un->un_f_mmc_gesn_polling = TRUE;
+		} else if (strcasecmp(value, "false") == 0) {
+			un->un_f_mmc_gesn_polling = FALSE;
+		} else {
+			goto value_invalid;
+		}
+		SD_INFO(SD_LOG_ATTACH_DETACH, un, "sd_set_properties: "
+		    "mmc-gesn-polling set to %d\n",
+		    un->un_f_mmc_gesn_polling);
+	}
+
 	return;
 
 value_invalid:
@@ -6529,7 +6579,6 @@
 	int		log_sense_page;
 	int		medium_present;
 	time_t		intvlp;
-	dev_t		dev;
 	struct pm_trans_data	sd_pm_tran_data;
 	uchar_t		save_state;
 	int		sval;
@@ -6545,7 +6594,6 @@
 		return (DDI_FAILURE);
 	}
 
-	dev = sd_make_device(SD_DEVINFO(un));
 	ssc = sd_ssc_init(un);
 
 	SD_TRACE(SD_LOG_IO_PM, un, "sdpower: entry, level = %d\n", level);
@@ -6959,11 +7007,8 @@
 
 					un->un_f_watcht_stopped = FALSE;
 					mutex_exit(SD_MUTEX(un));
-					temp_token = scsi_watch_request_submit(
-					    SD_SCSI_DEVP(un),
-					    sd_check_media_time,
-					    SENSE_LENGTH, sd_media_watch_cb,
-					    (caddr_t)dev);
+					temp_token =
+					    sd_watch_request_submit(un);
 					mutex_enter(SD_MUTEX(un));
 					un->un_swr_token = temp_token;
 				}
@@ -7539,6 +7584,12 @@
 	un->un_f_rmw_type = SD_RMW_TYPE_DEFAULT;
 
 	/*
+	 * GET EVENT STATUS NOTIFICATION media polling enabled by default, but
+	 * can be overridden via [s]sd-config-list "mmc-gesn-polling" property.
+	 */
+	un->un_f_mmc_gesn_polling = TRUE;
+
+	/*
 	 * Retrieve the properties from the static driver table or the driver
 	 * configuration file (.conf) for this unit and update the soft state
 	 * for the device as needed for the indicated properties.
@@ -8016,7 +8067,6 @@
 		sd_set_mmc_caps(ssc);
 	}
 
-
 	/*
 	 * Add a zero-length attribute to tell the world we support
 	 * kernel ioctls (for layered drivers)
@@ -19475,33 +19525,34 @@
 	sd_ssc_fini(ssc);
 }
 
-/*
- *    Function: sd_log_lun_expansion_event
- *
- * Description: Log lun expansion sys event
+
+/*
+ *    Function: sd_log_dev_status_event
+ *
+ * Description: Log EC_dev_status sysevent
  *
  *     Context: Never called from interrupt context
  */
 static void
-sd_log_lun_expansion_event(struct sd_lun *un, int km_flag)
+sd_log_dev_status_event(struct sd_lun *un, char *esc, int km_flag)
 {
 	int err;
 	char			*path;
-	nvlist_t		*dle_attr_list;
+	nvlist_t		*attr_list;
 
 	/* Allocate and build sysevent attribute list */
-	err = nvlist_alloc(&dle_attr_list, NV_UNIQUE_NAME_TYPE, km_flag);
+	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, km_flag);
 	if (err != 0) {
 		SD_ERROR(SD_LOG_ERROR, un,
-		    "sd_log_lun_expansion_event: fail to allocate space\n");
+		    "sd_log_dev_status_event: fail to allocate space\n");
 		return;
 	}
 
 	path = kmem_alloc(MAXPATHLEN, km_flag);
 	if (path == NULL) {
-		nvlist_free(dle_attr_list);
+		nvlist_free(attr_list);
 		SD_ERROR(SD_LOG_ERROR, un,
-		    "sd_log_lun_expansion_event: fail to allocate space\n");
+		    "sd_log_dev_status_event: fail to allocate space\n");
 		return;
 	}
 	/*
@@ -19513,27 +19564,56 @@
 	(void) snprintf(path + strlen(path), MAXPATHLEN - strlen(path),
 	    ":a");
 
-	err = nvlist_add_string(dle_attr_list, DEV_PHYS_PATH, path);
+	err = nvlist_add_string(attr_list, DEV_PHYS_PATH, path);
 	if (err != 0) {
-		nvlist_free(dle_attr_list);
+		nvlist_free(attr_list);
 		kmem_free(path, MAXPATHLEN);
 		SD_ERROR(SD_LOG_ERROR, un,
-		    "sd_log_lun_expansion_event: fail to add attribute\n");
+		    "sd_log_dev_status_event: fail to add attribute\n");
 		return;
 	}
 
 	/* Log dynamic lun expansion sysevent */
 	err = ddi_log_sysevent(SD_DEVINFO(un), SUNW_VENDOR, EC_DEV_STATUS,
-	    ESC_DEV_DLE, dle_attr_list, NULL, km_flag);
+	    esc, attr_list, NULL, km_flag);
 	if (err != DDI_SUCCESS) {
 		SD_ERROR(SD_LOG_ERROR, un,
-		    "sd_log_lun_expansion_event: fail to log sysevent\n");
-	}
-
-	nvlist_free(dle_attr_list);
+		    "sd_log_dev_status_event: fail to log sysevent\n");
+	}
+
+	nvlist_free(attr_list);
 	kmem_free(path, MAXPATHLEN);
 }
 
+
+/*
+ *    Function: sd_log_lun_expansion_event
+ *
+ * Description: Log lun expansion sys event
+ *
+ *     Context: Never called from interrupt context
+ */
+static void
+sd_log_lun_expansion_event(struct sd_lun *un, int km_flag)
+{
+	sd_log_dev_status_event(un, ESC_DEV_DLE, km_flag);
+}
+
+
+/*
+ *    Function: sd_log_eject_request_event
+ *
+ * Description: Log eject request sysevent
+ *
+ *     Context: Never called from interrupt context
+ */
+static void
+sd_log_eject_request_event(struct sd_lun *un, int km_flag)
+{
+	sd_log_dev_status_event(un, ESC_DEV_EJECT_REQUEST, km_flag);
+}
+
+
 /*
  *    Function: sd_media_change_task
  *
@@ -21822,6 +21902,94 @@
 
 
 /*
+ *    Function: sd_send_scsi_GET_EVENT_STATUS_NOTIFICATION
+ *
+ * Description: Issue the scsi GET EVENT STATUS NOTIFICATION command.
+ *
+ *   Arguments: ssc   - ssc contains pointer to driver soft state (unit)
+ *                      structure for this target.
+ *		bufaddr
+ *		buflen
+ *		class_req
+ *
+ * Return Code: 0   - Success
+ *		errno return code from sd_ssc_send()
+ *
+ *     Context: Can sleep. Does not return until command is completed.
+ */
+
+static int
+sd_send_scsi_GET_EVENT_STATUS_NOTIFICATION(sd_ssc_t *ssc, uchar_t *bufaddr,
+	size_t buflen, uchar_t class_req)
+{
+	union scsi_cdb		cdb;
+	struct uscsi_cmd	ucmd_buf;
+	int			status;
+	struct sd_lun		*un;
+
+	ASSERT(ssc != NULL);
+	un = ssc->ssc_un;
+	ASSERT(un != NULL);
+	ASSERT(!mutex_owned(SD_MUTEX(un)));
+	ASSERT(bufaddr != NULL);
+
+	SD_TRACE(SD_LOG_IO, un,
+	    "sd_send_scsi_GET_EVENT_STATUS_NOTIFICATION: entry: un:0x%p\n", un);
+
+	bzero(&cdb, sizeof (cdb));
+	bzero(&ucmd_buf, sizeof (ucmd_buf));
+	bzero(bufaddr, buflen);
+
+	cdb.scc_cmd = SCMD_GET_EVENT_STATUS_NOTIFICATION;
+	cdb.cdb_opaque[1] = 1; /* polled */
+	cdb.cdb_opaque[4] = class_req;
+	FORMG1COUNT(&cdb, buflen);
+
+	ucmd_buf.uscsi_cdb	= (char *)&cdb;
+	ucmd_buf.uscsi_cdblen	= CDB_GROUP1;
+	ucmd_buf.uscsi_bufaddr	= (caddr_t)bufaddr;
+	ucmd_buf.uscsi_buflen	= buflen;
+	ucmd_buf.uscsi_rqbuf	= NULL;
+	ucmd_buf.uscsi_rqlen	= 0;
+	ucmd_buf.uscsi_flags	= USCSI_READ | USCSI_SILENT;
+	ucmd_buf.uscsi_timeout	= 60;
+
+	status = sd_ssc_send(ssc, &ucmd_buf, FKIOCTL,
+	    UIO_SYSSPACE, SD_PATH_DIRECT);
+
+	/*
+	 * Only handle status == 0, the upper-level caller
+	 * will put different assessment based on the context.
+	 */
+	if (status == 0) {
+		sd_ssc_assessment(ssc, SD_FMT_STANDARD);
+
+		if (ucmd_buf.uscsi_resid != 0) {
+			status = EIO;
+		}
+	}
+
+	SD_TRACE(SD_LOG_IO, un,
+	    "sd_send_scsi_GET_EVENT_STATUS_NOTIFICATION: exit\n");
+
+	return (status);
+}
+
+
+static boolean_t
+sd_gesn_media_data_valid(uchar_t *data)
+{
+	uint16_t			len;
+
+	len = (data[1] << 8) | data[0];
+	return ((len >= 6) &&
+	    ((data[2] & SD_GESN_HEADER_NEA) == 0) &&
+	    ((data[2] & SD_GESN_HEADER_CLASS) == SD_GESN_MEDIA_CLASS) &&
+	    ((data[3] & (1 << SD_GESN_MEDIA_CLASS)) != 0));
+}
+
+
+/*
  *    Function: sdioctl
  *
  * Description: Driver's ioctl(9e) entry point function.
@@ -23350,6 +23518,32 @@
 }
 
 /*
+ *    Function: sd_watch_request_submit
+ *
+ * Description: Call scsi_watch_request_submit or scsi_mmc_watch_request_submit
+ *		depending on which is supported by device.
+ */
+static opaque_t
+sd_watch_request_submit(struct sd_lun *un)
+{
+	dev_t			dev;
+
+	/* All submissions are unified to use same device number */
+	dev = sd_make_device(SD_DEVINFO(un));
+
+	if (un->un_f_mmc_cap && un->un_f_mmc_gesn_polling) {
+		return (scsi_mmc_watch_request_submit(SD_SCSI_DEVP(un),
+		    sd_check_media_time, SENSE_LENGTH, sd_media_watch_cb,
+		    (caddr_t)dev));
+	} else {
+		return (scsi_watch_request_submit(SD_SCSI_DEVP(un),
+		    sd_check_media_time, SENSE_LENGTH, sd_media_watch_cb,
+		    (caddr_t)dev));
+	}
+}
+
+
+/*
  *    Function: sd_check_media
  *
  * Description: This utility routine implements the functionality for the
@@ -23380,18 +23574,11 @@
 	opaque_t		token = NULL;
 	int			rval = 0;
 	sd_ssc_t		*ssc;
-	dev_t			sub_dev;
 
 	if ((un = ddi_get_soft_state(sd_state, SDUNIT(dev))) == NULL) {
 		return (ENXIO);
 	}
 
-	/*
-	 * sub_dev is used when submitting request to scsi watch.
-	 * All submissions are unified to use same device number.
-	 */
-	sub_dev = sd_make_device(SD_DEVINFO(un));
-
 	SD_TRACE(SD_LOG_COMMON, un, "sd_check_media: entry\n");
 
 	ssc = sd_ssc_init(un);
@@ -23423,9 +23610,7 @@
 			goto done;
 		}
 
-		token = scsi_watch_request_submit(SD_SCSI_DEVP(un),
-		    sd_check_media_time, SENSE_LENGTH, sd_media_watch_cb,
-		    (caddr_t)sub_dev);
+		token = sd_watch_request_submit(un);
 
 		sd_pm_exit(un);
 
@@ -23663,12 +23848,25 @@
 		return (0);
 	}
 
-	/*
-	 * If there was a check condition then sensep points to valid sense data
-	 * If status was not a check condition but a reservation or busy status
-	 * then the new state is DKIO_NONE
-	 */
-	if (sensep != NULL) {
+	if (un->un_f_mmc_cap && un->un_f_mmc_gesn_polling) {
+		if (sd_gesn_media_data_valid(resultp->mmc_data)) {
+			if ((resultp->mmc_data[5] &
+			    SD_GESN_MEDIA_EVENT_STATUS_PRESENT) != 0) {
+				state = DKIO_INSERTED;
+			} else {
+				state = DKIO_EJECTED;
+			}
+			if ((resultp->mmc_data[4] & SD_GESN_MEDIA_EVENT_CODE) ==
+			    SD_GESN_MEDIA_EVENT_EJECTREQUEST) {
+				sd_log_eject_request_event(un, KM_NOSLEEP);
+			}
+		}
+	} else if (sensep != NULL) {
+		/*
+		 * If there was a check condition then sensep points to valid
+		 * sense data. If status was not a check condition but a
+		 * reservation or busy status then the new state is DKIO_NONE.
+		 */
 		skey = scsi_sense_key(sensep);
 		asc = scsi_sense_asc(sensep);
 		ascq = scsi_sense_ascq(sensep);
--- a/usr/src/uts/common/sys/scsi/generic/commands.h	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/uts/common/sys/scsi/generic/commands.h	Sat Sep 05 09:21:22 2009 -0700
@@ -20,15 +20,13 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef	_SYS_SCSI_GENERIC_COMMANDS_H
 #define	_SYS_SCSI_GENERIC_COMMANDS_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -289,6 +287,36 @@
 /*	SCMD_SET_LIMITS		0x33	*/
 
 /*
+ * Group 1 Commands, MMC Devices
+ */
+
+/* GET EVENT STATUS NOTIFICATION, MMC-3 5.6 */
+#define	SCMD_GET_EVENT_STATUS_NOTIFICATION	0x4a
+
+/* event header */
+#define	SD_GESN_HEADER_LEN			4
+#define	SD_GESN_HEADER_NEA			0x80	/* byte 2 */
+#define	SD_GESN_HEADER_CLASS			0x07	/* byte 2 */
+
+/* media class event class and event data that follows the header */
+#define	SD_GESN_MEDIA_CLASS			4
+
+#define	SD_GESN_MEDIA_DATA_LEN			4
+#define	SD_GESN_MEDIA_EVENT_CODE		0x0f	/* byte 0 */
+#define	SD_GESN_MEDIA_EVENT_STATUS_PRESENT	0x02	/* byte 1 */
+#define	SD_GESN_MEDIA_EVENT_STATUS_TRAY_OPEN	0x01	/* byte 1 */
+
+/* media event code */
+#define	SD_GESN_MEDIA_EVENT_NOCHG		0
+#define	SD_GESN_MEDIA_EVENT_EJECTREQUEST	1
+#define	SD_GESN_MEDIA_EVENT_NEWMEDIA		2
+#define	SD_GESN_MEDIA_EVENT_MEDIAREMOVAL	3
+#define	SD_GESN_MEDIA_EVENT_MEDIACHANGED	4
+#define	SD_GESN_MEDIA_EVENT_BGFORMATCOMPLETED	5
+#define	SD_GESN_MEDIA_EVENT_BGFORMATRESTARTED	6
+
+
+/*
  * Group 3 Commands
  */
 #define	SCMD_VAR_LEN		0x7f
--- a/usr/src/uts/common/sys/scsi/scsi_watch.h	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/uts/common/sys/scsi/scsi_watch.h	Sat Sep 05 09:21:22 2009 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -34,6 +34,7 @@
 	struct scsi_status		*statusp;
 	struct scsi_extended_sense	*sensep;
 	uchar_t				actual_sense_length;
+	uchar_t				mmc_data[8];
 	struct scsi_pkt			*pkt;
 };
 
@@ -57,6 +58,9 @@
 opaque_t scsi_watch_request_submit(struct scsi_device *devp,
 	    int interval, int sense_length,
 	    int (*callback)(), caddr_t cb_arg);
+opaque_t scsi_mmc_watch_request_submit(struct scsi_device *devp,
+	    int interval, int sense_length,
+	    int (*callback)(), caddr_t cb_arg);
 int	scsi_watch_request_terminate(opaque_t token, int flags);
 int	scsi_watch_get_ref_count(opaque_t token);
 void	scsi_watch_resume(opaque_t token);
--- a/usr/src/uts/common/sys/scsi/targets/sddef.h	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/uts/common/sys/scsi/targets/sddef.h	Sat Sep 05 09:21:22 2009 -0700
@@ -454,7 +454,9 @@
 	    un_f_pm_log_sense_smart	:1,	/* log sense support SMART */
 						/* feature attribute */
 	    un_f_is_solid_state		:1,	/* has solid state media */
-	    un_f_reserved		:6;
+	    un_f_mmc_gesn_polling	:1,	/* use GET EVENT STATUS */
+						/* NOTIFICATION for polling */
+	    un_f_reserved		:5;
 
 	/* Ptr to table of strings for ASC/ASCQ error message printing */
 	struct scsi_asq_key_strings	*un_additional_codes;
--- a/usr/src/uts/common/sys/sysevent/eventdefs.h	Fri Sep 04 15:35:04 2009 -0700
+++ b/usr/src/uts/common/sys/sysevent/eventdefs.h	Sat Sep 05 09:21:22 2009 -0700
@@ -202,9 +202,16 @@
 /* device tree branch removed */
 #define	ESC_DEV_BRANCH_REMOVE	"ESC_dev_branch_remove"
 
-/* device capacity dynamically changed */
+/*
+ * EC_DEV_STATUS subclass definitions
+ *
+ * device capacity dynamically changed
+ */
 #define	ESC_DEV_DLE		"ESC_dev_dle"
 
+/* LUN has received an eject request from the user */
+#define	ESC_DEV_EJECT_REQUEST	"ESC_dev_eject_request"
+
 /* FMA Fault and Error event protocol subclass */
 #define	ESC_FM_ERROR		"ESC_FM_error"
 #define	ESC_FM_ERROR_REPLAY	"ESC_FM_error_replay"