@@ -391,3 +391,212 @@ static int get_ibm_vpd_log(int argc, char **argv, struct command *cmd, struct pl
391391 dev_close (dev );
392392 return err ;
393393}
394+
395+ #define NVME_VENDOR_SPECIFIC_EVENT 0xde
396+ #define NVME_IBM_CHG_DEF 0x1
397+ #define NVME_IBM_RPT_ERR 0x2
398+
399+ struct ibm_change_def_event {
400+ __le64 pom ;
401+ __u8 vs1 ;
402+ __u8 vs2 ;
403+ __u8 dp ;
404+ };
405+
406+ struct ibm_reported_err_event {
407+ __le64 pom ;
408+ __u8 temp ;
409+ __u8 retry_cnt ;
410+ __u8 sc ;
411+ __u8 sct ;
412+ __le64 cmd_specific_info ;
413+ __u8 * cmd ;
414+
415+ };
416+
417+ /* persistent event type deh */
418+ struct nvme_pel_ibm_specific_event {
419+ __le16 vsecode ;
420+ __u8 vsetype ;
421+ __u8 uuid ;
422+ __le16 vsedl ;
423+ __u8 * vse_data ;
424+ };
425+
426+ static const char * raw_use = "use binary output" ;
427+
428+ void nvme_show_ibm_persistent_event_log (void * pevent_log_info ,
429+ __u8 action , __u32 size , const char * devname ,
430+ enum nvme_print_flags flags )
431+ {
432+ __u32 offset ;
433+ struct nvme_pel_ibm_specific_event * vendor_speci_event ;
434+ struct nvme_persistent_event_log * pevent_log_head ;
435+ struct nvme_persistent_event_entry * pevent_entry_head ;
436+ int human = flags & VERBOSE ;
437+ bool ibm_event = false;
438+ int i = 0 ;
439+
440+ if (flags & BINARY )
441+ return d_raw ((unsigned char * )pevent_log_info , size );
442+
443+ offset = sizeof (* pevent_log_head );
444+
445+ printf ("Persistent Event Log for device: %s\n" , devname );
446+ printf ("Action for Persistent Event Log: %u\n" , action );
447+
448+ if (size >= offset ) {
449+ pevent_log_head = pevent_log_info ;
450+ nvme_show_pel_header (pevent_log_head , human );
451+ } else {
452+ printf ("No log data can be shown with this log length\n" );
453+ return ;
454+ }
455+
456+ printf ("\n" );
457+ printf (" i=%d tnev=%d\n" , i , le32_to_cpu (pevent_log_head -> tnev ));
458+ for (i = 0 ; i < le32_to_cpu (pevent_log_head -> tnev ); i ++ ) {
459+ if (offset + sizeof (* pevent_entry_head ) >= size )
460+ break ;
461+
462+ pevent_entry_head = pevent_log_info + offset ;
463+ if ((offset + pevent_entry_head -> ehl + 3 +
464+ le16_to_cpu (pevent_entry_head -> el )) >= size )
465+ break ;
466+
467+ offset += pevent_entry_head -> ehl + 3 ;
468+
469+ switch (pevent_entry_head -> etype ) {
470+ case NVME_VENDOR_SPECIFIC_EVENT :
471+ printf ("\nPersistent Event Entries:\n" );
472+ printf ("Event Number: %u\n" , i );
473+ printf ("Event Type Field: 0x%X\n" , pevent_entry_head -> etype );
474+ printf ("Event Type Revision: 0x%X\n" , pevent_entry_head -> etype_rev );
475+
476+ vendor_speci_event = pevent_log_info + offset ;
477+
478+ printf ("Vendor Specific Event Code: 0x%X\n" ,
479+ le16_to_cpu (vendor_speci_event -> vsecode ));
480+ printf ("Vendor Specific Event Data Type: 0x%X\n" ,
481+ vendor_speci_event -> vsetype );
482+ printf ("UUID Index: %u\n" , vendor_speci_event -> uuid );
483+ printf ("VSEDL: %u\n" , le16_to_cpu (vendor_speci_event -> vsedl ));
484+
485+ if (le16_to_cpu (vendor_speci_event -> vsecode ) == NVME_IBM_CHG_DEF ) {
486+ struct ibm_change_def_event * change_def ;
487+
488+ change_def = pevent_log_info + offset + 6 ;
489+ printf ("POM: %" PRIu64 "\n" , le64_to_cpu (change_def -> pom ));
490+ printf ("VS1: %u\n" , change_def -> vs1 );
491+ printf ("VS2: %u\n" , change_def -> vs2 );
492+ printf ("DP : %u\n" , change_def -> dp );
493+ }
494+
495+ if (le16_to_cpu (vendor_speci_event -> vsecode ) == NVME_IBM_RPT_ERR ) {
496+ struct ibm_reported_err_event * report_err ;
497+
498+ report_err = pevent_log_info + offset + 6 ;
499+ printf ("POM: %" PRIu64 "\n" , le64_to_cpu (report_err -> pom ));
500+ printf ("TEMP: %u\n" , report_err -> temp );
501+ printf ("Retry Count: %u\n" , report_err -> retry_cnt );
502+ printf ("SC : %u\n" , report_err -> sc );
503+ printf ("SCT : %u\n" , report_err -> sct );
504+ printf ("CMD Specific Info: %" PRIu64 "\n" ,
505+ le64_to_cpu (report_err -> cmd_specific_info ));
506+ }
507+ ibm_event = true;
508+ printf ("\n" );
509+ break ;
510+ default :
511+ break ;
512+ }
513+ offset += le16_to_cpu (pevent_entry_head -> el );
514+ }
515+
516+ if (!ibm_event )
517+ printf ("NO IBM specific persistent events found!\n" );
518+ }
519+
520+ static int get_ibm_persistent_event_log (int argc , char * * argv ,
521+ struct command * cmd , struct plugin * plugin )
522+ {
523+ const char * desc = "Retrieve Persistent Event log info for "
524+ "the given device in either decoded format(default), json or binary." ;
525+ const char * action = "action the controller shall take during "
526+ "processing this persistent log page command." ;
527+ const char * log_len = "number of bytes to retrieve" ;
528+ struct nvme_persistent_event_log pevent_log ;
529+ void * pevent_log_info = NULL ;
530+ enum nvme_print_flags flags ;
531+ struct nvme_dev * dev ;
532+ __u32 log_length = 0 ;
533+ int err = 0 ;
534+
535+ struct config {
536+ __u8 action ;
537+ __u32 log_len ;
538+ char * output_format ;
539+ bool raw_binary ;
540+ };
541+
542+ struct config cfg = {
543+ .action = 0xff ,
544+ .log_len = 0 ,
545+ .output_format = "normal" ,
546+ .raw_binary = false,
547+ };
548+
549+ OPT_ARGS (opts ) = {
550+ OPT_BYTE ("action" , 'a' , & cfg .action , action ),
551+ OPT_UINT ("log_len" , 'l' , & cfg .log_len , log_len ),
552+ OPT_FMT ("output-format" , 'o' , & cfg .output_format , output_format ),
553+ OPT_FLAG ("raw-binary" , 'b' , & cfg .raw_binary , raw_use ),
554+ OPT_END ()
555+ };
556+
557+ err = parse_and_open (& dev , argc , argv , desc , opts );
558+ if (err )
559+ goto ret ;
560+
561+ err = flags = validate_output_format (cfg .output_format , & flags );
562+ if (flags < 0 )
563+ goto close_dev ;
564+
565+ if (cfg .raw_binary )
566+ flags = BINARY ;
567+
568+ /* get persistent event log */
569+ err = nvme_get_log_persistent_event (dev_fd (dev ), NVME_PEVENT_LOG_RELEASE_CTX ,
570+ sizeof (pevent_log ), & pevent_log );
571+
572+ if (err )
573+ return err ;
574+
575+ memset (& pevent_log , 0 , sizeof (pevent_log ));
576+
577+ err = nvme_get_log_persistent_event (dev_fd (dev ), NVME_PEVENT_LOG_EST_CTX_AND_READ ,
578+ sizeof (pevent_log ), & pevent_log );
579+ if (err ) {
580+ fprintf (stderr , "Setting persistent event log read ctx failed (ignored)!\n" );
581+ return err ;
582+ }
583+
584+ log_length = le64_to_cpu (pevent_log .tll );
585+ pevent_log_info = nvme_alloc (log_length );
586+ if (!pevent_log_info ) {
587+ perror ("could not alloc buffer for persistent event log page (ignored)!\n" );
588+ return err ;
589+ }
590+
591+ err = nvme_get_log_persistent_event (dev_fd (dev ), NVME_PEVENT_LOG_READ ,
592+ log_length , pevent_log_info );
593+ if (!err ) {
594+ nvme_show_ibm_persistent_event_log (pevent_log_info , cfg .action ,
595+ log_length , dev -> name , flags );
596+ }
597+
598+ close_dev :
599+ dev_close (dev );
600+ ret :
601+ return err ;
602+ }
0 commit comments