Print this page
OS-1997 mpt_sas: expose LED controls to libtopo
Reviewed by: Keith Wesolowski <keith.wesolowski@joyent.com>

@@ -369,12 +369,11 @@
     uint32_t *status, uint8_t cmd);
 static dev_info_t *mptsas_get_dip_from_dev(dev_t dev,
     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);
 
 
 /*
  * Enumeration / DR functions
  */

@@ -6451,11 +6450,12 @@
                                 break;
                         }
                 }
 
                 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));
                 }
                 if (rval == DDI_SUCCESS) {
                         mptsas_tgt_free(&mpt->m_active->m_tgttbl,

@@ -11951,10 +11951,70 @@
         mutex_exit(&mpt->m_mutex);
         return (status);
 }
 
 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 ||
+             (lc.Command == MPTSAS_LEDCTL_FLAG_SET && lc.LedStatus != 0 &&
+             lc.LedStatus != 1)) {
+                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 >> (lc.Led - 1)) & 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 = 0;
         int count = 0;
         int ret = 0;

@@ -12127,35 +12187,18 @@
                         if (cmd == DEVCTL_DEVICE_ONLINE) {
                                 ptgt->m_tgt_unconfigured = 0;
                         } 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));
                         }
                         mutex_exit(&mpt->m_mutex);
                         ndi_dc_freehdl(dcp);

@@ -12164,10 +12207,13 @@
         }
         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)) {
                                 status = EFAULT;
                                 break;

@@ -14624,12 +14670,13 @@
                                 if ((!MDI_PI_IS_ONLINE(*pip)) &&
                                     (!MDI_PI_IS_STANDBY(*pip)) &&
                                     (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;
                                 }
                                 if (rval != DDI_SUCCESS) {

@@ -14882,12 +14929,12 @@
                 }
                 NDBG20(("new path:%s onlining,", MDI_PI(*pip)->pi_addr));
                 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));
                         }
                         mutex_exit(&mpt->m_mutex);
                 }

@@ -15244,12 +15291,12 @@
                          */
                         ndi_rtn = ndi_devi_online(*lun_dip, NDI_ONLINE_ATTACH);
                 }
                 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));
                         }
                         mutex_exit(&mpt->m_mutex);
                 }

@@ -16146,27 +16193,30 @@
                 ptgt = mptsas_phy_to_tgt(mpt, (int)phymask, phynum);
         }
         return (ptgt);
 }
 
-#ifdef MPTSAS_GET_LED
-static int
-mptsas_get_led_status(mptsas_t *mpt, mptsas_target_t *ptgt,
-    uint32_t *slotstatus)
-{
-        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)
+mptsas_flush_led_status(mptsas_t *mpt, mptsas_target_t *ptgt)
 {
+        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
  */
 static int mptsas_send_sep(mptsas_t *mpt, mptsas_target_t *ptgt,
     uint32_t *status, uint8_t act)