nvme.h revision 248747
1240616Sjimharris/*-
2240616Sjimharris * Copyright (C) 2012 Intel Corporation
3240616Sjimharris * All rights reserved.
4240616Sjimharris *
5240616Sjimharris * Redistribution and use in source and binary forms, with or without
6240616Sjimharris * modification, are permitted provided that the following conditions
7240616Sjimharris * are met:
8240616Sjimharris * 1. Redistributions of source code must retain the above copyright
9240616Sjimharris *    notice, this list of conditions and the following disclaimer.
10240616Sjimharris * 2. Redistributions in binary form must reproduce the above copyright
11240616Sjimharris *    notice, this list of conditions and the following disclaimer in the
12240616Sjimharris *    documentation and/or other materials provided with the distribution.
13240616Sjimharris *
14240616Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15240616Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16240616Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17240616Sjimharris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18240616Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19240616Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20240616Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21240616Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22240616Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23240616Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24240616Sjimharris * SUCH DAMAGE.
25240616Sjimharris *
26240616Sjimharris * $FreeBSD: head/sys/dev/nvme/nvme.h 248747 2013-03-26 19:52:57Z jimharris $
27240616Sjimharris */
28240616Sjimharris
29240616Sjimharris#ifndef __NVME_H__
30240616Sjimharris#define __NVME_H__
31240616Sjimharris
32240616Sjimharris#ifdef _KERNEL
33240616Sjimharris#include <sys/types.h>
34240616Sjimharris#endif
35240616Sjimharris
36240616Sjimharris#define	NVME_IDENTIFY_CONTROLLER	_IOR('n', 0, struct nvme_controller_data)
37240616Sjimharris#define	NVME_IDENTIFY_NAMESPACE		_IOR('n', 1, struct nvme_namespace_data)
38240616Sjimharris#define	NVME_IO_TEST			_IOWR('n', 2, struct nvme_io_test)
39240616Sjimharris#define	NVME_BIO_TEST			_IOWR('n', 4, struct nvme_io_test)
40248746Sjimharris#define	NVME_RESET_CONTROLLER		_IO('n', 5)
41240616Sjimharris
42240616Sjimharris/*
43240616Sjimharris * Use to mark a command to apply to all namespaces, or to retrieve global
44240616Sjimharris *  log pages.
45240616Sjimharris */
46240616Sjimharris#define NVME_GLOBAL_NAMESPACE_TAG	((uint32_t)0xFFFFFFFF)
47240616Sjimharris
48240616Sjimharrisunion cap_lo_register {
49240616Sjimharris	uint32_t	raw;
50240616Sjimharris	struct {
51240616Sjimharris		/** maximum queue entries supported */
52240616Sjimharris		uint32_t mqes		: 16;
53240616Sjimharris
54240616Sjimharris		/** contiguous queues required */
55240616Sjimharris		uint32_t cqr		: 1;
56240616Sjimharris
57240616Sjimharris		/** arbitration mechanism supported */
58240616Sjimharris		uint32_t ams		: 2;
59240616Sjimharris
60240616Sjimharris		uint32_t reserved1	: 5;
61240616Sjimharris
62240616Sjimharris		/** timeout */
63240616Sjimharris		uint32_t to		: 8;
64240616Sjimharris	} bits __packed;
65240616Sjimharris} __packed;
66240616Sjimharris
67240616Sjimharrisunion cap_hi_register {
68240616Sjimharris	uint32_t	raw;
69240616Sjimharris	struct {
70240616Sjimharris		/** doorbell stride */
71240616Sjimharris		uint32_t dstrd		: 4;
72240616Sjimharris
73240616Sjimharris		uint32_t reserved3	: 1;
74240616Sjimharris
75240616Sjimharris		/** command sets supported */
76240616Sjimharris		uint32_t css_nvm	: 1;
77240616Sjimharris
78240616Sjimharris		uint32_t css_reserved	: 3;
79240616Sjimharris		uint32_t reserved2	: 7;
80240616Sjimharris
81240616Sjimharris		/** memory page size minimum */
82240616Sjimharris		uint32_t mpsmin		: 4;
83240616Sjimharris
84240616Sjimharris		/** memory page size maximum */
85240616Sjimharris		uint32_t mpsmax		: 4;
86240616Sjimharris
87240616Sjimharris		uint32_t reserved1	: 8;
88240616Sjimharris	} bits __packed;
89240616Sjimharris} __packed;
90240616Sjimharris
91240616Sjimharrisunion cc_register {
92240616Sjimharris	uint32_t	raw;
93240616Sjimharris	struct {
94240616Sjimharris		/** enable */
95240616Sjimharris		uint32_t en		: 1;
96240616Sjimharris
97240616Sjimharris		uint32_t reserved1	: 3;
98240616Sjimharris
99240616Sjimharris		/** i/o command set selected */
100240616Sjimharris		uint32_t css		: 3;
101240616Sjimharris
102240616Sjimharris		/** memory page size */
103240616Sjimharris		uint32_t mps		: 4;
104240616Sjimharris
105240616Sjimharris		/** arbitration mechanism selected */
106240616Sjimharris		uint32_t ams		: 3;
107240616Sjimharris
108240616Sjimharris		/** shutdown notification */
109240616Sjimharris		uint32_t shn		: 2;
110240616Sjimharris
111240616Sjimharris		/** i/o submission queue entry size */
112240616Sjimharris		uint32_t iosqes		: 4;
113240616Sjimharris
114240616Sjimharris		/** i/o completion queue entry size */
115240616Sjimharris		uint32_t iocqes		: 4;
116240616Sjimharris
117240616Sjimharris		uint32_t reserved2	: 8;
118240616Sjimharris	} bits __packed;
119240616Sjimharris} __packed;
120240616Sjimharris
121240616Sjimharrisenum shn_value {
122240616Sjimharris	NVME_SHN_NORMAL		= 0x1,
123240616Sjimharris	NVME_SHN_ABRUPT		= 0x2,
124240616Sjimharris};
125240616Sjimharris
126240616Sjimharrisunion csts_register {
127240616Sjimharris	uint32_t	raw;
128240616Sjimharris	struct {
129240616Sjimharris		/** ready */
130240616Sjimharris		uint32_t rdy		: 1;
131240616Sjimharris
132240616Sjimharris		/** controller fatal status */
133240616Sjimharris		uint32_t cfs		: 1;
134240616Sjimharris
135240616Sjimharris		/** shutdown status */
136240616Sjimharris		uint32_t shst		: 2;
137240616Sjimharris
138240616Sjimharris		uint32_t reserved1	: 28;
139240616Sjimharris	} bits __packed;
140240616Sjimharris} __packed;
141240616Sjimharris
142240616Sjimharrisenum shst_value {
143240616Sjimharris	NVME_SHST_NORMAL	= 0x0,
144240616Sjimharris	NVME_SHST_OCCURRING	= 0x1,
145240616Sjimharris	NVME_SHST_COMPLETE	= 0x2,
146240616Sjimharris};
147240616Sjimharris
148240616Sjimharrisunion aqa_register {
149240616Sjimharris	uint32_t	raw;
150240616Sjimharris	struct {
151240616Sjimharris		/** admin submission queue size */
152240616Sjimharris		uint32_t asqs		: 12;
153240616Sjimharris
154240616Sjimharris		uint32_t reserved1	: 4;
155240616Sjimharris
156240616Sjimharris		/** admin completion queue size */
157240616Sjimharris		uint32_t acqs		: 12;
158240616Sjimharris
159240616Sjimharris		uint32_t reserved2	: 4;
160240616Sjimharris	} bits __packed;
161240616Sjimharris} __packed;
162240616Sjimharris
163240616Sjimharrisstruct nvme_registers
164240616Sjimharris{
165240616Sjimharris	/** controller capabilities */
166240616Sjimharris	union cap_lo_register	cap_lo;
167240616Sjimharris	union cap_hi_register	cap_hi;
168240616Sjimharris
169240616Sjimharris	uint32_t	vs;		/* version */
170240616Sjimharris	uint32_t	intms;		/* interrupt mask set */
171240616Sjimharris	uint32_t	intmc;		/* interrupt mask clear */
172240616Sjimharris
173240616Sjimharris	/** controller configuration */
174240616Sjimharris	union cc_register	cc;
175240616Sjimharris
176240616Sjimharris	uint32_t	reserved1;
177240616Sjimharris	uint32_t	csts;		/* controller status */
178240616Sjimharris	uint32_t	reserved2;
179240616Sjimharris
180240616Sjimharris	/** admin queue attributes */
181240616Sjimharris	union aqa_register	aqa;
182240616Sjimharris
183240616Sjimharris	uint64_t	asq;		/* admin submission queue base addr */
184240616Sjimharris	uint64_t	acq;		/* admin completion queue base addr */
185240616Sjimharris	uint32_t	reserved3[0x3f2];
186240616Sjimharris
187240616Sjimharris	struct {
188240616Sjimharris	    uint32_t	sq_tdbl;	/* submission queue tail doorbell */
189240616Sjimharris	    uint32_t	cq_hdbl;	/* completion queue head doorbell */
190240616Sjimharris	} doorbell[1] __packed;
191240616Sjimharris} __packed;
192240616Sjimharris
193240616Sjimharrisstruct nvme_command
194240616Sjimharris{
195240616Sjimharris	/* dword 0 */
196240616Sjimharris	uint16_t opc	:  8;	/* opcode */
197240616Sjimharris	uint16_t fuse	:  2;	/* fused operation */
198240616Sjimharris	uint16_t rsvd1	:  6;
199240616Sjimharris	uint16_t cid;		/* command identifier */
200240616Sjimharris
201240616Sjimharris	/* dword 1 */
202240616Sjimharris	uint32_t nsid;		/* namespace identifier */
203240616Sjimharris
204240616Sjimharris	/* dword 2-3 */
205240616Sjimharris	uint32_t rsvd2;
206240616Sjimharris	uint32_t rsvd3;
207240616Sjimharris
208240616Sjimharris	/* dword 4-5 */
209240616Sjimharris	uint64_t mptr;		/* metadata pointer */
210240616Sjimharris
211240616Sjimharris	/* dword 6-7 */
212240616Sjimharris	uint64_t prp1;		/* prp entry 1 */
213240616Sjimharris
214240616Sjimharris	/* dword 8-9 */
215240616Sjimharris	uint64_t prp2;		/* prp entry 2 */
216240616Sjimharris
217240616Sjimharris	/* dword 10-15 */
218240616Sjimharris	uint32_t cdw10;		/* command-specific */
219240616Sjimharris	uint32_t cdw11;		/* command-specific */
220240616Sjimharris	uint32_t cdw12;		/* command-specific */
221240616Sjimharris	uint32_t cdw13;		/* command-specific */
222240616Sjimharris	uint32_t cdw14;		/* command-specific */
223240616Sjimharris	uint32_t cdw15;		/* command-specific */
224240616Sjimharris} __packed;
225240616Sjimharris
226240616Sjimharrisstruct nvme_completion {
227240616Sjimharris
228240616Sjimharris	/* dword 0 */
229240616Sjimharris	uint32_t cdw0;		/* command-specific */
230240616Sjimharris
231240616Sjimharris	/* dword 1 */
232240616Sjimharris	uint32_t rsvd1;
233240616Sjimharris
234240616Sjimharris	/* dword 2 */
235240616Sjimharris	uint16_t sqhd;		/* submission queue head pointer */
236240616Sjimharris	uint16_t sqid;		/* submission queue identifier */
237240616Sjimharris
238240616Sjimharris	/* dword 3 */
239240616Sjimharris	uint16_t cid;		/* command identifier */
240240616Sjimharris	uint16_t p	:  1;	/* phase tag */
241240616Sjimharris	uint16_t sf_sc	:  8;	/* status field - status code */
242240616Sjimharris	uint16_t sf_sct	:  3;	/* status field - status code type */
243240616Sjimharris	uint16_t rsvd2	:  2;
244240616Sjimharris	uint16_t sf_m	:  1;	/* status field - more */
245240616Sjimharris	uint16_t sf_dnr	:  1;	/* status field - do not retry */
246240616Sjimharris} __packed;
247240616Sjimharris
248240616Sjimharrisstruct nvme_dsm_range {
249240616Sjimharris
250240616Sjimharris	uint32_t attributes;
251240616Sjimharris	uint32_t length;
252240616Sjimharris	uint64_t starting_lba;
253240616Sjimharris} __packed;
254240616Sjimharris
255240616Sjimharris/* status code types */
256240616Sjimharrisenum nvme_status_code_type {
257240616Sjimharris	NVME_SCT_GENERIC		= 0x0,
258240616Sjimharris	NVME_SCT_COMMAND_SPECIFIC	= 0x1,
259240616Sjimharris	NVME_SCT_MEDIA_ERROR		= 0x2,
260240616Sjimharris	/* 0x3-0x6 - reserved */
261240616Sjimharris	NVME_SCT_VENDOR_SPECIFIC	= 0x7,
262240616Sjimharris};
263240616Sjimharris
264240616Sjimharris/* generic command status codes */
265240616Sjimharrisenum nvme_generic_command_status_code {
266240616Sjimharris	NVME_SC_SUCCESS				= 0x00,
267240616Sjimharris	NVME_SC_INVALID_OPCODE			= 0x01,
268240616Sjimharris	NVME_SC_INVALID_FIELD			= 0x02,
269240616Sjimharris	NVME_SC_COMMAND_ID_CONFLICT		= 0x03,
270240616Sjimharris	NVME_SC_DATA_TRANSFER_ERROR		= 0x04,
271240616Sjimharris	NVME_SC_ABORTED_POWER_LOSS		= 0x05,
272240616Sjimharris	NVME_SC_INTERNAL_DEVICE_ERROR		= 0x06,
273240616Sjimharris	NVME_SC_ABORTED_BY_REQUEST		= 0x07,
274240616Sjimharris	NVME_SC_ABORTED_SQ_DELETION		= 0x08,
275240616Sjimharris	NVME_SC_ABORTED_FAILED_FUSED		= 0x09,
276240616Sjimharris	NVME_SC_ABORTED_MISSING_FUSED		= 0x0a,
277240616Sjimharris	NVME_SC_INVALID_NAMESPACE_OR_FORMAT	= 0x0b,
278240616Sjimharris	NVME_SC_COMMAND_SEQUENCE_ERROR		= 0x0c,
279240616Sjimharris
280240616Sjimharris	NVME_SC_LBA_OUT_OF_RANGE		= 0x80,
281240616Sjimharris	NVME_SC_CAPACITY_EXCEEDED		= 0x81,
282240616Sjimharris	NVME_SC_NAMESPACE_NOT_READY		= 0x82,
283240616Sjimharris};
284240616Sjimharris
285240616Sjimharris/* command specific status codes */
286240616Sjimharrisenum nvme_command_specific_status_code {
287240616Sjimharris	NVME_SC_COMPLETION_QUEUE_INVALID	= 0x00,
288240616Sjimharris	NVME_SC_INVALID_QUEUE_IDENTIFIER	= 0x01,
289240616Sjimharris	NVME_SC_MAXIMUM_QUEUE_SIZE_EXCEEDED	= 0x02,
290240616Sjimharris	NVME_SC_ABORT_COMMAND_LIMIT_EXCEEDED	= 0x03,
291240616Sjimharris	/* 0x04 - reserved */
292240616Sjimharris	NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED = 0x05,
293240616Sjimharris	NVME_SC_INVALID_FIRMWARE_SLOT		= 0x06,
294240616Sjimharris	NVME_SC_INVALID_FIRMWARE_IMAGE		= 0x07,
295240616Sjimharris	NVME_SC_INVALID_INTERRUPT_VECTOR	= 0x08,
296240616Sjimharris	NVME_SC_INVALID_LOG_PAGE		= 0x09,
297240616Sjimharris	NVME_SC_INVALID_FORMAT			= 0x0a,
298240616Sjimharris	NVME_SC_FIRMWARE_REQUIRES_RESET		= 0x0b,
299240616Sjimharris
300240616Sjimharris	NVME_SC_CONFLICTING_ATTRIBUTES		= 0x80,
301240616Sjimharris	NVME_SC_INVALID_PROTECTION_INFO		= 0x81,
302240616Sjimharris	NVME_SC_ATTEMPTED_WRITE_TO_RO_PAGE	= 0x82,
303240616Sjimharris};
304240616Sjimharris
305240616Sjimharris/* media error status codes */
306240616Sjimharrisenum nvme_media_error_status_code {
307240616Sjimharris	NVME_SC_WRITE_FAULTS			= 0x80,
308240616Sjimharris	NVME_SC_UNRECOVERED_READ_ERROR		= 0x81,
309240616Sjimharris	NVME_SC_GUARD_CHECK_ERROR		= 0x82,
310240616Sjimharris	NVME_SC_APPLICATION_TAG_CHECK_ERROR	= 0x83,
311240616Sjimharris	NVME_SC_REFERENCE_TAG_CHECK_ERROR	= 0x84,
312240616Sjimharris	NVME_SC_COMPARE_FAILURE			= 0x85,
313240616Sjimharris	NVME_SC_ACCESS_DENIED			= 0x86,
314240616Sjimharris};
315240616Sjimharris
316240616Sjimharris/* admin opcodes */
317240616Sjimharrisenum nvme_admin_opcode {
318240616Sjimharris	NVME_OPC_DELETE_IO_SQ			= 0x00,
319240616Sjimharris	NVME_OPC_CREATE_IO_SQ			= 0x01,
320240616Sjimharris	NVME_OPC_GET_LOG_PAGE			= 0x02,
321240616Sjimharris	/* 0x03 - reserved */
322240616Sjimharris	NVME_OPC_DELETE_IO_CQ			= 0x04,
323240616Sjimharris	NVME_OPC_CREATE_IO_CQ			= 0x05,
324240616Sjimharris	NVME_OPC_IDENTIFY			= 0x06,
325240616Sjimharris	/* 0x07 - reserved */
326240616Sjimharris	NVME_OPC_ABORT				= 0x08,
327240616Sjimharris	NVME_OPC_SET_FEATURES			= 0x09,
328240616Sjimharris	NVME_OPC_GET_FEATURES			= 0x0a,
329240616Sjimharris	/* 0x0b - reserved */
330240616Sjimharris	NVME_OPC_ASYNC_EVENT_REQUEST		= 0x0c,
331240616Sjimharris	/* 0x0d-0x0f - reserved */
332240616Sjimharris	NVME_OPC_FIRMWARE_ACTIVATE		= 0x10,
333240616Sjimharris	NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD	= 0x11,
334240616Sjimharris
335240616Sjimharris	NVME_OPC_FORMAT_NVM			= 0x80,
336240616Sjimharris	NVME_OPC_SECURITY_SEND			= 0x81,
337240616Sjimharris	NVME_OPC_SECURITY_RECEIVE		= 0x82,
338240616Sjimharris};
339240616Sjimharris
340240616Sjimharris/* nvme nvm opcodes */
341240616Sjimharrisenum nvme_nvm_opcode {
342240616Sjimharris	NVME_OPC_FLUSH				= 0x00,
343240616Sjimharris	NVME_OPC_WRITE				= 0x01,
344240616Sjimharris	NVME_OPC_READ				= 0x02,
345240616Sjimharris	/* 0x03 - reserved */
346240616Sjimharris	NVME_OPC_WRITE_UNCORRECTABLE		= 0x04,
347240616Sjimharris	NVME_OPC_COMPARE			= 0x05,
348240616Sjimharris	/* 0x06-0x07 - reserved */
349240616Sjimharris	NVME_OPC_DATASET_MANAGEMENT		= 0x09,
350240616Sjimharris};
351240616Sjimharris
352240616Sjimharrisenum nvme_feature {
353240616Sjimharris	/* 0x00 - reserved */
354240616Sjimharris	NVME_FEAT_ARBITRATION			= 0x01,
355240616Sjimharris	NVME_FEAT_POWER_MANAGEMENT		= 0x02,
356240616Sjimharris	NVME_FEAT_LBA_RANGE_TYPE		= 0x03,
357240616Sjimharris	NVME_FEAT_TEMPERATURE_THRESHOLD		= 0x04,
358240616Sjimharris	NVME_FEAT_ERROR_RECOVERY		= 0x05,
359240616Sjimharris	NVME_FEAT_VOLATILE_WRITE_CACHE		= 0x06,
360240616Sjimharris	NVME_FEAT_NUMBER_OF_QUEUES		= 0x07,
361240616Sjimharris	NVME_FEAT_INTERRUPT_COALESCING		= 0x08,
362240616Sjimharris	NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION = 0x09,
363240616Sjimharris	NVME_FEAT_WRITE_ATOMICITY		= 0x0A,
364248737Sjimharris	NVME_FEAT_ASYNC_EVENT_CONFIGURATION	= 0x0B,
365240616Sjimharris	/* 0x0C-0x7F - reserved */
366240616Sjimharris	NVME_FEAT_SOFTWARE_PROGRESS_MARKER	= 0x80,
367240616Sjimharris	/* 0x81-0xBF - command set specific (reserved) */
368240616Sjimharris	/* 0xC0-0xFF - vendor specific */
369240616Sjimharris};
370240616Sjimharris
371240616Sjimharrisenum nvme_dsm_attribute {
372240616Sjimharris	NVME_DSM_ATTR_INTEGRAL_READ		= 0x1,
373240616Sjimharris	NVME_DSM_ATTR_INTEGRAL_WRITE		= 0x2,
374240616Sjimharris	NVME_DSM_ATTR_DEALLOCATE		= 0x4,
375240616Sjimharris};
376240616Sjimharris
377240616Sjimharrisstruct nvme_controller_data {
378240616Sjimharris
379240616Sjimharris	/* bytes 0-255: controller capabilities and features */
380240616Sjimharris
381240616Sjimharris	/** pci vendor id */
382240616Sjimharris	uint16_t		vid;
383240616Sjimharris
384240616Sjimharris	/** pci subsystem vendor id */
385240616Sjimharris	uint16_t		ssvid;
386240616Sjimharris
387240616Sjimharris	/** serial number */
388240616Sjimharris	int8_t			sn[20];
389240616Sjimharris
390240616Sjimharris	/** model number */
391240616Sjimharris	int8_t			mn[40];
392240616Sjimharris
393240616Sjimharris	/** firmware revision */
394240616Sjimharris	uint8_t			fr[8];
395240616Sjimharris
396240616Sjimharris	/** recommended arbitration burst */
397240616Sjimharris	uint8_t			rab;
398240616Sjimharris
399240616Sjimharris	/** ieee oui identifier */
400240616Sjimharris	uint8_t			ieee[3];
401240616Sjimharris
402240616Sjimharris	/** multi-interface capabilities */
403240616Sjimharris	uint8_t			mic;
404240616Sjimharris
405240616Sjimharris	/** maximum data transfer size */
406240616Sjimharris	uint8_t			mdts;
407240616Sjimharris
408240616Sjimharris	uint8_t			reserved1[178];
409240616Sjimharris
410240616Sjimharris	/* bytes 256-511: admin command set attributes */
411240616Sjimharris
412240616Sjimharris	/** optional admin command support */
413240616Sjimharris	struct {
414240616Sjimharris		/* supports security send/receive commands */
415240616Sjimharris		uint16_t	security  : 1;
416240616Sjimharris
417240616Sjimharris		/* supports format nvm command */
418240616Sjimharris		uint16_t	format    : 1;
419240616Sjimharris
420240616Sjimharris		/* supports firmware activate/download commands */
421240616Sjimharris		uint16_t	firmware  : 1;
422240616Sjimharris
423240616Sjimharris		uint16_t	oacs_rsvd : 13;
424240616Sjimharris	} __packed oacs;
425240616Sjimharris
426240616Sjimharris	/** abort command limit */
427240616Sjimharris	uint8_t			acl;
428240616Sjimharris
429240616Sjimharris	/** asynchronous event request limit */
430240616Sjimharris	uint8_t			aerl;
431240616Sjimharris
432240616Sjimharris	/** firmware updates */
433240616Sjimharris	struct {
434240616Sjimharris		/* first slot is read-only */
435240616Sjimharris		uint8_t		slot1_ro  : 1;
436240616Sjimharris
437240616Sjimharris		/* number of firmware slots */
438240616Sjimharris		uint8_t		num_slots : 3;
439240616Sjimharris
440240616Sjimharris		uint8_t		frmw_rsvd : 4;
441240616Sjimharris	} __packed frmw;
442240616Sjimharris
443240616Sjimharris	/** log page attributes */
444240616Sjimharris	struct {
445240616Sjimharris		/* per namespace smart/health log page */
446240616Sjimharris		uint8_t		ns_smart : 1;
447240616Sjimharris
448240616Sjimharris		uint8_t		lpa_rsvd : 7;
449240616Sjimharris	} __packed lpa;
450240616Sjimharris
451240616Sjimharris	/** error log page entries */
452240616Sjimharris	uint8_t			elpe;
453240616Sjimharris
454240616Sjimharris	/** number of power states supported */
455240616Sjimharris	uint8_t			npss;
456240616Sjimharris
457240616Sjimharris	/** admin vendor specific command configuration */
458240616Sjimharris	struct {
459240616Sjimharris		/* admin vendor specific commands use spec format */
460240616Sjimharris		uint8_t		spec_format : 1;
461240616Sjimharris
462240616Sjimharris		uint8_t		avscc_rsvd  : 7;
463240616Sjimharris	} __packed avscc;
464240616Sjimharris
465240616Sjimharris	uint8_t			reserved2[247];
466240616Sjimharris
467240616Sjimharris	/* bytes 512-703: nvm command set attributes */
468240616Sjimharris
469240616Sjimharris	/** submission queue entry size */
470240616Sjimharris	struct {
471240616Sjimharris		uint8_t		min : 4;
472240616Sjimharris		uint8_t		max : 4;
473240616Sjimharris	} __packed sqes;
474240616Sjimharris
475240616Sjimharris	/** completion queue entry size */
476240616Sjimharris	struct {
477240616Sjimharris		uint8_t		min : 4;
478240616Sjimharris		uint8_t		max : 4;
479240616Sjimharris	} __packed cqes;
480240616Sjimharris
481240616Sjimharris	uint8_t			reserved3[2];
482240616Sjimharris
483240616Sjimharris	/** number of namespaces */
484240616Sjimharris	uint32_t		nn;
485240616Sjimharris
486240616Sjimharris	/** optional nvm command support */
487240616Sjimharris	struct {
488240616Sjimharris		uint16_t	compare : 1;
489240616Sjimharris		uint16_t	write_unc : 1;
490240616Sjimharris		uint16_t	dsm: 1;
491240616Sjimharris		uint16_t	reserved: 13;
492240616Sjimharris	} __packed oncs;
493240616Sjimharris
494240616Sjimharris	/** fused operation support */
495240616Sjimharris	uint16_t		fuses;
496240616Sjimharris
497240616Sjimharris	/** format nvm attributes */
498240616Sjimharris	uint8_t			fna;
499240616Sjimharris
500240616Sjimharris	/** volatile write cache */
501240616Sjimharris	struct {
502240616Sjimharris		uint8_t		present : 1;
503240616Sjimharris		uint8_t		reserved : 7;
504240616Sjimharris	} __packed vwc;
505240616Sjimharris
506240616Sjimharris	/* TODO: flesh out remaining nvm command set attributes */
507240616Sjimharris	uint8_t			reserved4[178];
508240616Sjimharris
509240616Sjimharris	/* bytes 704-2047: i/o command set attributes */
510240616Sjimharris	uint8_t			reserved5[1344];
511240616Sjimharris
512240616Sjimharris	/* bytes 2048-3071: power state descriptors */
513240616Sjimharris	uint8_t			reserved6[1024];
514240616Sjimharris
515240616Sjimharris	/* bytes 3072-4095: vendor specific */
516240616Sjimharris	uint8_t			reserved7[1024];
517240671Sjimharris} __packed __aligned(4);
518240616Sjimharris
519240616Sjimharrisstruct nvme_namespace_data {
520240616Sjimharris
521240616Sjimharris	/** namespace size */
522240616Sjimharris	uint64_t		nsze;
523240616Sjimharris
524240616Sjimharris	/** namespace capacity */
525240616Sjimharris	uint64_t		ncap;
526240616Sjimharris
527240616Sjimharris	/** namespace utilization */
528240616Sjimharris	uint64_t		nuse;
529240616Sjimharris
530240616Sjimharris	/** namespace features */
531240616Sjimharris	struct {
532240616Sjimharris		/** thin provisioning */
533240616Sjimharris		uint8_t		thin_prov : 1;
534240616Sjimharris		uint8_t		reserved1 : 7;
535240616Sjimharris	} __packed nsfeat;
536240616Sjimharris
537240616Sjimharris	/** number of lba formats */
538240616Sjimharris	uint8_t			nlbaf;
539240616Sjimharris
540240616Sjimharris	/** formatted lba size */
541240616Sjimharris	struct {
542240616Sjimharris		uint8_t		format    : 4;
543240616Sjimharris		uint8_t		extended  : 1;
544240616Sjimharris		uint8_t		reserved2 : 3;
545240616Sjimharris	} __packed flbas;
546240616Sjimharris
547240616Sjimharris	/** metadata capabilities */
548240616Sjimharris	struct {
549240616Sjimharris		/* metadata can be transferred as part of data prp list */
550240616Sjimharris		uint8_t		extended  : 1;
551240616Sjimharris
552240616Sjimharris		/* metadata can be transferred with separate metadata pointer */
553240616Sjimharris		uint8_t		pointer   : 1;
554240616Sjimharris
555240616Sjimharris		uint8_t		reserved3 : 6;
556240616Sjimharris	} __packed mc;
557240616Sjimharris
558240616Sjimharris	/** end-to-end data protection capabilities */
559240616Sjimharris	struct {
560240616Sjimharris		/* protection information type 1 */
561240616Sjimharris		uint8_t		pit1     : 1;
562240616Sjimharris
563240616Sjimharris		/* protection information type 2 */
564240616Sjimharris		uint8_t		pit2     : 1;
565240616Sjimharris
566240616Sjimharris		/* protection information type 3 */
567240616Sjimharris		uint8_t		pit3     : 1;
568240616Sjimharris
569240616Sjimharris		/* first eight bytes of metadata */
570240616Sjimharris		uint8_t		md_start : 1;
571240616Sjimharris
572240616Sjimharris		/* last eight bytes of metadata */
573240616Sjimharris		uint8_t		md_end   : 1;
574240616Sjimharris	} __packed dpc;
575240616Sjimharris
576240616Sjimharris	/** end-to-end data protection type settings */
577240616Sjimharris	struct {
578240616Sjimharris		/* protection information type */
579240616Sjimharris		uint8_t		pit       : 3;
580240616Sjimharris
581240616Sjimharris		/* 1 == protection info transferred at start of metadata */
582240616Sjimharris		/* 0 == protection info transferred at end of metadata */
583240616Sjimharris		uint8_t		md_start  : 1;
584240616Sjimharris
585240616Sjimharris		uint8_t		reserved4 : 4;
586240616Sjimharris	} __packed dps;
587240616Sjimharris
588240616Sjimharris	uint8_t			reserved5[98];
589240616Sjimharris
590240616Sjimharris	/** lba format support */
591240616Sjimharris	struct {
592240616Sjimharris		/** metadata size */
593240616Sjimharris		uint32_t	ms	  : 16;
594240616Sjimharris
595240616Sjimharris		/** lba data size */
596240616Sjimharris		uint32_t	lbads	  : 8;
597240616Sjimharris
598240616Sjimharris		/** relative performance */
599240616Sjimharris		uint32_t	rp	  : 2;
600240616Sjimharris
601240616Sjimharris		uint32_t	reserved6 : 6;
602240616Sjimharris	} __packed lbaf[16];
603240616Sjimharris
604240616Sjimharris	uint8_t			reserved6[192];
605240616Sjimharris
606240616Sjimharris	uint8_t			vendor_specific[3712];
607240671Sjimharris} __packed __aligned(4);
608240616Sjimharris
609240616Sjimharrisenum nvme_log_page {
610240616Sjimharris
611240616Sjimharris	/* 0x00 - reserved */
612240616Sjimharris	NVME_LOG_ERROR			= 0x01,
613240616Sjimharris	NVME_LOG_HEALTH_INFORMATION	= 0x02,
614240616Sjimharris	NVME_LOG_FIRMWARE_SLOT		= 0x03,
615240616Sjimharris	/* 0x04-0x7F - reserved */
616240616Sjimharris	/* 0x80-0xBF - I/O command set specific */
617240616Sjimharris	/* 0xC0-0xFF - vendor specific */
618240616Sjimharris};
619240616Sjimharris
620240616Sjimharrisunion nvme_critical_warning_state {
621240616Sjimharris
622240616Sjimharris	uint8_t		raw;
623240616Sjimharris
624240616Sjimharris	struct {
625240616Sjimharris		uint8_t	available_spare		: 1;
626240616Sjimharris		uint8_t	temperature		: 1;
627240616Sjimharris		uint8_t	device_reliability	: 1;
628240616Sjimharris		uint8_t	read_only		: 1;
629240616Sjimharris		uint8_t	volatile_memory_backup	: 1;
630240616Sjimharris		uint8_t	reserved		: 3;
631240616Sjimharris	} __packed bits;
632240616Sjimharris} __packed;
633240616Sjimharris
634240616Sjimharrisstruct nvme_health_information_page {
635240616Sjimharris
636240616Sjimharris	union nvme_critical_warning_state	critical_warning;
637240616Sjimharris
638240616Sjimharris	uint16_t		temperature;
639240616Sjimharris	uint8_t			available_spare;
640240616Sjimharris	uint8_t			available_spare_threshold;
641240616Sjimharris	uint8_t			percentage_used;
642240616Sjimharris
643240616Sjimharris	uint8_t			reserved[26];
644240616Sjimharris
645240616Sjimharris	/*
646240616Sjimharris	 * Note that the following are 128-bit values, but are
647240616Sjimharris	 *  defined as an array of 2 64-bit values.
648240616Sjimharris	 */
649240616Sjimharris	/* Data Units Read is always in 512-byte units. */
650240616Sjimharris	uint64_t		data_units_read[2];
651240616Sjimharris	/* Data Units Written is always in 512-byte units. */
652240616Sjimharris	uint64_t		data_units_written[2];
653240616Sjimharris	/* For NVM command set, this includes Compare commands. */
654240616Sjimharris	uint64_t		host_read_commands[2];
655240616Sjimharris	uint64_t		host_write_commands[2];
656240616Sjimharris	/* Controller Busy Time is reported in minutes. */
657240616Sjimharris	uint64_t		controller_busy_time[2];
658240616Sjimharris	uint64_t		power_cycles[2];
659240616Sjimharris	uint64_t		power_on_hours[2];
660240616Sjimharris	uint64_t		unsafe_shutdowns[2];
661240616Sjimharris	uint64_t		media_errors[2];
662240616Sjimharris	uint64_t		num_error_info_log_entries[2];
663240616Sjimharris
664240616Sjimharris	uint8_t			reserved2[320];
665240671Sjimharris} __packed __aligned(4);
666240616Sjimharris
667240616Sjimharris#define NVME_TEST_MAX_THREADS	128
668240616Sjimharris
669240616Sjimharrisstruct nvme_io_test {
670240616Sjimharris
671240616Sjimharris	enum nvme_nvm_opcode	opc;
672240616Sjimharris	uint32_t		size;
673240616Sjimharris	uint32_t		time;	/* in seconds */
674240616Sjimharris	uint32_t		num_threads;
675240616Sjimharris	uint32_t		flags;
676240616Sjimharris	uint32_t		io_completed[NVME_TEST_MAX_THREADS];
677240616Sjimharris};
678240616Sjimharris
679240616Sjimharrisenum nvme_io_test_flags {
680240616Sjimharris
681240616Sjimharris	/*
682240616Sjimharris	 * Specifies whether dev_refthread/dev_relthread should be
683240616Sjimharris	 *  called during NVME_BIO_TEST.  Ignored for other test
684240616Sjimharris	 *  types.
685240616Sjimharris	 */
686240616Sjimharris	NVME_TEST_FLAG_REFTHREAD =	0x1,
687240616Sjimharris};
688240616Sjimharris
689240616Sjimharris#ifdef _KERNEL
690240616Sjimharris
691240616Sjimharrisstruct bio;
692240616Sjimharris
693240616Sjimharrisstruct nvme_namespace;
694248738Sjimharrisstruct nvme_controller;
695240616Sjimharrisstruct nvme_consumer;
696240616Sjimharris
697240616Sjimharristypedef void (*nvme_cb_fn_t)(void *, const struct nvme_completion *);
698240616Sjimharris
699248738Sjimharristypedef void *(*nvme_cons_ns_fn_t)(struct nvme_namespace *, void *);
700248738Sjimharristypedef void *(*nvme_cons_ctrlr_fn_t)(struct nvme_controller *);
701248738Sjimharristypedef void (*nvme_cons_async_fn_t)(void *, const struct nvme_completion *);
702248738Sjimharris
703240616Sjimharrisenum nvme_namespace_flags {
704240616Sjimharris	NVME_NS_DEALLOCATE_SUPPORTED	= 0x1,
705240616Sjimharris	NVME_NS_FLUSH_SUPPORTED		= 0x2,
706240616Sjimharris};
707240616Sjimharris
708248739Sjimharris/* Admin functions */
709248739Sjimharrisvoid	nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr,
710248739Sjimharris				   uint8_t feature, uint32_t cdw11,
711248739Sjimharris				   void *payload, uint32_t payload_size,
712248739Sjimharris				   nvme_cb_fn_t cb_fn, void *cb_arg);
713248739Sjimharrisvoid	nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr,
714248739Sjimharris				   uint8_t feature, uint32_t cdw11,
715248739Sjimharris				   void *payload, uint32_t payload_size,
716248739Sjimharris				   nvme_cb_fn_t cb_fn, void *cb_arg);
717248740Sjimharrisvoid	nvme_ctrlr_cmd_get_log_page(struct nvme_controller *ctrlr,
718248740Sjimharris				    uint8_t log_page, uint32_t nsid,
719248740Sjimharris				    void *payload, uint32_t payload_size,
720248740Sjimharris				    nvme_cb_fn_t cb_fn, void *cb_arg);
721248739Sjimharris
722240616Sjimharris/* NVM I/O functions */
723241657Sjimharrisint	nvme_ns_cmd_write(struct nvme_namespace *ns, void *payload,
724240616Sjimharris			  uint64_t lba, uint32_t lba_count, nvme_cb_fn_t cb_fn,
725240616Sjimharris			  void *cb_arg);
726241657Sjimharrisint	nvme_ns_cmd_read(struct nvme_namespace *ns, void *payload,
727240616Sjimharris			 uint64_t lba, uint32_t lba_count, nvme_cb_fn_t cb_fn,
728240616Sjimharris			 void *cb_arg);
729241657Sjimharrisint	nvme_ns_cmd_deallocate(struct nvme_namespace *ns, void *payload,
730240616Sjimharris			       uint8_t num_ranges, nvme_cb_fn_t cb_fn,
731240616Sjimharris			       void *cb_arg);
732241657Sjimharrisint	nvme_ns_cmd_flush(struct nvme_namespace *ns, nvme_cb_fn_t cb_fn,
733240616Sjimharris			  void *cb_arg);
734240616Sjimharris
735240616Sjimharris/* Registration functions */
736248738Sjimharrisstruct nvme_consumer *	nvme_register_consumer(nvme_cons_ns_fn_t    ns_fn,
737248738Sjimharris					       nvme_cons_ctrlr_fn_t ctrlr_fn,
738248738Sjimharris					       nvme_cons_async_fn_t async_fn);
739240616Sjimharrisvoid		nvme_unregister_consumer(struct nvme_consumer *consumer);
740240616Sjimharris
741248738Sjimharris/* Controller helper functions */
742248738Sjimharrisdevice_t	nvme_ctrlr_get_device(struct nvme_controller *ctrlr);
743248747Sjimharrisconst struct nvme_controller_data *
744248747Sjimharris		nvme_ctrlr_get_data(struct nvme_controller *ctrlr);
745248738Sjimharris
746240616Sjimharris/* Namespace helper functions */
747240616Sjimharrisuint32_t	nvme_ns_get_max_io_xfer_size(struct nvme_namespace *ns);
748240616Sjimharrisuint32_t	nvme_ns_get_sector_size(struct nvme_namespace *ns);
749240616Sjimharrisuint64_t	nvme_ns_get_num_sectors(struct nvme_namespace *ns);
750240616Sjimharrisuint64_t	nvme_ns_get_size(struct nvme_namespace *ns);
751240616Sjimharrisuint32_t	nvme_ns_get_flags(struct nvme_namespace *ns);
752240616Sjimharrisconst char *	nvme_ns_get_serial_number(struct nvme_namespace *ns);
753240616Sjimharrisconst char *	nvme_ns_get_model_number(struct nvme_namespace *ns);
754248747Sjimharrisconst struct nvme_namespace_data *
755248747Sjimharris		nvme_ns_get_data(struct nvme_namespace *ns);
756240616Sjimharris
757240616Sjimharrisint	nvme_ns_bio_process(struct nvme_namespace *ns, struct bio *bp,
758240616Sjimharris			    nvme_cb_fn_t cb_fn);
759240616Sjimharris
760240616Sjimharris#endif /* _KERNEL */
761240616Sjimharris
762240616Sjimharris#endif /* __NVME_H__ */
763