[RAMEN9610-8702][COMMON] diskcipher: support f2fs
[GitHub/moto-9609/android_kernel_motorola_exynos9610.git] / drivers / scsi / ufs / ufs-exynos-fmp.c
1 /*
2 * Copyright (C) 2016 Samsung Electronics Co., Ltd.
3 * Author: Boojin Kim <boojin.kim@samsung.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
10
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <crypto/diskcipher.h>
14 #include <crypto/fmp.h>
15 #include "ufshcd.h"
16 #include "ufs-exynos.h"
17
18 /* smu functions */
19 #if defined(CONFIG_SCSI_UFS_EXYNOS_SMU)
20 static void exynos_ufs_smu_entry0_init(struct exynos_ufs *ufs)
21 {
22 writel(0x0, ufs->reg_ufsp + UFSPSBEGIN0);
23 writel(0xffffffff, ufs->reg_ufsp + UFSPSEND0);
24 writel(0xff, ufs->reg_ufsp + UFSPSLUN0);
25 writel(0xf1, ufs->reg_ufsp + UFSPSCTRL0);
26 }
27
28 int exynos_ufs_smu_init(struct exynos_ufs *ufs)
29 {
30 if (!ufs || (ufs->smu == SMU_ID_MAX)) {
31 exynos_ufs_smu_entry0_init(ufs);
32 return 0;
33 }
34
35 dev_info(ufs->dev, "%s with id:%d\n", __func__, ufs->smu);
36 return exynos_smu_init(ufs->smu, SMU_INIT);
37 }
38
39 int exynos_ufs_smu_resume(struct exynos_ufs *ufs)
40 {
41 int fmp_id;
42
43 if (!ufs)
44 return 0;
45
46 if (ufs->smu < SMU_ID_MAX)
47 fmp_id = ufs->smu;
48 else if (ufs->fmp < SMU_ID_MAX)
49 fmp_id = ufs->fmp;
50 else {
51 exynos_ufs_smu_entry0_init(ufs);
52 return 0;
53 }
54
55 dev_info(ufs->dev, "%s with id:%d\n", __func__, fmp_id);
56 return exynos_smu_resume(fmp_id);
57 }
58
59 int exynos_ufs_smu_abort(struct exynos_ufs *ufs)
60 {
61 if (!ufs || (ufs->smu == SMU_ID_MAX))
62 return 0;
63
64 dev_info(ufs->dev, "%s with id:%d\n", __func__, ufs->smu);
65 return exynos_smu_abort(ufs->smu, SMU_ABORT);
66 }
67 #endif
68 /* fmp functions */
69 #ifdef CONFIG_SCSI_UFS_EXYNOS_FMP
70 int exynos_ufs_fmp_sec_cfg(struct exynos_ufs *ufs)
71 {
72 if (!ufs || (ufs->fmp == SMU_ID_MAX))
73 return 0;
74
75 if (ufs->fmp != SMU_EMBEDDED)
76 dev_err(ufs->dev, "%s is fails id:%d\n",
77 __func__, ufs->fmp);
78
79
80 dev_info(ufs->dev, "%s with id:%d\n", __func__, ufs->fmp);
81 return exynos_fmp_sec_config(ufs->fmp);
82 }
83
84 static struct bio *get_bio(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
85 {
86 struct exynos_ufs *ufs;
87
88 if (!hba || !lrbp) {
89 pr_err("%s: Invalid MMC:%p data:%p\n", __func__, hba, lrbp);
90 return NULL;
91 }
92
93 ufs = dev_get_platdata(hba->dev);
94 if (ufs->fmp == SMU_ID_MAX)
95 return NULL;
96
97 if (!virt_addr_valid(lrbp->cmd)) {
98 dev_err(hba->dev, "Invalid cmd:%p\n", lrbp->cmd);
99 return NULL;
100 }
101
102 if (!virt_addr_valid(lrbp->cmd->request->bio)) {
103 if (lrbp->cmd->request->bio)
104 dev_err(hba->dev, "Invalid bio:%p\n", lrbp->cmd->request->bio);
105 return NULL;
106 }
107 else
108 return lrbp->cmd->request->bio;
109 }
110
111 int exynos_ufs_fmp_cfg(struct ufs_hba *hba,
112 struct ufshcd_lrb *lrbp,
113 struct scatterlist *sg,
114 uint32_t index, int sector_offset, int page_index)
115 {
116 struct fmp_request req;
117 struct crypto_diskcipher *dtfm;
118 u64 iv;
119 struct bio *bio = get_bio(hba, lrbp);
120
121 if (!bio)
122 return 0;
123
124 dtfm = crypto_diskcipher_get(bio);
125 if (unlikely(IS_ERR(dtfm))) {
126 pr_warn("%s: fails to get crypt\n", __func__);
127 return -EINVAL;
128 } else if (dtfm) {
129 #ifdef CONFIG_CRYPTO_DISKCIPHER_DUN
130 if (bio_dun(bio))
131 iv = bio_dun(bio) + page_index;
132 else
133 iv = bio->bi_iter.bi_sector + (sector_t) sector_offset;
134 #else
135 iv = bio->bi_iter.bi_sector + (sector_t) sector_offset;
136 #endif
137
138 req.table = (void *)&lrbp->ucd_prdt_ptr[index];
139 req.cmdq_enabled = 0;
140 req.iv = &iv;
141 req.ivsize = sizeof(iv);
142 #ifdef CONFIG_EXYNOS_FMP_FIPS
143 /* check fips flag. use fmp without diskcipher */
144 if (!dtfm->algo) {
145 if (exynos_fmp_crypt((void *)dtfm, &req))
146 pr_warn("%s: fails to test fips\n", __func__);
147 return 0;
148 }
149 #endif
150 if (crypto_diskcipher_set_crypt(dtfm, &req)) {
151 pr_warn("%s: fails to set crypt\n", __func__);
152 return -EINVAL;
153 }
154 return 0;
155 }
156
157 exynos_fmp_bypass(&lrbp->ucd_prdt_ptr[index], 0);
158 return 0;
159 }
160
161 int exynos_ufs_fmp_clear(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
162 {
163 int ret = 0;
164 int sg_segments, idx;
165 struct scatterlist *sg;
166 struct ufshcd_sg_entry *prd_table;
167 struct crypto_diskcipher *dtfm;
168 struct fmp_crypto_info *ci;
169 struct fmp_request req;
170 struct bio *bio = get_bio(hba, lrbp);
171
172 if (!bio)
173 return 0;
174
175 sg_segments = scsi_sg_count(lrbp->cmd);
176 if (!sg_segments)
177 return 0;
178
179 dtfm = crypto_diskcipher_get(bio);
180 if (dtfm) {
181 #ifdef CONFIG_EXYNOS_FMP_FIPS
182 /* check fips flag. use fmp without diskcipher */
183 if (!dtfm->algo) {
184 prd_table =
185 (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr;
186 scsi_for_each_sg(lrbp->cmd, sg, sg_segments, idx) {
187 req.table = (void *)&prd_table[idx];
188 ret = exynos_fmp_clear((void *)dtfm, &req);
189 if (ret) {
190 pr_warn("%s: fails to clear fips\n",
191 __func__);
192 break;
193 }
194 }
195 return 0;
196 }
197 #endif
198 /* clear key on descrptor */
199 ci = crypto_tfm_ctx(crypto_diskcipher_tfm(dtfm));
200 if (ci && (ci->enc_mode == EXYNOS_FMP_FILE_ENC)) {
201 prd_table =
202 (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr;
203 scsi_for_each_sg(lrbp->cmd, sg, sg_segments, idx) {
204 req.table = (void *)&prd_table[idx];
205 ret = crypto_diskcipher_clear_crypt(dtfm, &req);
206 if (ret) {
207 pr_err("%s: fail to clear desc (%d)\n",
208 __func__, ret);
209 break;
210 }
211 }
212 }
213 }
214 return ret;
215 }
216 #endif