--- old/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Mon Nov 26 00:31:46 2012
+++ new/usr/src/uts/common/io/scsi/adapters/mpt_sas/mptsas.c	Mon Nov 26 00:31:46 2012
@@ -22,6 +22,7 @@
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2012, Joyent, Inc. All rights reserved.
  */
 
 /*
@@ -69,6 +70,7 @@
 #include <sys/file.h>
 #include <sys/cpuvar.h>
 #include <sys/policy.h>
+#include <sys/model.h>
 #include <sys/sysevent.h>
 #include <sys/sysevent/eventdefs.h>
 #include <sys/sysevent/dr.h>
@@ -369,8 +371,7 @@
     mptsas_phymask_t *phymask);
 static mptsas_target_t *mptsas_addr_to_ptgt(mptsas_t *mpt, char *addr,
     mptsas_phymask_t phymask);
-static int mptsas_set_led_status(mptsas_t *mpt, mptsas_target_t *ptgt,
-    uint32_t slotstatus);
+static int mptsas_flush_led_status(mptsas_t *mpt, mptsas_target_t *ptgt);
 
 
 /*
@@ -1089,6 +1090,10 @@
 		goto fail;
 	}
 
+	/* Mark us as a primary ioctl node for an instance. */
+	(void) ddi_prop_update_int(DDI_DEV_T_NONE, dip, "primary-ioctl-node",
+	    instance);
+
 	/* Indicate that we are 'sizeof (scsi_*(9S))' clean. */
 	scsi_size_clean(dip);
 
@@ -6451,7 +6456,8 @@
 		}
 
 		mutex_enter(&mpt->m_mutex);
-		if (mptsas_set_led_status(mpt, ptgt, 0) != DDI_SUCCESS) {
+		ptgt->m_led_status = 0;
+		if (mptsas_flush_led_status(mpt, ptgt) != DDI_SUCCESS) {
 			NDBG14(("mptsas: clear LED for tgt %x failed",
 			    ptgt->m_slot_num));
 		}
@@ -11951,6 +11957,156 @@
 }
 
 static int
