]>
git.proxmox.com Git - mirror_smartmontools-debian.git/blob - nvmecmds.cpp
b3f6a0f180051f5f1b1262845183ddd03a34eba0
4 * Home page of code is: http://www.smartmontools.org
6 * Copyright (C) 2016 Christian Franke
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
13 * You should have received a copy of the GNU General Public License
14 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
21 const char * nvmecmds_cvsid
= "$Id: nvmecmds.cpp 4313 2016-05-01 16:17:53Z chrfranke $"
24 #include "dev_interface.h"
25 #include "atacmds.h" // swapx(), ASSERT_*(), dont_print_serial_number
26 #include "scsicmds.h" // dStrHex()
29 using namespace smartmontools
;
31 // Check nvme_* struct sizes
32 ASSERT_SIZEOF_STRUCT(nvme_id_ctrl
, 4096);
33 ASSERT_SIZEOF_STRUCT(nvme_id_ns
, 4096);
34 ASSERT_SIZEOF_STRUCT(nvme_error_log_page
, 64);
35 ASSERT_SIZEOF_STRUCT(nvme_smart_log
, 512);
38 // Print NVMe debug messages?
39 unsigned char nvme_debugmode
= 0;
41 // Dump up to 4096 bytes, do not dump trailing zero bytes.
42 // TODO: Handle this by new unified function in utility.cpp
43 static void debug_hex_dump(const void * data
, unsigned size
)
45 const unsigned char * p
= (const unsigned char *)data
;
46 const unsigned limit
= 4096; // sizeof(nvme_id_ctrl)
47 unsigned sz
= (size
<= limit
? size
: limit
);
49 while (sz
> 0x10 && !p
[sz
-1])
53 sz
= (sz
& ~0x0f) + 0x10;
64 // Call NVMe pass-through and print debug info if requested.
65 static bool nvme_pass_through(nvme_device
* device
, const nvme_cmd_in
& in
,
68 int64_t start_usec
= -1;
71 pout(" [NVMe call: opcode=0x%02x, size=0x%04x, nsid=0x%08x, cdw10=0x%08x",
72 in
.opcode
, in
.size
, in
.nsid
, in
.cdw10
);
73 if (in
.cdw11
|| in
.cdw12
|| in
.cdw13
|| in
.cdw14
|| in
.cdw15
)
74 pout(",\n cdw1x=0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x",
75 in
.cdw11
, in
.cdw12
, in
.cdw13
, in
.cdw14
, in
.cdw15
);
78 start_usec
= smi()->get_timer_usec();
81 bool ok
= device
->nvme_pass_through(in
, out
);
83 if ( dont_print_serial_number
&& ok
84 && in
.opcode
== nvme_admin_identify
&& in
.cdw10
== 0x01) {
85 // Invalidate serial number
86 nvme_id_ctrl
& id_ctrl
= *reinterpret_cast<nvme_id_ctrl
*>(in
.buffer
);
87 memset(id_ctrl
.sn
, 'X', sizeof(id_ctrl
.sn
));
91 if (start_usec
>= 0) {
92 int64_t duration_usec
= smi()->get_timer_usec() - start_usec
;
93 if (duration_usec
>= 500)
94 pout(" [Duration: %.3fs]\n", duration_usec
/ 1000000.0);
98 pout(" [NVMe call failed: ");
100 pout("NVMe Status=0x%04x", out
.status
);
102 pout("%s", device
->get_errmsg());
105 pout(" [NVMe call succeeded: result=0x%08x", out
.result
);
106 if (nvme_debugmode
> 1 && in
.direction() == nvme_cmd_in::data_in
) {
108 debug_hex_dump(in
.buffer
, in
.size
);
118 // Call NVMe pass-through and print debug info if requested.
119 // Version without output parameters.
120 static bool nvme_pass_through(nvme_device
* device
, const nvme_cmd_in
& in
)
123 return nvme_pass_through(device
, in
, out
);
126 // Read NVMe identify info with controller/namespace field CNS.
127 static bool nvme_read_identify(nvme_device
* device
, unsigned nsid
,
128 unsigned char cns
, void * data
, unsigned size
)
130 memset(data
, 0, size
);
132 in
.set_data_in(nvme_admin_identify
, data
, size
);
136 return nvme_pass_through(device
, in
);
139 // Read NVMe Identify Controller data structure.
140 bool nvme_read_id_ctrl(nvme_device
* device
, nvme_id_ctrl
& id_ctrl
)
142 if (!nvme_read_identify(device
, 0, 0x01, &id_ctrl
, sizeof(id_ctrl
)))
147 swapx(&id_ctrl
.ssvid
);
148 swapx(&id_ctrl
.cntlid
);
149 swapx(&id_ctrl
.oacs
);
150 swapx(&id_ctrl
.wctemp
);
151 swapx(&id_ctrl
.cctemp
);
152 swapx(&id_ctrl
.mtfa
);
153 swapx(&id_ctrl
.hmpre
);
154 swapx(&id_ctrl
.hmmin
);
155 swapx(&id_ctrl
.rpmbs
);
157 swapx(&id_ctrl
.oncs
);
158 swapx(&id_ctrl
.fuses
);
159 swapx(&id_ctrl
.awun
);
160 swapx(&id_ctrl
.awupf
);
161 swapx(&id_ctrl
.acwu
);
162 swapx(&id_ctrl
.sgls
);
163 for (int i
= 0; i
< 32; i
++) {
164 swapx(&id_ctrl
.psd
[i
].max_power
);
165 swapx(&id_ctrl
.psd
[i
].entry_lat
);
166 swapx(&id_ctrl
.psd
[i
].exit_lat
);
167 swapx(&id_ctrl
.psd
[i
].idle_power
);
168 swapx(&id_ctrl
.psd
[i
].active_power
);
175 // Read NVMe Identify Namespace data structure for namespace NSID.
176 bool nvme_read_id_ns(nvme_device
* device
, unsigned nsid
, nvme_id_ns
& id_ns
)
178 if (!nvme_read_identify(device
, nsid
, 0x00, &id_ns
, sizeof(id_ns
)))
186 swapx(&id_ns
.nawupf
);
190 swapx(&id_ns
.nabspf
);
191 for (int i
= 0; i
< 16; i
++)
192 swapx(&id_ns
.lbaf
[i
].ms
);
198 // Read NVMe log page with identifier LID.
199 bool nvme_read_log_page(nvme_device
* device
, unsigned char lid
, void * data
, unsigned size
)
201 if (!(4 <= size
&& size
<= 0x4000 && (size
% 4) == 0))
202 throw std::logic_error("nvme_read_log_page(): invalid size");
204 memset(data
, 0, size
);
206 in
.set_data_in(nvme_admin_get_log_page
, data
, size
);
207 in
.nsid
= device
->get_nsid();
208 in
.cdw10
= lid
| (((size
/ 4) - 1) << 16);
210 return nvme_pass_through(device
, in
);
213 // Read NVMe Error Information Log.
214 bool nvme_read_error_log(nvme_device
* device
, nvme_error_log_page
* error_log
, unsigned num_entries
)
216 if (!nvme_read_log_page(device
, 0x01, error_log
, num_entries
* sizeof(*error_log
)))
220 for (unsigned i
= 0; i
< num_entries
; i
++) {
221 swapx(&error_log
[i
].error_count
);
222 swapx(&error_log
[i
].sqid
);
223 swapx(&error_log
[i
].cmdid
);
224 swapx(&error_log
[i
].status_field
);
225 swapx(&error_log
[i
].parm_error_location
);
226 swapx(&error_log
[i
].lba
);
227 swapx(&error_log
[i
].nsid
);
234 // Read NVMe SMART/Health Information log.
235 bool nvme_read_smart_log(nvme_device
* device
, nvme_smart_log
& smart_log
)
237 if (!nvme_read_log_page(device
, 0x02, &smart_log
, sizeof(smart_log
)))
241 swapx(&smart_log
.warning_temp_time
);
242 swapx(&smart_log
.critical_comp_time
);
243 for (int i
= 0; i
< 8; i
++)
244 swapx(&smart_log
.temp_sensor
[i
]);