xref: /openbmc/linux/drivers/nvme/host/pr.c (revision b668f2f5)
1*b668f2f5SMike Christie // SPDX-License-Identifier: GPL-2.0
2*b668f2f5SMike Christie /*
3*b668f2f5SMike Christie  * Copyright (c) 2015 Intel Corporation
4*b668f2f5SMike Christie  *	Keith Busch <kbusch@kernel.org>
5*b668f2f5SMike Christie  */
6*b668f2f5SMike Christie #include <linux/blkdev.h>
7*b668f2f5SMike Christie #include <linux/pr.h>
8*b668f2f5SMike Christie #include <asm/unaligned.h>
9*b668f2f5SMike Christie 
10*b668f2f5SMike Christie #include "nvme.h"
11*b668f2f5SMike Christie 
12*b668f2f5SMike Christie static char nvme_pr_type(enum pr_type type)
13*b668f2f5SMike Christie {
14*b668f2f5SMike Christie 	switch (type) {
15*b668f2f5SMike Christie 	case PR_WRITE_EXCLUSIVE:
16*b668f2f5SMike Christie 		return 1;
17*b668f2f5SMike Christie 	case PR_EXCLUSIVE_ACCESS:
18*b668f2f5SMike Christie 		return 2;
19*b668f2f5SMike Christie 	case PR_WRITE_EXCLUSIVE_REG_ONLY:
20*b668f2f5SMike Christie 		return 3;
21*b668f2f5SMike Christie 	case PR_EXCLUSIVE_ACCESS_REG_ONLY:
22*b668f2f5SMike Christie 		return 4;
23*b668f2f5SMike Christie 	case PR_WRITE_EXCLUSIVE_ALL_REGS:
24*b668f2f5SMike Christie 		return 5;
25*b668f2f5SMike Christie 	case PR_EXCLUSIVE_ACCESS_ALL_REGS:
26*b668f2f5SMike Christie 		return 6;
27*b668f2f5SMike Christie 	default:
28*b668f2f5SMike Christie 		return 0;
29*b668f2f5SMike Christie 	}
30*b668f2f5SMike Christie }
31*b668f2f5SMike Christie 
32*b668f2f5SMike Christie static int nvme_send_ns_head_pr_command(struct block_device *bdev,
33*b668f2f5SMike Christie 		struct nvme_command *c, u8 *data, unsigned int data_len)
34*b668f2f5SMike Christie {
35*b668f2f5SMike Christie 	struct nvme_ns_head *head = bdev->bd_disk->private_data;
36*b668f2f5SMike Christie 	int srcu_idx = srcu_read_lock(&head->srcu);
37*b668f2f5SMike Christie 	struct nvme_ns *ns = nvme_find_path(head);
38*b668f2f5SMike Christie 	int ret = -EWOULDBLOCK;
39*b668f2f5SMike Christie 
40*b668f2f5SMike Christie 	if (ns) {
41*b668f2f5SMike Christie 		c->common.nsid = cpu_to_le32(ns->head->ns_id);
42*b668f2f5SMike Christie 		ret = nvme_submit_sync_cmd(ns->queue, c, data, data_len);
43*b668f2f5SMike Christie 	}
44*b668f2f5SMike Christie 	srcu_read_unlock(&head->srcu, srcu_idx);
45*b668f2f5SMike Christie 	return ret;
46*b668f2f5SMike Christie }
47*b668f2f5SMike Christie 
48*b668f2f5SMike Christie static int nvme_send_ns_pr_command(struct nvme_ns *ns, struct nvme_command *c,
49*b668f2f5SMike Christie 		u8 *data, unsigned int data_len)
50*b668f2f5SMike Christie {
51*b668f2f5SMike Christie 	c->common.nsid = cpu_to_le32(ns->head->ns_id);
52*b668f2f5SMike Christie 	return nvme_submit_sync_cmd(ns->queue, c, data, data_len);
53*b668f2f5SMike Christie }
54*b668f2f5SMike Christie 
55*b668f2f5SMike Christie static int nvme_sc_to_pr_err(int nvme_sc)
56*b668f2f5SMike Christie {
57*b668f2f5SMike Christie 	if (nvme_is_path_error(nvme_sc))
58*b668f2f5SMike Christie 		return PR_STS_PATH_FAILED;
59*b668f2f5SMike Christie 
60*b668f2f5SMike Christie 	switch (nvme_sc) {
61*b668f2f5SMike Christie 	case NVME_SC_SUCCESS:
62*b668f2f5SMike Christie 		return PR_STS_SUCCESS;
63*b668f2f5SMike Christie 	case NVME_SC_RESERVATION_CONFLICT:
64*b668f2f5SMike Christie 		return PR_STS_RESERVATION_CONFLICT;
65*b668f2f5SMike Christie 	case NVME_SC_ONCS_NOT_SUPPORTED:
66*b668f2f5SMike Christie 		return -EOPNOTSUPP;
67*b668f2f5SMike Christie 	case NVME_SC_BAD_ATTRIBUTES:
68*b668f2f5SMike Christie 	case NVME_SC_INVALID_OPCODE:
69*b668f2f5SMike Christie 	case NVME_SC_INVALID_FIELD:
70*b668f2f5SMike Christie 	case NVME_SC_INVALID_NS:
71*b668f2f5SMike Christie 		return -EINVAL;
72*b668f2f5SMike Christie 	default:
73*b668f2f5SMike Christie 		return PR_STS_IOERR;
74*b668f2f5SMike Christie 	}
75*b668f2f5SMike Christie }
76*b668f2f5SMike Christie 
77*b668f2f5SMike Christie static int nvme_pr_command(struct block_device *bdev, u32 cdw10,
78*b668f2f5SMike Christie 				u64 key, u64 sa_key, u8 op)
79*b668f2f5SMike Christie {
80*b668f2f5SMike Christie 	struct nvme_command c = { };
81*b668f2f5SMike Christie 	u8 data[16] = { 0, };
82*b668f2f5SMike Christie 	int ret;
83*b668f2f5SMike Christie 
84*b668f2f5SMike Christie 	put_unaligned_le64(key, &data[0]);
85*b668f2f5SMike Christie 	put_unaligned_le64(sa_key, &data[8]);
86*b668f2f5SMike Christie 
87*b668f2f5SMike Christie 	c.common.opcode = op;
88*b668f2f5SMike Christie 	c.common.cdw10 = cpu_to_le32(cdw10);
89*b668f2f5SMike Christie 
90*b668f2f5SMike Christie 	if (IS_ENABLED(CONFIG_NVME_MULTIPATH) &&
91*b668f2f5SMike Christie 	    bdev->bd_disk->fops == &nvme_ns_head_ops)
92*b668f2f5SMike Christie 		ret = nvme_send_ns_head_pr_command(bdev, &c, data,
93*b668f2f5SMike Christie 						   sizeof(data));
94*b668f2f5SMike Christie 	else
95*b668f2f5SMike Christie 		ret = nvme_send_ns_pr_command(bdev->bd_disk->private_data, &c,
96*b668f2f5SMike Christie 					      data, sizeof(data));
97*b668f2f5SMike Christie 	if (ret < 0)
98*b668f2f5SMike Christie 		return ret;
99*b668f2f5SMike Christie 
100*b668f2f5SMike Christie 	return nvme_sc_to_pr_err(ret);
101*b668f2f5SMike Christie }
102*b668f2f5SMike Christie 
103*b668f2f5SMike Christie static int nvme_pr_register(struct block_device *bdev, u64 old,
104*b668f2f5SMike Christie 		u64 new, unsigned flags)
105*b668f2f5SMike Christie {
106*b668f2f5SMike Christie 	u32 cdw10;
107*b668f2f5SMike Christie 
108*b668f2f5SMike Christie 	if (flags & ~PR_FL_IGNORE_KEY)
109*b668f2f5SMike Christie 		return -EOPNOTSUPP;
110*b668f2f5SMike Christie 
111*b668f2f5SMike Christie 	cdw10 = old ? 2 : 0;
112*b668f2f5SMike Christie 	cdw10 |= (flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0;
113*b668f2f5SMike Christie 	cdw10 |= (1 << 30) | (1 << 31); /* PTPL=1 */
114*b668f2f5SMike Christie 	return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_register);
115*b668f2f5SMike Christie }
116*b668f2f5SMike Christie 
117*b668f2f5SMike Christie static int nvme_pr_reserve(struct block_device *bdev, u64 key,
118*b668f2f5SMike Christie 		enum pr_type type, unsigned flags)
119*b668f2f5SMike Christie {
120*b668f2f5SMike Christie 	u32 cdw10;
121*b668f2f5SMike Christie 
122*b668f2f5SMike Christie 	if (flags & ~PR_FL_IGNORE_KEY)
123*b668f2f5SMike Christie 		return -EOPNOTSUPP;
124*b668f2f5SMike Christie 
125*b668f2f5SMike Christie 	cdw10 = nvme_pr_type(type) << 8;
126*b668f2f5SMike Christie 	cdw10 |= ((flags & PR_FL_IGNORE_KEY) ? 1 << 3 : 0);
127*b668f2f5SMike Christie 	return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_acquire);
128*b668f2f5SMike Christie }
129*b668f2f5SMike Christie 
130*b668f2f5SMike Christie static int nvme_pr_preempt(struct block_device *bdev, u64 old, u64 new,
131*b668f2f5SMike Christie 		enum pr_type type, bool abort)
132*b668f2f5SMike Christie {
133*b668f2f5SMike Christie 	u32 cdw10 = nvme_pr_type(type) << 8 | (abort ? 2 : 1);
134*b668f2f5SMike Christie 
135*b668f2f5SMike Christie 	return nvme_pr_command(bdev, cdw10, old, new, nvme_cmd_resv_acquire);
136*b668f2f5SMike Christie }
137*b668f2f5SMike Christie 
138*b668f2f5SMike Christie static int nvme_pr_clear(struct block_device *bdev, u64 key)
139*b668f2f5SMike Christie {
140*b668f2f5SMike Christie 	u32 cdw10 = 1 | (key ? 0 : 1 << 3);
141*b668f2f5SMike Christie 
142*b668f2f5SMike Christie 	return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
143*b668f2f5SMike Christie }
144*b668f2f5SMike Christie 
145*b668f2f5SMike Christie static int nvme_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
146*b668f2f5SMike Christie {
147*b668f2f5SMike Christie 	u32 cdw10 = nvme_pr_type(type) << 8 | (key ? 0 : 1 << 3);
148*b668f2f5SMike Christie 
149*b668f2f5SMike Christie 	return nvme_pr_command(bdev, cdw10, key, 0, nvme_cmd_resv_release);
150*b668f2f5SMike Christie }
151*b668f2f5SMike Christie 
152*b668f2f5SMike Christie const struct pr_ops nvme_pr_ops = {
153*b668f2f5SMike Christie 	.pr_register	= nvme_pr_register,
154*b668f2f5SMike Christie 	.pr_reserve	= nvme_pr_reserve,
155*b668f2f5SMike Christie 	.pr_release	= nvme_pr_release,
156*b668f2f5SMike Christie 	.pr_preempt	= nvme_pr_preempt,
157*b668f2f5SMike Christie 	.pr_clear	= nvme_pr_clear,
158*b668f2f5SMike Christie };
159