1 /*
2 * Copyright (c) 2021 NXP
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * WARNING: This test will overwrite data on any disk utilized. Do not run
9 * this test with an disk that has useful data
10 */
11
12 #include <zephyr/kernel.h>
13 #include <zephyr/ztest.h>
14 #include <zephyr/storage/disk_access.h>
15 #include <zephyr/device.h>
16
17 #if defined(CONFIG_DISK_DRIVER_SDMMC)
18 #define DISK_NAME CONFIG_SDMMC_VOLUME_NAME
19 #elif IS_ENABLED(CONFIG_DISK_DRIVER_MMC)
20 #define DISK_NAME CONFIG_MMC_VOLUME_NAME
21 #elif IS_ENABLED(CONFIG_DISK_DRIVER_RAM)
22 #define DISK_NAME "RAM"
23 #elif IS_ENABLED(CONFIG_NVME)
24 #define DISK_NAME "nvme0n0"
25 #else
26 #error "No disk device defined, is your board supported?"
27 #endif
28
29 /* Assume the largest sector we will encounter is 512 bytes */
30 #define SECTOR_SIZE 512
31
32 /* Sector counts to read */
33 #define SECTOR_COUNT1 8
34 #define SECTOR_COUNT2 1
35 #define SECTOR_COUNT3 29
36 #define SECTOR_COUNT4 31
37
38 #define OVERFLOW_CANARY 0xDE
39
40 static const char *disk_pdrv = DISK_NAME;
41 static uint32_t disk_sector_count;
42 static uint32_t disk_sector_size;
43
44 /* + 4 to make sure the second buffer is dword-aligned for NVME */
45 static uint8_t scratch_buf[2][SECTOR_COUNT4 * SECTOR_SIZE + 4];
46
47
48 /* Sets up test by initializing disk */
test_setup(void)49 static void test_setup(void)
50 {
51 int rc;
52 uint32_t cmd_buf;
53
54 rc = disk_access_init(disk_pdrv);
55 zassert_equal(rc, 0, "Disk access initialization failed");
56
57 rc = disk_access_status(disk_pdrv);
58 zassert_equal(rc, DISK_STATUS_OK, "Disk status is not OK");
59
60 rc = disk_access_ioctl(disk_pdrv, DISK_IOCTL_GET_SECTOR_COUNT, &cmd_buf);
61 zassert_equal(rc, 0, "Disk ioctl get sector count failed");
62
63 TC_PRINT("Disk reports %u sectors\n", cmd_buf);
64 disk_sector_count = cmd_buf;
65
66 rc = disk_access_ioctl(disk_pdrv, DISK_IOCTL_GET_SECTOR_SIZE, &cmd_buf);
67 zassert_equal(rc, 0, "Disk ioctl get sector size failed");
68 TC_PRINT("Disk reports sector size %u\n", cmd_buf);
69 disk_sector_size = cmd_buf;
70
71 /* We could allocate memory once we know the sector size, but instead
72 * just verify our assumed maximum size
73 */
74 zassert_true(cmd_buf <= SECTOR_SIZE,
75 "Test will fail, SECTOR_SIZE definition must be increased");
76 }
77
78 /* Reads sectors, verifying overflow does not occur */
read_sector(uint8_t * buf,uint32_t start,uint32_t num_sectors)79 static int read_sector(uint8_t *buf, uint32_t start, uint32_t num_sectors)
80 {
81 int rc;
82
83 /* Set up overflow canary */
84 buf[num_sectors * disk_sector_size] = OVERFLOW_CANARY;
85 rc = disk_access_read(disk_pdrv, buf, start, num_sectors);
86 /* Check canary */
87 zassert_equal(buf[num_sectors * disk_sector_size], OVERFLOW_CANARY,
88 "Read overflowed requested length");
89 return rc; /* Let calling function check return code */
90 }
91
92 /* Tests reading from a variety of sectors */
test_sector_read(uint8_t * buf,uint32_t num_sectors)93 static void test_sector_read(uint8_t *buf, uint32_t num_sectors)
94 {
95 int rc, sector;
96
97 TC_PRINT("Testing reads of %u sectors\n", num_sectors);
98 /* Read from disk sector 0*/
99 rc = read_sector(buf, 0, num_sectors);
100 zassert_equal(rc, 0, "Failed to read from sector zero");
101 /* Read from a sector in the "middle" of the disk */
102 if (disk_sector_count / 2 > num_sectors) {
103 sector = disk_sector_count / 2 - num_sectors;
104 } else {
105 sector = 0;
106 }
107
108 rc = read_sector(buf, sector, num_sectors);
109 zassert_equal(rc, 0, "Failed to read from mid disk sector");
110 /* Read from the last sector */
111 rc = read_sector(buf, disk_sector_count - 1, num_sectors);
112 if (num_sectors == 1) {
113 zassert_equal(rc, 0, "Failed to read from last sector");
114 } else {
115 zassert_not_equal(rc, 0, "Disk should fail to read out of sector bounds");
116 }
117 }
118
119 /* Write sector of disk, and check the data to ensure it is valid
120 * WARNING: this test is destructive- it will overwrite data on the disk!
121 */
write_sector_checked(uint8_t * wbuf,uint8_t * rbuf,uint32_t start,uint32_t num_sectors)122 static int write_sector_checked(uint8_t *wbuf, uint8_t *rbuf,
123 uint32_t start, uint32_t num_sectors)
124 {
125 int rc, i;
126
127 /* First, fill the write buffer with data */
128 for (i = 0; i < num_sectors * disk_sector_size; i++) {
129 wbuf[i] = (i & (~num_sectors));
130 }
131 /* Now write data to the sector */
132 rc = disk_access_write(disk_pdrv, wbuf, start, num_sectors);
133 if (rc) {
134 return rc; /* Let calling function handle disk error */
135 }
136 /* Read back the written data into another buffer */
137 memset(rbuf, 0, num_sectors * disk_sector_size);
138 rc = read_sector(rbuf, start, num_sectors);
139 if (rc) {
140 return rc;
141 }
142 /* Check the read data versus the written data */
143 zassert_mem_equal(wbuf, rbuf, num_sectors * disk_sector_size,
144 "Read data did not match data written to disk");
145 return rc;
146 }
147
148 /* Tests writing to a variety of sectors
149 * WARNING: this test is destructive- it will overwrite data on the disk!
150 */
test_sector_write(uint8_t * wbuf,uint8_t * rbuf,uint32_t num_sectors)151 static void test_sector_write(uint8_t *wbuf, uint8_t *rbuf, uint32_t num_sectors)
152 {
153 int rc, sector;
154
155 TC_PRINT("Testing writes of %u sectors\n", num_sectors);
156 /* Write to disk sector zero */
157 rc = write_sector_checked(wbuf, rbuf, 0, num_sectors);
158 zassert_equal(rc, 0, "Failed to write to sector zero");
159 /* Write to a sector in the "middle" of the disk */
160 if (disk_sector_count / 2 > num_sectors) {
161 sector = disk_sector_count / 2 - num_sectors;
162 } else {
163 sector = 0;
164 }
165
166 rc = write_sector_checked(wbuf, rbuf, sector, num_sectors);
167 zassert_equal(rc, 0, "Failed to write to mid disk sector");
168 /* Write to the last sector */
169 rc = write_sector_checked(wbuf, rbuf, disk_sector_count - 1, num_sectors);
170 if (num_sectors == 1) {
171 zassert_equal(rc, 0, "Failed to write to last sector");
172 } else {
173 zassert_not_equal(rc, 0, "Disk should fail to write out of sector bounds");
174 }
175 }
176
177 /* Test multiple reads in series, and reading from a variety of blocks */
ZTEST(disk_driver,test_read)178 ZTEST(disk_driver, test_read)
179 {
180 int rc, i;
181
182 /* Verify all 4 read sizes work */
183 test_sector_read(scratch_buf[0], SECTOR_COUNT1);
184 test_sector_read(scratch_buf[0], SECTOR_COUNT2);
185 test_sector_read(scratch_buf[0], SECTOR_COUNT3);
186 test_sector_read(scratch_buf[0], SECTOR_COUNT4);
187
188 /* Verify that reading from the same location returns to same data */
189 memset(scratch_buf[0], 0, SECTOR_COUNT1 * disk_sector_size);
190 rc = read_sector(scratch_buf[0], 0, SECTOR_COUNT1);
191 zassert_equal(rc, 0, "Failed to read from disk");
192 for (i = 0; i < 10; i++) {
193 /* Read from sector, and compare it to the first read */
194 memset(scratch_buf[1], 0xff, SECTOR_COUNT1 * disk_sector_size);
195 rc = read_sector(scratch_buf[1], 0, SECTOR_COUNT1);
196 zassert_equal(rc, 0, "Failed to read from disk at same sector location");
197 zassert_mem_equal(scratch_buf[1], scratch_buf[0],
198 SECTOR_COUNT1 * disk_sector_size,
199 "Multiple reads mismatch");
200 }
201 }
202
203 /* test writing data, and then verifying it was written correctly.
204 * WARNING: this test is destructive- it will overwrite data on the disk!
205 */
ZTEST(disk_driver,test_write)206 ZTEST(disk_driver, test_write)
207 {
208 int rc, i;
209
210 /* Verify all 4 sector write sizes work */
211 test_sector_write(scratch_buf[0], scratch_buf[1], SECTOR_COUNT1);
212 test_sector_write(scratch_buf[0], scratch_buf[1], SECTOR_COUNT2);
213 test_sector_write(scratch_buf[0], scratch_buf[1], SECTOR_COUNT3);
214 test_sector_write(scratch_buf[0], scratch_buf[1], SECTOR_COUNT4);
215
216 /* Verify that multiple writes to the same location work */
217 for (i = 0; i < 10; i++) {
218 /* Write to sector- helper function verifies written data is correct */
219 rc = write_sector_checked(scratch_buf[0], scratch_buf[1], 0, SECTOR_COUNT1);
220 zassert_equal(rc, 0, "Failed to write to disk at same sector location");
221 }
222 }
223
224
disk_driver_setup(void)225 static void *disk_driver_setup(void)
226 {
227 test_setup();
228
229 return NULL;
230 }
231
232 ZTEST_SUITE(disk_driver, NULL, disk_driver_setup, NULL, NULL, NULL);
233