nvmectl(8): sync with FreeBSD HEAD r316105. - Expand the SMART / Health Information Log Page (Page 02) printout based on NVM Express 1.2.1 Standard. - Implement Intel-specific log pages. - Implement HGST-specific log pages. - Implement wdc-specific nvme control options. - Add the ability to dump log pages directly in binary to stdout.diff -r1.2 -r1.3 src/sbin/nvmectl/Makefile
(nonaka)
--- src/sbin/nvmectl/Makefile 2017/02/13 11:16:46 1.2
+++ src/sbin/nvmectl/Makefile 2017/04/29 00:06:40 1.3
@@ -1,21 +1,22 @@ | @@ -1,21 +1,22 @@ | |||
1 | # $NetBSD: Makefile,v 1.2 2017/02/13 11:16:46 nonaka Exp $ | 1 | # $NetBSD: Makefile,v 1.3 2017/04/29 00:06:40 nonaka Exp $ | |
2 | 2 | |||
3 | .include <bsd.own.mk> | 3 | .include <bsd.own.mk> | |
4 | 4 | |||
5 | PROG= nvmectl | 5 | PROG= nvmectl | |
6 | SRCS= nvmectl.c | 6 | SRCS= nvmectl.c | |
7 | SRCS+= devlist.c | 7 | SRCS+= devlist.c | |
8 | SRCS+= firmware.c | 8 | SRCS+= firmware.c | |
9 | SRCS+= identify.c | 9 | SRCS+= identify.c | |
10 | SRCS+= logpage.c | 10 | SRCS+= logpage.c | |
11 | SRCS+= perftest.c | 11 | SRCS+= perftest.c | |
12 | SRCS+= power.c | 12 | SRCS+= power.c | |
13 | SRCS+= reset.c | 13 | SRCS+= reset.c | |
14 | SRCS+= wdc.c | |||
14 | SRCS+= bignum.c | 15 | SRCS+= bignum.c | |
15 | SRCS+= humanize_bignum.c | 16 | SRCS+= humanize_bignum.c | |
16 | MAN= nvmectl.8 | 17 | MAN= nvmectl.8 | |
17 | 18 | |||
18 | DPADD+= ${LIBUTIL} | 19 | DPADD+= ${LIBUTIL} | |
19 | LDADD+= -lutil | 20 | LDADD+= -lutil | |
20 | 21 | |||
21 | .include <bsd.prog.mk> | 22 | .include <bsd.prog.mk> |
--- src/sbin/nvmectl/nvmectl.8 2016/06/05 09:13:08 1.2
+++ src/sbin/nvmectl/nvmectl.8 2017/04/29 00:06:40 1.3
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | .\" $NetBSD: nvmectl.8,v 1.2 2016/06/05 09:13:08 wiz Exp $ | 1 | .\" $NetBSD: nvmectl.8,v 1.3 2017/04/29 00:06:40 nonaka Exp $ | |
2 | .\" | 2 | .\" | |
3 | .\" Copyright (c) 2012 Intel Corporation | 3 | .\" Copyright (c) 2012 Intel Corporation | |
4 | .\" All rights reserved. | 4 | .\" All rights reserved. | |
5 | .\" | 5 | .\" | |
6 | .\" Redistribution and use in source and binary forms, with or without | 6 | .\" Redistribution and use in source and binary forms, with or without | |
7 | .\" modification, are permitted provided that the following conditions | 7 | .\" modification, are permitted provided that the following conditions | |
8 | .\" are met: | 8 | .\" are met: | |
9 | .\" 1. Redistributions of source code must retain the above copyright | 9 | .\" 1. Redistributions of source code must retain the above copyright | |
10 | .\" notice, this list of conditions, and the following disclaimer, | 10 | .\" notice, this list of conditions, and the following disclaimer, | |
11 | .\" without modification. | 11 | .\" without modification. | |
12 | .\" 2. Redistributions in binary form must reproduce at minimum a disclaimer | 12 | .\" 2. Redistributions in binary form must reproduce at minimum a disclaimer | |
13 | .\" substantially similar to the "NO WARRANTY" disclaimer below | 13 | .\" substantially similar to the "NO WARRANTY" disclaimer below | |
14 | .\" ("Disclaimer") and any redistribution must be conditioned upon | 14 | .\" ("Disclaimer") and any redistribution must be conditioned upon | |
@@ -22,27 +22,27 @@ | @@ -22,27 +22,27 @@ | |||
22 | .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 22 | .\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
23 | .\" HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | .\" HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | 26 | .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
27 | .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | 27 | .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
28 | .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | .\" POSSIBILITY OF SUCH DAMAGES. | 29 | .\" POSSIBILITY OF SUCH DAMAGES. | |
30 | .\" | 30 | .\" | |
31 | .\" nvmecontrol man page. | 31 | .\" nvmecontrol man page. | |
32 | .\" | 32 | .\" | |
33 | .\" Author: Jim Harris <jimharris@FreeBSD.org> | 33 | .\" Author: Jim Harris <jimharris@FreeBSD.org> | |
34 | .\" | 34 | .\" | |
35 | .\" $FreeBSD: head/sbin/nvmecontrol/nvmecontrol.8 299151 2016-05-06 03:11:34Z pfg $ | 35 | .\" $FreeBSD: head/sbin/nvmecontrol/nvmecontrol.8 314230 2017-02-25 00:09:16Z imp $ | |
36 | .\" | 36 | .\" | |
37 | .Dd May 19, 2016 | 37 | .Dd May 19, 2016 | |
38 | .Dt NVMECTL 8 | 38 | .Dt NVMECTL 8 | |
39 | .Os | 39 | .Os | |
40 | .Sh NAME | 40 | .Sh NAME | |
41 | .Nm nvmectl | 41 | .Nm nvmectl | |
42 | .Nd NVM Express control utility | 42 | .Nd NVM Express control utility | |
43 | .Sh SYNOPSIS | 43 | .Sh SYNOPSIS | |
44 | .Nm | 44 | .Nm | |
45 | .Ic devlist | 45 | .Ic devlist | |
46 | .Nm | 46 | .Nm | |
47 | .Ic identify | 47 | .Ic identify | |
48 | .Op Fl x Op Fl v | 48 | .Op Fl x Op Fl v | |
@@ -52,96 +52,159 @@ | @@ -52,96 +52,159 @@ | |||
52 | .\".Op Fl p | 52 | .\".Op Fl p | |
53 | .\".Aq Fl n Ar num_threads | 53 | .\".Aq Fl n Ar num_threads | |
54 | .\".Aq Fl o Ar read|write | 54 | .\".Aq Fl o Ar read|write | |
55 | .\".Aq Fl s Ar size_in_bytes | 55 | .\".Aq Fl s Ar size_in_bytes | |
56 | .\".Aq Fl t Ar time_in_sec | 56 | .\".Aq Fl t Ar time_in_sec | |
57 | .\".Aq namespace id | 57 | .\".Aq namespace id | |
58 | .\".Nm | 58 | .\".Nm | |
59 | .\".Ic reset | 59 | .\".Ic reset | |
60 | .\".Aq controller id | 60 | .\".Aq controller id | |
61 | .Nm | 61 | .Nm | |
62 | .Ic logpage | 62 | .Ic logpage | |
63 | .Op Fl x | 63 | .Op Fl x | |
64 | .Op Fl p Ar page_id | 64 | .Op Fl p Ar page_id | |
65 | .Op Fl v Ar vendor-string | |||
66 | .Op Fl b | |||
65 | .Ar device_id Ns | Ns Ar namespace_id | 67 | .Ar device_id Ns | Ns Ar namespace_id | |
66 | .\".Nm | 68 | .\".Nm | |
67 | .\".Ic firmware | 69 | .\".Ic firmware | |
68 | .\".Op Fl a | 70 | .\".Op Fl a | |
69 | .\".Op Fl s Ar slot | 71 | .\".Op Fl s Ar slot | |
70 | .\".Op Fl f Ar path_to_firmware | 72 | .\".Op Fl f Ar path_to_firmware | |
71 | .\".Aq device id | 73 | .\".Aq device id | |
72 | .Nm | 74 | .Nm | |
73 | .Ic power | 75 | .Ic power | |
74 | .Op Fl l | 76 | .Op Fl l | |
75 | .Op Fl p Ar power_state | 77 | .Op Fl p Ar power_state | |
76 | .Op Fl w Ar workload_hint | 78 | .Op Fl w Ar workload_hint | |
77 | .Ar device_id | 79 | .Ar device_id | |
80 | .Nm | |||
81 | .Ic wdc cap-diag | |||
82 | .Op Fl o path_template | |||
83 | .Ar device id | |||
84 | .Nm | |||
85 | .Ic wdc drive-log | |||
86 | .Op Fl o path_template | |||
87 | .Ar device id | |||
88 | .Nm | |||
89 | .Ic wdc get-crash-dump | |||
90 | .Op Fl o path_template | |||
91 | .Ar device id | |||
92 | .\" .Nm | |||
93 | .\" .Ic wdc purge | |||
94 | .\" .Aq device id | |||
95 | .\" .Nm | |||
96 | .\" .Ic wdc purge-monitor | |||
97 | .\" .Aq device id | |||
78 | .Sh DESCRIPTION | 98 | .Sh DESCRIPTION | |
79 | NVM Express (NVMe) is a storage protocol standard, for SSDs and other | 99 | NVM Express (NVMe) is a storage protocol standard, for SSDs and other | |
80 | high-speed storage devices over PCI Express. | 100 | high-speed storage devices over PCI Express. | |
101 | .Pp | |||
102 | .Ss logpage | |||
103 | The logpage command knows how to print log pages of various types. | |||
104 | It also knows about vendor specific log pages from hgst/wdc and intel. | |||
105 | Page 0xc1 for hgst/wdc contains the advanced smart information about | |||
106 | the drive. | |||
107 | Page 0xc1 is read latency stats for intel. | |||
108 | Page 0xc2 is write latency stats for intel. | |||
109 | Page 0xc5 is temperature stats for intel. | |||
110 | Page 0xca is advanced smart information for intel. | |||
111 | .Pp | |||
112 | Specifying | |||
113 | .Fl p | |||
114 | .Ic help | |||
115 | will list all valid vendors and pages. | |||
116 | .Fl x | |||
117 | will print the page as hex. | |||
118 | .Fl b | |||
119 | will print the binary data for the page. | |||
120 | .Ss wdc | |||
121 | The various wdc command retrieve log data from the wdc/hgst drives. | |||
122 | The | |||
123 | .Fl o | |||
124 | flag specifies a path template to use to output the files. | |||
125 | Each file takes the path template (which defaults to nothing), appends | |||
126 | the drive's serial number and the type of dump it is followed | |||
127 | by .bin. | |||
128 | These logs must be sent to the vendor for analysis. | |||
129 | This tool only provides a way to extract them. | |||
81 | .Sh EXAMPLES | 130 | .Sh EXAMPLES | |
82 | .Dl nvmectl devlist | 131 | .Dl nvmectl devlist | |
83 | .Pp | 132 | .Pp | |
84 | Display a list of NVMe controllers and namespaces along with their device nodes. | 133 | Display a list of NVMe controllers and namespaces along with their device nodes. | |
85 | .Pp | 134 | .Pp | |
86 | .Dl nvmectl identify nvme0 | 135 | .Dl nvmectl identify nvme0 | |
87 | .Pp | 136 | .Pp | |
88 | Display a human-readable summary of the nvme0 IDENTIFY_CONTROLLER data. | 137 | Display a human-readable summary of the nvme0 IDENTIFY_CONTROLLER data. | |
89 | .Pp | 138 | .Pp | |
90 | .Dl nvmectl identify -x -v nvme0ns1 | 139 | .Dl nvmectl identify -x -v nvme0ns1 | |
91 | .Pp | 140 | .Pp | |
92 | Display an hexadecimal dump of the nvme0 | 141 | Display an hexadecimal dump of the nvme0 | |
93 | .Dv IDENTIFY_NAMESPACE | 142 | .Dv IDENTIFY_NAMESPACE | |
94 | data for namespace 1. | 143 | data for namespace 1. | |
95 | .\".Pp | 144 | .\".Pp | |
96 | .\".Dl nvmectl perftest -n 32 -o read -s 512 -t 30 nvme0ns1 | 145 | .\".Dl nvmectl perftest -n 32 -o read -s 512 -t 30 nvme0ns1 | |
97 | .\".Pp | 146 | .\".Pp | |
98 | .\"Run a performance test on nvme0ns1 using 32 kernel threads for 30 seconds. Each | 147 | .\"Run a performance test on nvme0ns1 using 32 kernel threads for 30 seconds. | |
99 | .\"thread will issue a single 512 byte read command. Results are printed to | 148 | .\"Each thread will issue a single 512 byte read command. | |
100 | .\"stdout when 30 seconds expires. | 149 | .\"Results are printed to stdout when 30 seconds expires. | |
101 | .\".Pp | 150 | .\".Pp | |
102 | .\".Dl nvmectl reset nvme0 | 151 | .\".Dl nvmectl reset nvme0 | |
103 | .\".Pp | 152 | .\".Pp | |
104 | .\"Perform a controller-level reset of the nvme0 controller. | 153 | .\"Perform a controller-level reset of the nvme0 controller. | |
105 | .Pp | 154 | .Pp | |
106 | .Dl nvmectl logpage -p 1 nvme0 | 155 | .Dl nvmectl logpage -p 1 nvme0 | |
107 | .Pp | 156 | .Pp | |
108 | Display a human-readable summary of the nvme0 controller's Error Information Log. | 157 | Display a human-readable summary of the nvme0 controller's Error Information Log. | |
109 | Log pages defined by the NVMe specification include Error Information Log (ID=1), | 158 | Log pages defined by the NVMe specification include Error Information Log (ID=1), | |
110 | SMART/Health Information Log (ID=2), and Firmware Slot Log (ID=3). | 159 | SMART/Health Information Log (ID=2), and Firmware Slot Log (ID=3). | |
111 | .Pp | 160 | .Pp | |
161 | .Dl nvmectl logpage -p 0xc1 -v wdc nvme0 | |||
162 | .Pp | |||
163 | Display a human-readable summary of the nvme0's wdc-specific advanced | |||
164 | SMART data. | |||
165 | .Pp | |||
112 | .Dl nvmectl logpage -p 1 -x nvme0 | 166 | .Dl nvmectl logpage -p 1 -x nvme0 | |
113 | .Pp | 167 | .Pp | |
114 | Display a hexadecimal dump of the nvme0 controller's Error Information Log. | 168 | Display a hexadecimal dump of the nvme0 controller's Error Information Log. | |
169 | .Pp | |||
170 | .Dl nvmectl logpage -p 0xcb -b nvme0 > /tmp/page-cb.bin | |||
171 | .Pp | |||
172 | Print the contents of vendor specific page 0xcb as binary data on | |||
173 | standard out. | |||
174 | Redirect it to a temporary file. | |||
115 | .\".Pp | 175 | .\".Pp | |
116 | .\".Dl nvmectl firmware -s 2 -f /tmp/nvme_firmware nvme0 | 176 | .\".Dl nvmectl firmware -s 2 -f /tmp/nvme_firmware nvme0 | |
117 | .\".Pp | 177 | .\".Pp | |
118 | .\"Download the firmware image contained in "/tmp/nvme_firmware" to slot 2 of the | 178 | .\"Download the firmware image contained in "/tmp/nvme_firmware" to slot 2 of the | |
119 | .\"nvme0 controller, but do not activate the image. | 179 | .\"nvme0 controller, but do not activate the image. | |
120 | .\".Pp | 180 | .\".Pp | |
121 | .\".Dl nvmectl firmware -s 4 -a nvme0 | 181 | .\".Dl nvmectl firmware -s 4 -a nvme0 | |
122 | .\".Pp | 182 | .\".Pp | |
123 | .\"Activate the firmware in slot 4 of the nvme0 controller on the next reset. | 183 | .\"Activate the firmware in slot 4 of the nvme0 controller on the next reset. | |
124 | .\".Pp | 184 | .\".Pp | |
125 | .\".Dl nvmectl firmware -s 7 -f /tmp/nvme_firmware -a nvme0 | 185 | .\".Dl nvmectl firmware -s 7 -f /tmp/nvme_firmware -a nvme0 | |
126 | .\".Pp | 186 | .\".Pp | |
127 | .\"Download the firmware image contained in "/tmp/nvme_firmware" to slot 7 of the | 187 | .\"Download the firmware image contained in "/tmp/nvme_firmware" to slot 7 of the | |
128 | .\"nvme0 controller and activate it on the next reset. | 188 | .\"nvme0 controller and activate it on the next reset. | |
129 | .Pp | 189 | .Pp | |
130 | .Dl nvmectl power -l nvme0 | 190 | .Dl nvmectl power -l nvme0 | |
131 | .Pp | 191 | .Pp | |
132 | List all the current power modes. | 192 | List all the current power modes. | |
133 | .Pp | 193 | .Pp | |
134 | .Dl nvmectl power -p 3 nvme0 | 194 | .Dl nvmectl power -p 3 nvme0 | |
135 | .Pp | 195 | .Pp | |
136 | Set the current power mode. | 196 | Set the current power mode. | |
137 | .Pp | 197 | .Pp | |
138 | .Dl nvmectl power nvme0 | 198 | .Dl nvmectl power nvme0 | |
139 | .Pp | 199 | .Pp | |
140 | Get the current power mode. | 200 | Get the current power mode. | |
201 | .Sh HISTORY | |||
202 | The nvmecontrol utility appeared in | |||
203 | .Fx 9.2 . | |||
141 | .Sh AUTHORS | 204 | .Sh AUTHORS | |
142 | .An -nosplit | 205 | .An -nosplit | |
143 | nvmecontrol was developed by Intel and originally written by | 206 | nvmecontrol was developed by Intel and originally written by | |
144 | .An Jim Harris Aq Mt jimharris@FreeBSD.org . | 207 | .An Jim Harris Aq Mt jimharris@FreeBSD.org . | |
145 | .Pp | 208 | .Pp | |
146 | This man page was written by | 209 | This man page was written by | |
147 | .An Jim Harris Aq Mt jimharris@FreeBSD.org . | 210 | .An Jim Harris Aq Mt jimharris@FreeBSD.org . |
--- src/sbin/nvmectl/nvmectl.c 2016/06/04 20:59:49 1.2
+++ src/sbin/nvmectl/nvmectl.c 2017/04/29 00:06:40 1.3
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: nvmectl.c,v 1.2 2016/06/04 20:59:49 joerg Exp $ */ | 1 | /* $NetBSD: nvmectl.c,v 1.3 2017/04/29 00:06:40 nonaka Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (C) 2012-2013 Intel Corporation | 4 | * Copyright (C) 2012-2013 Intel Corporation | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
@@ -18,87 +18,100 @@ | @@ -18,87 +18,100 @@ | |||
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | */ | 27 | */ | |
28 | 28 | |||
29 | #include <sys/cdefs.h> | 29 | #include <sys/cdefs.h> | |
30 | #ifndef lint | 30 | #ifndef lint | |
31 | __RCSID("$NetBSD: nvmectl.c,v 1.2 2016/06/04 20:59:49 joerg Exp $"); | 31 | __RCSID("$NetBSD: nvmectl.c,v 1.3 2017/04/29 00:06:40 nonaka Exp $"); | |
32 | #if 0 | 32 | #if 0 | |
33 | __FBSDID("$FreeBSD: head/sbin/nvmecontrol/nvmecontrol.c 295087 2016-01-30 22:48:06Z imp $"); | 33 | __FBSDID("$FreeBSD: head/sbin/nvmecontrol/nvmecontrol.c 314229 2017-02-25 00:09:12Z imp $"); | |
34 | #endif | 34 | #endif | |
35 | #endif | 35 | #endif | |
36 | 36 | |||
37 | #include <sys/param.h> | 37 | #include <sys/param.h> | |
38 | #include <sys/ioccom.h> | 38 | #include <sys/ioccom.h> | |
39 | #include <sys/stat.h> | 39 | #include <sys/stat.h> | |
40 | 40 | |||
41 | #include <ctype.h> | 41 | #include <ctype.h> | |
42 | #include <err.h> | 42 | #include <err.h> | |
43 | #include <errno.h> | 43 | #include <errno.h> | |
44 | #include <fcntl.h> | 44 | #include <fcntl.h> | |
45 | #include <paths.h> | 45 | #include <paths.h> | |
46 | #include <stdbool.h> | 46 | #include <stdbool.h> | |
47 | #include <stddef.h> | 47 | #include <stddef.h> | |
48 | #include <stdio.h> | 48 | #include <stdio.h> | |
49 | #include <stdlib.h> | 49 | #include <stdlib.h> | |
50 | #include <string.h> | 50 | #include <string.h> | |
51 | #include <unistd.h> | 51 | #include <unistd.h> | |
52 | 52 | |||
53 | #include "nvmectl.h" | 53 | #include "nvmectl.h" | |
54 | 54 | |||
55 | typedef void (*nvme_fn_t)(int argc, char *argv[]); | 55 | static struct nvme_function funcs[] = { | |
56 | ||||
57 | static struct nvme_function { | |||
58 | const char *name; | |||
59 | nvme_fn_t fn; | |||
60 | const char *usage; | |||
61 | } funcs[] = { | |||
62 | {"devlist", devlist, DEVLIST_USAGE}, | 56 | {"devlist", devlist, DEVLIST_USAGE}, | |
63 | {"identify", identify, IDENTIFY_USAGE}, | 57 | {"identify", identify, IDENTIFY_USAGE}, | |
64 | #ifdef PERFTEST_USAGE | 58 | #ifdef PERFTEST_USAGE | |
65 | {"perftest", perftest, PERFTEST_USAGE}, | 59 | {"perftest", perftest, PERFTEST_USAGE}, | |
66 | #endif | 60 | #endif | |
67 | #ifdef RESET_USAGE | 61 | #ifdef RESET_USAGE | |
68 | {"reset", reset, RESET_USAGE}, | 62 | {"reset", reset, RESET_USAGE}, | |
69 | #endif | 63 | #endif | |
70 | {"logpage", logpage, LOGPAGE_USAGE}, | 64 | {"logpage", logpage, LOGPAGE_USAGE}, | |
71 | #ifdef FIRMWARE_USAGE | 65 | #ifdef FIRMWARE_USAGE | |
72 | {"firmware", firmware, FIRMWARE_USAGE}, | 66 | {"firmware", firmware, FIRMWARE_USAGE}, | |
73 | #endif | 67 | #endif | |
74 | {"power", power, POWER_USAGE}, | 68 | {"power", power, POWER_USAGE}, | |
69 | {"wdc", wdc, WDC_USAGE}, | |||
75 | {NULL, NULL, NULL}, | 70 | {NULL, NULL, NULL}, | |
76 | }; | 71 | }; | |
77 | 72 | |||
78 | __dead static void | 73 | void | |
79 | usage(void) | 74 | gen_usage(struct nvme_function *f) | |
80 | { | 75 | { | |
81 | struct nvme_function *f; | |||
82 | 76 | |||
83 | f = funcs; | |||
84 | fprintf(stderr, "usage:\n"); | 77 | fprintf(stderr, "usage:\n"); | |
85 | while (f->name != NULL) { | 78 | while (f->name != NULL) { | |
86 | fprintf(stderr, "%s", f->usage); | 79 | fprintf(stderr, "%s", f->usage); | |
87 | f++; | 80 | f++; | |
88 | } | 81 | } | |
89 | exit(1); | 82 | exit(1); | |
90 | } | 83 | } | |
91 | 84 | |||
85 | void | |||
86 | dispatch(int argc, char *argv[], struct nvme_function *tbl) | |||
87 | { | |||
88 | struct nvme_function *f = tbl; | |||
89 | ||||
90 | if (argv[1] == NULL) { | |||
91 | gen_usage(tbl); | |||
92 | return; | |||
93 | } | |||
94 | ||||
95 | while (f->name != NULL) { | |||
96 | if (strcmp(argv[1], f->name) == 0) | |||
97 | f->fn(argc-1, &argv[1]); | |||
98 | f++; | |||
99 | } | |||
100 | ||||
101 | fprintf(stderr, "Unknown command: %s\n", argv[1]); | |||
102 | gen_usage(tbl); | |||
103 | } | |||
104 | ||||
92 | static void | 105 | static void | |
93 | print_bytes(void *data, uint32_t length) | 106 | print_bytes(void *data, uint32_t length) | |
94 | { | 107 | { | |
95 | uint32_t i, j; | 108 | uint32_t i, j; | |
96 | uint8_t *p, *end; | 109 | uint8_t *p, *end; | |
97 | 110 | |||
98 | end = (uint8_t *)data + length; | 111 | end = (uint8_t *)data + length; | |
99 | 112 | |||
100 | for (i = 0; i < length; i++) { | 113 | for (i = 0; i < length; i++) { | |
101 | p = (uint8_t *)data + (i*16); | 114 | p = (uint8_t *)data + (i*16); | |
102 | printf("%03x: ", i*16); | 115 | printf("%03x: ", i*16); | |
103 | for (j = 0; j < 16 && p < end; j++) | 116 | for (j = 0; j < 16 && p < end; j++) | |
104 | printf("%02x ", *p++); | 117 | printf("%02x ", *p++); | |
@@ -259,29 +272,21 @@ nvme_strvis(u_char *dst, int dlen, const | @@ -259,29 +272,21 @@ nvme_strvis(u_char *dst, int dlen, const | |||
259 | if (--dlen < 1) | 272 | if (--dlen < 1) | |
260 | break; | 273 | break; | |
261 | *dst++ = *src; | 274 | *dst++ = *src; | |
262 | } | 275 | } | |
263 | ++src, --slen; | 276 | ++src, --slen; | |
264 | } | 277 | } | |
265 | 278 | |||
266 | *dst++ = 0; | 279 | *dst++ = 0; | |
267 | } | 280 | } | |
268 | 281 | |||
269 | int | 282 | int | |
270 | main(int argc, char *argv[]) | 283 | main(int argc, char *argv[]) | |
271 | { | 284 | { | |
272 | struct nvme_function *f; | |||
273 | 285 | |||
274 | if (argc < 2) | 286 | if (argc < 2) | |
275 | usage(); | 287 | gen_usage(funcs); | |
276 | ||||
277 | f = funcs; | |||
278 | while (f->name != NULL) { | |||
279 | if (strcmp(argv[1], f->name) == 0) | |||
280 | f->fn(argc-1, &argv[1]); | |||
281 | f++; | |||
282 | } | |||
283 | 288 | |||
284 | usage(); | 289 | dispatch(argc, argv, funcs); | |
285 | 290 | |||
286 | return (0); | 291 | return (0); | |
287 | } | 292 | } |
--- src/sbin/nvmectl/nvmectl.h 2016/06/04 20:59:49 1.2
+++ src/sbin/nvmectl/nvmectl.h 2017/04/29 00:06:40 1.3
@@ -1,94 +1,109 @@ | @@ -1,94 +1,109 @@ | |||
1 | /* $NetBSD: nvmectl.h,v 1.2 2016/06/04 20:59:49 joerg Exp $ */ | 1 | /* $NetBSD: nvmectl.h,v 1.3 2017/04/29 00:06:40 nonaka Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (C) 2012-2013 Intel Corporation | 4 | * Copyright (C) 2012-2013 Intel Corporation | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | * | 27 | * | |
28 | * $FreeBSD: head/sbin/nvmecontrol/nvmecontrol.h 295087 2016-01-30 22:48:06Z imp $ | 28 | * $FreeBSD: head/sbin/nvmecontrol/nvmecontrol.h 314230 2017-02-25 00:09:16Z imp $ | |
29 | */ | 29 | */ | |
30 | 30 | |||
31 | #ifndef __NVMECTL_H__ | 31 | #ifndef __NVMECTL_H__ | |
32 | #define __NVMECTL_H__ | 32 | #define __NVMECTL_H__ | |
33 | 33 | |||
34 | #include <sys/ioctl.h> | 34 | #include <sys/ioctl.h> | |
35 | 35 | |||
36 | #include <dev/ic/nvmeio.h> | 36 | #include <dev/ic/nvmeio.h> | |
37 | #include "nvme.h" | 37 | #include "nvme.h" | |
38 | 38 | |||
39 | typedef void (*nvme_fn_t)(int argc, char *argv[]); | |||
40 | ||||
41 | struct nvme_function { | |||
42 | const char *name; | |||
43 | nvme_fn_t fn; | |||
44 | const char *usage; | |||
45 | }; | |||
46 | ||||
39 | #define NVME_CTRLR_PREFIX "nvme" | 47 | #define NVME_CTRLR_PREFIX "nvme" | |
40 | #define NVME_NS_PREFIX "ns" | 48 | #define NVME_NS_PREFIX "ns" | |
41 | 49 | |||
42 | #define DEVLIST_USAGE \ | 50 | #define DEVLIST_USAGE \ | |
43 | " nvmectl devlist\n" | 51 | " nvmectl devlist\n" | |
44 | 52 | |||
45 | #define IDENTIFY_USAGE \ | 53 | #define IDENTIFY_USAGE \ | |
46 | " nvmectl identify [-x [-v]] <controller id|namespace id>\n" | 54 | " nvmectl identify [-x [-v]] <controller id|namespace id>\n" | |
47 | 55 | |||
48 | #if 0 | 56 | #if 0 | |
49 | #define PERFTEST_USAGE \ | 57 | #define PERFTEST_USAGE \ | |
50 | " nvmectl perftest <-n num_threads> <-o read|write>\n" \ | 58 | " nvmectl perftest <-n num_threads> <-o read|write>\n" \ | |
51 | " <-s size_in_bytes> <-t time_in_seconds>\n" \ | 59 | " <-s size_in_bytes> <-t time_in_seconds>\n" \ | |
52 | " <-i intr|wait> [-f refthread] [-p]\n" \ | 60 | " <-i intr|wait> [-f refthread] [-p]\n" \ | |
53 | " <namespace id>\n" | 61 | " <namespace id>\n" | |
54 | #endif | 62 | #endif | |
55 | 63 | |||
56 | #if 0 | 64 | #if 0 | |
57 | #define RESET_USAGE \ | 65 | #define RESET_USAGE \ | |
58 | " nvmectl reset <controller id>\n" | 66 | " nvmectl reset <controller id>\n" | |
59 | #endif | 67 | #endif | |
60 | 68 | |||
61 | #define LOGPAGE_USAGE \ | 69 | #define LOGPAGE_USAGE \ | |
62 | " nvmectl logpage <-p page_id> [-x] <controller id|namespace id>\n" \ | 70 | " nvmectl logpage <-p page_id> [-b] [-v vendor] [-x] " \ | |
71 | "<controller id|namespace id>\n" | |||
63 | 72 | |||
64 | #if 0 | 73 | #if 0 | |
65 | #define FIRMWARE_USAGE \ | 74 | #define FIRMWARE_USAGE \ | |
66 | " nvmectl firmware [-s slot] [-f path_to_firmware] [-a] <controller id>\n" | 75 | " nvmectl firmware [-s slot] [-f path_to_firmware] [-a] <controller id>\n" | |
67 | #endif | 76 | #endif | |
68 | 77 | |||
69 | #define POWER_USAGE \ | 78 | #define POWER_USAGE \ | |
70 | " nvmectl power [-l] [-p new-state [-w workload-hint]] <controller id>\n" | 79 | " nvmectl power [-l] [-p new-state [-w workload-hint]] <controller id>\n" | |
71 | 80 | |||
81 | #define WDC_USAGE \ | |||
82 | " nvmecontrol wdc (cap-diag|drive-log|get-crash-dump|purge|purge-montior)\n" | |||
83 | ||||
72 | void devlist(int, char *[]) __dead; | 84 | void devlist(int, char *[]) __dead; | |
73 | void identify(int, char *[]) __dead; | 85 | void identify(int, char *[]) __dead; | |
74 | #ifdef PERFTEST_USAGE | 86 | #ifdef PERFTEST_USAGE | |
75 | void perftest(int, char *[]); | 87 | void perftest(int, char *[]) __dead; | |
76 | #endif | 88 | #endif | |
77 | #ifdef RESET_USAGE | 89 | #ifdef RESET_USAGE | |
78 | void reset(int, char *[]); | 90 | void reset(int, char *[]) __dead; | |
79 | #endif | 91 | #endif | |
80 | void logpage(int, char *[]) __dead; | 92 | void logpage(int, char *[]) __dead; | |
81 | #ifdef FIRMWARE_USAGE | 93 | #ifdef FIRMWARE_USAGE | |
82 | void firmware(int, char *[]); | 94 | void firmware(int, char *[]) __dead; | |
83 | #endif | 95 | #endif | |
84 | void power(int, char *[]) __dead; | 96 | void power(int, char *[]) __dead; | |
97 | void wdc(int, char *[]) __dead; | |||
85 | 98 | |||
86 | int open_dev(const char *, int *, int, int); | 99 | int open_dev(const char *, int *, int, int); | |
87 | void parse_ns_str(const char *, char *, int *); | 100 | void parse_ns_str(const char *, char *, int *); | |
88 | void read_controller_data(int, struct nvm_identify_controller *); | 101 | void read_controller_data(int, struct nvm_identify_controller *); | |
89 | void read_namespace_data(int, int, struct nvm_identify_namespace *); | 102 | void read_namespace_data(int, int, struct nvm_identify_namespace *); | |
90 | void print_hex(void *, uint32_t); | 103 | void print_hex(void *, uint32_t); | |
91 | void read_logpage(int, uint8_t, int, void *, uint32_t); | 104 | void read_logpage(int, uint8_t, int, void *, uint32_t); | |
105 | void gen_usage(struct nvme_function *) __dead; | |||
106 | void dispatch(int argc, char *argv[], struct nvme_function *f); | |||
92 | void nvme_strvis(uint8_t *, int, const uint8_t *, int); | 107 | void nvme_strvis(uint8_t *, int, const uint8_t *, int); | |
93 | 108 | |||
94 | #endif /* __NVMECTL_H__ */ | 109 | #endif /* __NVMECTL_H__ */ |
--- src/sbin/nvmectl/firmware.c 2016/06/04 16:29:35 1.1
+++ src/sbin/nvmectl/firmware.c 2017/04/29 00:06:40 1.2
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: firmware.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */ | 1 | /* $NetBSD: firmware.c,v 1.2 2017/04/29 00:06:40 nonaka Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2013 EMC Corp. | 4 | * Copyright (c) 2013 EMC Corp. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Copyright (C) 2012-2013 Intel Corporation | 7 | * Copyright (C) 2012-2013 Intel Corporation | |
8 | * All rights reserved. | 8 | * All rights reserved. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -21,29 +21,29 @@ | @@ -21,29 +21,29 @@ | |||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | #ifndef lint | 33 | #ifndef lint | |
34 | __RCSID("$NetBSD: firmware.c,v 1.1 2016/06/04 16:29:35 nonaka Exp $"); | 34 | __RCSID("$NetBSD: firmware.c,v 1.2 2017/04/29 00:06:40 nonaka Exp $"); | |
35 | #if 0 | 35 | #if 0 | |
36 | __FBSDID("$FreeBSD: head/sbin/nvmecontrol/firmware.c 258071 2013-11-12 21:14:19Z jimharris $"); | 36 | __FBSDID("$FreeBSD: head/sbin/nvmecontrol/firmware.c 313188 2017-02-04 05:52:50Z imp $"); | |
37 | #endif | 37 | #endif | |
38 | #endif | 38 | #endif | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/ioccom.h> | 41 | #include <sys/ioccom.h> | |
42 | #include <sys/stat.h> | 42 | #include <sys/stat.h> | |
43 | #include <sys/types.h> | 43 | #include <sys/types.h> | |
44 | 44 | |||
45 | #include <ctype.h> | 45 | #include <ctype.h> | |
46 | #include <err.h> | 46 | #include <err.h> | |
47 | #include <fcntl.h> | 47 | #include <fcntl.h> | |
48 | #include <inttypes.h> | 48 | #include <inttypes.h> | |
49 | #include <stdbool.h> | 49 | #include <stdbool.h> | |
@@ -111,27 +111,27 @@ read_image_file(char *path, void **buf, | @@ -111,27 +111,27 @@ read_image_file(char *path, void **buf, | |||
111 | path, *size, filesize); | 111 | path, *size, filesize); | |
112 | } | 112 | } | |
113 | 113 | |||
114 | static void | 114 | static void | |
115 | update_firmware(int fd, uint8_t *payload, int32_t payload_size) | 115 | update_firmware(int fd, uint8_t *payload, int32_t payload_size) | |
116 | { | 116 | { | |
117 | struct nvme_pt_command pt; | 117 | struct nvme_pt_command pt; | |
118 | int32_t off, resid, size; | 118 | int32_t off, resid, size; | |
119 | void *chunk; | 119 | void *chunk; | |
120 | 120 | |||
121 | off = 0; | 121 | off = 0; | |
122 | resid = payload_size; | 122 | resid = payload_size; | |
123 | 123 | |||
124 | if ((chunk = malloc(NVME_MAX_XFER_SIZE)) == NULL) | 124 | if ((chunk = aligned_alloc(PAGE_SIZE, NVME_MAX_XFER_SIZE)) == NULL) | |
125 | errx(1, "unable to malloc %d bytes", NVME_MAX_XFER_SIZE); | 125 | errx(1, "unable to malloc %d bytes", NVME_MAX_XFER_SIZE); | |
126 | 126 | |||
127 | while (resid > 0) { | 127 | while (resid > 0) { | |
128 | size = (resid >= NVME_MAX_XFER_SIZE) ? | 128 | size = (resid >= NVME_MAX_XFER_SIZE) ? | |
129 | NVME_MAX_XFER_SIZE : resid; | 129 | NVME_MAX_XFER_SIZE : resid; | |
130 | memcpy(chunk, payload + off, size); | 130 | memcpy(chunk, payload + off, size); | |
131 | 131 | |||
132 | memset(&pt, 0, sizeof(pt)); | 132 | memset(&pt, 0, sizeof(pt)); | |
133 | pt.cmd.opcode = NVM_ADMIN_FW_DOWNLOAD; | 133 | pt.cmd.opcode = NVM_ADMIN_FW_DOWNLOAD; | |
134 | pt.cmd.cdw10 = (size / sizeof(uint32_t)) - 1; | 134 | pt.cmd.cdw10 = (size / sizeof(uint32_t)) - 1; | |
135 | pt.cmd.cdw11 = (off / sizeof(uint32_t)); | 135 | pt.cmd.cdw11 = (off / sizeof(uint32_t)); | |
136 | pt.buf = chunk; | 136 | pt.buf = chunk; | |
137 | pt.len = size; | 137 | pt.len = size; |
--- src/sbin/nvmectl/nvme.h 2016/06/04 16:29:35 1.1
+++ src/sbin/nvmectl/nvme.h 2017/04/29 00:06:40 1.2
@@ -1,47 +1,48 @@ | @@ -1,47 +1,48 @@ | |||
1 | /* $NetBSD: nvme.h,v 1.1 2016/06/04 16:29:35 nonaka Exp $ */ | 1 | /* $NetBSD: nvme.h,v 1.2 2017/04/29 00:06:40 nonaka Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (C) 2012-2013 Intel Corporation | 4 | * Copyright (C) 2012-2013 Intel Corporation | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * | 15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
26 | * SUCH DAMAGE. | 26 | * SUCH DAMAGE. | |
27 | * | 27 | * | |
28 | * $FreeBSD: head/sys/dev/nvme/nvme.h 296617 2016-03-10 17:13:10Z mav $ | 28 | * $FreeBSD: head/sys/dev/nvme/nvme.h 314888 2017-03-07 23:02:59Z imp $ | |
29 | */ | 29 | */ | |
30 | 30 | |||
31 | #ifndef __NVME_H__ | 31 | #ifndef __NVME_H__ | |
32 | #define __NVME_H__ | 32 | #define __NVME_H__ | |
33 | 33 | |||
34 | #define NVME_MAX_XFER_SIZE MAXPHYS | 34 | /* Cap nvme to 1MB transfers driver explodes with larger sizes */ | |
35 | #define NVME_MAX_XFER_SIZE (MAXPHYS < (1<<20) ? MAXPHYS : (1<<20)) | |||
35 | 36 | |||
36 | /* Get/Set Features */ | 37 | /* Get/Set Features */ | |
37 | #define NVME_FEAT_ARBITRATION 0x01 | 38 | #define NVME_FEAT_ARBITRATION 0x01 | |
38 | #define NVME_FEAT_POWER_MANAGEMENT 0x02 | 39 | #define NVME_FEAT_POWER_MANAGEMENT 0x02 | |
39 | #define NVME_FEAT_LBA_RANGE_TYPE 0x03 | 40 | #define NVME_FEAT_LBA_RANGE_TYPE 0x03 | |
40 | #define NVME_FEAT_TEMPERATURE_THRESHOLD 0x04 | 41 | #define NVME_FEAT_TEMPERATURE_THRESHOLD 0x04 | |
41 | #define NVME_FEAT_ERROR_RECOVERY 0x05 | 42 | #define NVME_FEAT_ERROR_RECOVERY 0x05 | |
42 | #define NVME_FEAT_VOLATILE_WRITE_CACHE 0x06 | 43 | #define NVME_FEAT_VOLATILE_WRITE_CACHE 0x06 | |
43 | #define NVME_FEAT_NUMBER_OF_QUEUES 0x07 | 44 | #define NVME_FEAT_NUMBER_OF_QUEUES 0x07 | |
44 | #define NVME_FEAT_INTERRUPT_COALESCING 0x08 | 45 | #define NVME_FEAT_INTERRUPT_COALESCING 0x08 | |
45 | #define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION 0x09 | 46 | #define NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION 0x09 | |
46 | #define NVME_FEAT_WRITE_ATOMICITY_NORMAL 0x0a | 47 | #define NVME_FEAT_WRITE_ATOMICITY_NORMAL 0x0a | |
47 | #define NVME_FEAT_ASYNC_EVENT_CONFIGURATION 0x0b | 48 | #define NVME_FEAT_ASYNC_EVENT_CONFIGURATION 0x0b | |
@@ -50,26 +51,39 @@ | @@ -50,26 +51,39 @@ | |||
50 | /* NVM Command Set specific */ | 51 | /* NVM Command Set specific */ | |
51 | #define NVME_FEAT_SOFTWARE_PROGRESS_MARKER 0x80 | 52 | #define NVME_FEAT_SOFTWARE_PROGRESS_MARKER 0x80 | |
52 | #define NVME_FEAT_HOST_IDENTIFIER 0x81 | 53 | #define NVME_FEAT_HOST_IDENTIFIER 0x81 | |
53 | #define NVME_FEAT_RESERVATION_NOTIFICATION_MASK 0x82 | 54 | #define NVME_FEAT_RESERVATION_NOTIFICATION_MASK 0x82 | |
54 | #define NVME_FEAT_RESERVATION_PERSISTANCE 0x83 | 55 | #define NVME_FEAT_RESERVATION_PERSISTANCE 0x83 | |
55 | 56 | |||
56 | /* Get Log Page */ | 57 | /* Get Log Page */ | |
57 | #define NVME_LOG_ERROR 0x01 | 58 | #define NVME_LOG_ERROR 0x01 | |
58 | #define NVME_LOG_HEALTH_INFORMATION 0x02 | 59 | #define NVME_LOG_HEALTH_INFORMATION 0x02 | |
59 | #define NVME_LOG_FIRMWARE_SLOT 0x03 | 60 | #define NVME_LOG_FIRMWARE_SLOT 0x03 | |
60 | #define NVME_LOG_CHANGED_NAMESPACE_LIST 0x04 | 61 | #define NVME_LOG_CHANGED_NAMESPACE_LIST 0x04 | |
61 | #define NVME_LOG_COMMAND_EFFECTS_LOG 0x05 | 62 | #define NVME_LOG_COMMAND_EFFECTS_LOG 0x05 | |
62 | #define NVME_LOG_RESERVATION_NOTIFICATION 0x80 | 63 | #define NVME_LOG_RESERVATION_NOTIFICATION 0x80 | |
64 | /* | |||
65 | * The following are Intel Specific log pages, but they seem | |||
66 | * to be widely implemented. | |||
67 | */ | |||
68 | #define INTEL_LOG_READ_LAT_LOG 0xc1 | |||
69 | #define INTEL_LOG_WRITE_LAT_LOG 0xc2 | |||
70 | #define INTEL_LOG_TEMP_STATS 0xc5 | |||
71 | #define INTEL_LOG_ADD_SMART 0xca | |||
72 | #define INTEL_LOG_DRIVE_MKT_NAME 0xdd | |||
73 | /* | |||
74 | * HGST log page, with lots ofs sub pages. | |||
75 | */ | |||
76 | #define HGST_INFO_LOG 0xc1 | |||
63 | 77 | |||
64 | /* Error Information Log (Log Identifier 01h) */ | 78 | /* Error Information Log (Log Identifier 01h) */ | |
65 | struct nvme_error_information_entry { | 79 | struct nvme_error_information_entry { | |
66 | uint64_t error_count; | 80 | uint64_t error_count; | |
67 | uint16_t sqid; | 81 | uint16_t sqid; | |
68 | uint16_t cid; | 82 | uint16_t cid; | |
69 | uint16_t status; | 83 | uint16_t status; | |
70 | uint16_t error_location; | 84 | uint16_t error_location; | |
71 | uint64_t lba; | 85 | uint64_t lba; | |
72 | uint32_t nsid; | 86 | uint32_t nsid; | |
73 | uint8_t vendor_specific; | 87 | uint8_t vendor_specific; | |
74 | uint8_t _reserved1[3]; | 88 | uint8_t _reserved1[3]; | |
75 | uint64_t command_specific; | 89 | uint64_t command_specific; | |
@@ -91,51 +105,63 @@ struct nvme_health_information_page { | @@ -91,51 +105,63 @@ struct nvme_health_information_page { | |||
91 | 105 | |||
92 | uint8_t _reserved1[26]; | 106 | uint8_t _reserved1[26]; | |
93 | 107 | |||
94 | uint64_t data_units_read[2]; | 108 | uint64_t data_units_read[2]; | |
95 | uint64_t data_units_written[2]; | 109 | uint64_t data_units_written[2]; | |
96 | uint64_t host_read_commands[2]; | 110 | uint64_t host_read_commands[2]; | |
97 | uint64_t host_write_commands[2]; | 111 | uint64_t host_write_commands[2]; | |
98 | uint64_t controller_busy_time[2]; | 112 | uint64_t controller_busy_time[2]; | |
99 | uint64_t power_cycles[2]; | 113 | uint64_t power_cycles[2]; | |
100 | uint64_t power_on_hours[2]; | 114 | uint64_t power_on_hours[2]; | |
101 | uint64_t unsafe_shutdowns[2]; | 115 | uint64_t unsafe_shutdowns[2]; | |
102 | uint64_t media_errors[2]; | 116 | uint64_t media_errors[2]; | |
103 | uint64_t num_error_info_log_entries[2]; | 117 | uint64_t num_error_info_log_entries[2]; | |
104 | uint32_t warning_composite_temperature_time; | 118 | uint32_t warning_temp_time; | |
105 | uint32_t critical_composite_temperature_time; | 119 | uint32_t error_temp_time; | |
106 | uint16_t temperature_sensor[8]; | 120 | uint16_t temp_sensor[8]; | |
107 | 121 | |||
108 | uint8_t reserved[296]; | 122 | uint8_t reserved[296]; | |
109 | } __packed __aligned(4); | 123 | } __packed __aligned(4); | |
110 | 124 | |||
111 | /* Firmware Commit */ | 125 | /* Firmware Commit */ | |
112 | #define NVME_COMMIT_ACTION_REPLACE_NO_ACTIVATE 0 | 126 | #define NVME_COMMIT_ACTION_REPLACE_NO_ACTIVATE 0 | |
113 | #define NVME_COMMIT_ACTION_REPLACE_ACTIVATE 1 | 127 | #define NVME_COMMIT_ACTION_REPLACE_ACTIVATE 1 | |
114 | #define NVME_COMMIT_ACTION_ACTIVATE_RESET 2 | 128 | #define NVME_COMMIT_ACTION_ACTIVATE_RESET 2 | |
115 | #define NVME_COMMIT_ACTION_ACTIVATE_NO_RESET 3 | 129 | #define NVME_COMMIT_ACTION_ACTIVATE_NO_RESET 3 | |
116 | 130 | |||
117 | /* Firmware Slot Information (Log Identifier 03h) */ | 131 | /* Firmware Slot Information (Log Identifier 03h) */ | |
118 | struct nvme_firmware_page { | 132 | struct nvme_firmware_page { | |
119 | uint8_t afi; | 133 | uint8_t afi; | |
120 | #define NVME_FW_PAGE_AFI_SLOT_RST __BITS(4, 6) | 134 | #define NVME_FW_PAGE_AFI_SLOT_RST __BITS(4, 6) | |
121 | #define NVME_FW_PAGE_AFI_SLOT __BITS(0, 2) | 135 | #define NVME_FW_PAGE_AFI_SLOT __BITS(0, 2) | |
122 | uint8_t _reserved1[7]; | 136 | uint8_t _reserved1[7]; | |
123 | 137 | |||
124 | uint64_t revision[7]; /* revisions for 7 slots */ | 138 | uint64_t revision[7]; /* revisions for 7 slots */ | |
125 | 139 | |||
126 | uint8_t reserved[448]; | 140 | uint8_t reserved[448]; | |
127 | } __packed __aligned(4); | 141 | } __packed __aligned(4); | |
128 | 142 | |||
143 | struct intel_log_temp_stats { | |||
144 | uint64_t current; | |||
145 | uint64_t overtemp_flag_last; | |||
146 | uint64_t overtemp_flag_life; | |||
147 | uint64_t max_temp; | |||
148 | uint64_t min_temp; | |||
149 | uint64_t _rsvd[5]; | |||
150 | uint64_t max_oper_temp; | |||
151 | uint64_t min_oper_temp; | |||
152 | uint64_t est_offset; | |||
153 | } __packed __aligned(4); | |||
154 | ||||
129 | /* Commands Supported and Effects (Log Identifier 05h) */ | 155 | /* Commands Supported and Effects (Log Identifier 05h) */ | |
130 | struct nvme_command_effeects_page { | 156 | struct nvme_command_effeects_page { | |
131 | uint32_t acs[256]; | 157 | uint32_t acs[256]; | |
132 | #define NVME_CE_PAGE_CS_CSE __BITS(16, 18) | 158 | #define NVME_CE_PAGE_CS_CSE __BITS(16, 18) | |
133 | #define NVME_CE_PAGE_CS_CCC __BIT(4) | 159 | #define NVME_CE_PAGE_CS_CCC __BIT(4) | |
134 | #define NVME_CE_PAGE_CS_NIC __BIT(3) | 160 | #define NVME_CE_PAGE_CS_NIC __BIT(3) | |
135 | #define NVME_CE_PAGE_CS_NCC __BIT(2) | 161 | #define NVME_CE_PAGE_CS_NCC __BIT(2) | |
136 | #define NVME_CE_PAGE_CS_LBCC __BIT(1) | 162 | #define NVME_CE_PAGE_CS_LBCC __BIT(1) | |
137 | #define NVME_CE_PAGE_CS_CSUPP __BIT(0) | 163 | #define NVME_CE_PAGE_CS_CSUPP __BIT(0) | |
138 | uint32_t iocs[256]; | 164 | uint32_t iocs[256]; | |
139 | 165 | |||
140 | uint8_t reserved[2048]; | 166 | uint8_t reserved[2048]; | |
141 | } __packed __aligned(4); | 167 | } __packed __aligned(4); |
--- src/sbin/nvmectl/logpage.c 2017/02/13 11:16:46 1.3
+++ src/sbin/nvmectl/logpage.c 2017/04/29 00:06:40 1.4
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: logpage.c,v 1.3 2017/02/13 11:16:46 nonaka Exp $ */ | 1 | /* $NetBSD: logpage.c,v 1.4 2017/04/29 00:06:40 nonaka Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2013 EMC Corp. | 4 | * Copyright (c) 2013 EMC Corp. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * Copyright (C) 2012-2013 Intel Corporation | 7 | * Copyright (C) 2012-2013 Intel Corporation | |
8 | * All rights reserved. | 8 | * All rights reserved. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
@@ -21,53 +21,87 @@ | @@ -21,53 +21,87 @@ | |||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | #ifndef lint | 33 | #ifndef lint | |
34 | __RCSID("$NetBSD: logpage.c,v 1.3 2017/02/13 11:16:46 nonaka Exp $"); | 34 | __RCSID("$NetBSD: logpage.c,v 1.4 2017/04/29 00:06:40 nonaka Exp $"); | |
35 | #if 0 | 35 | #if 0 | |
36 | __FBSDID("$FreeBSD: head/sbin/nvmecontrol/logpage.c 285796 2015-07-22 16:10:29Z jimharris $"); | 36 | __FBSDID("$FreeBSD: head/sbin/nvmecontrol/logpage.c 314230 2017-02-25 00:09:16Z imp $"); | |
37 | #endif | 37 | #endif | |
38 | #endif | 38 | #endif | |
39 | 39 | |||
40 | #include <sys/param.h> | 40 | #include <sys/param.h> | |
41 | #include <sys/ioccom.h> | 41 | #include <sys/ioccom.h> | |
42 | #include <sys/endian.h> | |||
42 | 43 | |||
43 | #include <ctype.h> | 44 | #include <ctype.h> | |
44 | #include <err.h> | 45 | #include <err.h> | |
45 | #include <fcntl.h> | 46 | #include <fcntl.h> | |
46 | #include <stdbool.h> | 47 | #include <stdbool.h> | |
47 | #include <stddef.h> | 48 | #include <stddef.h> | |
48 | #include <stdio.h> | 49 | #include <stdio.h> | |
49 | #include <stdlib.h> | 50 | #include <stdlib.h> | |
50 | #include <string.h> | 51 | #include <string.h> | |
51 | #include <unistd.h> | 52 | #include <unistd.h> | |
52 | 53 | |||
53 | #include "nvmectl.h" | 54 | #include "nvmectl.h" | |
54 | #include "bn.h" | 55 | #include "bn.h" | |
55 | 56 | |||
56 | #define DEFAULT_SIZE (4096) | 57 | #define DEFAULT_SIZE (4096) | |
57 | #define MAX_FW_SLOTS (7) | 58 | #define MAX_FW_SLOTS (7) | |
58 | 59 | |||
59 | typedef void (*print_fn_t)(void *buf, uint32_t size); | 60 | typedef void (*print_fn_t)(void *buf, uint32_t size); | |
60 | 61 | |||
62 | struct kv_name { | |||
63 | uint32_t key; | |||
64 | const char *name; | |||
65 | }; | |||
66 | ||||
67 | static const char * | |||
68 | kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key) | |||
69 | { | |||
70 | static char bad[32]; | |||
71 | size_t i; | |||
72 | ||||
73 | for (i = 0; i < kv_count; i++, kv++) | |||
74 | if (kv->key == key) | |||
75 | return kv->name; | |||
76 | snprintf(bad, sizeof(bad), "Attribute %#x", key); | |||
77 | return bad; | |||
78 | } | |||
79 | ||||
80 | static void | |||
81 | print_bin(void *data, uint32_t length) | |||
82 | { | |||
83 | write(STDOUT_FILENO, data, length); | |||
84 | } | |||
85 | ||||
86 | /* "Missing" from endian.h */ | |||
87 | static __inline uint64_t | |||
88 | le48dec(const void *pp) | |||
89 | { | |||
90 | uint8_t const *p = (uint8_t const *)pp; | |||
91 | ||||
92 | return (((uint64_t)le16dec(p + 4) << 32) | le32dec(p)); | |||
93 | } | |||
94 | ||||
61 | static void * | 95 | static void * | |
62 | get_log_buffer(uint32_t size) | 96 | get_log_buffer(uint32_t size) | |
63 | { | 97 | { | |
64 | void *buf; | 98 | void *buf; | |
65 | 99 | |||
66 | if ((buf = malloc(size)) == NULL) | 100 | if ((buf = malloc(size)) == NULL) | |
67 | errx(1, "unable to malloc %u bytes", size); | 101 | errx(1, "unable to malloc %u bytes", size); | |
68 | 102 | |||
69 | memset(buf, 0, size); | 103 | memset(buf, 0, size); | |
70 | return (buf); | 104 | return (buf); | |
71 | } | 105 | } | |
72 | 106 | |||
73 | void | 107 | void | |
@@ -168,82 +202,89 @@ print_bignum(const char *title, uint64_t | @@ -168,82 +202,89 @@ print_bignum(const char *title, uint64_t | |||
168 | buf[0] = '\0'; | 202 | buf[0] = '\0'; | |
169 | BIGNUM *bn = BN_bin2bn(tmp, __arraycount(tmp), NULL); | 203 | BIGNUM *bn = BN_bin2bn(tmp, __arraycount(tmp), NULL); | |
170 | if (bn != NULL) { | 204 | if (bn != NULL) { | |
171 | humanize_bignum(buf, METRIX_PREFIX_BUFSIZ + strlen(suffix), | 205 | humanize_bignum(buf, METRIX_PREFIX_BUFSIZ + strlen(suffix), | |
172 | bn, suffix, HN_AUTOSCALE, HN_DECIMAL); | 206 | bn, suffix, HN_AUTOSCALE, HN_DECIMAL); | |
173 | BN_free(bn); | 207 | BN_free(bn); | |
174 | } | 208 | } | |
175 | if (buf[0] == '\0') | 209 | if (buf[0] == '\0') | |
176 | snprintf(buf, sizeof(buf), "0x%016jx%016jx", h, l); | 210 | snprintf(buf, sizeof(buf), "0x%016jx%016jx", h, l); | |
177 | printf("%-31s %s\n", title, buf); | 211 | printf("%-31s %s\n", title, buf); | |
178 | } | 212 | } | |
179 | 213 | |||
180 | static void | 214 | static void | |
215 | print_temp(uint16_t t) | |||
216 | { | |||
217 | printf("%u K, %2.2f C, %3.2f F\n", t, (float)t - 273.15, | |||
218 | (float)t * 9 / 5 - 459.67); | |||
219 | } | |||
220 | ||||
221 | static void | |||
181 | print_log_health(void *buf, uint32_t size __unused) | 222 | print_log_health(void *buf, uint32_t size __unused) | |
182 | { | 223 | { | |
183 | struct nvme_health_information_page *health = buf; | 224 | struct nvme_health_information_page *health = buf; | |
184 | float composite_temperature = health->composite_temperature; | 225 | int i; | |
185 | 226 | |||
186 | printf("SMART/Health Information Log\n"); | 227 | printf("SMART/Health Information Log\n"); | |
187 | printf("============================\n"); | 228 | printf("============================\n"); | |
188 | 229 | |||
189 | printf("Critical Warning State: 0x%02x\n", | 230 | printf("Critical Warning State: 0x%02x\n", | |
190 | health->critical_warning); | 231 | health->critical_warning); | |
191 | printf(" Available spare: %d\n", | 232 | printf(" Available spare: %d\n", | |
192 | (uint8_t)__SHIFTOUT(health->critical_warning, | 233 | (uint8_t)__SHIFTOUT(health->critical_warning, | |
193 | NVME_HEALTH_PAGE_CW_AVAIL_SPARE)); | 234 | NVME_HEALTH_PAGE_CW_AVAIL_SPARE)); | |
194 | printf(" Temperature: %d\n", | 235 | printf(" Temperature: %d\n", | |
195 | (uint8_t)__SHIFTOUT(health->critical_warning, | 236 | (uint8_t)__SHIFTOUT(health->critical_warning, | |
196 | NVME_HEALTH_PAGE_CW_TEMPERTURE)); | 237 | NVME_HEALTH_PAGE_CW_TEMPERTURE)); | |
197 | printf(" Device reliability: %d\n", | 238 | printf(" Device reliability: %d\n", | |
198 | (uint8_t)__SHIFTOUT(health->critical_warning, | 239 | (uint8_t)__SHIFTOUT(health->critical_warning, | |
199 | NVME_HEALTH_PAGE_CW_DEVICE_RELIABLITY)); | 240 | NVME_HEALTH_PAGE_CW_DEVICE_RELIABLITY)); | |
200 | printf(" Read only: %d\n", | 241 | printf(" Read only: %d\n", | |
201 | (uint8_t)__SHIFTOUT(health->critical_warning, | 242 | (uint8_t)__SHIFTOUT(health->critical_warning, | |
202 | NVME_HEALTH_PAGE_CW_READ_ONLY)); | 243 | NVME_HEALTH_PAGE_CW_READ_ONLY)); | |
203 | printf(" Volatile memory backup: %d\n", | 244 | printf(" Volatile memory backup: %d\n", | |
204 | (uint8_t)__SHIFTOUT(health->critical_warning, | 245 | (uint8_t)__SHIFTOUT(health->critical_warning, | |
205 | NVME_HEALTH_PAGE_CW_VOLATILE_MEMORY_BACKUP)); | 246 | NVME_HEALTH_PAGE_CW_VOLATILE_MEMORY_BACKUP)); | |
206 | printf("Temperature: %u K, %2.2f C, %3.2f F\n", | 247 | printf("Temperature: "); | |
207 | health->composite_temperature, | 248 | print_temp(health->composite_temperature); | |
208 | composite_temperature - (float)273.15, | |||
209 | (composite_temperature * (float)9/5) - (float)459.67); | |||
210 | printf("Available spare: %u\n", | 249 | printf("Available spare: %u\n", | |
211 | health->available_spare); | 250 | health->available_spare); | |
212 | printf("Available spare threshold: %u\n", | 251 | printf("Available spare threshold: %u\n", | |
213 | health->available_spare_threshold); | 252 | health->available_spare_threshold); | |
214 | printf("Percentage used: %u\n", | 253 | printf("Percentage used: %u\n", | |
215 | health->percentage_used); | 254 | health->percentage_used); | |
216 | 255 | |||
217 | print_bignum("Data units (512 byte) read:", | 256 | print_bignum("Data units (512 byte) read:", health->data_units_read, ""); | |
218 | health->data_units_read, ""); | 257 | print_bignum("Data units (512 byte) written:", health->data_units_written, | |
219 | print_bignum("Data units (512 byte) written:", | 258 | ""); | |
220 | health->data_units_written, ""); | 259 | print_bignum("Host read commands:", health->host_read_commands, ""); | |
221 | print_bignum("Host read commands:", | 260 | print_bignum("Host write commands:", health->host_write_commands, ""); | |
222 | health->host_read_commands, ""); | 261 | print_bignum("Controller busy time (minutes):", health->controller_busy_time, | |
223 | print_bignum("Host write commands:", | 262 | ""); | |
224 | health->host_write_commands, ""); | 263 | print_bignum("Power cycles:", health->power_cycles, ""); | |
225 | print_bignum("Controller busy time (minutes):", | 264 | print_bignum("Power on hours:", health->power_on_hours, ""); | |
226 | health->controller_busy_time, ""); | 265 | print_bignum("Unsafe shutdowns:", health->unsafe_shutdowns, ""); | |
227 | print_bignum("Power cycles:", | 266 | print_bignum("Media errors:", health->media_errors, ""); | |
228 | health->power_cycles, ""); | |||
229 | print_bignum("Power on hours:", | |||
230 | health->power_on_hours, ""); | |||
231 | print_bignum("Unsafe shutdowns:", | |||
232 | health->unsafe_shutdowns, ""); | |||
233 | print_bignum("Media errors:", | |||
234 | health->media_errors, ""); | |||
235 | print_bignum("No. error info log entries:", | 267 | print_bignum("No. error info log entries:", | |
236 | health->num_error_info_log_entries, ""); | 268 | health->num_error_info_log_entries, ""); | |
269 | ||||
270 | printf("Warning Temp Composite Time: %d\n", health->warning_temp_time); | |||
271 | printf("Error Temp Composite Time: %d\n", health->error_temp_time); | |||
272 | for (i = 0; i < 7; i++) { | |||
273 | if (health->temp_sensor[i] == 0) | |||
274 | continue; | |||
275 | printf("Temperature Sensor %d: ", i + 1); | |||
276 | print_temp(health->temp_sensor[i]); | |||
277 | } | |||
237 | } | 278 | } | |
238 | 279 | |||
239 | static void | 280 | static void | |
240 | print_log_firmware(void *buf, uint32_t size __unused) | 281 | print_log_firmware(void *buf, uint32_t size __unused) | |
241 | { | 282 | { | |
242 | u_int i; | 283 | u_int i; | |
243 | const char *status; | 284 | const char *status; | |
244 | struct nvme_firmware_page *fw = buf; | 285 | struct nvme_firmware_page *fw = buf; | |
245 | 286 | |||
246 | printf("Firmware Slot Log\n"); | 287 | printf("Firmware Slot Log\n"); | |
247 | printf("=================\n"); | 288 | printf("=================\n"); | |
248 | 289 | |||
249 | for (i = 0; i < MAX_FW_SLOTS; i++) { | 290 | for (i = 0; i < MAX_FW_SLOTS; i++) { | |
@@ -255,83 +296,683 @@ print_log_firmware(void *buf, uint32_t s | @@ -255,83 +296,683 @@ print_log_firmware(void *buf, uint32_t s | |||
255 | 296 | |||
256 | if (fw->revision[i] == 0LLU) | 297 | if (fw->revision[i] == 0LLU) | |
257 | printf("Empty\n"); | 298 | printf("Empty\n"); | |
258 | else | 299 | else | |
259 | if (isprint(*(uint8_t *)&fw->revision[i])) | 300 | if (isprint(*(uint8_t *)&fw->revision[i])) | |
260 | printf("[%s] %.8s\n", status, | 301 | printf("[%s] %.8s\n", status, | |
261 | (char *)&fw->revision[i]); | 302 | (char *)&fw->revision[i]); | |
262 | else | 303 | else | |
263 | printf("[%s] %016jx\n", status, | 304 | printf("[%s] %016jx\n", status, | |
264 | fw->revision[i]); | 305 | fw->revision[i]); | |
265 | } | 306 | } | |
266 | } | 307 | } | |
267 | 308 | |||
309 | /* | |||
310 | * Intel specific log pages from | |||
311 | * http://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/ssd-dc-p3700-spec.pdf | |||
312 | * | |||
313 | * Though the version as of this date has a typo for the size of log page 0xca, | |||
314 | * offset 147: it is only 1 byte, not 6. | |||
315 | */ | |||
316 | static void | |||
317 | print_intel_temp_stats(void *buf, uint32_t size __unused) | |||
318 | { | |||
319 | struct intel_log_temp_stats *temp = buf; | |||
320 | ||||
321 | printf("Intel Temperature Log\n"); | |||
322 | printf("=====================\n"); | |||
323 | ||||
324 | printf("Current: "); | |||
325 | print_temp(temp->current); | |||
326 | printf("Overtemp Last Flags %#jx\n", | |||
327 | (uintmax_t)temp->overtemp_flag_last); | |||
328 | printf("Overtemp Lifetime Flags %#jx\n", | |||
329 | (uintmax_t)temp->overtemp_flag_life); | |||
330 | printf("Max Temperature "); | |||
331 | print_temp(temp->max_temp); | |||
332 | printf("Min Temperature "); | |||
333 | print_temp(temp->min_temp); | |||
334 | printf("Max Operating Temperature "); | |||
335 | print_temp(temp->max_oper_temp); | |||
336 | printf("Min Operating Temperature "); | |||
337 | print_temp(temp->min_oper_temp); | |||
338 | printf("Estimated Temperature Offset: %ju C/K\n", | |||
339 | (uintmax_t)temp->est_offset); | |||
340 | } | |||
341 | ||||
342 | /* | |||
343 | * Format from Table 22, section 5.7 IO Command Latency Statistics. | |||
344 | * Read and write stats pages have identical encoding. | |||
345 | */ | |||
346 | static void | |||
347 | print_intel_read_write_lat_log(void *buf, uint32_t size __unused) | |||
348 | { | |||
349 | const char *walker = buf; | |||
350 | int i; | |||
351 | ||||
352 | printf("Major: %d\n", le16dec(walker + 0)); | |||
353 | printf("Minor: %d\n", le16dec(walker + 2)); | |||
354 | for (i = 0; i < 32; i++) | |||
355 | printf("%4dus-%4dus: %ju\n", i * 32, (i + 1) * 32, | |||
356 | (uintmax_t)le32dec(walker + 4 + i * 4)); | |||
357 | for (i = 1; i < 32; i++) | |||
358 | printf("%4dms-%4dms: %ju\n", i, i + 1, | |||
359 | (uintmax_t)le32dec(walker + 132 + i * 4)); | |||
360 | for (i = 1; i < 32; i++) | |||
361 | printf("%4dms-%4dms: %ju\n", i * 32, (i + 1) * 32, | |||
362 | (uintmax_t)le32dec(walker + 256 + i * 4)); | |||
363 | } | |||
364 | ||||
365 | static void | |||
366 | print_intel_read_lat_log(void *buf, uint32_t size) | |||
367 | { | |||
368 | ||||
369 | printf("Intel Read Latency Log\n"); | |||
370 | printf("======================\n"); | |||
371 | print_intel_read_write_lat_log(buf, size); | |||
372 | } | |||
373 | ||||
374 | static void | |||
375 | print_intel_write_lat_log(void *buf, uint32_t size) | |||
376 | { | |||
377 | ||||
378 | printf("Intel Write Latency Log\n"); | |||
379 | printf("=======================\n"); | |||
380 | print_intel_read_write_lat_log(buf, size); | |||
381 | } | |||
382 | ||||
383 | /* | |||
384 | * Table 19. 5.4 SMART Attributes. | |||
385 | * Samsung also implements this and some extra data not documented. | |||
386 | */ | |||
387 | static void | |||
388 | print_intel_add_smart(void *buf, uint32_t size __unused) | |||
389 | { | |||
390 | uint8_t *walker = buf; | |||
391 | uint8_t *end = walker + 150; | |||
392 | const char *name; | |||
393 | uint64_t raw; | |||
394 | uint8_t normalized; | |||
395 | ||||
396 | static struct kv_name kv[] = { | |||
397 | { 0xab, "Program Fail Count" }, | |||
398 | { 0xac, "Erase Fail Count" }, | |||
399 | { 0xad, "Wear Leveling Count" }, | |||
400 | { 0xb8, "End to End Error Count" }, | |||
401 | { 0xc7, "CRC Error Count" }, | |||
402 | { 0xe2, "Timed: Media Wear" }, | |||
403 | { 0xe3, "Timed: Host Read %" }, | |||
404 | { 0xe4, "Timed: Elapsed Time" }, | |||
405 | { 0xea, "Thermal Throttle Status" }, | |||
406 | { 0xf0, "Retry Buffer Overflows" }, | |||
407 | { 0xf3, "PLL Lock Loss Count" }, | |||
408 | { 0xf4, "NAND Bytes Written" }, | |||
409 | { 0xf5, "Host Bytes Written" }, | |||
410 | }; | |||
411 | ||||
412 | printf("Additional SMART Data Log\n"); | |||
413 | printf("=========================\n"); | |||
414 | /* | |||
415 | * walker[0] = Key | |||
416 | * walker[1,2] = reserved | |||
417 | * walker[3] = Normalized Value | |||
418 | * walker[4] = reserved | |||
419 | * walker[5..10] = Little Endian Raw value | |||
420 | * (or other represenations) | |||
421 | * walker[11] = reserved | |||
422 | */ | |||
423 | while (walker < end) { | |||
424 | name = kv_lookup(kv, __arraycount(kv), *walker); | |||
425 | normalized = walker[3]; | |||
426 | raw = le48dec(walker + 5); | |||
427 | switch (*walker){ | |||
428 | case 0: | |||
429 | break; | |||
430 | case 0xad: | |||
431 | printf("%-32s: %3d min: %u max: %u ave: %u\n", name, | |||
432 | normalized, le16dec(walker + 5), le16dec(walker + 7), | |||
433 | le16dec(walker + 9)); | |||
434 | break; | |||
435 | case 0xe2: | |||
436 | printf("%-32s: %3d %.3f%%\n", name, normalized, raw / 1024.0); | |||
437 | break; | |||
438 | case 0xea: | |||
439 | printf("%-32s: %3d %d%% %d times\n", name, normalized, | |||
440 | walker[5], le32dec(walker+6)); | |||
441 | break; | |||
442 | default: | |||
443 | printf("%-32s: %3d %ju\n", name, normalized, (uintmax_t)raw); | |||
444 | break; | |||
445 | } | |||
446 | walker += 12; | |||
447 | } | |||
448 | } | |||
449 | ||||
450 | /* | |||
451 | * HGST's 0xc1 page. This is a grab bag of additional data. Please see | |||
452 | * https://www.hgst.com/sites/default/files/resources/US_SN150_ProdManual.pdf | |||
453 | * https://www.hgst.com/sites/default/files/resources/US_SN100_ProdManual.pdf | |||
454 | * Appendix A for details | |||
455 | */ | |||
456 | ||||
457 | typedef void (*subprint_fn_t)(void *buf, uint16_t subtype, uint8_t res, uint32_t size); | |||
458 | ||||
459 | struct subpage_print { | |||
460 | uint16_t key; | |||
461 | subprint_fn_t fn; | |||
462 | }; | |||
463 | ||||
464 | static void print_hgst_info_write_errors(void *, uint16_t, uint8_t, uint32_t); | |||
465 | static void print_hgst_info_read_errors(void *, uint16_t, uint8_t, uint32_t); | |||
466 | static void print_hgst_info_verify_errors(void *, uint16_t, uint8_t, uint32_t); | |||
467 | static void print_hgst_info_self_test(void *, uint16_t, uint8_t, uint32_t); | |||
468 | static void print_hgst_info_background_scan(void *, uint16_t, uint8_t, uint32_t); | |||
469 | static void print_hgst_info_erase_errors(void *, uint16_t, uint8_t, uint32_t); | |||
470 | static void print_hgst_info_erase_counts(void *, uint16_t, uint8_t, uint32_t); | |||
471 | static void print_hgst_info_temp_history(void *, uint16_t, uint8_t, uint32_t); | |||
472 | static void print_hgst_info_ssd_perf(void *, uint16_t, uint8_t, uint32_t); | |||
473 | static void print_hgst_info_firmware_load(void *, uint16_t, uint8_t, uint32_t); | |||
474 | ||||
475 | static struct subpage_print hgst_subpage[] = { | |||
476 | { 0x02, print_hgst_info_write_errors }, | |||
477 | { 0x03, print_hgst_info_read_errors }, | |||
478 | { 0x05, print_hgst_info_verify_errors }, | |||
479 | { 0x10, print_hgst_info_self_test }, | |||
480 | { 0x15, print_hgst_info_background_scan }, | |||
481 | { 0x30, print_hgst_info_erase_errors }, | |||
482 | { 0x31, print_hgst_info_erase_counts }, | |||
483 | { 0x32, print_hgst_info_temp_history }, | |||
484 | { 0x37, print_hgst_info_ssd_perf }, | |||
485 | { 0x38, print_hgst_info_firmware_load }, | |||
486 | }; | |||
487 | ||||
488 | /* Print a subpage that is basically just key value pairs */ | |||
489 | static void | |||
490 | print_hgst_info_subpage_gen(void *buf, uint16_t subtype __unused, uint32_t size, | |||
491 | const struct kv_name *kv, size_t kv_count) | |||
492 | { | |||
493 | uint8_t *wsp, *esp; | |||
494 | uint16_t ptype; | |||
495 | uint8_t plen; | |||
496 | uint64_t param; | |||
497 | int i; | |||
498 | ||||
499 | wsp = buf; | |||
500 | esp = wsp + size; | |||
501 | while (wsp < esp) { | |||
502 | ptype = le16dec(wsp); | |||
503 | wsp += 2; | |||
504 | wsp++; /* Flags, just ignore */ | |||
505 | plen = *wsp++; | |||
506 | param = 0; | |||
507 | for (i = 0; i < plen; i++) | |||
508 | param |= (uint64_t)*wsp++ << (i * 8); | |||
509 | printf(" %-30s: %jd\n", kv_lookup(kv, kv_count, ptype), | |||
510 | (uintmax_t)param); | |||
511 | } | |||
512 | } | |||
513 | ||||
514 | static void | |||
515 | print_hgst_info_write_errors(void *buf, uint16_t subtype, uint8_t res __unused, | |||
516 | uint32_t size) | |||
517 | { | |||
518 | static const struct kv_name kv[] = { | |||
519 | { 0x0000, "Corrected Without Delay" }, | |||
520 | { 0x0001, "Corrected Maybe Delayed" }, | |||
521 | { 0x0002, "Re-Writes" }, | |||
522 | { 0x0003, "Errors Corrected" }, | |||
523 | { 0x0004, "Correct Algorithm Used" }, | |||
524 | { 0x0005, "Bytes Processed" }, | |||
525 | { 0x0006, "Uncorrected Errors" }, | |||
526 | { 0x8000, "Flash Write Commands" }, | |||
527 | { 0x8001, "HGST Special" }, | |||
528 | }; | |||
529 | ||||
530 | printf("Write Errors Subpage:\n"); | |||
531 | print_hgst_info_subpage_gen(buf, subtype, size, kv, __arraycount(kv)); | |||
532 | } | |||
533 | ||||
534 | static void | |||
535 | print_hgst_info_read_errors(void *buf, uint16_t subtype, uint8_t res __unused, | |||
536 | uint32_t size) | |||
537 | { | |||
538 | static const struct kv_name kv[] = { | |||
539 | { 0x0000, "Corrected Without Delay" }, | |||
540 | { 0x0001, "Corrected Maybe Delayed" }, | |||
541 | { 0x0002, "Re-Reads" }, | |||
542 | { 0x0003, "Errors Corrected" }, | |||
543 | { 0x0004, "Correct Algorithm Used" }, | |||
544 | { 0x0005, "Bytes Processed" }, | |||
545 | { 0x0006, "Uncorrected Errors" }, | |||
546 | { 0x8000, "Flash Read Commands" }, | |||
547 | { 0x8001, "XOR Recovered" }, | |||
548 | { 0x8002, "Total Corrected Bits" }, | |||
549 | }; | |||
550 | ||||
551 | printf("Read Errors Subpage:\n"); | |||
552 | print_hgst_info_subpage_gen(buf, subtype, size, kv, __arraycount(kv)); | |||
553 | } | |||
554 | ||||
555 | static void | |||
556 | print_hgst_info_verify_errors(void *buf, uint16_t subtype, uint8_t res __unused, | |||
557 | uint32_t size) | |||
558 | { | |||
559 | static const struct kv_name kv[] = { | |||
560 | { 0x0000, "Corrected Without Delay" }, | |||
561 | { 0x0001, "Corrected Maybe Delayed" }, | |||
562 | { 0x0002, "Re-Reads" }, | |||
563 | { 0x0003, "Errors Corrected" }, | |||
564 | { 0x0004, "Correct Algorithm Used" }, | |||
565 | { 0x0005, "Bytes Processed" }, | |||
566 | { 0x0006, "Uncorrected Errors" }, | |||
567 | { 0x8000, "Commands Processed" }, | |||
568 | }; | |||
569 | ||||
570 | printf("Verify Errors Subpage:\n"); | |||
571 | print_hgst_info_subpage_gen(buf, subtype, size, kv, __arraycount(kv)); | |||
572 | } | |||
573 | ||||
574 | static void | |||
575 | print_hgst_info_self_test(void *buf, uint16_t subtype __unused, uint8_t res __unused, | |||
576 | uint32_t size) | |||
577 | { | |||
578 | size_t i; | |||
579 | uint8_t *walker = buf; | |||
580 | uint16_t code, hrs; | |||
581 | uint32_t lba; | |||
582 | ||||
583 | printf("Self Test Subpage:\n"); | |||
584 | for (i = 0; i < size / 20; i++) { /* Each entry is 20 bytes */ | |||
585 | code = le16dec(walker); | |||
586 | walker += 2; | |||
587 | walker++; /* Ignore fixed flags */ | |||
588 | if (*walker == 0) /* Last entry is zero length */ | |||
589 | break; | |||
590 | if (*walker++ != 0x10) { | |||
591 | printf("Bad length for self test report\n"); | |||
592 | return; | |||
593 | } | |||
594 | printf(" %-30s: %d\n", "Recent Test", code); | |||
595 | printf(" %-28s: %#x\n", "Self-Test Results", *walker & 0xf); | |||
596 | printf(" %-28s: %#x\n", "Self-Test Code", (*walker >> 5) & 0x7); | |||
597 | walker++; | |||
598 | printf(" %-28s: %#x\n", "Self-Test Number", *walker++); | |||
599 | hrs = le16dec(walker); | |||
600 | walker += 2; | |||
601 | lba = le32dec(walker); | |||
602 | walker += 4; | |||
603 | printf(" %-28s: %u\n", "Total Power On Hrs", hrs); | |||
604 | printf(" %-28s: %#jx (%jd)\n", "LBA", (uintmax_t)lba, | |||
605 | (uintmax_t)lba); | |||
606 | printf(" %-28s: %#x\n", "Sense Key", *walker++ & 0xf); | |||
607 | printf(" %-28s: %#x\n", "Additional Sense Code", *walker++); | |||
608 | printf(" %-28s: %#x\n", "Additional Sense Qualifier", *walker++); | |||
609 | printf(" %-28s: %#x\n", "Vendor Specific Detail", *walker++); | |||
610 | } | |||
611 | } | |||
612 | ||||
613 | static void | |||
614 | print_hgst_info_background_scan(void *buf, uint16_t subtype __unused, | |||
615 | uint8_t res __unused, uint32_t size) | |||
616 | { | |||
617 | uint8_t *walker = buf; | |||
618 | uint8_t status; | |||
619 | uint16_t code, nscan, progress; | |||
620 | uint32_t pom, nand; | |||
621 | ||||
622 | printf("Background Media Scan Subpage:\n"); | |||
623 | /* Decode the header */ | |||
624 | code = le16dec(walker); | |||
625 | walker += 2; | |||
626 | walker++; /* Ignore fixed flags */ | |||
627 | if (*walker++ != 0x10) { | |||
628 | printf("Bad length for background scan header\n"); | |||
629 | return; | |||
630 | } | |||
631 | if (code != 0) { | |||
632 | printf("Expceted code 0, found code %#x\n", code); | |||
633 | return; | |||
634 | } | |||
635 | pom = le32dec(walker); | |||
636 | walker += 4; | |||
637 | walker++; /* Reserved */ | |||
638 | status = *walker++; | |||
639 | nscan = le16dec(walker); | |||
640 | walker += 2; | |||
641 | progress = le16dec(walker); | |||
642 | walker += 2; | |||
643 | walker += 6; /* Reserved */ | |||
644 | printf(" %-30s: %d\n", "Power On Minutes", pom); | |||
645 | printf(" %-30s: %x (%s)\n", "BMS Status", status, | |||
646 | status == 0 ? "idle" : (status == 1 ? "active" : | |||
647 | (status == 8 ? "suspended" : "unknown"))); | |||
648 | printf(" %-30s: %d\n", "Number of BMS", nscan); | |||
649 | printf(" %-30s: %d\n", "Progress Current BMS", progress); | |||
650 | /* Report retirements */ | |||
651 | if (walker - (uint8_t *)buf != 20) { | |||
652 | printf("Coding error, offset not 20\n"); | |||
653 | return; | |||
654 | } | |||
655 | size -= 20; | |||
656 | printf(" %-30s: %d\n", "BMS retirements", size / 0x18); | |||
657 | while (size > 0) { | |||
658 | code = le16dec(walker); | |||
659 | walker += 2; | |||
660 | walker++; | |||
661 | if (*walker++ != 0x14) { | |||
662 | printf("Bad length parameter\n"); | |||
663 | return; | |||
664 | } | |||
665 | pom = le32dec(walker); | |||
666 | walker += 4; | |||
667 | /* | |||
668 | * Spec sheet says the following are hard coded, if true, just | |||
669 | * print the NAND retirement. | |||
670 | */ | |||
671 | if (walker[0] == 0x41 && | |||
672 | walker[1] == 0x0b && | |||
673 | walker[2] == 0x01 && | |||
674 | walker[3] == 0x00 && | |||
675 | walker[4] == 0x00 && | |||
676 | walker[5] == 0x00 && | |||
677 | walker[6] == 0x00 && | |||
678 | walker[7] == 0x00) { | |||
679 | walker += 8; | |||
680 | walker += 4; /* Skip reserved */ | |||
681 | nand = le32dec(walker); | |||
682 | walker += 4; | |||
683 | printf(" %-30s: %d\n", "Retirement number", code); | |||
684 | printf(" %-28s: %#x\n", "NAND (C/T)BBBPPP", nand); | |||
685 | } else { | |||
686 | printf("Parameter %#x entry corrupt\n", code); | |||
687 | walker += 16; | |||
688 | } | |||
689 | } | |||
690 | } | |||
691 | ||||
692 | static void | |||
693 | print_hgst_info_erase_errors(void *buf, uint16_t subtype __unused, | |||
694 | uint8_t res __unused, uint32_t size) | |||
695 | { | |||
696 | static const struct kv_name kv[] = { | |||
697 | { 0x0000, "Corrected Without Delay" }, | |||
698 | { 0x0001, "Corrected Maybe Delayed" }, | |||
699 | { 0x0002, "Re-Erase" }, | |||
700 | { 0x0003, "Errors Corrected" }, | |||
701 | { 0x0004, "Correct Algorithm Used" }, | |||
702 | { 0x0005, "Bytes Processed" }, | |||
703 | { 0x0006, "Uncorrected Errors" }, | |||
704 | { 0x8000, "Flash Erase Commands" }, | |||
705 | { 0x8001, "Mfg Defect Count" }, | |||
706 | { 0x8002, "Grown Defect Count" }, | |||
707 | { 0x8003, "Erase Count -- User" }, | |||
708 | { 0x8004, "Erase Count -- System" }, | |||
709 | }; | |||
710 | ||||
711 | printf("Erase Errors Subpage:\n"); | |||
712 | print_hgst_info_subpage_gen(buf, subtype, size, kv, __arraycount(kv)); | |||
713 | } | |||
714 | ||||
715 | static void | |||
716 | print_hgst_info_erase_counts(void *buf, uint16_t subtype, uint8_t res __unused, | |||
717 | uint32_t size) | |||
718 | { | |||
719 | /* My drive doesn't export this -- so not coding up */ | |||
720 | printf("XXX: Erase counts subpage: %p, %#x %d\n", buf, subtype, size); | |||
721 | } | |||
722 | ||||
723 | static void | |||
724 | print_hgst_info_temp_history(void *buf, uint16_t subtype __unused, | |||
725 | uint8_t res __unused, uint32_t size __unused) | |||
726 | { | |||
727 | uint8_t *walker = buf; | |||
728 | uint32_t min; | |||
729 | ||||
730 | printf("Temperature History:\n"); | |||
731 | printf(" %-30s: %d C\n", "Current Temperature", *walker++); | |||
732 | printf(" %-30s: %d C\n", "Reference Temperature", *walker++); | |||
733 | printf(" %-30s: %d C\n", "Maximum Temperature", *walker++); | |||
734 | printf(" %-30s: %d C\n", "Minimum Temperature", *walker++); | |||
735 | min = le32dec(walker); | |||
736 | walker += 4; | |||
737 | printf(" %-30s: %d:%02d:00\n", "Max Temperature Time", min / 60, min % 60); | |||
738 | min = le32dec(walker); | |||
739 | walker += 4; | |||
740 | printf(" %-30s: %d:%02d:00\n", "Over Temperature Duration", min / 60, | |||
741 | min % 60); | |||
742 | min = le32dec(walker); | |||
743 | walker += 4; | |||
744 | printf(" %-30s: %d:%02d:00\n", "Min Temperature Time", min / 60, min % 60); | |||
745 | } | |||
746 | ||||
747 | static void | |||
748 | print_hgst_info_ssd_perf(void *buf, uint16_t subtype __unused, uint8_t res, | |||
749 | uint32_t size __unused) | |||
750 | { | |||
751 | uint8_t *walker = buf; | |||
752 | uint64_t val; | |||
753 | ||||
754 | printf("SSD Performance Subpage Type %d:\n", res); | |||
755 | val = le64dec(walker); | |||
756 | walker += 8; | |||
757 | printf(" %-30s: %ju\n", "Host Read Commands", val); | |||
758 | val = le64dec(walker); | |||
759 | walker += 8; | |||
760 | printf(" %-30s: %ju\n", "Host Read Blocks", val); | |||
761 | val = le64dec(walker); | |||
762 | walker += 8; | |||
763 | printf(" %-30s: %ju\n", "Host Cache Read Hits Commands", val); | |||
764 | val = le64dec(walker); | |||
765 | walker += 8; | |||
766 | printf(" %-30s: %ju\n", "Host Cache Read Hits Blocks", val); | |||
767 | val = le64dec(walker); | |||
768 | walker += 8; | |||
769 | printf(" %-30s: %ju\n", "Host Read Commands Stalled", val); | |||
770 | val = le64dec(walker); | |||
771 | walker += 8; | |||
772 | printf(" %-30s: %ju\n", "Host Write Commands", val); | |||
773 | val = le64dec(walker); | |||
774 | walker += 8; | |||
775 | printf(" %-30s: %ju\n", "Host Write Blocks", val); | |||
776 | val = le64dec(walker); | |||
777 | walker += 8; | |||
778 | printf(" %-30s: %ju\n", "Host Write Odd Start Commands", val); | |||
779 | val = le64dec(walker); | |||
780 | walker += 8; | |||
781 | printf(" %-30s: %ju\n", "Host Write Odd End Commands", val); | |||
782 | val = le64dec(walker); | |||
783 | walker += 8; | |||
784 | printf(" %-30s: %ju\n", "Host Write Commands Stalled", val); | |||
785 | val = le64dec(walker); | |||
786 | walker += 8; | |||
787 | printf(" %-30s: %ju\n", "NAND Read Commands", val); | |||
788 | val = le64dec(walker); | |||
789 | walker += 8; | |||
790 | printf(" %-30s: %ju\n", "NAND Read Blocks", val); | |||
791 | val = le64dec(walker); | |||
792 | walker += 8; | |||
793 | printf(" %-30s: %ju\n", "NAND Write Commands", val); | |||
794 | val = le64dec(walker); | |||
795 | walker += 8; | |||
796 | printf(" %-30s: %ju\n", "NAND Write Blocks", val); | |||
797 | val = le64dec(walker); | |||
798 | walker += 8; | |||
799 | printf(" %-30s: %ju\n", "NAND Read Before Writes", val); | |||
800 | } | |||
801 | ||||
802 | static void | |||
803 | print_hgst_info_firmware_load(void *buf, uint16_t subtype __unused, | |||
804 | uint8_t res __unused, uint32_t size __unused) | |||
805 | { | |||
806 | uint8_t *walker = buf; | |||
807 | ||||
808 | printf("Firmware Load Subpage:\n"); | |||
809 | printf(" %-30s: %d\n", "Firmware Downloads", le32dec(walker)); | |||
810 | } | |||
811 | ||||
812 | static void | |||
813 | kv_indirect(void *buf, uint32_t subtype, uint8_t res, uint32_t size, | |||
814 | struct subpage_print *sp, size_t nsp) | |||
815 | { | |||
816 | size_t i; | |||
817 | ||||
818 | for (i = 0; i < nsp; i++, sp++) { | |||
819 | if (sp->key == subtype) { | |||
820 | sp->fn(buf, subtype, res, size); | |||
821 | return; | |||
822 | } | |||
823 | } | |||
824 | printf("No handler for page type %x\n", subtype); | |||
825 | } | |||
826 | ||||
827 | static void | |||
828 | print_hgst_info_log(void *buf, uint32_t size __unused) | |||
829 | { | |||
830 | uint8_t *walker, *end, *subpage; | |||
831 | int pages __unused; | |||
832 | uint16_t len; | |||
833 | uint8_t subtype, res; | |||
834 | ||||
835 | printf("HGST Extra Info Log\n"); | |||
836 | printf("===================\n"); | |||
837 | ||||
838 | walker = buf; | |||
839 | pages = *walker++; | |||
840 | walker++; | |||
841 | len = le16dec(walker); | |||
842 | walker += 2; | |||
843 | end = walker + len; /* Length is exclusive of this header */ | |||
844 | ||||
845 | while (walker < end) { | |||
846 | subpage = walker + 4; | |||
847 | subtype = *walker++ & 0x3f; /* subtype */ | |||
848 | res = *walker++; /* Reserved */ | |||
849 | len = le16dec(walker); | |||
850 | walker += len + 2; /* Length, not incl header */ | |||
851 | if (walker > end) { | |||
852 | printf("Ooops! Off the end of the list\n"); | |||
853 | break; | |||
854 | } | |||
855 | kv_indirect(subpage, subtype, res, len, hgst_subpage, | |||
856 | __arraycount(hgst_subpage)); | |||
857 | } | |||
858 | } | |||
859 | ||||
860 | /* | |||
861 | * Table of log page printer / sizing. | |||
862 | * | |||
863 | * This includes Intel specific pages that are widely implemented. | |||
864 | * Make sure you keep all the pages of one vendor together so -v help | |||
865 | * lists all the vendors pages. | |||
866 | */ | |||
268 | static struct logpage_function { | 867 | static struct logpage_function { | |
269 | uint8_t log_page; | 868 | uint8_t log_page; | |
270 | print_fn_t fn; | 869 | const char *vendor; | |
870 | const char *name; | |||
871 | print_fn_t print_fn; | |||
872 | size_t size; | |||
271 | } logfuncs[] = { | 873 | } logfuncs[] = { | |
272 | {NVME_LOG_ERROR, print_log_error }, | 874 | {NVME_LOG_ERROR, NULL, "Drive Error Log", | |
273 | {NVME_LOG_HEALTH_INFORMATION, print_log_health }, | 875 | print_log_error, 0}, | |
274 | {NVME_LOG_FIRMWARE_SLOT, print_log_firmware }, | 876 | {NVME_LOG_HEALTH_INFORMATION, NULL, "Health/SMART Data", | |
275 | {0, NULL }, | 877 | print_log_health, sizeof(struct nvme_health_information_page)}, | |
878 | {NVME_LOG_FIRMWARE_SLOT, NULL, "Firmware Information", | |||
879 | print_log_firmware, sizeof(struct nvme_firmware_page)}, | |||
880 | {HGST_INFO_LOG, "hgst", "Detailed Health/SMART", | |||
881 | print_hgst_info_log, DEFAULT_SIZE}, | |||
882 | {HGST_INFO_LOG, "wds", "Detailed Health/SMART", | |||
883 | print_hgst_info_log, DEFAULT_SIZE}, | |||
884 | {INTEL_LOG_TEMP_STATS, "intel", "Temperature Stats", | |||
885 | print_intel_temp_stats, sizeof(struct intel_log_temp_stats)}, | |||
886 | {INTEL_LOG_READ_LAT_LOG, "intel", "Read Latencies", | |||
887 | print_intel_read_lat_log, DEFAULT_SIZE}, | |||
888 | {INTEL_LOG_WRITE_LAT_LOG, "intel", "Write Latencies", | |||
889 | print_intel_write_lat_log, DEFAULT_SIZE}, | |||
890 | {INTEL_LOG_ADD_SMART, "intel", "Extra Health/SMART Data", | |||
891 | print_intel_add_smart, DEFAULT_SIZE}, | |||
892 | {INTEL_LOG_ADD_SMART, "samsung", "Extra Health/SMART Data", | |||
893 | print_intel_add_smart, DEFAULT_SIZE}, | |||
894 | ||||
895 | {0, NULL, NULL, NULL, 0}, | |||
276 | }; | 896 | }; | |
277 | 897 | |||
278 | __dead static void | 898 | __dead static void | |
279 | logpage_usage(void) | 899 | logpage_usage(void) | |
280 | { | 900 | { | |
281 | fprintf(stderr, "usage:\n"); | 901 | fprintf(stderr, "usage:\n"); | |
282 | fprintf(stderr, LOGPAGE_USAGE); | 902 | fprintf(stderr, LOGPAGE_USAGE); | |
283 | exit(1); | 903 | exit(1); | |
284 | } | 904 | } | |
285 | 905 | |||
906 | __dead static void | |||
907 | logpage_help(void) | |||
908 | { | |||
909 | struct logpage_function *f; | |||
910 | const char *v; | |||
911 | ||||
912 | fprintf(stderr, "\n"); | |||
913 | fprintf(stderr, "%-8s %-10s %s\n", "Page", "Vendor","Page Name"); | |||
914 | fprintf(stderr, "-------- ---------- ----------\n"); | |||
915 | for (f = logfuncs; f->log_page > 0; f++) { | |||
916 | v = f->vendor == NULL ? "-" : f->vendor; | |||
917 | fprintf(stderr, "0x%02x %-10s %s\n", f->log_page, v, f->name); | |||
918 | } | |||
919 | ||||
920 | exit(1); | |||
921 | } | |||
922 | ||||
286 | void | 923 | void | |
287 | logpage(int argc, char *argv[]) | 924 | logpage(int argc, char *argv[]) | |
288 | { | 925 | { | |
289 | int fd, nsid; | 926 | int fd, nsid; | |
290 | int log_page = 0, pageflag = false; | 927 | int log_page = 0, pageflag = false; | |
291 | int hexflag = false, ns_specified; | 928 | int binflag = false, hexflag = false, ns_specified; | |
292 | int ch; | 929 | int ch; | |
293 | char *p; | 930 | char *p; | |
294 | char cname[64]; | 931 | char cname[64]; | |
295 | uint32_t size; | 932 | uint32_t size; | |
296 | void *buf; | 933 | void *buf; | |
934 | const char *vendor = NULL; | |||
297 | struct logpage_function *f; | 935 | struct logpage_function *f; | |
298 | struct nvm_identify_controller cdata; | 936 | struct nvm_identify_controller cdata; | |
299 | print_fn_t print_fn; | 937 | print_fn_t print_fn; | |
300 | 938 | |||
301 | while ((ch = getopt(argc, argv, "p:x")) != -1) { | 939 | while ((ch = getopt(argc, argv, "bp:xv:")) != -1) { | |
302 | switch (ch) { | 940 | switch (ch) { | |
941 | case 'b': | |||
942 | binflag = true; | |||
943 | break; | |||
303 | case 'p': | 944 | case 'p': | |
945 | if (strcmp(optarg, "help") == 0) | |||
946 | logpage_help(); | |||
947 | ||||
304 | /* TODO: Add human-readable ASCII page IDs */ | 948 | /* TODO: Add human-readable ASCII page IDs */ | |
305 | log_page = strtol(optarg, &p, 0); | 949 | log_page = strtol(optarg, &p, 0); | |
306 | if (p != NULL && *p != '\0') { | 950 | if (p != NULL && *p != '\0') { | |
307 | fprintf(stderr, | 951 | fprintf(stderr, | |
308 | "\"%s\" not valid log page id.\n", | 952 | "\"%s\" not valid log page id.\n", | |
309 | optarg); | 953 | optarg); | |
310 | logpage_usage(); | 954 | logpage_usage(); | |
311 | /* TODO: Define valid log page id ranges in nvme.h? */ | |||
312 | } else if (log_page == 0 || | |||
313 | (log_page >= 0x04 && log_page <= 0x7F) || | |||
314 | (log_page >= 0x80 && log_page <= 0xBF)) { | |||
315 | fprintf(stderr, | |||
316 | "\"%s\" not valid log page id.\n", | |||
317 | optarg); | |||
318 | logpage_usage(); | |||
319 | } | 955 | } | |
320 | pageflag = true; | 956 | pageflag = true; | |
321 | break; | 957 | break; | |
322 | case 'x': | 958 | case 'x': | |
323 | hexflag = true; | 959 | hexflag = true; | |
324 | break; | 960 | break; | |
961 | case 'v': | |||
962 | if (strcmp(optarg, "help") == 0) | |||
963 | logpage_help(); | |||
964 | vendor = optarg; | |||
965 | break; | |||
325 | } | 966 | } | |
326 | } | 967 | } | |
327 | 968 | |||
328 | if (!pageflag) { | 969 | if (!pageflag) { | |
329 | printf("Missing page_id (-p).\n"); | 970 | printf("Missing page_id (-p).\n"); | |
330 | logpage_usage(); | 971 | logpage_usage(); | |
331 | } | 972 | } | |
332 | 973 | |||
333 | /* Check that a controller and/or namespace was specified. */ | 974 | /* Check that a controller and/or namespace was specified. */ | |
334 | if (optind >= argc) | 975 | if (optind >= argc) | |
335 | logpage_usage(); | 976 | logpage_usage(); | |
336 | 977 | |||
337 | if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) { | 978 | if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) { | |
@@ -352,53 +993,49 @@ logpage(int argc, char *argv[]) | @@ -352,53 +993,49 @@ logpage(int argc, char *argv[]) | |||
352 | * namespace basis. | 993 | * namespace basis. | |
353 | */ | 994 | */ | |
354 | if (ns_specified) { | 995 | if (ns_specified) { | |
355 | if (log_page != NVME_LOG_HEALTH_INFORMATION) | 996 | if (log_page != NVME_LOG_HEALTH_INFORMATION) | |
356 | errx(1, "log page %d valid only at controller level", | 997 | errx(1, "log page %d valid only at controller level", | |
357 | log_page); | 998 | log_page); | |
358 | if (!(cdata.lpa & NVME_ID_CTRLR_LPA_NS_SMART)) | 999 | if (!(cdata.lpa & NVME_ID_CTRLR_LPA_NS_SMART)) | |
359 | errx(1, | 1000 | errx(1, | |
360 | "controller does not support per namespace " | 1001 | "controller does not support per namespace " | |
361 | "smart/health information"); | 1002 | "smart/health information"); | |
362 | } | 1003 | } | |
363 | 1004 | |||
364 | print_fn = print_hex; | 1005 | print_fn = print_hex; | |
365 | if (!hexflag) { | 1006 | size = DEFAULT_SIZE; | |
1007 | if (binflag) | |||
1008 | print_fn = print_bin; | |||
1009 | if (!binflag && !hexflag) { | |||
366 | /* | 1010 | /* | |
367 | * See if there is a pretty print function for the | 1011 | * See if there is a pretty print function for the specified log | |
368 | * specified log page. If one isn't found, we | 1012 | * page. If one isn't found, we just revert to the default | |
369 | * just revert to the default (print_hex). | 1013 | * (print_hex). If there was a vendor specified bt the user, and | |
1014 | * the page is vendor specific, don't match the print function | |||
1015 | * unless the vendors match. | |||
370 | */ | 1016 | */ | |
371 | f = logfuncs; | 1017 | for (f = logfuncs; f->log_page > 0; f++) { | |
372 | while (f->log_page > 0) { | 1018 | if (f->vendor != NULL && vendor != NULL && | |
373 | if (log_page == f->log_page) { | 1019 | strcmp(f->vendor, vendor) != 0) | |
374 | print_fn = f->fn; | 1020 | continue; | |
375 | break; | 1021 | if (log_page != f->log_page) | |
376 | } | 1022 | continue; | |
377 | f++; | 1023 | print_fn = f->print_fn; | |
1024 | size = f->size; | |||
1025 | break; | |||
378 | } | 1026 | } | |
379 | } | 1027 | } | |
380 | 1028 | |||
381 | /* Read the log page */ | 1029 | if (log_page == NVME_LOG_ERROR) { | |
382 | switch (log_page) { | |||
383 | case NVME_LOG_ERROR: | |||
384 | size = sizeof(struct nvme_error_information_entry); | 1030 | size = sizeof(struct nvme_error_information_entry); | |
385 | size *= (cdata.elpe + 1); | 1031 | size *= (cdata.elpe + 1); | |
386 | break; | |||
387 | case NVME_LOG_HEALTH_INFORMATION: | |||
388 | size = sizeof(struct nvme_health_information_page); | |||
389 | break; | |||
390 | case NVME_LOG_FIRMWARE_SLOT: | |||
391 | size = sizeof(struct nvme_firmware_page); | |||
392 | break; | |||
393 | default: | |||
394 | size = DEFAULT_SIZE; | |||
395 | break; | |||
396 | } | 1032 | } | |
397 | 1033 | |||
1034 | /* Read the log page */ | |||
398 | buf = get_log_buffer(size); | 1035 | buf = get_log_buffer(size); | |
399 | read_logpage(fd, log_page, nsid, buf, size); | 1036 | read_logpage(fd, log_page, nsid, buf, size); | |
400 | print_fn(buf, size); | 1037 | print_fn(buf, size); | |
401 | 1038 | |||
402 | close(fd); | 1039 | close(fd); | |
403 | exit(0); | 1040 | exit(0); | |
404 | } | 1041 | } |