Merge patch series "scsi: ufs: ufs-qcom: Debug clean ups"
[linux-block.git] / drivers / cxl / security.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright(c) 2022 Intel Corporation. All rights reserved. */
3 #include <linux/libnvdimm.h>
4 #include <asm/unaligned.h>
5 #include <linux/module.h>
6 #include <linux/async.h>
7 #include <linux/slab.h>
8 #include <linux/memregion.h>
9 #include "cxlmem.h"
10 #include "cxl.h"
11
12 static unsigned long cxl_pmem_get_security_flags(struct nvdimm *nvdimm,
13                                                  enum nvdimm_passphrase_type ptype)
14 {
15         struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
16         struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
17         struct cxl_dev_state *cxlds = cxlmd->cxlds;
18         unsigned long security_flags = 0;
19         struct cxl_get_security_output {
20                 __le32 flags;
21         } out;
22         struct cxl_mbox_cmd mbox_cmd;
23         u32 sec_out;
24         int rc;
25
26         mbox_cmd = (struct cxl_mbox_cmd) {
27                 .opcode = CXL_MBOX_OP_GET_SECURITY_STATE,
28                 .size_out = sizeof(out),
29                 .payload_out = &out,
30         };
31
32         rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
33         if (rc < 0)
34                 return 0;
35
36         sec_out = le32_to_cpu(out.flags);
37         if (ptype == NVDIMM_MASTER) {
38                 if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PASS_SET)
39                         set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
40                 else
41                         set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
42                 if (sec_out & CXL_PMEM_SEC_STATE_MASTER_PLIMIT)
43                         set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
44                 return security_flags;
45         }
46
47         if (sec_out & CXL_PMEM_SEC_STATE_USER_PASS_SET) {
48                 if (sec_out & CXL_PMEM_SEC_STATE_FROZEN ||
49                     sec_out & CXL_PMEM_SEC_STATE_USER_PLIMIT)
50                         set_bit(NVDIMM_SECURITY_FROZEN, &security_flags);
51
52                 if (sec_out & CXL_PMEM_SEC_STATE_LOCKED)
53                         set_bit(NVDIMM_SECURITY_LOCKED, &security_flags);
54                 else
55                         set_bit(NVDIMM_SECURITY_UNLOCKED, &security_flags);
56         } else {
57                 set_bit(NVDIMM_SECURITY_DISABLED, &security_flags);
58         }
59
60         return security_flags;
61 }
62
63 static int cxl_pmem_security_change_key(struct nvdimm *nvdimm,
64                                         const struct nvdimm_key_data *old_data,
65                                         const struct nvdimm_key_data *new_data,
66                                         enum nvdimm_passphrase_type ptype)
67 {
68         struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
69         struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
70         struct cxl_dev_state *cxlds = cxlmd->cxlds;
71         struct cxl_mbox_cmd mbox_cmd;
72         struct cxl_set_pass set_pass;
73
74         set_pass = (struct cxl_set_pass) {
75                 .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER :
76                                                  CXL_PMEM_SEC_PASS_USER,
77         };
78         memcpy(set_pass.old_pass, old_data->data, NVDIMM_PASSPHRASE_LEN);
79         memcpy(set_pass.new_pass, new_data->data, NVDIMM_PASSPHRASE_LEN);
80
81         mbox_cmd = (struct cxl_mbox_cmd) {
82                 .opcode = CXL_MBOX_OP_SET_PASSPHRASE,
83                 .size_in = sizeof(set_pass),
84                 .payload_in = &set_pass,
85         };
86
87         return cxl_internal_send_cmd(cxlds, &mbox_cmd);
88 }
89
90 static int __cxl_pmem_security_disable(struct nvdimm *nvdimm,
91                                        const struct nvdimm_key_data *key_data,
92                                        enum nvdimm_passphrase_type ptype)
93 {
94         struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
95         struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
96         struct cxl_dev_state *cxlds = cxlmd->cxlds;
97         struct cxl_disable_pass dis_pass;
98         struct cxl_mbox_cmd mbox_cmd;
99
100         dis_pass = (struct cxl_disable_pass) {
101                 .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER :
102                                                  CXL_PMEM_SEC_PASS_USER,
103         };
104         memcpy(dis_pass.pass, key_data->data, NVDIMM_PASSPHRASE_LEN);
105
106         mbox_cmd = (struct cxl_mbox_cmd) {
107                 .opcode = CXL_MBOX_OP_DISABLE_PASSPHRASE,
108                 .size_in = sizeof(dis_pass),
109                 .payload_in = &dis_pass,
110         };
111
112         return cxl_internal_send_cmd(cxlds, &mbox_cmd);
113 }
114
115 static int cxl_pmem_security_disable(struct nvdimm *nvdimm,
116                                      const struct nvdimm_key_data *key_data)
117 {
118         return __cxl_pmem_security_disable(nvdimm, key_data, NVDIMM_USER);
119 }
120
121 static int cxl_pmem_security_disable_master(struct nvdimm *nvdimm,
122                                             const struct nvdimm_key_data *key_data)
123 {
124         return __cxl_pmem_security_disable(nvdimm, key_data, NVDIMM_MASTER);
125 }
126
127 static int cxl_pmem_security_freeze(struct nvdimm *nvdimm)
128 {
129         struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
130         struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
131         struct cxl_dev_state *cxlds = cxlmd->cxlds;
132         struct cxl_mbox_cmd mbox_cmd = {
133                 .opcode = CXL_MBOX_OP_FREEZE_SECURITY,
134         };
135
136         return cxl_internal_send_cmd(cxlds, &mbox_cmd);
137 }
138
139 static int cxl_pmem_security_unlock(struct nvdimm *nvdimm,
140                                     const struct nvdimm_key_data *key_data)
141 {
142         struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
143         struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
144         struct cxl_dev_state *cxlds = cxlmd->cxlds;
145         u8 pass[NVDIMM_PASSPHRASE_LEN];
146         struct cxl_mbox_cmd mbox_cmd;
147         int rc;
148
149         memcpy(pass, key_data->data, NVDIMM_PASSPHRASE_LEN);
150         mbox_cmd = (struct cxl_mbox_cmd) {
151                 .opcode = CXL_MBOX_OP_UNLOCK,
152                 .size_in = NVDIMM_PASSPHRASE_LEN,
153                 .payload_in = pass,
154         };
155
156         rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
157         if (rc < 0)
158                 return rc;
159
160         return 0;
161 }
162
163 static int cxl_pmem_security_passphrase_erase(struct nvdimm *nvdimm,
164                                               const struct nvdimm_key_data *key,
165                                               enum nvdimm_passphrase_type ptype)
166 {
167         struct cxl_nvdimm *cxl_nvd = nvdimm_provider_data(nvdimm);
168         struct cxl_memdev *cxlmd = cxl_nvd->cxlmd;
169         struct cxl_dev_state *cxlds = cxlmd->cxlds;
170         struct cxl_mbox_cmd mbox_cmd;
171         struct cxl_pass_erase erase;
172         int rc;
173
174         erase = (struct cxl_pass_erase) {
175                 .type = ptype == NVDIMM_MASTER ? CXL_PMEM_SEC_PASS_MASTER :
176                                                  CXL_PMEM_SEC_PASS_USER,
177         };
178         memcpy(erase.pass, key->data, NVDIMM_PASSPHRASE_LEN);
179         mbox_cmd = (struct cxl_mbox_cmd) {
180                 .opcode = CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE,
181                 .size_in = sizeof(erase),
182                 .payload_in = &erase,
183         };
184
185         rc = cxl_internal_send_cmd(cxlds, &mbox_cmd);
186         if (rc < 0)
187                 return rc;
188
189         return 0;
190 }
191
192 static const struct nvdimm_security_ops __cxl_security_ops = {
193         .get_flags = cxl_pmem_get_security_flags,
194         .change_key = cxl_pmem_security_change_key,
195         .disable = cxl_pmem_security_disable,
196         .freeze = cxl_pmem_security_freeze,
197         .unlock = cxl_pmem_security_unlock,
198         .erase = cxl_pmem_security_passphrase_erase,
199         .disable_master = cxl_pmem_security_disable_master,
200 };
201
202 const struct nvdimm_security_ops *cxl_security_ops = &__cxl_security_ops;