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


   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.

  24  */
  25 
  26 #pragma ident   "%Z%%M% %I%     %E% SMI"
  27 
  28 #include <assert.h>
  29 #include <errno.h>
  30 #include <libdiskstatus.h>
  31 #include <limits.h>
  32 #include <stdlib.h>
  33 #include <strings.h>
  34 #include <sys/fm/io/scsi.h>
  35 
  36 #include "ds_scsi.h"
  37 #include "ds_scsi_sim.h"
  38 #include "ds_scsi_uscsi.h"
  39 
  40 typedef struct ds_scsi_info {
  41         disk_status_t           *si_dsp;
  42         void                    *si_sim;
  43         int                     si_cdblen;
  44         int                     si_supp_mode;
  45         int                     si_supp_log;
  46         int                     si_extensions;
  47         int                     si_reftemp;


  60  */
  61 typedef int (*logpage_validation_fn_t)(ds_scsi_info_t *,
  62     scsi_log_parameter_header_t *, int, nvlist_t *);
  63 typedef int (*logpage_analyze_fn_t)(ds_scsi_info_t *,
  64     scsi_log_parameter_header_t *, int);
  65 
  66 typedef struct logpage_validation_entry {
  67         uchar_t                 ve_code;
  68         int                     ve_supported;
  69         const char              *ve_desc;
  70         logpage_validation_fn_t ve_validate;
  71         logpage_analyze_fn_t    ve_analyze;
  72 } logpage_validation_entry_t;
  73 
  74 static int logpage_ie_verify(ds_scsi_info_t *,
  75     scsi_log_parameter_header_t *, int, nvlist_t *);
  76 static int logpage_temp_verify(ds_scsi_info_t *,
  77     scsi_log_parameter_header_t *, int, nvlist_t *);
  78 static int logpage_selftest_verify(ds_scsi_info_t *,
  79     scsi_log_parameter_header_t *, int, nvlist_t *);


  80 
  81 static int logpage_ie_analyze(ds_scsi_info_t *,
  82     scsi_log_parameter_header_t *, int);
  83 static int logpage_temp_analyze(ds_scsi_info_t *,
  84     scsi_log_parameter_header_t *, int);
  85 static int logpage_selftest_analyze(ds_scsi_info_t *,
  86     scsi_log_parameter_header_t *, int);


  87 
  88 static struct logpage_validation_entry log_validation[] = {
  89         { LOGPAGE_IE,           LOGPAGE_SUPP_IE,
  90             "informational-exceptions",
  91             logpage_ie_verify,  logpage_ie_analyze },
  92         { LOGPAGE_TEMP,         LOGPAGE_SUPP_TEMP,
  93             "temperature",
  94             logpage_temp_verify, logpage_temp_analyze },
  95         { LOGPAGE_SELFTEST,     LOGPAGE_SUPP_SELFTEST,
  96             "self-test",
  97             logpage_selftest_verify, logpage_selftest_analyze }



  98 };
  99 
 100 #define NLOG_VALIDATION (sizeof (log_validation) / sizeof (log_validation[0]))
 101 
 102 /*
 103  * Given an extended sense page, retrieves the sense key, as well as the
 104  * additional sense code information.
 105  */
 106 static void
 107 scsi_translate_error(struct scsi_extended_sense *rq, uint_t *skeyp,
 108     uint_t *ascp, uint_t *ascqp)
 109 {
 110         struct scsi_descr_sense_hdr *sdsp =
 111             (struct scsi_descr_sense_hdr *)rq;
 112 
 113         *skeyp = rq->es_key;
 114 
 115         /*
 116          * Get asc, ascq and info field from sense data.  There are two
 117          * possible formats (fixed sense data and descriptor sense data)


 740                             lphp->lph_length) != 0)
 741                                 return (scsi_set_errno(sip, EDS_NOMEM));
 742                         bad = B_TRUE;
 743                         break;
 744 
 745                 }
 746 
 747                 plen = lphp->lph_length +
 748                     sizeof (scsi_log_parameter_header_t);
 749         }
 750 
 751         if (bad) {
 752                 sip->si_supp_log &= ~LOGPAGE_SUPP_SELFTEST;
 753                 dprintf("selftest logpage validation failed\n");
 754         }
 755 
 756         return (0);
 757 }
 758 
 759 /*













































 760  * Load the current IE mode pages
 761  */
 762 static int
 763 load_ie_modepage(ds_scsi_info_t *sip)
 764 {
 765         struct scsi_ms_hdrs junk_hdrs;
 766         int result;
 767         uint_t skey, asc, ascq;
 768 
 769         if (!(sip->si_supp_mode & MODEPAGE_SUPP_IEC))
 770                 return (0);
 771 
 772         bzero(&sip->si_iec_current, sizeof (sip->si_iec_current));
 773         bzero(&sip->si_iec_changeable, sizeof (sip->si_iec_changeable));
 774 
 775         if ((result = scsi_mode_sense(sip,
 776             MODEPAGE_INFO_EXCPT, PC_CURRENT, &sip->si_iec_current,
 777             MODEPAGE_INFO_EXCPT_LEN, &sip->si_hdrs, &skey, &asc,
 778             &ascq)) == 0) {
 779                 result = scsi_mode_sense(sip,


1127                                     BE_64(stp->st_lba)) != 0)
1128                                         return (scsi_set_errno(sip,
1129                                             EDS_NOMEM));
1130 
1131                                 if (SELFTEST_COMPLETE(stp->st_results)) {
1132                                         if (stp->st_results != SELFTEST_OK)
1133                                                 sip->si_dsp->ds_faults |=
1134                                                     DS_FAULT_TESTFAIL;
1135                                         return (0);
1136                                 }
1137                         }
1138                 }
1139 
1140                 plen = lphp->lph_length +
1141                     sizeof (scsi_log_parameter_header_t);
1142         }
1143 
1144         return (0);
1145 }
1146 



























































