]>
git.proxmox.com Git - mirror_smartmontools-debian.git/blob - nvmecmds.cpp
4 * Home page of code is: http://www.smartmontools.org
6 * Copyright (C) 2016 Christian Franke
8 * SPDX-License-Identifier: GPL-2.0-or-later
14 const char * nvmecmds_cvsid
= "$Id: nvmecmds.cpp 4760 2018-08-19 18:45:53Z chrfranke $"
17 #include "dev_interface.h"
18 #include "atacmds.h" // swapx(), ASSERT_*(), dont_print_serial_number
19 #include "scsicmds.h" // dStrHex()
22 using namespace smartmontools
;
24 // Check nvme_* struct sizes
25 ASSERT_SIZEOF_STRUCT(nvme_id_ctrl
, 4096);
26 ASSERT_SIZEOF_STRUCT(nvme_id_ns
, 4096);
27 ASSERT_SIZEOF_STRUCT(nvme_error_log_page
, 64);
28 ASSERT_SIZEOF_STRUCT(nvme_smart_log
, 512);
31 // Print NVMe debug messages?
32 unsigned char nvme_debugmode
= 0;
34 // Dump up to 4096 bytes, do not dump trailing zero bytes.
35 // TODO: Handle this by new unified function in utility.cpp
36 static void debug_hex_dump(const void * data
, unsigned size
)
38 const unsigned char * p
= (const unsigned char *)data
;
39 const unsigned limit
= 4096; // sizeof(nvme_id_ctrl)
40 unsigned sz
= (size
<= limit
? size
: limit
);
42 while (sz
> 0x10 && !p
[sz
-1])
46 sz
= (sz
& ~0x0f) + 0x10;
52 dStrHex((const uint8_t *)p
, sz
, 0);
57 // Call NVMe pass-through and print debug info if requested.
58 static bool nvme_pass_through(nvme_device
* device
, const nvme_cmd_in
& in
,
61 int64_t start_usec
= -1;
64 pout(" [NVMe call: opcode=0x%02x, size=0x%04x, nsid=0x%08x, cdw10=0x%08x",
65 in
.opcode
, in
.size
, in
.nsid
, in
.cdw10
);
66 if (in
.cdw11
|| in
.cdw12
|| in
.cdw13
|| in
.cdw14
|| in
.cdw15
)
67 pout(",\n cdw1x=0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
68 in
.cdw11
, in
.cdw12
, in
.cdw13
, in
.cdw14
, in
.cdw15
);
71 start_usec
= smi()->get_timer_usec();
74 bool ok
= device
->nvme_pass_through(in
, out
);
76 if ( dont_print_serial_number
&& ok
77 && in
.opcode
== nvme_admin_identify
&& in
.cdw10
== 0x01) {
78 // Invalidate serial number
79 nvme_id_ctrl
& id_ctrl
= *reinterpret_cast<nvme_id_ctrl
*>(in
.buffer
);
80 memset(id_ctrl
.sn
, 'X', sizeof(id_ctrl
.sn
));
84 if (start_usec
>= 0) {
85 int64_t duration_usec
= smi()->get_timer_usec() - start_usec
;
86 if (duration_usec
>= 500)
87 pout(" [Duration: %.3fs]\n", duration_usec
/ 1000000.0);
91 pout(" [NVMe call failed: ");
93 pout("NVMe Status=0x%04x", out
.status
);
95 pout("%s", device
->get_errmsg());
98 pout(" [NVMe call succeeded: result=0x%08x", out
.result
);
99 if (nvme_debugmode
> 1 && in
.direction() == nvme_cmd_in::data_in
) {
101 debug_hex_dump(in
.buffer
, in
.size
);
111 // Call NVMe pass-through and print debug info if requested.
112 // Version without output parameters.
113 static bool nvme_pass_through(nvme_device
* device
, const nvme_cmd_in
& in
)
116 return nvme_pass_through(device
, in
, out
);
119 // Read NVMe identify info with controller/namespace field CNS.
120 static bool nvme_read_identify(nvme_device
* device
, unsigned nsid
,
121 unsigned char cns
, void * data
, unsigned size
)
123 memset(data
, 0, size
);
125 in
.set_data_in(nvme_admin_identify
, data
, size
);
129 return nvme_pass_through(device
, in
);
132 // Read NVMe Identify Controller data structure.
133 bool nvme_read_id_ctrl(nvme_device
* device
, nvme_id_ctrl
& id_ctrl
)
135 if (!nvme_read_identify(device
, 0, 0x01, &id_ctrl
, sizeof(id_ctrl
)))
140 swapx(&id_ctrl
.ssvid
);
141 swapx(&id_ctrl
.cntlid
);
142 swapx(&id_ctrl
.oacs
);
143 swapx(&id_ctrl
.wctemp
);
144 swapx(&id_ctrl
.cctemp
);
145 swapx(&id_ctrl
.mtfa
);
146 swapx(&id_ctrl
.hmpre
);
147 swapx(&id_ctrl
.hmmin
);
148 swapx(&id_ctrl
.rpmbs
);
150 swapx(&id_ctrl
.oncs
);
151 swapx(&id_ctrl
.fuses
);
152 swapx(&id_ctrl
.awun
);
153 swapx(&id_ctrl
.awupf
);
154 swapx(&id_ctrl
.acwu
);
155 swapx(&id_ctrl
.sgls
);
156 for (int i
= 0; i
< 32; i
++) {
157 swapx(&id_ctrl
.psd
[i
].max_power
);
158 swapx(&id_ctrl
.psd
[i
].entry_lat
);
159 swapx(&id_ctrl
.psd
[i
].exit_lat
);
160 swapx(&id_ctrl
.psd
[i
].idle_power
);
161 swapx(&id_ctrl
.psd
[i
].active_power
);
168 // Read NVMe Identify Namespace data structure for namespace NSID.
169 bool nvme_read_id_ns(nvme_device
* device
, unsigned nsid
, nvme_id_ns
& id_ns
)
171 if (!nvme_read_identify(device
, nsid
, 0x00, &id_ns
, sizeof(id_ns
)))
179 swapx(&id_ns
.nawupf
);
183 swapx(&id_ns
.nabspf
);
184 for (int i
= 0; i
< 16; i
++)
185 swapx(&id_ns
.lbaf
[i
].ms
);
191 // Read NVMe log page with identifier LID.
192 bool nvme_read_log_page(nvme_device
* device
, unsigned char lid
, void * data
,
193 unsigned size
, bool broadcast_nsid
)
195 if (!(4 <= size
&& size
<= 0x4000 && (size
% 4) == 0))
196 throw std::logic_error("nvme_read_log_page(): invalid size");
198 memset(data
, 0, size
);
200 in
.set_data_in(nvme_admin_get_log_page
, data
, size
);
201 in
.nsid
= broadcast_nsid
? 0xffffffff : device
->get_nsid();
202 in
.cdw10
= lid
| (((size
/ 4) - 1) << 16);
204 return nvme_pass_through(device
, in
);
207 // Read NVMe Error Information Log.
208 bool nvme_read_error_log(nvme_device
* device
, nvme_error_log_page
* error_log
, unsigned num_entries
)
210 if (!nvme_read_log_page(device
, 0x01, error_log
, num_entries
* sizeof(*error_log
), true))
214 for (unsigned i
= 0; i
< num_entries
; i
++) {
215 swapx(&error_log
[i
].error_count
);
216 swapx(&error_log
[i
].sqid
);
217 swapx(&error_log
[i
].cmdid
);
218 swapx(&error_log
[i
].status_field
);
219 swapx(&error_log
[i
].parm_error_location
);
220 swapx(&error_log
[i
].lba
);
221 swapx(&error_log
[i
].nsid
);
228 // Read NVMe SMART/Health Information log.
229 bool nvme_read_smart_log(nvme_device
* device
, nvme_smart_log
& smart_log
)
231 if (!nvme_read_log_page(device
, 0x02, &smart_log
, sizeof(smart_log
), true))
235 swapx(&smart_log
.warning_temp_time
);
236 swapx(&smart_log
.critical_comp_time
);
237 for (int i
= 0; i
< 8; i
++)
238 swapx(&smart_log
.temp_sensor
[i
]);