+led_control(mptsas_t *mpt, intptr_t data, int mode)
+{
+	int ret = 0;
+	mptsas_led_control_t lc;
+	mptsas_target_t *ptgt;
+
+	if (ddi_copyin((void *)data, &lc, sizeof (lc), mode) != 0) {
+		return (EFAULT);
+	}
+
+	if ((lc.Command != MPTSAS_LEDCTL_FLAG_SET &&
+	    lc.Command != MPTSAS_LEDCTL_FLAG_GET) ||
+	    lc.Led < MPTSAS_LEDCTL_LED_IDENT ||
+	    lc.Led > MPTSAS_LEDCTL_LED_OK2RM) {
+		return (EINVAL);
+	}
+
+	/* Locate the target we're interrogating... */
+	mutex_enter(&mpt->m_mutex);
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		if (ptgt->m_enclosure == lc.Enclosure &&
+		    ptgt->m_slot_num == lc.Slot) {
+			break;
+		}
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+	if (ptgt == NULL) {
+		/* We could not find a target for that enclosure/slot. */
+		mutex_exit(&mpt->m_mutex);
+		return (ENOENT);
+	}
+
+	if (lc.Command == MPTSAS_LEDCTL_FLAG_SET) {
+		/* Update our internal LED state. */
+		ptgt->m_led_status &= ~(1 << (lc.Led - 1));
+		ptgt->m_led_status |= (!!lc.LedStatus) << (lc.Led - 1);
+
+		/* Flush it to the controller. */
+		ret = mptsas_flush_led_status(mpt, ptgt);
+		mutex_exit(&mpt->m_mutex);
+		return (ret);
+	}
+
+	/* Return our internal LED state. */
+	lc.LedStatus = !!(ptgt->m_led_status & (1 << (lc.Led - 1)));
+	mutex_exit(&mpt->m_mutex);
+
+	if (ddi_copyout(&lc, (void *)data, sizeof (lc), mode) != 0) {
+		return (EFAULT);
+	}
+
+	return (0);
+}
+
+static int
+get_disk_info(mptsas_t *mpt, intptr_t data, int mode)
+{
+	int i;
+	int count = 0;
+	int ret = 0;
+	mptsas_target_t *ptgt;
+	mptsas_disk_info_t *di;
+	STRUCT_DECL(mptsas_get_disk_info, gdi);
+
+	STRUCT_INIT(gdi, get_udatamodel());
+
+	if (ddi_copyin((void *)data, STRUCT_BUF(gdi), STRUCT_SIZE(gdi),
+	    mode) != 0) {
+		return (EFAULT);
+	}
+
+restart:
+	/* Find out how many targets there are. */
+	mutex_enter(&mpt->m_mutex);
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		count++;
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+	}
+	mutex_exit(&mpt->m_mutex);
+
+	/*
+	 * If we haven't been asked to copy out information on each target,
+	 * then just return the count.
+	 */
+	STRUCT_FSET(gdi, DiskCount, count);
+	if (STRUCT_FGETP(gdi, PtrDiskInfoArray) == NULL)
+		goto copy_out;
+
+	/*
+	 * If we haven't been given a large enough buffer to copy out into,
+	 * let the caller know.
+	 */
+	if (STRUCT_FGET(gdi, DiskInfoArraySize) <
+	    count * sizeof (mptsas_disk_info_t)) {
+		ret = ENOSPC;
+		goto copy_out;
+	}
+
+	di = kmem_zalloc(count * sizeof (mptsas_disk_info_t), KM_SLEEP);
+
+	mutex_enter(&mpt->m_mutex);
+	i = 0;
+	ptgt = (mptsas_target_t *)mptsas_hash_traverse(&mpt->m_active->m_tgttbl,
+	    MPTSAS_HASH_FIRST);
+	while (ptgt != NULL) {
+		if (i >= count) {
+			/*
+			 * The number of targets changed while we weren't
+			 * looking.  Go again.
+			 */
+			mutex_exit(&mpt->m_mutex);
+			kmem_free(di, count * sizeof (mptsas_disk_info_t));
+			goto restart;
+		}
+		di[i].Instance = mpt->m_instance;
+		di[i].Enclosure = ptgt->m_enclosure;
+		di[i].Slot = ptgt->m_slot_num;
+		di[i].SasAddress = ptgt->m_sas_wwn;
+
+		ptgt = (mptsas_target_t *)mptsas_hash_traverse(
+		    &mpt->m_active->m_tgttbl, MPTSAS_HASH_NEXT);
+		i++;
+	}
+	mutex_exit(&mpt->m_mutex);
+	STRUCT_FSET(gdi, DiskCount, i);
+
+	/* Copy out the disk information to the caller. */
+	if (ddi_copyout((void *)di, STRUCT_FGETP(gdi, PtrDiskInfoArray),
+	    i * sizeof (mptsas_disk_info_t), mode) != 0) {
+		ret = EFAULT;
+	}
+
+	kmem_free(di, count * sizeof (mptsas_disk_info_t));
+
+copy_out:
+	if (ddi_copyout(STRUCT_BUF(gdi), (void *)data, STRUCT_SIZE(gdi),
+	    mode) != 0) {
+		ret = EFAULT;
+	}
+
+	return (ret);
+}
+
+static int
 mptsas_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp,
     int *rval)
 {
@@ -12037,31 +12193,14 @@
 			} else if (cmd == DEVCTL_DEVICE_OFFLINE) {
 				ptgt->m_tgt_unconfigured = 1;
 			}
-			slotstatus = 0;
-#ifdef MPTSAS_GET_LED
-			/*
-			 * The get led status can't get a valid/reasonable
-			 * state, so ignore the get led status, and write the
-			 * required value directly
-			 */
-			if (mptsas_get_led_status(mpt, ptgt, &slotstatus) !=
-			    DDI_SUCCESS) {
-				NDBG14(("mptsas_ioctl: get LED for tgt %s "
-				    "failed %x", addr, slotstatus));
-				slotstatus = 0;
-			}
-			NDBG14(("mptsas_ioctl: LED status %x for %s",
-			    slotstatus, addr));
-#endif
 			if (cmd == DEVCTL_DEVICE_OFFLINE) {
-				slotstatus |=
-				    MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE;
+				ptgt->m_led_status |=
+				    (1 << (MPTSAS_LEDCTL_LED_OK2RM - 1));
 			} else {
-				slotstatus &=
-				    ~MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE;
+				ptgt->m_led_status &=
+				    ~(1 << (MPTSAS_LEDCTL_LED_OK2RM - 1));
 			}