1147 /*
1148  * Analyze the IE mode sense page explicitly.  This is only needed if the IE log
1149  * page is not supported.
1150  */
1151 static int
1152 analyze_ie_sense(ds_scsi_info_t *sip)
1153 {
1154         uint_t skey, asc, ascq;
1155         nvlist_t *nvl;
1156 
1157         /*
1158          * Don't bother checking if we weren't able to set our MRIE correctly.
1159          */
1160         if (sip->si_iec_current.ie_mrie != IE_REPORT_ON_REQUEST)
1161                 return (0);
1162 
1163         if (scsi_request_sense(sip, &skey, &asc, &ascq) != 0) {
1164                 dprintf("failed to request IE page (KEY=0x%x ASC=0x%x "
1165                     "ASCQ=0x%x)\n", skey, asc, ascq);
1166                 return (scsi_set_errno(sip, EDS_IO));




   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  * Copyright 2016 Nexenta Systems, Inc.  All rights reserved.
  25  */
  26 


  27 #include <assert.h>
  28 #include <errno.h>
  29 #include <libdiskstatus.h>
  30 #include <limits.h>
  31 #include <stdlib.h>
  32 #include <strings.h>
  33 #include <sys/fm/io/scsi.h>
  34 
  35 #include "ds_scsi.h"
  36 #include "ds_scsi_sim.h"
  37 #include "ds_scsi_uscsi.h"
  38 
  39 typedef struct ds_scsi_info {
  40         disk_status_t           *si_dsp;
  41         void                    *si_sim;
  42         int                     si_cdblen;
  43         int                     si_supp_mode;
  44         int                     si_supp_log;
  45         int                     si_extensions;
  46         int                     si_reftemp;


  59  */
  60 typedef int (*logpage_validation_fn_t)(ds_scsi_info_t *,
  61     scsi_log_parameter_header_t *, int, nvlist_t *);
  62 typedef int (*logpage_analyze_fn_t)(ds_scsi_info_t *,
  63     scsi_log_parameter_header_t *, int);
  64 
  65 typedef struct logpage_validation_entry {
  66         uchar_t                 ve_code;
  67         int                     ve_supported;
  68         const char              *ve_desc;
  69         logpage_validation_fn_t ve_validate;
  70         logpage_analyze_fn_t    ve_analyze;
  71 } logpage_validation_entry_t;
  72 
  73 static int logpage_ie_verify(ds_scsi_info_t *,
  74     scsi_log_parameter_header_t *, int, nvlist_t *);
  75 static int logpage_temp_verify(ds_scsi_info_t *,
  76     scsi_log_parameter_header_t *, int, nvlist_t *);
  77 static int logpage_selftest_verify(ds_scsi_info_t *,
  78     scsi_log_parameter_header_t *, int, nvlist_t *);
  79 static int logpage_ssm_verify(ds_scsi_info_t *,
  80     scsi_log_parameter_header_t *, int, nvlist_t *);
  81 
  82 static int logpage_ie_analyze(ds_scsi_info_t *,
  83     scsi_log_parameter_header_t *, int);
  84 static int logpage_temp_analyze(ds_scsi_info_t *,
  85     scsi_log_parameter_header_t *, int);
  86 static int logpage_selftest_analyze(ds_scsi_info_t *,
  87     scsi_log_parameter_header_t *, int);
  88 static int logpage_ssm_analyze(ds_scsi_info_t *,
  89     scsi_log_parameter_header_t *, int);
  90 
  91 static struct logpage_validation_entry log_validation[] = {
  92         { LOGPAGE_IE,           LOGPAGE_SUPP_IE,
  93             "informational-exceptions",
  94             logpage_ie_verify,  logpage_ie_analyze },
  95         { LOGPAGE_TEMP,         LOGPAGE_SUPP_TEMP,
  96             "temperature",
  97             logpage_temp_verify, logpage_temp_analyze },
  98         { LOGPAGE_SELFTEST,     LOGPAGE_SUPP_SELFTEST,
  99             "self-test",
 100             logpage_selftest_verify, logpage_selftest_analyze },
 101         { LOGPAGE_SSM,          LOGPAGE_SUPP_SSM,
 102             FM_EREPORT_SCSI_SSMWEAROUT,
 103             logpage_ssm_verify, logpage_ssm_analyze }
 104 };
 105 
 106 #define NLOG_VALIDATION (sizeof (log_validation) / sizeof (log_validation[0]))
 107 
 108 /*
 109  * Given an extended sense page, retrieves the sense key, as well as the
 110  * additional sense code information.
 111  */
 112 static void
 113 scsi_translate_error(struct scsi_extended_sense *rq, uint_t *skeyp,
 114     uint_t *ascp, uint_t *ascqp)
 115 {
 116         struct scsi_descr_sense_hdr *sdsp =
 117             (struct scsi_descr_sense_hdr *)rq;
 118 
 119         *skeyp = rq->es_key;
 120 
 121         /*
 122          * Get asc, ascq and info field from sense data.  There are two
 123          * possible formats (fixed sense data and descriptor sense data)


 746                             lphp->lph_length) != 0)
 747                                 return (scsi_set_errno(sip, EDS_NOMEM));
 748                         bad = B_TRUE;
 749                         break;
 750 
 751                 }
 752 
 753                 plen = lphp->lph_length +
 754                     sizeof (scsi_log_parameter_header_t);
 755         }
 756 
 757         if (bad) {
 758                 sip->si_supp_log &= ~LOGPAGE_SUPP_SELFTEST;
 759                 dprintf("selftest logpage validation failed\n");
 760         }
 761 
 762         return (0);
 763 }
 764 
 765 /*
 766  * Verify the contents of the Solid State Media (SSM) log page.
 767  * As of SBC3r36 SSM log page contains one log parameter:
 768  * "Percentage Used Endurance Indicator" which is mandatory.
 769  * For the verification phase, we sanity check this parameter
 770  * by making sure it's present and it's length is set to 0x04.
 771  */
 772 static int
 773 logpage_ssm_verify(ds_scsi_info_t *sip,
 774     scsi_log_parameter_header_t *lphp, int log_length, nvlist_t *nvl)
 775 {
 776         ushort_t param_code;
 777         int i, plen = 0;
 778 
 779         for (i = 0; i < log_length; i += plen) {
 780                 lphp = (scsi_log_parameter_header_t *)((char *)lphp + plen);
 781                 param_code = BE_16(lphp->lph_param);
 782 
 783                 switch (param_code) {
 784                 case LOGPARAM_PRCNT_USED:
 785                         if (nvlist_add_boolean_value(nvl,
 786                             FM_EREPORT_SCSI_SSMWEAROUT, B_TRUE) != 0)
 787                                 return (scsi_set_errno(sip, EDS_NOMEM));
 788                         if (lphp->lph_length != LOGPARAM_PRCNT_USED_PARAM_LEN) {
 789                                 if (nvlist_add_uint8(nvl,
 790                                     "invalid-length", lphp->lph_length) != 0)
 791                                         return (scsi_set_errno(sip, EDS_NOMEM));
 792 
 793                                 dprintf("solid state media logpage bad len\n");
 794                                 break;
 795                         }
 796 
 797                         /* verification succeded */
 798                         return (0);
 799                 }
 800 
 801                 plen = lphp->lph_length +
 802                     sizeof (scsi_log_parameter_header_t);
 803         }
 804 
 805         /* verification failed */
 806         sip->si_supp_log &= ~LOGPAGE_SUPP_SSM;
 807         return (0);
 808 }
 809 
 810 /*
 811  * Load the current IE mode pages
 812  */
 813 static int
 814 load_ie_modepage(ds_scsi_info_t *sip)
 815 {
 816         struct scsi_ms_hdrs junk_hdrs;
 817         int result;
 818         uint_t skey, asc, ascq;
 819 
 820         if (!(sip->si_supp_mode & MODEPAGE_SUPP_IEC))
 821                 return (0);
 822 
 823         bzero(&sip->si_iec_current, sizeof (sip->si_iec_current));
 824         bzero(&sip->si_iec_changeable, sizeof (sip->si_iec_changeable));
 825 
 826         if ((result = scsi_mode_sense(sip,
 827             MODEPAGE_INFO_EXCPT, PC_CURRENT, &sip->si_iec_current,
 828             MODEPAGE_INFO_EXCPT_LEN, &sip->si_hdrs, &skey, &asc,
 829             &ascq)) == 0) {
 830                 result = scsi_mode_sense(sip,


1178                                     BE_64(stp->st_lba)) != 0)
1179                                         return (scsi_set_errno(sip,
1180                                             EDS_NOMEM));
1181 
1182                                 if (SELFTEST_COMPLETE(stp->st_results)) {
1183                                         if (stp->st_results != SELFTEST_OK)
1184                                                 sip->si_dsp->ds_faults |=
1185                                                     DS_FAULT_TESTFAIL;
1186                                         return (0);
1187                                 }
1188                         }
1189                 }
1190 
1191                 plen = lphp->lph_length +
1192                     sizeof (scsi_log_parameter_header_t);
1193         }
1194 
1195         return (0);
1196 }
1197 
1198 /*
1199  * Analyze the contents of the Solid State Media (SSM) log page's
1200  * "Percentage Used Endurance Indicator" log parameter.
1201  * We generate a fault if the percentage used is equal to or over
1202  * PRCNT_USED_FAULT_THRSH
1203  */
1204 static int
1205 logpage_ssm_analyze(ds_scsi_info_t *sip, scsi_log_parameter_header_t *lphp,
1206     int log_length)
1207 {
1208         uint16_t param_code;
1209         scsi_ssm_log_param_t *ssm;
1210         nvlist_t *nvl;
1211         int i, plen = 0;
1212 
1213         assert(sip->si_dsp->ds_overtemp == NULL);
1214         if (nvlist_alloc(&sip->si_dsp->ds_overtemp, NV_UNIQUE_NAME, 0) != 0)
1215                 return (scsi_set_errno(sip, EDS_NOMEM));
1216         nvl = sip->si_dsp->ds_overtemp;
1217 
1218         for (i = 0; i < log_length; i += plen) {
1219                 lphp = (scsi_log_parameter_header_t *)((uint8_t *)lphp + plen);
1220                 param_code = BE_16(lphp->lph_param);
1221                 ssm = (scsi_ssm_log_param_t *)lphp;
1222 
1223                 switch (param_code) {
1224                 case LOGPARAM_PRCNT_USED:
1225                         if (lphp->lph_length != LOGPARAM_PRCNT_USED_PARAM_LEN)
1226                                 break;
1227 
1228                         if ((nvlist_add_uint8(nvl,
1229                             FM_EREPORT_PAYLOAD_SCSI_CURSSMWEAROUT,
1230                             ssm->ssm_prcnt_used) != 0) ||
1231                             (nvlist_add_uint8(nvl,
1232                             FM_EREPORT_PAYLOAD_SCSI_THRSHSSMWEAROUT,
1233                             PRCNT_USED_FAULT_THRSH) != 0))
1234                                 return (scsi_set_errno(sip, EDS_NOMEM));
1235 
1236                         if (ssm->ssm_prcnt_used >= PRCNT_USED_FAULT_THRSH)
1237                                 sip->si_dsp->ds_faults |= DS_FAULT_SSMWEAROUT;
1238 
1239                         return (0);
1240                 }
1241 
1242                 plen = lphp->lph_length +
1243                     sizeof (scsi_log_parameter_header_t);
1244         }
1245 
1246         /*
1247          * If we got this far we didn't see LOGPARAM_PRCNT_USED
1248          * which is strange since we verified that it's there
1249          */
1250         dprintf("solid state media logpage analyze failed\n");
1251 #if DEBUG
1252         abort();
1253 #endif
1254         return (scsi_set_errno(sip, EDS_NOT_SUPPORTED));
1255 }
1256 
1257 /*
1258  * Analyze the IE mode sense page explicitly.  This is only needed if the IE log
1259  * page is not supported.
1260  */
1261 static int
1262 analyze_ie_sense(ds_scsi_info_t *sip)
1263 {
1264         uint_t skey, asc, ascq;
1265         nvlist_t *nvl;
1266 
1267         /*
1268          * Don't bother checking if we weren't able to set our MRIE correctly.
1269          */
1270         if (sip->si_iec_current.ie_mrie != IE_REPORT_ON_REQUEST)
1271                 return (0);
1272 
1273         if (scsi_request_sense(sip, &skey, &asc, &ascq) != 0) {
1274                 dprintf("failed to request IE page (KEY=0x%x ASC=0x%x "
1275                     "ASCQ=0x%x)\n", skey, asc, ascq);
1276                 return (scsi_set_errno(sip, EDS_IO));