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));
|