-			if (mptsas_set_led_status(mpt, ptgt, slotstatus) !=
-			    DDI_SUCCESS) {
+			if (mptsas_flush_led_status(mpt, ptgt) != DDI_SUCCESS) {
 				NDBG14(("mptsas_ioctl: set LED for tgt %s "
 				    "failed %x", addr, slotstatus));
 			}
@@ -12071,6 +12210,12 @@
 		goto out;
 	}
 	switch (cmd) {
+		case MPTIOCTL_GET_DISK_INFO:
+			status = get_disk_info(mpt, data, mode);
+			break;
+		case MPTIOCTL_LED_CONTROL:
+			status = led_control(mpt, data, mode);
+			break;
 		case MPTIOCTL_UPDATE_FLASH:
 			if (ddi_copyin((void *)data, &flashdata,
 				sizeof (struct mptsas_update_flash), mode)) {
@@ -14531,8 +14676,9 @@
 				    (ptgt->m_tgt_unconfigured == 0)) {
 					rval = mdi_pi_online(*pip, 0);
 					mutex_enter(&mpt->m_mutex);
-					(void) mptsas_set_led_status(mpt, ptgt,
-					    0);
+					ptgt->m_led_status = 0;
+					(void) mptsas_flush_led_status(mpt,
+					    ptgt);
 					mutex_exit(&mpt->m_mutex);
 				} else {
 					rval = DDI_SUCCESS;
@@ -14789,8 +14935,8 @@
 		mdi_rtn = mdi_pi_online(*pip, 0);
 		if (mdi_rtn == MDI_SUCCESS) {
 			mutex_enter(&mpt->m_mutex);
-			if (mptsas_set_led_status(mpt, ptgt, 0) !=
-			    DDI_SUCCESS) {
+			ptgt->m_led_status = 0;
+			if (mptsas_flush_led_status(mpt, ptgt) != DDI_SUCCESS) {
 				NDBG14(("mptsas: clear LED for slot %x "
 				    "failed", ptgt->m_slot_num));
 			}
@@ -15151,8 +15297,8 @@
 		}
 		if (ndi_rtn == NDI_SUCCESS) {
 			mutex_enter(&mpt->m_mutex);
-			if (mptsas_set_led_status(mpt, ptgt, 0) !=
-			    DDI_SUCCESS) {
+			ptgt->m_led_status = 0;
+			if (mptsas_flush_led_status(mpt, ptgt) != DDI_SUCCESS) {
 				NDBG14(("mptsas: clear LED for tgt %x "
 				    "failed", ptgt->m_slot_num));
 			}
@@ -16053,23 +16199,26 @@
 	return (ptgt);
 }
 
-#ifdef MPTSAS_GET_LED
 static int
-mptsas_get_led_status(mptsas_t *mpt, mptsas_target_t *ptgt,
-    uint32_t *slotstatus)
+mptsas_flush_led_status(mptsas_t *mpt, mptsas_target_t *ptgt)
 {
-	return (mptsas_send_sep(mpt, ptgt, slotstatus,
-	    MPI2_SEP_REQ_ACTION_READ_STATUS));
-}
-#endif
-static int
-mptsas_set_led_status(mptsas_t *mpt, mptsas_target_t *ptgt, uint32_t slotstatus)
-{
+	uint32_t slotstatus = 0;
+
+	/* Build an MPI2 Slot Status based on our view of the world */
+	if (ptgt->m_led_status & (1 << (MPTSAS_LEDCTL_LED_IDENT - 1)))
+		slotstatus |= MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST;
+	if (ptgt->m_led_status & (1 << (MPTSAS_LEDCTL_LED_FAIL - 1)))
+		slotstatus |= MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT;
+	if (ptgt->m_led_status & (1 << (MPTSAS_LEDCTL_LED_OK2RM - 1)))
+		slotstatus |= MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE;
+
+	/* Write it to the controller */
 	NDBG14(("mptsas_ioctl: set LED status %x for slot %x",
 	    slotstatus, ptgt->m_slot_num));
 	return (mptsas_send_sep(mpt, ptgt, &slotstatus,
 	    MPI2_SEP_REQ_ACTION_WRITE_STATUS));
 }
+
 /*
  *  send sep request, use enclosure/slot addressing
  */
