Print this page
8074 need to add FMA event for SSD wearout

@@ -19,14 +19,13 @@
  * CDDL HEADER END
  */
 /*
  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  */
 
-#pragma ident   "%Z%%M% %I%     %E% SMI"
-
 #include <assert.h>
 #include <errno.h>
 #include <libdiskstatus.h>
 #include <limits.h>
 #include <stdlib.h>

@@ -75,17 +74,21 @@
     scsi_log_parameter_header_t *, int, nvlist_t *);
 static int logpage_temp_verify(ds_scsi_info_t *,
     scsi_log_parameter_header_t *, int, nvlist_t *);
 static int logpage_selftest_verify(ds_scsi_info_t *,
     scsi_log_parameter_header_t *, int, nvlist_t *);
+static int logpage_ssm_verify(ds_scsi_info_t *,
+    scsi_log_parameter_header_t *, int, nvlist_t *);
 
 static int logpage_ie_analyze(ds_scsi_info_t *,
     scsi_log_parameter_header_t *, int);
 static int logpage_temp_analyze(ds_scsi_info_t *,
     scsi_log_parameter_header_t *, int);
 static int logpage_selftest_analyze(ds_scsi_info_t *,
     scsi_log_parameter_header_t *, int);
+static int logpage_ssm_analyze(ds_scsi_info_t *,
+    scsi_log_parameter_header_t *, int);
 
 static struct logpage_validation_entry log_validation[] = {
         { LOGPAGE_IE,           LOGPAGE_SUPP_IE,
             "informational-exceptions",
             logpage_ie_verify,  logpage_ie_analyze },

@@ -92,11 +95,14 @@
         { LOGPAGE_TEMP,         LOGPAGE_SUPP_TEMP,
             "temperature",
             logpage_temp_verify, logpage_temp_analyze },
         { LOGPAGE_SELFTEST,     LOGPAGE_SUPP_SELFTEST,
             "self-test",
-            logpage_selftest_verify, logpage_selftest_analyze }
+            logpage_selftest_verify, logpage_selftest_analyze },
+        { LOGPAGE_SSM,          LOGPAGE_SUPP_SSM,
+            FM_EREPORT_SCSI_SSMWEAROUT,
+            logpage_ssm_verify, logpage_ssm_analyze }
 };
 
 #define NLOG_VALIDATION (sizeof (log_validation) / sizeof (log_validation[0]))
 
 /*

@@ -755,10 +761,55 @@
 
         return (0);
 }
 
 /*
+ * Verify the contents of the Solid State Media (SSM) log page.
+ * As of SBC3r36 SSM log page contains one log parameter:
+ * "Percentage Used Endurance Indicator" which is mandatory.
+ * For the verification phase, we sanity check this parameter
+ * by making sure it's present and it's length is set to 0x04.
+ */
+static int
+logpage_ssm_verify(ds_scsi_info_t *sip,
+    scsi_log_parameter_header_t *lphp, int log_length, nvlist_t *nvl)
+{
+        ushort_t param_code;
+        int i, plen = 0;
+
+        for (i = 0; i < log_length; i += plen) {
+                lphp = (scsi_log_parameter_header_t *)((char *)lphp + plen);
+                param_code = BE_16(lphp->lph_param);
+
+                switch (param_code) {
+                case LOGPARAM_PRCNT_USED:
+                        if (nvlist_add_boolean_value(nvl,
+                            FM_EREPORT_SCSI_SSMWEAROUT, B_TRUE) != 0)
+                                return (scsi_set_errno(sip, EDS_NOMEM));
+                        if (lphp->lph_length != LOGPARAM_PRCNT_USED_PARAM_LEN) {
+                                if (nvlist_add_uint8(nvl,
+                                    "invalid-length", lphp->lph_length) != 0)
+                                        return (scsi_set_errno(sip, EDS_NOMEM));
+
+                                dprintf("solid state media logpage bad len\n");
+                                break;
+                        }
+
+                        /* verification succeded */
+                        return (0);
+                }
+
+                plen = lphp->lph_length +
+                    sizeof (scsi_log_parameter_header_t);
+        }
+
+        /* verification failed */
+        sip->si_supp_log &= ~LOGPAGE_SUPP_SSM;
+        return (0);
+}
+
+/*
  * Load the current IE mode pages
  */
 static int
 load_ie_modepage(ds_scsi_info_t *sip)
 {

@@ -1142,10 +1193,69 @@
         }
 
         return (0);
 }
 
+/*
+ * Analyze the contents of the Solid State Media (SSM) log page's
+ * "Percentage Used Endurance Indicator" log parameter.
+ * We generate a fault if the percentage used is equal to or over
+ * PRCNT_USED_FAULT_THRSH
+ */
+static int
+logpage_ssm_analyze(ds_scsi_info_t *sip, scsi_log_parameter_header_t *lphp,
+    int log_length)
+{
+        uint16_t param_code;
+        scsi_ssm_log_param_t *ssm;
+        nvlist_t *nvl;
+        int i, plen = 0;
+
+        assert(sip->si_dsp->ds_overtemp == NULL);
+        if (nvlist_alloc(&sip->si_dsp->ds_overtemp, NV_UNIQUE_NAME, 0) != 0)
+                return (scsi_set_errno(sip, EDS_NOMEM));
+        nvl = sip->si_dsp->ds_overtemp;
+
+        for (i = 0; i < log_length; i += plen) {
+                lphp = (scsi_log_parameter_header_t *)((uint8_t *)lphp + plen);
+                param_code = BE_16(lphp->lph_param);
+                ssm = (scsi_ssm_log_param_t *)lphp;
+
+                switch (param_code) {
+                case LOGPARAM_PRCNT_USED:
+                        if (lphp->lph_length != LOGPARAM_PRCNT_USED_PARAM_LEN)
+                                break;
+
+                        if ((nvlist_add_uint8(nvl,
+                            FM_EREPORT_PAYLOAD_SCSI_CURSSMWEAROUT,
+                            ssm->ssm_prcnt_used) != 0) ||
+                            (nvlist_add_uint8(nvl,
+                            FM_EREPORT_PAYLOAD_SCSI_THRSHSSMWEAROUT,
+                            PRCNT_USED_FAULT_THRSH) != 0))
+                                return (scsi_set_errno(sip, EDS_NOMEM));
+
+                        if (ssm->ssm_prcnt_used >= PRCNT_USED_FAULT_THRSH)
+                                sip->si_dsp->ds_faults |= DS_FAULT_SSMWEAROUT;
+
+                        return (0);
+                }
+
+                plen = lphp->lph_length +
+                    sizeof (scsi_log_parameter_header_t);
+        }
+
+        /*
+         * If we got this far we didn't see LOGPARAM_PRCNT_USED
+         * which is strange since we verified that it's there
+         */
+        dprintf("solid state media logpage analyze failed\n");
+#if DEBUG
+        abort();
+#endif
+        return (scsi_set_errno(sip, EDS_NOT_SUPPORTED));
+}
+
 /*
  * Analyze the IE mode sense page explicitly.  This is only needed if the IE log
  * page is not supported.
  */
 static int