1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2008-2011 Freescale Semiconductor, Inc.
4  */
5 
6 /* #define DEBUG */
7 
8 #include <asm/global_data.h>
9 
10 #include <command.h>
11 #include <env.h>
12 #include <env_internal.h>
13 #include <fdtdec.h>
14 #include <linux/stddef.h>
15 #include <malloc.h>
16 #include <memalign.h>
17 #include <part.h>
18 #include <search.h>
19 #include <scsi.h>
20 #include <errno.h>
21 #include <dm/ofnode.h>
22 
23 DECLARE_GLOBAL_DATA_PTR;
24 static env_t envbuf;
25 
26 struct env_scsi_info {
27 	struct blk_desc *blk;
28 	struct disk_partition part;
29 	int count;
30 };
31 
32 static struct env_scsi_info env_part;
33 
env_scsi_get_part(void)34 static inline struct env_scsi_info *env_scsi_get_part(void)
35 {
36 	struct env_scsi_info *ep = &env_part;
37 
38 	if (scsi_get_blk_by_uuid(CONFIG_SCSI_ENV_PART_UUID, &ep->blk, &ep->part))
39 		return NULL;
40 
41 	ep->count = CONFIG_ENV_SIZE / ep->part.blksz;
42 
43 	return ep;
44 }
45 
env_scsi_save(void)46 static int env_scsi_save(void)
47 {
48 	struct env_scsi_info *ep = env_scsi_get_part();
49 	int ret;
50 
51 	if (!ep)
52 		return -ENOENT;
53 
54 	ret = env_export(&envbuf);
55 	if (ret)
56 		return ret;
57 
58 	if (blk_dwrite(ep->blk, ep->part.start, ep->count, &envbuf) != ep->count)
59 		return -EIO;
60 
61 	return 0;
62 }
63 
env_scsi_erase(void)64 static int env_scsi_erase(void)
65 {
66 	struct env_scsi_info *ep = env_scsi_get_part();
67 
68 	if (!ep)
69 		return -ENOENT;
70 
71 	return (int)blk_derase(ep->blk, ep->part.start, ep->count);
72 }
73 
74 #if defined(ENV_IS_EMBEDDED)
env_scsi_load(void)75 static int env_scsi_load(void)
76 {
77 	return 0;
78 }
79 #else
env_scsi_load(void)80 static int env_scsi_load(void)
81 {
82 	struct env_scsi_info *ep = env_scsi_get_part();
83 	int ret;
84 
85 	if (!ep) {
86 		env_set_default(CONFIG_SCSI_ENV_PART_UUID " partition not found", 0);
87 		return -ENOENT;
88 	}
89 
90 	if (blk_dread(ep->blk, ep->part.start, ep->count, &envbuf) != ep->count) {
91 		env_set_default(CONFIG_SCSI_ENV_PART_UUID " partition read failed", 0);
92 		return -EIO;
93 	}
94 
95 	ret = env_import((char *)&envbuf, 1, H_EXTERNAL);
96 	if (ret) {
97 		debug("ENV import failed\n");
98 		env_set_default("Cannot load environment", 0);
99 	} else {
100 		gd->env_addr = (ulong)envbuf.data;
101 	}
102 
103 	return ret;
104 }
105 #endif
106 
107 U_BOOT_ENV_LOCATION(scsi) = {
108 	.location	= ENVL_SCSI,
109 	ENV_NAME("SCSI")
110 	.load		= env_scsi_load,
111 #if defined(CONFIG_CMD_SAVEENV) && !defined(CONFIG_XPL_BUILD)
112 	.save		= env_save_ptr(env_scsi_save),
113 	.erase		= ENV_ERASE_PTR(env_scsi_erase),
114 #endif
115 };
116