129129#define WDC_NVME_CAP_DUI_OPCODE 0xFA
130130#define WDC_NVME_CAP_DUI_DISABLE_IO 0x01
131131#define WDC_NVME_DUI_MAX_SECTION 0x3A
132+ #define WDC_NVME_DUI_MAX_SECTION_V2 0x26
132133#define WDC_NVME_DUI_MAX_DATA_AREA 0x05
133134
134135/* Crash dump */
@@ -453,15 +454,31 @@ struct wdc_dui_log_section {
453454 __le32 section_size ;
454455};
455456
457+ /* DUI log header V2 */
458+ struct __attribute__((__packed__ )) wdc_dui_log_section_v2 {
459+ __le16 section_type ;
460+ __le16 data_area_id ;
461+ __le64 section_size ;
462+ };
463+
456464struct wdc_dui_log_hdr {
457465 __u8 telemetry_hdr [512 ];
458466 __le16 hdr_version ;
459467 __le16 section_count ;
460- __u8 log_size [ 4 ] ;
468+ __le32 log_size ;
461469 struct wdc_dui_log_section log_section [WDC_NVME_DUI_MAX_SECTION ];
462470 __u8 log_data [40 ];
463471};
464472
473+ struct __attribute__((__packed__ )) wdc_dui_log_hdr_v2 {
474+ __u8 telemetry_hdr [512 ];
475+ __le16 hdr_version ;
476+ __le16 section_count ;
477+ __le64 log_size ;
478+ struct wdc_dui_log_section_v2 log_section [WDC_NVME_DUI_MAX_SECTION_V2 ];
479+ __u8 log_data [40 ];
480+ };
481+
465482/* Purge monitor response */
466483struct wdc_nvme_purge_monitor_data {
467484 __le16 rsvd1 ;
@@ -1082,7 +1099,34 @@ static __u32 wdc_dump_dui_data(int fd, __u32 dataLen, __u32 offset, __u8 *dump_d
10821099
10831100 ret = nvme_submit_passthru (fd , NVME_IOCTL_ADMIN_CMD , & admin_cmd );
10841101 if (ret != 0 ) {
1085- fprintf (stderr , "ERROR : WDC : reading DUI length failed\n" );
1102+ fprintf (stderr , "ERROR : WDC : reading DUI data failed\n" );
1103+ fprintf (stderr , "NVMe Status:%s(%x)\n" , nvme_status_to_string (ret ), ret );
1104+ }
1105+
1106+ return ret ;
1107+ }
1108+
1109+ static __u32 wdc_dump_dui_data_v2 (int fd , __u32 dataLen , __u64 offset , __u8 * dump_data , bool last_xfer )
1110+ {
1111+ int ret ;
1112+ struct nvme_admin_cmd admin_cmd ;
1113+
1114+ memset (& admin_cmd , 0 , sizeof (struct nvme_admin_cmd ));
1115+ admin_cmd .opcode = WDC_NVME_CAP_DUI_OPCODE ;
1116+ admin_cmd .nsid = 0xFFFFFFFF ;
1117+ admin_cmd .addr = (__u64 )(uintptr_t )dump_data ;
1118+ admin_cmd .data_len = dataLen ;
1119+ admin_cmd .cdw10 = ((dataLen >> 2 ) - 1 );
1120+ admin_cmd .cdw12 = (__u32 )(offset & 0x00000000FFFFFFFF );
1121+ admin_cmd .cdw13 = (__u32 )(offset >> 32 );
1122+ if (last_xfer )
1123+ admin_cmd .cdw14 = 0 ;
1124+ else
1125+ admin_cmd .cdw14 = WDC_NVME_CAP_DUI_DISABLE_IO ;
1126+
1127+ ret = nvme_submit_passthru (fd , NVME_IOCTL_ADMIN_CMD , & admin_cmd );
1128+ if (ret != 0 ) {
1129+ fprintf (stderr , "ERROR : WDC : reading DUI data V2 failed\n" );
10861130 fprintf (stderr , "NVMe Status:%s(%x)\n" , nvme_status_to_string (ret ), ret );
10871131 }
10881132
@@ -1257,18 +1301,18 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area)
12571301 int ret = 0 ;
12581302 __u32 dui_log_hdr_size = WDC_NVME_CAP_DUI_HEADER_SIZE ;
12591303 struct wdc_dui_log_hdr * log_hdr ;
1304+ struct wdc_dui_log_hdr_v2 * log_hdr_v2 ;
12601305 __u32 cap_dui_length ;
1261- __u8 * dump_data ;
1306+ __u64 cap_dui_length_v2 ;
1307+ __u8 * dump_data = NULL ;
12621308 __u64 buffer_addr ;
1263- __u32 curr_data_offset ;
1264- __s32 log_size = 0 ;
1265- __s32 total_size = 0 ;
1309+ __s64 total_size = 0 ;
12661310 int i ;
12671311 bool last_xfer = false;
12681312
12691313 log_hdr = (struct wdc_dui_log_hdr * ) malloc (dui_log_hdr_size );
12701314 if (log_hdr == NULL ) {
1271- fprintf (stderr , "%s: ERROR : malloc : %s\n" , __func__ , strerror (errno ));
1315+ fprintf (stderr , "%s: ERROR : log header malloc failed : %s\n" , __func__ , strerror (errno ));
12721316 return -1 ;
12731317 }
12741318 memset (log_hdr , 0 , dui_log_hdr_size );
@@ -1281,72 +1325,142 @@ static int wdc_do_cap_dui(int fd, char *file, __u32 xfer_size, int data_area)
12811325 goto out ;
12821326 }
12831327
1284- cap_dui_length = (log_hdr -> log_size [3 ] << 24 | log_hdr -> log_size [2 ] << 16 |
1285- log_hdr -> log_size [1 ] << 8 | log_hdr -> log_size [0 ]);
1328+ /* Check the Log Header version */
1329+ if (log_hdr -> hdr_version == 2 ) { /* Process Version 2 of the header */
1330+ __s64 log_size = 0 ;
1331+ __u64 curr_data_offset = 0 ;
1332+ __u64 xfer_size_long = (__u64 )xfer_size ;
12861333
1287- if (cap_dui_length == 0 ) {
1288- fprintf (stderr , "INFO : WDC : Capture Device Unit Info log is empty\n" );
1289- } else {
1334+ log_hdr_v2 = (struct wdc_dui_log_hdr_v2 * )log_hdr ;
12901335
1291- /* parse log header for all sections up to specified data area inclusively */
1292- if (data_area != WDC_NVME_DUI_MAX_DATA_AREA ) {
1293- for (int i = 0 ; i < WDC_NVME_DUI_MAX_SECTION ; i ++ ) {
1294- __u16 data_area_id = le16_to_cpu (log_hdr -> log_section [i ].data_area_id );
1295- __u16 section_size = le32_to_cpu (log_hdr -> log_section [i ].section_size );
1336+ cap_dui_length_v2 = le64_to_cpu (log_hdr_v2 -> log_size );
12961337
1297- if (data_area_id <= data_area &&
1298- data_area_id != 0 )
1299- log_size += section_size ;
1300- else
1301- break ;
1338+ fprintf (stderr , "INFO : WDC : Capture V2 Device Unit Info log\n" );
1339+
1340+ if (cap_dui_length_v2 == 0 ) {
1341+ fprintf (stderr , "INFO : WDC : Capture V2 Device Unit Info log is empty\n" );
1342+ } else {
1343+ /* parse log header for all sections up to specified data area inclusively */
1344+ if (data_area != WDC_NVME_DUI_MAX_DATA_AREA ) {
1345+ for (int i = 0 ; i < WDC_NVME_DUI_MAX_SECTION_V2 ; i ++ ) {
1346+ if (log_hdr_v2 -> log_section [i ].data_area_id <= data_area &&
1347+ log_hdr_v2 -> log_section [i ].data_area_id != 0 )
1348+ log_size += log_hdr_v2 -> log_section [i ].section_size ;
1349+ else
1350+ break ;
1351+ }
1352+ } else
1353+ log_size = cap_dui_length_v2 ;
1354+
1355+ total_size = log_size ;
1356+
1357+ dump_data = (__u8 * ) malloc (sizeof (__u8 ) * total_size );
1358+ if (dump_data == NULL ) {
1359+ fprintf (stderr , "%s: ERROR : dump data V2 malloc failed : %s, size = 0x%lx\n" ,
1360+ __func__ , strerror (errno ), (long unsigned int )total_size );
1361+ ret = -1 ;
1362+ goto out ;
13021363 }
1303- } else
1304- log_size = cap_dui_length ;
1364+ memset (dump_data , 0 , sizeof (__u8 ) * total_size );
13051365
1306- total_size = log_size ;
1307- dump_data = (__u8 * ) malloc (sizeof (__u8 ) * total_size );
1308- if (dump_data == NULL ) {
1309- fprintf (stderr , "%s: ERROR : malloc : %s\n" , __func__ , strerror (errno ));
1310- ret = -1 ;
1311- goto out ;
1366+ /* copy the telemetry and log headers into the dump_data buffer */
1367+ memcpy (dump_data , log_hdr_v2 , WDC_NVME_CAP_DUI_HEADER_SIZE );
1368+
1369+ log_size -= WDC_NVME_CAP_DUI_HEADER_SIZE ;
1370+ curr_data_offset = WDC_NVME_CAP_DUI_HEADER_SIZE ;
1371+ i = 0 ;
1372+
1373+ for (; log_size > 0 ; log_size -= xfer_size_long ) {
1374+ xfer_size_long = min (xfer_size_long , log_size );
1375+
1376+ if (log_size <= xfer_size_long )
1377+ last_xfer = true;
1378+
1379+ buffer_addr = (__u64 )(uintptr_t )dump_data + (__u64 )curr_data_offset ;
1380+
1381+ ret = wdc_dump_dui_data_v2 (fd , (__u32 )xfer_size_long , curr_data_offset , (__u8 * )buffer_addr , last_xfer );
1382+ if (ret != 0 ) {
1383+ fprintf (stderr , "%s: ERROR : WDC : Get chunk %d, size = 0x%lx, offset = 0x%lx, addr = 0x%lx\n" ,
1384+ __func__ , i , (long unsigned int )total_size , (long unsigned int )curr_data_offset , (long unsigned int )buffer_addr );
1385+ fprintf (stderr , "%s: ERROR : WDC : NVMe Status:%s(%x)\n" , __func__ , nvme_status_to_string (ret ), ret );
1386+ break ;
1387+ }
1388+
1389+ curr_data_offset += xfer_size_long ;
1390+ i ++ ;
1391+ }
13121392 }
1313- memset (dump_data , 0 , sizeof (__u8 ) * total_size );
1393+ } else {
1394+ __s32 log_size = 0 ;
1395+ __u32 curr_data_offset = 0 ;
13141396
1315- /* copy the telemetry and log headers into the dump_data buffer */
1316- memcpy (dump_data , log_hdr , WDC_NVME_CAP_DUI_HEADER_SIZE );
1397+ cap_dui_length = le32_to_cpu (log_hdr -> log_size );
13171398
1318- log_size -= WDC_NVME_CAP_DUI_HEADER_SIZE ;
1319- curr_data_offset = WDC_NVME_CAP_DUI_HEADER_SIZE ;
1320- i = 0 ;
1399+ fprintf (stderr , "INFO : WDC : Capture V1 Device Unit Info log\n" );
13211400
1322- for (; log_size > 0 ; log_size -= xfer_size ) {
1323- xfer_size = min (xfer_size , log_size );
1401+ if (cap_dui_length == 0 ) {
1402+ fprintf (stderr , "INFO : WDC : Capture V1 Device Unit Info log is empty\n" );
1403+ } else {
1404+ /* parse log header for all sections up to specified data area inclusively */
1405+ if (data_area != WDC_NVME_DUI_MAX_DATA_AREA ) {
1406+ for (int i = 0 ; i < WDC_NVME_DUI_MAX_SECTION ; i ++ ) {
1407+ if (log_hdr -> log_section [i ].data_area_id <= data_area &&
1408+ log_hdr -> log_section [i ].data_area_id != 0 )
1409+ log_size += log_hdr -> log_section [i ].section_size ;
1410+ else
1411+ break ;
1412+ }
1413+ } else
1414+ log_size = cap_dui_length ;
1415+
1416+ total_size = log_size ;
1417+ dump_data = (__u8 * ) malloc (sizeof (__u8 ) * total_size );
1418+ if (dump_data == NULL ) {
1419+ fprintf (stderr , "%s: ERROR : dump data V1 malloc failed : %s\n" , __func__ , strerror (errno ));
1420+ ret = -1 ;
1421+ goto out ;
1422+ }
1423+ memset (dump_data , 0 , sizeof (__u8 ) * total_size );
13241424
1325- if ( log_size <= xfer_size )
1326- last_xfer = true ;
1425+ /* copy the telemetry and log headers into the dump_data buffer */
1426+ memcpy ( dump_data , log_hdr , WDC_NVME_CAP_DUI_HEADER_SIZE ) ;
13271427
1328- buffer_addr = (__u64 )(uintptr_t )dump_data + (__u64 )curr_data_offset ;
1428+ log_size -= WDC_NVME_CAP_DUI_HEADER_SIZE ;
1429+ curr_data_offset = WDC_NVME_CAP_DUI_HEADER_SIZE ;
1430+ i = 0 ;
13291431
1330- ret = wdc_dump_dui_data (fd , xfer_size , curr_data_offset , (__u8 * )buffer_addr , last_xfer );
1331- if (ret != 0 ) {
1332- fprintf (stderr , "%s: ERROR : WDC : Get chunk %d, size = 0x%x, offset = 0x%x, addr = 0x%lx\n" ,
1333- __func__ , i , total_size , curr_data_offset , (long unsigned int )buffer_addr );
1334- fprintf (stderr , "%s: ERROR : WDC : NVMe Status:%s(%x)\n" , __func__ , nvme_status_to_string (ret ), ret );
1335- break ;
1432+ for (; log_size > 0 ; log_size -= xfer_size ) {
1433+ xfer_size = min (xfer_size , log_size );
1434+
1435+ if (log_size <= xfer_size )
1436+ last_xfer = true;
1437+
1438+ buffer_addr = (__u64 )(uintptr_t )dump_data + (__u64 )curr_data_offset ;
1439+
1440+ ret = wdc_dump_dui_data (fd , xfer_size , curr_data_offset , (__u8 * )buffer_addr , last_xfer );
1441+ if (ret != 0 ) {
1442+ fprintf (stderr , "%s: ERROR : WDC : Get chunk %d, size = 0x%lx, offset = 0x%x, addr = 0x%lx\n" ,
1443+ __func__ , i , (long unsigned int )total_size , curr_data_offset , (long unsigned int )buffer_addr );
1444+ fprintf (stderr , "%s: ERROR : WDC : NVMe Status:%s(%x)\n" , __func__ , nvme_status_to_string (ret ), ret );
1445+ break ;
1446+ }
1447+
1448+ curr_data_offset += xfer_size ;
1449+ i ++ ;
13361450 }
13371451
1338- curr_data_offset += xfer_size ;
1339- i ++ ;
13401452 }
1453+ }
13411454
1342- if (ret == 0 ) {
1343- fprintf (stderr , "%s: NVMe Status:%s(%x)\n" , __func__ , nvme_status_to_string (ret ), ret );
1344- fprintf (stderr , "INFO : WDC : Capture Device Unit Info log, length = 0x%x \n" , total_size );
1455+ if (ret == 0 ) {
1456+ fprintf (stderr , "%s: NVMe Status:%s(%x)\n" , __func__ , nvme_status_to_string (ret ), ret );
1457+ fprintf (stderr , "INFO : WDC : Capture Device Unit Info log, length = 0x%lx \n" , ( long unsigned int ) total_size );
13451458
1346- ret = wdc_create_log_file (file , dump_data , total_size );
1347- }
1348- free (dump_data );
1459+ ret = wdc_create_log_file (file , dump_data , total_size );
13491460 }
1461+
1462+ free (dump_data );
1463+
13501464out :
13511465 free (log_hdr );
13521466 return ret ;
0 commit comments