summaryrefslogtreecommitdiffstats
path: root/drivers/nvme/host/nvme.h
blob: 07aefa5f15159ccbf9ef0d0ca2e6b37b5fd6cadb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (c) 2011-2014, Intel Corporation.
 */

#ifndef _NVME_H
#define _NVME_H

#include <linux/nvme.h>
#include <dma.h>
#include <block.h>

#define ADMIN_TIMEOUT		(60 * HZ)
#define SHUTDOWN_TIMEOUT	( 5 * HZ)

/*
 * Common request structure for NVMe passthrough.  All drivers must have
 * this structure as the first member of their request-private data.
 */
struct nvme_request {
	struct nvme_command	*cmd;
	union nvme_result	result;
	u16			status;

	void *buffer;
	unsigned int buffer_len;
	dma_addr_t buffer_dma_addr;
	enum dma_data_direction dma_dir;
};

struct nvme_ctrl {
	const struct nvme_ctrl_ops *ops;
	struct device_d *dev;
	int instance;

	u32 ctrl_config;
	u32 queue_count;
	u64 cap;
	u32 page_size;
	u32 max_hw_sectors;
	u32 vs;
};

/*
 * Anchor structure for namespaces.  There is one for each namespace in a
 * NVMe subsystem that any of our controllers can see, and the namespace
 * structure for each controller is chained of it.  For private namespaces
 * there is a 1:1 relation to our namespace structures, that is ->list
 * only ever has a single entry for private namespaces.
 */
struct nvme_ns_head {
	unsigned		ns_id;
	int			instance;
};

struct nvme_ns {
	struct nvme_ctrl *ctrl;
	struct nvme_ns_head *head;
	struct block_device blk;

	int lba_shift;
	bool readonly;
};

static inline struct nvme_ns *to_nvme_ns(struct block_device *blk)
{
	return container_of(blk, struct nvme_ns, blk);
}

struct nvme_ctrl_ops {
	int (*reg_read32)(struct nvme_ctrl *ctrl, u32 off, u32 *val);
	int (*reg_write32)(struct nvme_ctrl *ctrl, u32 off, u32 val);
	int (*reg_read64)(struct nvme_ctrl *ctrl, u32 off, u64 *val);

	int (*submit_sync_cmd)(struct nvme_ctrl *ctrl,
			       struct nvme_command *cmd,
			       union nvme_result *result,
			       void *buffer,
			       unsigned bufflen,
			       unsigned timeout, int qid);
};

static inline bool nvme_ctrl_ready(struct nvme_ctrl *ctrl)
{
	u32 val = 0;

	if (ctrl->ops->reg_read32(ctrl, NVME_REG_CSTS, &val))
		return false;
	return val & NVME_CSTS_RDY;
}

static inline u64 nvme_block_nr(struct nvme_ns *ns, sector_t sector)
{
	return (sector >> (ns->lba_shift - 9));
}

static inline void nvme_end_request(struct nvme_request *rq, __le16 status,
		union nvme_result result)
{
	rq->status = le16_to_cpu(status) >> 1;
	rq->result = result;
}

int nvme_disable_ctrl(struct nvme_ctrl *ctrl, u64 cap);
int nvme_enable_ctrl(struct nvme_ctrl *ctrl, u64 cap);
int nvme_shutdown_ctrl(struct nvme_ctrl *ctrl);
int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device_d *dev,
		   const struct nvme_ctrl_ops *ops);
void nvme_start_ctrl(struct nvme_ctrl *ctrl);
int nvme_init_identify(struct nvme_ctrl *ctrl);

enum nvme_queue_id {
	NVME_QID_ADMIN,
	NVME_QID_IO,
	NVME_QID_NUM,
	NVME_QID_ANY = -1,
};

int __nvme_submit_sync_cmd(struct nvme_ctrl *ctrl,
			   struct nvme_command *cmd,
			   union nvme_result *result,
			   void *buffer, unsigned bufflen,
			   unsigned timeout, int qid);
int nvme_submit_sync_cmd(struct nvme_ctrl *ctrl,
			 struct nvme_command *cmd,
			 void *buffer, unsigned bufflen);


int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count);
/*
 * Without the multipath code enabled, multiple controller per subsystems are
 * visible as devices and thus we cannot use the subsystem instance.
 */
static inline void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns,
				      struct nvme_ctrl *ctrl, int *flags)
{
	sprintf(disk_name, "nvme%dn%d", ctrl->instance, ns->head->instance);
}

#endif /* _NVME_H */