blob: 95aac664442ed940a28f83f017c74e88f960bb0a [file] [log] [blame]
Rahul Shaharebfb30f92019-04-17 09:31:35 +05301/* Copyright (c) 2015,2019 The Linux Foundation. All rights reserved.
Channagoud Kadabi723f6792015-01-29 13:26:06 -08002 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <ufs.h>
30#include <ucs.h>
31#include <upiu.h>
32#include <rpmb.h>
33#include <debug.h>
34#include <stdlib.h>
35#include <string.h>
36#include <endian.h>
37#include <arch/defines.h>
38
Sridhar Parasuramc97e0542015-06-26 16:14:58 -070039static const char *str_err[] =
40{
41 "Operation Ok",
42 "General failure",
43 "Authentication error (MAC comparison not matching, MAC calculation failure)",
44 "Counter failure (counters not matching in comparison, counter incrementing failure)",
45 "Address failure (address out of range, wrong address alignment)",
46 "Write failure (data/counter/result write failure)",
47 "Read failure (data/counter/result read failure)",
48 "Authentication Key not yet programmed",
49};
50
Channagoud Kadabi723f6792015-01-29 13:26:06 -080051static struct rpmb_frame read_result_reg =
52{
53 .requestresponse[1] = READ_RESULT_FLAG,
54};
55
56int rpmb_read_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t *resp_buf, uint32_t *resp_len)
57{
58 // validate input parameters
59 ASSERT(req_buf);
60 ASSERT(resp_buf);
61 ASSERT(resp_len);
62
63 STACKBUF_DMA_ALIGN(cdb, sizeof(struct scsi_sec_protocol_cdb));
64 struct scsi_req_build_type req_upiu;
65 struct scsi_sec_protocol_cdb *cdb_out_param, *cdb_in_param;
66 uint32_t blks_remaining;
67 uint32_t blks_to_transfer;
68 uint64_t bytes_to_transfer;
69 uint64_t max_size;
70 blks_remaining = blk_cnt;
71 blks_to_transfer = blks_remaining;
72 bytes_to_transfer = blks_to_transfer * RPMB_FRAME_SIZE;
73
74#ifdef DEBUG_RPMB
75 dump_rpmb_frame((uint8_t *)req_buf, "request");
76#endif
77
78 // check if total bytes to transfer exceed max supported size
79 max_size = dev->rpmb_rw_size * RPMB_FRAME_SIZE * blk_cnt;
80 if (bytes_to_transfer > max_size)
81 {
82 dprintf(CRITICAL, "RPMB request transfer size %llu greater than max transfer size %llu\n", bytes_to_transfer, max_size);
83 return -UFS_FAILURE;
84 }
85#ifdef DEBUG_RPMB
Sridhar Parasuramc97e0542015-06-26 16:14:58 -070086 dprintf(INFO, "rpmb_read: req_buf: 0x%x blk_count: 0x%x\n", *req_buf, blk_cnt);
87 dprintf(INFO, "rpmb_read: bytes_to_transfer: 0x%llx blks_to_transfer: 0x%x\n",
Channagoud Kadabi723f6792015-01-29 13:26:06 -080088 bytes_to_transfer, blks_to_transfer);
89#endif
90 // send the request
91 cdb_out_param = (struct scsi_sec_protocol_cdb*) cdb;
92 memset(cdb_out_param, 0, sizeof(struct scsi_sec_protocol_cdb));
93
94 cdb_out_param->opcode = SCSI_CMD_SECPROT_OUT;
95 cdb_out_param->cdb1 = SCSI_SEC_PROT;
96 cdb_out_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
Channagoud Kadabi6a4331c2015-11-24 10:55:47 -080097 cdb_out_param->alloc_tlen = BE32(RPMB_FRAME_SIZE);
Channagoud Kadabi723f6792015-01-29 13:26:06 -080098
99 // Flush CDB to memory
100 dsb();
101 arch_clean_invalidate_cache_range((addr_t) cdb_out_param, sizeof(struct scsi_sec_protocol_cdb));
102
103 memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
104
105 req_upiu.cdb = (addr_t) cdb_out_param;
106 req_upiu.data_buffer_addr = (addr_t) req_buf;
Rahul Shaharebfb30f92019-04-17 09:31:35 +0530107 req_upiu.data_len = RPMB_FRAME_SIZE;
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800108 req_upiu.flags = UPIU_FLAGS_WRITE;
109 req_upiu.lun = UFS_WLUN_RPMB;
110 req_upiu.dd = UTRD_TARGET_TO_SYSTEM;
111
112#ifdef DEBUG_RPMB
113 dprintf(INFO, "Sending RPMB Read request\n");
114#endif
115 if (ucs_do_scsi_cmd(dev, &req_upiu))
116 {
117 dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
118 return -UFS_FAILURE;
119 }
120#ifdef DEBUG_RPMB
121 dprintf(INFO, "Sending RPMB Read request complete\n");
122#endif
123 // read the response
124 cdb_in_param = (struct scsi_sec_protocol_cdb*) cdb;
125 memset(cdb_in_param, 0, sizeof(struct scsi_sec_protocol_cdb));
126
127 cdb_in_param->opcode = SCSI_CMD_SECPROT_IN;
128 cdb_in_param->cdb1 = SCSI_SEC_PROT;
129 cdb_in_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
130 cdb_in_param->alloc_tlen = BE32(bytes_to_transfer);
131
132 // Flush CDB to memory
133 dsb();
134 arch_clean_invalidate_cache_range((addr_t) cdb_in_param, sizeof(struct scsi_sec_protocol_cdb));
135
136 memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
137
138 req_upiu.cdb = (addr_t) cdb_in_param;
139 req_upiu.data_buffer_addr = (addr_t) resp_buf;
140 req_upiu.data_len = bytes_to_transfer;
141 req_upiu.flags = UPIU_FLAGS_READ;
142 req_upiu.lun = UFS_WLUN_RPMB;
143 req_upiu.dd = UTRD_SYSTEM_TO_TARGET;
144
145#ifdef DEBUG_RPMB
146 dprintf(INFO, "Sending RPMB Read response\n");
147#endif
148 if (ucs_do_scsi_cmd(dev, &req_upiu))
149 {
150 dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
151 return -UFS_FAILURE;
152 }
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700153 // invalidate response buffer before reading response as this is part of request
154 // buffer overwritten
155 arch_clean_invalidate_cache_range((addr_t) resp_buf, RPMB_FRAME_SIZE);
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800156#ifdef DEBUG_RPMB
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700157 dprintf(INFO, "Sending RPMB Read response complete\n");
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800158 dump_rpmb_frame((uint8_t *)resp_buf, "response");
159#endif
160 *resp_len = bytes_to_transfer;
161 return UFS_SUCCESS;
162}
163
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700164int rpmb_write_ufs(struct ufs_dev *dev, uint32_t *req_buf, uint32_t blk_cnt, uint32_t rel_wr_count, uint32_t *resp_buf, uint32_t *resp_len)
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800165{
166 // validate input parameters
167 ASSERT(req_buf);
168 ASSERT(resp_buf);
169 ASSERT(resp_len);
170
171 STACKBUF_DMA_ALIGN(cdb, sizeof(struct scsi_sec_protocol_cdb));
172 struct scsi_req_build_type req_upiu;
173 struct scsi_sec_protocol_cdb *cdb_out_param, *cdb_in_param;
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700174 struct rpmb_frame *result = (struct rpmb_frame *)resp_buf;
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800175 uint32_t blks_remaining;
176 uint32_t blks_to_transfer;
177 uint64_t bytes_to_transfer;
178 uint64_t max_size;
179 uint32_t result_frame_bytes = RPMB_FRAME_SIZE;
180 uint32_t i;
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700181 uint32_t num_trans;
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800182
183 blks_remaining = blk_cnt;
184 blks_to_transfer = blks_remaining;
185 bytes_to_transfer = blks_to_transfer * RPMB_FRAME_SIZE;
186
187 // check if total bytes to transfer exceed max supported size
188 max_size = dev->rpmb_rw_size * RPMB_FRAME_SIZE * blk_cnt;
189 if (bytes_to_transfer > max_size)
190 {
191 dprintf(CRITICAL, "RPMB request transfer size %llu greater than max transfer size %llu\n", bytes_to_transfer, max_size);
192 return -UFS_FAILURE;
193 }
194#ifdef DEBUG_RPMB
195 dprintf(INFO, "%s: req_buf: 0x%x blk_count: 0x%x\n", __func__,*req_buf, blk_cnt);
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700196 dprintf(INFO, "%s: bytes_to_transfer: 0x%llx blks_to_transfer: 0x%x\n", __func__, bytes_to_transfer, blk_cnt);
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800197#endif
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700198 if (bytes_to_transfer <= (rel_wr_count * RPMB_FRAME_SIZE))
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800199 {
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700200 num_trans = 1;
201 }
202 else
203 {
204 // send uptop rel_wr_count number of frames in one shot + anything pending
205 num_trans = blk_cnt/rel_wr_count;
206 if (num_trans % rel_wr_count) // if anymore frames still pending
207 num_trans++;
208 }
209 for (i = 0; i < num_trans; i++)
210 {
211 if ((num_trans - i) == 1) // last loop or one and only loop
212 {
213 // last loop will contain a max of rel_wr_count number of frames or less
214 bytes_to_transfer = RPMB_FRAME_SIZE * blks_remaining;
215 }
216 else
217 {
218 bytes_to_transfer = RPMB_FRAME_SIZE * rel_wr_count;
219 }
220
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800221 // send the request
222 cdb_out_param = (struct scsi_sec_protocol_cdb*) cdb;
223 memset(cdb_out_param, 0, sizeof(struct scsi_sec_protocol_cdb));
224
225 cdb_out_param->opcode = SCSI_CMD_SECPROT_OUT;
226 cdb_out_param->cdb1 = SCSI_SEC_PROT;
227 cdb_out_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700228 cdb_out_param->alloc_tlen = BE32(bytes_to_transfer);
229
230 // Flush CDB to memory
231 dsb();
232 arch_clean_invalidate_cache_range((addr_t) cdb_out_param, sizeof(struct scsi_sec_protocol_cdb));
233
234 memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
235
236 req_upiu.cdb = (addr_t) cdb_out_param;
237 req_upiu.data_buffer_addr = (addr_t) req_buf;
238 req_upiu.data_len = bytes_to_transfer;
239 req_upiu.flags = UPIU_FLAGS_WRITE;
240 req_upiu.lun = UFS_WLUN_RPMB;
241 req_upiu.dd = UTRD_TARGET_TO_SYSTEM;
242
243#ifdef DEBUG_RPMB
244 dprintf(INFO, "Sending RPMB write request: Start\n");
245 for(uint8_t j = 0; j < (bytes_to_transfer/RPMB_FRAME_SIZE); j++)
246 {
247 dprintf(INFO, "request buffer address: %p\n", (req_buf + (j * RPMB_FRAME_SIZE)));
248 dump_rpmb_frame((uint8_t *)req_buf + (j * RPMB_FRAME_SIZE), "request");
249 }
250#endif
251 if (ucs_do_scsi_cmd(dev, &req_upiu))
252 {
253 dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
254 return -UFS_FAILURE;
255 }
256#ifdef DEBUG_RPMB
257 dprintf(INFO, "Sending RPMB write request: Done\n");
258#endif
259 // Result Read
260 cdb_out_param = (struct scsi_sec_protocol_cdb*) cdb;
261 memset(cdb_out_param, 0, sizeof(struct scsi_sec_protocol_cdb));
262
263 cdb_out_param->opcode = SCSI_CMD_SECPROT_OUT;
264 cdb_out_param->cdb1 = SCSI_SEC_PROT;
265 cdb_out_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800266 cdb_out_param->alloc_tlen = BE32(RPMB_FRAME_SIZE);
267
268 // Flush CDB to memory
269 dsb();
270 arch_clean_invalidate_cache_range((addr_t) cdb_out_param, sizeof(struct scsi_sec_protocol_cdb));
271
272 memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
273
274 req_upiu.cdb = (addr_t) cdb_out_param;
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800275 req_upiu.data_buffer_addr = (addr_t) &read_result_reg ;
276 req_upiu.data_len = result_frame_bytes;
277 req_upiu.flags = UPIU_FLAGS_WRITE;
278 req_upiu.lun = UFS_WLUN_RPMB;
279 req_upiu.dd = UTRD_TARGET_TO_SYSTEM;
280
281#ifdef DEBUG_RPMB
282 dprintf(INFO, "Sending RPMB Result Read Register: Start \n");
283#endif
284 if (ucs_do_scsi_cmd(dev, &req_upiu))
285 {
286 dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
287 return -UFS_FAILURE;
288 }
289#ifdef DEBUG_RPMB
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700290 dprintf(INFO, "Sending RPMB Result Read Register: Done\n");
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800291#endif
292
293 // Retrieve verification result
294 cdb_in_param = (struct scsi_sec_protocol_cdb*) cdb;
295 memset(cdb_in_param, 0, sizeof(struct scsi_sec_protocol_cdb));
296
297 cdb_in_param->opcode = SCSI_CMD_SECPROT_IN;
298 cdb_in_param->cdb1 = SCSI_SEC_PROT;
299 cdb_in_param->sec_protocol_specific = BE16(SCSI_SEC_UFS_PROT_ID);
300 cdb_in_param->alloc_tlen = BE32(RPMB_FRAME_SIZE);
301
302 // Flush CDB to memory
303 dsb();
304 arch_clean_invalidate_cache_range((addr_t) cdb_in_param, sizeof(struct scsi_sec_protocol_cdb));
305
306 memset(&req_upiu, 0, sizeof(struct scsi_req_build_type));
307
308 req_upiu.cdb = (addr_t) cdb_in_param;
309 req_upiu.data_buffer_addr = (addr_t) resp_buf;
310 req_upiu.data_len = result_frame_bytes;
311 req_upiu.flags = UPIU_FLAGS_READ;
312 req_upiu.lun = UFS_WLUN_RPMB;
313 req_upiu.dd = UTRD_SYSTEM_TO_TARGET;
314
315#ifdef DEBUG_RPMB
316 dprintf(INFO, "Sending RPMB Response for Result Read Register : Start\n");
317#endif
318 if (ucs_do_scsi_cmd(dev, &req_upiu))
319 {
320 dprintf(CRITICAL, "%s:%d ucs_do_scsi_rpmb_read: failed\n", __func__, __LINE__);
321 return -UFS_FAILURE;
322 }
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700323 // invalidate response buffer before reading response as this is part of request
324 // buffer overwritten
325 arch_clean_invalidate_cache_range((addr_t) resp_buf, result_frame_bytes);
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800326#ifdef DEBUG_RPMB
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700327 dprintf(INFO, "Sending RPMB Response for Result Read Register: Done\n");
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800328 dump_rpmb_frame((uint8_t *)resp_buf, "response");
329#endif
330
Sridhar Parasuramc97e0542015-06-26 16:14:58 -0700331 if (result->result[0] == 0x80)
332 {
333 dprintf(CRITICAL, "Max write counter reached: \n");
334 break;
335 }
336
337 if (result->result[1])
338 {
339 dprintf(CRITICAL, "UFS RPMB write error: %s\n", str_err[result->result[1]]);
340 break;
341 }
342 if ((num_trans - i) == 1)
343 continue; // last frame no need to increment
344 else
345 {
346 req_buf = (uint32_t*) ((uint8_t*)req_buf + (RPMB_BLK_SIZE * rel_wr_count));
347 // If more than 1 transaction, then until the last loop, we will be transfering
348 // rel_wr_count number of half sections in one transaction
349 blks_remaining = blks_remaining - rel_wr_count;
350 }
Channagoud Kadabi723f6792015-01-29 13:26:06 -0800351 }
352
353 *resp_len = RPMB_MIN_BLK_CNT * RPMB_BLK_SIZE;
354
355 return 0;
356}