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