@@ -187,8 +187,19 @@ struct erri_get_cq_entry {
187
187
__u32 rsvd7 :25 ;
188
188
};
189
189
190
+ struct erri_config {
191
+ char * file ;
192
+ __u8 number ;
193
+ __u16 type ;
194
+ __u16 nrtdp ;
195
+ };
196
+
190
197
static const char * sel = "[0-3]: current/default/saved/supported" ;
191
198
static const char * no_uuid = "Skip UUID index search (UUID index not required for OCP 1.0)" ;
199
+ const char * data = "Error injection data structure entries" ;
200
+ const char * number = "number of valid error injection data entries" ;
201
+ static const char * type = "Error injection type" ;
202
+ static const char * nrtdp = "Number of reads to trigger device panic" ;
192
203
193
204
static int ocp_print_C3_log_normal (struct nvme_dev * dev ,
194
205
struct ssd_latency_monitor_log * log_data )
@@ -4039,3 +4050,97 @@ static int get_error_injection(int argc, char **argv, struct command *cmd, struc
4039
4050
4040
4051
return error_injection_get (dev , cfg .sel , !argconfig_parse_seen (opts , "no-uuid" ));
4041
4052
}
4053
+
4054
+ static int error_injection_set (struct nvme_dev * dev , struct erri_config * cfg , bool uuid )
4055
+ {
4056
+ int err ;
4057
+ __u32 result ;
4058
+ struct nvme_set_features_args args = {
4059
+ .args_size = sizeof (args ),
4060
+ .fd = dev_fd (dev ),
4061
+ .fid = 0xc0 ,
4062
+ .cdw11 = cfg -> number ,
4063
+ .data_len = cfg -> number * sizeof (struct erri_entry ),
4064
+ .timeout = nvme_cfg .timeout ,
4065
+ .result = & result ,
4066
+ };
4067
+
4068
+ _cleanup_fd_ int ffd = -1 ;
4069
+ _cleanup_free_ struct erri_entry * entry = NULL ;
4070
+
4071
+ if (uuid ) {
4072
+ /* OCP 2.0 requires UUID index support */
4073
+ err = ocp_get_uuid_index (dev , & args .uuidx );
4074
+ if (err || !args .uuidx ) {
4075
+ nvme_show_error ("ERROR: No OCP UUID index found" );
4076
+ return err ;
4077
+ }
4078
+ }
4079
+
4080
+ entry = nvme_alloc (args .data_len );
4081
+ if (!entry ) {
4082
+ nvme_show_error ("malloc: %s" , strerror (errno ));
4083
+ return - errno ;
4084
+ }
4085
+
4086
+ if (cfg -> file && strlen (cfg -> file )) {
4087
+ ffd = open (cfg -> file , O_RDONLY );
4088
+ if (ffd < 0 ) {
4089
+ nvme_show_error ("Failed to open file %s: %s" , cfg -> file , strerror (errno ));
4090
+ return - EINVAL ;
4091
+ }
4092
+ err = read (ffd , entry , args .data_len );
4093
+ if (err < 0 ) {
4094
+ nvme_show_error ("failed to read data buffer from input file: %s" ,
4095
+ strerror (errno ));
4096
+ return - errno ;
4097
+ }
4098
+ } else {
4099
+ entry -> enable = 1 ;
4100
+ entry -> single = 1 ;
4101
+ entry -> type = cfg -> type ;
4102
+ entry -> nrtdp = cfg -> nrtdp ;
4103
+ }
4104
+
4105
+ args .data = entry ;
4106
+
4107
+ err = nvme_set_features (& args );
4108
+ if (err ) {
4109
+ if (err < 0 )
4110
+ nvme_show_error ("set-error-injection: %s" , nvme_strerror (errno ));
4111
+ else if (err > 0 )
4112
+ nvme_show_status (err );
4113
+ return err ;
4114
+ }
4115
+
4116
+ printf ("set-error-injection, data: %s, number: %d, uuid: %d, type: %d, nrtdp: %d\n" ,
4117
+ cfg -> file , cfg -> number , args .uuidx , cfg -> type , cfg -> nrtdp );
4118
+ if (args .data )
4119
+ d (args .data , args .data_len , 16 , 1 );
4120
+
4121
+ return 0 ;
4122
+ }
4123
+
4124
+ static int set_error_injection (int argc , char * * argv , struct command * cmd , struct plugin * plugin )
4125
+ {
4126
+ const char * desc = "Inject error conditions" ;
4127
+ int err ;
4128
+ struct erri_config cfg = {
4129
+ .number = 1 ,
4130
+ };
4131
+
4132
+ _cleanup_nvme_dev_ struct nvme_dev * dev = NULL ;
4133
+
4134
+ NVME_ARGS (opts ,
4135
+ OPT_FILE ("data" , 'd' , & cfg .file , data ),
4136
+ OPT_BYTE ("number" , 'n' , & cfg .number , number ),
4137
+ OPT_FLAG ("no-uuid" , 'N' , NULL , no_uuid ),
4138
+ OPT_SHRT ("type" , 't' , & cfg .type , type ),
4139
+ OPT_SHRT ("nrtdp" , 'r' , & cfg .nrtdp , nrtdp ));
4140
+
4141
+ err = parse_and_open (& dev , argc , argv , desc , opts );
4142
+ if (err )
4143
+ return err ;
4144
+
4145
+ return error_injection_set (dev , & cfg , !argconfig_parse_seen (opts , "no-uuid" ));
4146
+ }
0 commit comments