Skip to content

Commit 3562eb0

Browse files
[NVMe-CLI] WDC: Add support for 64 bit data addresses in Get DUI Data functions
1 parent 836fd96 commit 3562eb0

1 file changed

Lines changed: 169 additions & 55 deletions

File tree

plugins/wdc/wdc-nvme.c

Lines changed: 169 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
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+
456464
struct 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 */
466483
struct 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+
13501464
out:
13511465
free(log_hdr);
13521466
return ret;

0 commit comments

Comments
 (0)