1 /*
2 * Copyright (c) 2018 Intel Corporation.
3 * Copyright 2024 NXP
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <string.h>
9 #include <zephyr/types.h>
10 #include <zephyr/sys/__assert.h>
11 #include <zephyr/sys/util.h>
12 #include <zephyr/init.h>
13 #include <zephyr/storage/disk_access.h>
14 #include <errno.h>
15 #include <zephyr/device.h>
16
17 #define LOG_LEVEL CONFIG_DISK_LOG_LEVEL
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_REGISTER(disk);
20
21 /* list of mounted file systems */
22 static sys_dlist_t disk_access_list = SYS_DLIST_STATIC_INIT(&disk_access_list);
23
24 /* lock to protect storage layer registration */
25 static K_MUTEX_DEFINE(mutex);
26
disk_access_get_di(const char * name)27 struct disk_info *disk_access_get_di(const char *name)
28 {
29 struct disk_info *disk = NULL, *itr;
30 size_t name_len = strlen(name);
31 sys_dnode_t *node;
32
33 k_mutex_lock(&mutex, K_FOREVER);
34 SYS_DLIST_FOR_EACH_NODE(&disk_access_list, node) {
35 itr = CONTAINER_OF(node, struct disk_info, node);
36
37 /*
38 * Move to next node if mount point length is
39 * shorter than longest_match match or if path
40 * name is shorter than the mount point name.
41 */
42 if (strlen(itr->name) != name_len) {
43 continue;
44 }
45
46 /* Check for disk name match */
47 if (strncmp(name, itr->name, name_len) == 0) {
48 disk = itr;
49 break;
50 }
51 }
52 k_mutex_unlock(&mutex);
53
54 return disk;
55 }
56
disk_access_init(const char * pdrv)57 int disk_access_init(const char *pdrv)
58 {
59 struct disk_info *disk = disk_access_get_di(pdrv);
60 int rc = -EINVAL;
61
62 if ((disk != NULL) && (disk->refcnt == 0U)) {
63 /* Disk has not been initialized, start it */
64 if ((disk->ops != NULL) && (disk->ops->init != NULL)) {
65 rc = disk->ops->init(disk);
66 if (rc == 0) {
67 /* Increment reference count */
68 disk->refcnt++;
69 }
70 }
71 } else if ((disk != NULL) && (disk->refcnt < UINT16_MAX)) {
72 /* Disk reference count is nonzero, simply increment it */
73 disk->refcnt++;
74 rc = 0;
75 }
76
77 return rc;
78 }
79
disk_access_status(const char * pdrv)80 int disk_access_status(const char *pdrv)
81 {
82 struct disk_info *disk = disk_access_get_di(pdrv);
83 int rc = -EINVAL;
84
85 if ((disk != NULL) && (disk->ops != NULL) &&
86 (disk->ops->status != NULL)) {
87 rc = disk->ops->status(disk);
88 }
89
90 return rc;
91 }
92
disk_access_read(const char * pdrv,uint8_t * data_buf,uint32_t start_sector,uint32_t num_sector)93 int disk_access_read(const char *pdrv, uint8_t *data_buf,
94 uint32_t start_sector, uint32_t num_sector)
95 {
96 struct disk_info *disk = disk_access_get_di(pdrv);
97 int rc = -EINVAL;
98
99 if ((disk != NULL) && (disk->ops != NULL) &&
100 (disk->ops->read != NULL)) {
101 rc = disk->ops->read(disk, data_buf, start_sector, num_sector);
102 }
103
104 return rc;
105 }
106
disk_access_write(const char * pdrv,const uint8_t * data_buf,uint32_t start_sector,uint32_t num_sector)107 int disk_access_write(const char *pdrv, const uint8_t *data_buf,
108 uint32_t start_sector, uint32_t num_sector)
109 {
110 struct disk_info *disk = disk_access_get_di(pdrv);
111 int rc = -EINVAL;
112
113 if ((disk != NULL) && (disk->ops != NULL) &&
114 (disk->ops->write != NULL)) {
115 rc = disk->ops->write(disk, data_buf, start_sector, num_sector);
116 }
117
118 return rc;
119 }
120
disk_access_ioctl(const char * pdrv,uint8_t cmd,void * buf)121 int disk_access_ioctl(const char *pdrv, uint8_t cmd, void *buf)
122 {
123 struct disk_info *disk = disk_access_get_di(pdrv);
124 int rc = -EINVAL;
125
126 if ((disk != NULL) && (disk->ops != NULL) &&
127 (disk->ops->ioctl != NULL)) {
128 switch (cmd) {
129 case DISK_IOCTL_CTRL_INIT:
130 if (disk->refcnt == 0U) {
131 rc = disk->ops->ioctl(disk, cmd, buf);
132 if (rc == 0) {
133 disk->refcnt++;
134 }
135 } else if (disk->refcnt < UINT16_MAX) {
136 disk->refcnt++;
137 rc = 0;
138 } else {
139 LOG_ERR("Disk reference count at max value");
140 }
141 break;
142 case DISK_IOCTL_CTRL_DEINIT:
143 if ((buf != NULL) && (*((bool *)buf))) {
144 /* Force deinit disk */
145 disk->refcnt = 0U;
146 disk->ops->ioctl(disk, cmd, buf);
147 rc = 0;
148 } else if (disk->refcnt == 1U) {
149 rc = disk->ops->ioctl(disk, cmd, buf);
150 if (rc == 0) {
151 disk->refcnt--;
152 }
153 } else if (disk->refcnt > 0) {
154 disk->refcnt--;
155 rc = 0;
156 } else {
157 LOG_WRN("Disk is already deinitialized");
158 }
159 break;
160 default:
161 rc = disk->ops->ioctl(disk, cmd, buf);
162 }
163 }
164
165 return rc;
166 }
167
disk_access_register(struct disk_info * disk)168 int disk_access_register(struct disk_info *disk)
169 {
170 int rc = 0;
171
172 k_mutex_lock(&mutex, K_FOREVER);
173 if ((disk == NULL) || (disk->name == NULL)) {
174 LOG_ERR("invalid disk interface!!");
175 rc = -EINVAL;
176 goto reg_err;
177 }
178
179 if (disk_access_get_di(disk->name) != NULL) {
180 LOG_ERR("disk interface already registered!!");
181 rc = -EINVAL;
182 goto reg_err;
183 }
184
185 /* Initialize reference count to zero */
186 disk->refcnt = 0U;
187
188 /* append to the disk list */
189 sys_dlist_append(&disk_access_list, &disk->node);
190 LOG_DBG("disk interface(%s) registered", disk->name);
191 reg_err:
192 k_mutex_unlock(&mutex);
193 return rc;
194 }
195
disk_access_unregister(struct disk_info * disk)196 int disk_access_unregister(struct disk_info *disk)
197 {
198 int rc = 0;
199
200 k_mutex_lock(&mutex, K_FOREVER);
201 if ((disk == NULL) || (disk->name == NULL)) {
202 LOG_ERR("invalid disk interface!!");
203 rc = -EINVAL;
204 goto unreg_err;
205 }
206
207 if (disk_access_get_di(disk->name) == NULL) {
208 LOG_ERR("disk interface not registered!!");
209 rc = -EINVAL;
210 goto unreg_err;
211 }
212 /* remove disk node from the list */
213 sys_dlist_remove(&disk->node);
214 LOG_DBG("disk interface(%s) unregistered", disk->name);
215 unreg_err:
216 k_mutex_unlock(&mutex);
217 return rc;
218 }
219