1433d6423SLionel Sambuc /* Block Device Driver Test driver, by D.C. van Moolenbroek */
2433d6423SLionel Sambuc #include <stdlib.h>
3433d6423SLionel Sambuc #include <stdarg.h>
4433d6423SLionel Sambuc #include <minix/blockdriver.h>
5433d6423SLionel Sambuc #include <minix/drvlib.h>
6433d6423SLionel Sambuc #include <minix/ds.h>
7433d6423SLionel Sambuc #include <minix/optset.h>
8433d6423SLionel Sambuc #include <sys/ioc_disk.h>
9433d6423SLionel Sambuc #include <sys/mman.h>
10433d6423SLionel Sambuc #include <assert.h>
11433d6423SLionel Sambuc
12433d6423SLionel Sambuc enum {
13433d6423SLionel Sambuc RESULT_OK, /* exactly as expected */
14433d6423SLionel Sambuc RESULT_DEATH, /* driver died */
15433d6423SLionel Sambuc RESULT_COMMFAIL, /* communication failed */
16433d6423SLionel Sambuc RESULT_BADTYPE, /* bad type in message */
17433d6423SLionel Sambuc RESULT_BADID, /* bad request ID in message */
18433d6423SLionel Sambuc RESULT_BADSTATUS, /* bad/unexpected status in message */
19433d6423SLionel Sambuc RESULT_TRUNC, /* request truncated unexpectedly */
20433d6423SLionel Sambuc RESULT_CORRUPT, /* buffer touched erroneously */
21433d6423SLionel Sambuc RESULT_MISSING, /* buffer left untouched erroneously */
22433d6423SLionel Sambuc RESULT_OVERFLOW, /* area around buffer touched */
23433d6423SLionel Sambuc RESULT_BADVALUE /* bad/unexpected return value */
24433d6423SLionel Sambuc };
25433d6423SLionel Sambuc
26433d6423SLionel Sambuc typedef struct {
27433d6423SLionel Sambuc int type;
28433d6423SLionel Sambuc ssize_t value;
29433d6423SLionel Sambuc } result_t;
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc static char driver_label[32] = ""; /* driver DS label */
32433d6423SLionel Sambuc static devminor_t driver_minor = -1; /* driver's partition minor to use */
33433d6423SLionel Sambuc static endpoint_t driver_endpt; /* driver endpoint */
34433d6423SLionel Sambuc
35433d6423SLionel Sambuc static int may_write = FALSE; /* may we write to the device? */
36433d6423SLionel Sambuc static int sector_size = 512; /* size of a single disk sector */
37433d6423SLionel Sambuc static int min_read = 512; /* minimum total size of read req */
38433d6423SLionel Sambuc static int min_write = 0; /* minimum total size of write req */
39433d6423SLionel Sambuc static int element_size = 512; /* minimum I/O vector element size */
40433d6423SLionel Sambuc static int max_size = 131072; /* maximum total size of any req */
41433d6423SLionel Sambuc /* Note that we do not test exceeding the max_size limit, so it is safe to set
42433d6423SLionel Sambuc * it to a value lower than the driver supports.
43433d6423SLionel Sambuc */
44433d6423SLionel Sambuc
45433d6423SLionel Sambuc /* These settings are used for automated test runs. */
46433d6423SLionel Sambuc static int contig = TRUE; /* allocate contiguous DMA memory? */
47433d6423SLionel Sambuc static int silent = FALSE; /* do not produce console output? */
48433d6423SLionel Sambuc
49433d6423SLionel Sambuc static struct part_geom part; /* base and size of target partition */
50433d6423SLionel Sambuc
51433d6423SLionel Sambuc #define NR_OPENED 10 /* maximum number of opened devices */
52433d6423SLionel Sambuc static dev_t opened[NR_OPENED]; /* list of currently opened devices */
53433d6423SLionel Sambuc static int nr_opened = 0; /* current number of opened devices */
54433d6423SLionel Sambuc
55433d6423SLionel Sambuc static int total_tests = 0; /* total number of tests performed */
56433d6423SLionel Sambuc static int failed_tests = 0; /* number of tests that failed */
57433d6423SLionel Sambuc static int failed_groups = 0; /* nr of groups that had failures */
58433d6423SLionel Sambuc static int group_failure; /* has this group had a failure yet? */
59433d6423SLionel Sambuc static int driver_deaths = 0; /* number of restarts that we saw */
60433d6423SLionel Sambuc
61433d6423SLionel Sambuc /* Options supported by this driver. */
62433d6423SLionel Sambuc static struct optset optset_table[] = {
63433d6423SLionel Sambuc { "label", OPT_STRING, driver_label, sizeof(driver_label) },
64433d6423SLionel Sambuc { "minor", OPT_INT, &driver_minor, 10 },
65433d6423SLionel Sambuc { "rw", OPT_BOOL, &may_write, TRUE },
66433d6423SLionel Sambuc { "ro", OPT_BOOL, &may_write, FALSE },
67433d6423SLionel Sambuc { "sector", OPT_INT, §or_size, 10 },
68433d6423SLionel Sambuc { "element", OPT_INT, &element_size, 10 },
69433d6423SLionel Sambuc { "min_read", OPT_INT, &min_read, 10 },
70433d6423SLionel Sambuc { "min_write", OPT_INT, &min_write, 10 },
71433d6423SLionel Sambuc { "max", OPT_INT, &max_size, 10 },
72433d6423SLionel Sambuc { "nocontig", OPT_BOOL, &contig, FALSE },
73433d6423SLionel Sambuc { "silent", OPT_BOOL, &silent, TRUE },
74433d6423SLionel Sambuc { NULL, 0, NULL, 0 }
75433d6423SLionel Sambuc };
76433d6423SLionel Sambuc
output(char * fmt,...)77433d6423SLionel Sambuc static void output(char *fmt, ...)
78433d6423SLionel Sambuc {
79433d6423SLionel Sambuc /* Print debugging information, unless configured to be silent.
80433d6423SLionel Sambuc */
81433d6423SLionel Sambuc va_list argp;
82433d6423SLionel Sambuc
83433d6423SLionel Sambuc if (silent)
84433d6423SLionel Sambuc return;
85433d6423SLionel Sambuc
86433d6423SLionel Sambuc va_start(argp, fmt);
87433d6423SLionel Sambuc
88433d6423SLionel Sambuc vprintf(fmt, argp);
89433d6423SLionel Sambuc
90433d6423SLionel Sambuc va_end(argp);
91433d6423SLionel Sambuc }
92433d6423SLionel Sambuc
alloc_dma_memory(size_t size)93433d6423SLionel Sambuc static void *alloc_dma_memory(size_t size)
94433d6423SLionel Sambuc {
95433d6423SLionel Sambuc /* Allocate memory that may be used for direct DMA. For most drivers,
96433d6423SLionel Sambuc * this means that the memory has to be physically contiguous. For some
97433d6423SLionel Sambuc * drivers (e.g. VND) we allow non-contiguous allocation, because VM is
98433d6423SLionel Sambuc * currently flaky and does not always manage to provide contiguous
99433d6423SLionel Sambuc * memory even when it should, thus causing needless test failures.
100433d6423SLionel Sambuc */
101433d6423SLionel Sambuc void *ptr;
102433d6423SLionel Sambuc
103433d6423SLionel Sambuc if (contig)
104433d6423SLionel Sambuc ptr = alloc_contig(size, 0, NULL);
105433d6423SLionel Sambuc else
106433d6423SLionel Sambuc ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
107433d6423SLionel Sambuc MAP_PREALLOC | MAP_ANON, -1, 0);
108433d6423SLionel Sambuc
109433d6423SLionel Sambuc if (ptr == MAP_FAILED)
1103c8950ccSBen Gras panic("unable to allocate %zu bytes of memory", size);
111433d6423SLionel Sambuc
112433d6423SLionel Sambuc return ptr;
113433d6423SLionel Sambuc }
114433d6423SLionel Sambuc
free_dma_memory(void * ptr,size_t size)115433d6423SLionel Sambuc static void free_dma_memory(void *ptr, size_t size)
116433d6423SLionel Sambuc {
117433d6423SLionel Sambuc /* Free memory previously allocated for direct DMA. */
118433d6423SLionel Sambuc if (contig)
119433d6423SLionel Sambuc free_contig(ptr, size);
120433d6423SLionel Sambuc else
121433d6423SLionel Sambuc munmap(ptr, size);
122433d6423SLionel Sambuc }
123433d6423SLionel Sambuc
set_result(result_t * res,int type,ssize_t value)124433d6423SLionel Sambuc static int set_result(result_t *res, int type, ssize_t value)
125433d6423SLionel Sambuc {
126433d6423SLionel Sambuc /* Set the result to the given result type and with the given optional
127433d6423SLionel Sambuc * extra value. Return the type.
128433d6423SLionel Sambuc */
129433d6423SLionel Sambuc res->type = type;
130433d6423SLionel Sambuc res->value = value;
131433d6423SLionel Sambuc
132433d6423SLionel Sambuc return type;
133433d6423SLionel Sambuc }
134433d6423SLionel Sambuc
accept_result(result_t * res,int type,ssize_t value)135433d6423SLionel Sambuc static int accept_result(result_t *res, int type, ssize_t value)
136433d6423SLionel Sambuc {
137433d6423SLionel Sambuc /* If the result is of the given type and value, reset it to a success
138433d6423SLionel Sambuc * result. This allows for a logical OR on error codes. Return whether
139433d6423SLionel Sambuc * the result was indeed reset.
140433d6423SLionel Sambuc */
141433d6423SLionel Sambuc
142433d6423SLionel Sambuc if (res->type == type && res->value == value) {
143433d6423SLionel Sambuc set_result(res, RESULT_OK, 0);
144433d6423SLionel Sambuc
145433d6423SLionel Sambuc return TRUE;
146433d6423SLionel Sambuc }
147433d6423SLionel Sambuc
148433d6423SLionel Sambuc return FALSE;
149433d6423SLionel Sambuc }
150433d6423SLionel Sambuc
got_result(result_t * res,char * desc)151433d6423SLionel Sambuc static void got_result(result_t *res, char *desc)
152433d6423SLionel Sambuc {
153433d6423SLionel Sambuc /* Process the result of a test. Keep statistics.
154433d6423SLionel Sambuc */
155433d6423SLionel Sambuc static int i = 0;
156433d6423SLionel Sambuc
157433d6423SLionel Sambuc total_tests++;
158433d6423SLionel Sambuc if (res->type != RESULT_OK) {
159433d6423SLionel Sambuc failed_tests++;
160433d6423SLionel Sambuc
161433d6423SLionel Sambuc if (group_failure == FALSE) {
162433d6423SLionel Sambuc failed_groups++;
163433d6423SLionel Sambuc group_failure = TRUE;
164433d6423SLionel Sambuc }
165433d6423SLionel Sambuc }
166433d6423SLionel Sambuc
167433d6423SLionel Sambuc output("#%02d: %-38s\t[%s]\n", ++i, desc,
168433d6423SLionel Sambuc (res->type == RESULT_OK) ? "PASS" : "FAIL");
169433d6423SLionel Sambuc
170433d6423SLionel Sambuc switch (res->type) {
171433d6423SLionel Sambuc case RESULT_DEATH:
172433d6423SLionel Sambuc output("- driver died\n");
173433d6423SLionel Sambuc break;
174433d6423SLionel Sambuc case RESULT_COMMFAIL:
175433d6423SLionel Sambuc output("- communication failed; ipc_sendrec returned %d\n",
176433d6423SLionel Sambuc res->value);
177433d6423SLionel Sambuc break;
178433d6423SLionel Sambuc case RESULT_BADTYPE:
179433d6423SLionel Sambuc output("- bad type %d in reply message\n", res->value);
180433d6423SLionel Sambuc break;
181433d6423SLionel Sambuc case RESULT_BADID:
182433d6423SLionel Sambuc output("- mismatched ID %d in reply message\n", res->value);
183433d6423SLionel Sambuc break;
184433d6423SLionel Sambuc case RESULT_BADSTATUS:
185433d6423SLionel Sambuc output("- bad or unexpected status %d in reply message\n",
186433d6423SLionel Sambuc res->value);
187433d6423SLionel Sambuc break;
188433d6423SLionel Sambuc case RESULT_TRUNC:
189433d6423SLionel Sambuc output("- result size not as expected (%u bytes left)\n",
190433d6423SLionel Sambuc res->value);
191433d6423SLionel Sambuc break;
192433d6423SLionel Sambuc case RESULT_CORRUPT:
193433d6423SLionel Sambuc output("- buffer has been modified erroneously\n");
194433d6423SLionel Sambuc break;
195433d6423SLionel Sambuc case RESULT_MISSING:
196433d6423SLionel Sambuc output("- buffer has been left untouched erroneously\n");
197433d6423SLionel Sambuc break;
198433d6423SLionel Sambuc case RESULT_OVERFLOW:
199433d6423SLionel Sambuc output("- area around target buffer modified\n");
200433d6423SLionel Sambuc break;
201433d6423SLionel Sambuc case RESULT_BADVALUE:
202433d6423SLionel Sambuc output("- bad or unexpected return value %d from call\n",
203433d6423SLionel Sambuc res->value);
204433d6423SLionel Sambuc break;
205433d6423SLionel Sambuc }
206433d6423SLionel Sambuc }
207433d6423SLionel Sambuc
test_group(char * name,int exec)208433d6423SLionel Sambuc static void test_group(char *name, int exec)
209433d6423SLionel Sambuc {
210433d6423SLionel Sambuc /* Start a new group of tests.
211433d6423SLionel Sambuc */
212433d6423SLionel Sambuc
213433d6423SLionel Sambuc output("Test group: %s%s\n", name, exec ? "" : " (skipping)");
214433d6423SLionel Sambuc
215433d6423SLionel Sambuc group_failure = FALSE;
216433d6423SLionel Sambuc }
217433d6423SLionel Sambuc
reopen_device(dev_t minor)218433d6423SLionel Sambuc static void reopen_device(dev_t minor)
219433d6423SLionel Sambuc {
220433d6423SLionel Sambuc /* Reopen a device after we were notified that the driver has died.
221433d6423SLionel Sambuc * Explicitly ignore any errors here; this is a feeble attempt to get
222433d6423SLionel Sambuc * ourselves back into business again.
223433d6423SLionel Sambuc */
224433d6423SLionel Sambuc message m;
225433d6423SLionel Sambuc
226433d6423SLionel Sambuc memset(&m, 0, sizeof(m));
227433d6423SLionel Sambuc m.m_type = BDEV_OPEN;
228433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.minor = minor;
229433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.access = (may_write) ? (BDEV_R_BIT | BDEV_W_BIT) : BDEV_R_BIT;
230433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.id = 0;
231433d6423SLionel Sambuc
232433d6423SLionel Sambuc (void) ipc_sendrec(driver_endpt, &m);
233433d6423SLionel Sambuc }
234433d6423SLionel Sambuc
sendrec_driver(message * m_ptr,ssize_t exp,result_t * res)235433d6423SLionel Sambuc static int sendrec_driver(message *m_ptr, ssize_t exp, result_t *res)
236433d6423SLionel Sambuc {
237433d6423SLionel Sambuc /* Make a call to the driver, and perform basic checks on the return
238433d6423SLionel Sambuc * message. Fill in the result structure, wiping out what was in there
239433d6423SLionel Sambuc * before. If the driver dies in the process, attempt to recover but
240433d6423SLionel Sambuc * fail the request.
241433d6423SLionel Sambuc */
242433d6423SLionel Sambuc message m_orig;
243433d6423SLionel Sambuc endpoint_t last_endpt;
244433d6423SLionel Sambuc int i, r;
245433d6423SLionel Sambuc
246433d6423SLionel Sambuc m_orig = *m_ptr;
247433d6423SLionel Sambuc
248433d6423SLionel Sambuc r = ipc_sendrec(driver_endpt, m_ptr);
249433d6423SLionel Sambuc
250433d6423SLionel Sambuc if (r == EDEADSRCDST) {
251433d6423SLionel Sambuc /* The driver has died. Find its new endpoint, and reopen all
252433d6423SLionel Sambuc * devices that we opened earlier. Then return failure.
253433d6423SLionel Sambuc */
254433d6423SLionel Sambuc output("WARNING: driver has died, attempting to proceed\n");
255433d6423SLionel Sambuc
256433d6423SLionel Sambuc driver_deaths++;
257433d6423SLionel Sambuc
258433d6423SLionel Sambuc /* Keep trying until we get a new endpoint. */
259433d6423SLionel Sambuc last_endpt = driver_endpt;
260433d6423SLionel Sambuc for (;;) {
261433d6423SLionel Sambuc r = ds_retrieve_label_endpt(driver_label,
262433d6423SLionel Sambuc &driver_endpt);
263433d6423SLionel Sambuc
264433d6423SLionel Sambuc if (r == OK && last_endpt != driver_endpt)
265433d6423SLionel Sambuc break;
266433d6423SLionel Sambuc
267433d6423SLionel Sambuc micro_delay(100000);
268433d6423SLionel Sambuc }
269433d6423SLionel Sambuc
270433d6423SLionel Sambuc for (i = 0; i < nr_opened; i++)
271433d6423SLionel Sambuc reopen_device(opened[i]);
272433d6423SLionel Sambuc
273433d6423SLionel Sambuc return set_result(res, RESULT_DEATH, 0);
274433d6423SLionel Sambuc }
275433d6423SLionel Sambuc
276433d6423SLionel Sambuc if (r != OK)
277433d6423SLionel Sambuc return set_result(res, RESULT_COMMFAIL, r);
278433d6423SLionel Sambuc
279433d6423SLionel Sambuc if (m_ptr->m_type != BDEV_REPLY)
280433d6423SLionel Sambuc return set_result(res, RESULT_BADTYPE, m_ptr->m_type);
281433d6423SLionel Sambuc
282433d6423SLionel Sambuc if (m_ptr->m_lblockdriver_lbdev_reply.id != m_orig.m_lbdev_lblockdriver_msg.id)
283433d6423SLionel Sambuc return set_result(res, RESULT_BADID,
284433d6423SLionel Sambuc m_ptr->m_lblockdriver_lbdev_reply.id);
285433d6423SLionel Sambuc
286433d6423SLionel Sambuc if ((exp < 0 && m_ptr->m_lblockdriver_lbdev_reply.status >= 0) ||
287433d6423SLionel Sambuc (exp >= 0 &&
288433d6423SLionel Sambuc m_ptr->m_lblockdriver_lbdev_reply.status < 0))
289433d6423SLionel Sambuc return set_result(res, RESULT_BADSTATUS,
290433d6423SLionel Sambuc m_ptr->m_lblockdriver_lbdev_reply.status);
291433d6423SLionel Sambuc
292433d6423SLionel Sambuc return set_result(res, RESULT_OK, 0);
293433d6423SLionel Sambuc }
294433d6423SLionel Sambuc
raw_xfer(dev_t minor,u64_t pos,iovec_s_t * iovec,int nr_req,int write,ssize_t exp,result_t * res)295433d6423SLionel Sambuc static void raw_xfer(dev_t minor, u64_t pos, iovec_s_t *iovec, int nr_req,
296433d6423SLionel Sambuc int write, ssize_t exp, result_t *res)
297433d6423SLionel Sambuc {
298433d6423SLionel Sambuc /* Perform a transfer with a safecopy iovec already supplied.
299433d6423SLionel Sambuc */
300433d6423SLionel Sambuc cp_grant_id_t grant;
301433d6423SLionel Sambuc message m;
302433d6423SLionel Sambuc int r;
303433d6423SLionel Sambuc
304433d6423SLionel Sambuc assert(nr_req <= NR_IOREQS);
305433d6423SLionel Sambuc assert(!write || may_write);
306433d6423SLionel Sambuc
307433d6423SLionel Sambuc if ((grant = cpf_grant_direct(driver_endpt, (vir_bytes) iovec,
308433d6423SLionel Sambuc sizeof(*iovec) * nr_req, CPF_READ)) == GRANT_INVALID)
309433d6423SLionel Sambuc panic("unable to allocate grant");
310433d6423SLionel Sambuc
311433d6423SLionel Sambuc memset(&m, 0, sizeof(m));
312433d6423SLionel Sambuc m.m_type = write ? BDEV_SCATTER : BDEV_GATHER;
313433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.minor = minor;
314433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.pos = pos;
315433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.count = nr_req;
316433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.grant = grant;
317433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.id = lrand48();
318433d6423SLionel Sambuc
319433d6423SLionel Sambuc r = sendrec_driver(&m, exp, res);
320433d6423SLionel Sambuc
321*10b7016bSDavid van Moolenbroek if (cpf_revoke(grant) == -1)
322433d6423SLionel Sambuc panic("unable to revoke grant");
323433d6423SLionel Sambuc
324433d6423SLionel Sambuc if (r != RESULT_OK)
325433d6423SLionel Sambuc return;
326433d6423SLionel Sambuc
327433d6423SLionel Sambuc if (m.m_lblockdriver_lbdev_reply.status == exp)
328433d6423SLionel Sambuc return;
329433d6423SLionel Sambuc
330433d6423SLionel Sambuc if (exp < 0)
331433d6423SLionel Sambuc set_result(res, RESULT_BADSTATUS,
332433d6423SLionel Sambuc m.m_lblockdriver_lbdev_reply.status);
333433d6423SLionel Sambuc else
334433d6423SLionel Sambuc set_result(res, RESULT_TRUNC,
335433d6423SLionel Sambuc exp - m.m_lblockdriver_lbdev_reply.status);
336433d6423SLionel Sambuc }
337433d6423SLionel Sambuc
vir_xfer(dev_t minor,u64_t pos,iovec_t * iovec,int nr_req,int write,ssize_t exp,result_t * res)338433d6423SLionel Sambuc static void vir_xfer(dev_t minor, u64_t pos, iovec_t *iovec, int nr_req,
339433d6423SLionel Sambuc int write, ssize_t exp, result_t *res)
340433d6423SLionel Sambuc {
341433d6423SLionel Sambuc /* Perform a transfer, creating and revoking grants for the I/O vector.
342433d6423SLionel Sambuc */
343433d6423SLionel Sambuc iovec_s_t iov_s[NR_IOREQS];
344433d6423SLionel Sambuc int i;
345433d6423SLionel Sambuc
346433d6423SLionel Sambuc assert(nr_req <= NR_IOREQS);
347433d6423SLionel Sambuc
348433d6423SLionel Sambuc for (i = 0; i < nr_req; i++) {
349433d6423SLionel Sambuc iov_s[i].iov_size = iovec[i].iov_size;
350433d6423SLionel Sambuc
351433d6423SLionel Sambuc if ((iov_s[i].iov_grant = cpf_grant_direct(driver_endpt,
352433d6423SLionel Sambuc (vir_bytes) iovec[i].iov_addr, iovec[i].iov_size,
353433d6423SLionel Sambuc write ? CPF_READ : CPF_WRITE)) == GRANT_INVALID)
354433d6423SLionel Sambuc panic("unable to allocate grant");
355433d6423SLionel Sambuc }
356433d6423SLionel Sambuc
357433d6423SLionel Sambuc raw_xfer(minor, pos, iov_s, nr_req, write, exp, res);
358433d6423SLionel Sambuc
359433d6423SLionel Sambuc for (i = 0; i < nr_req; i++) {
360433d6423SLionel Sambuc iovec[i].iov_size = iov_s[i].iov_size;
361433d6423SLionel Sambuc
362*10b7016bSDavid van Moolenbroek if (cpf_revoke(iov_s[i].iov_grant) == -1)
363433d6423SLionel Sambuc panic("unable to revoke grant");
364433d6423SLionel Sambuc }
365433d6423SLionel Sambuc }
366433d6423SLionel Sambuc
simple_xfer(dev_t minor,u64_t pos,u8_t * buf,size_t size,int write,ssize_t exp,result_t * res)367433d6423SLionel Sambuc static void simple_xfer(dev_t minor, u64_t pos, u8_t *buf, size_t size,
368433d6423SLionel Sambuc int write, ssize_t exp, result_t *res)
369433d6423SLionel Sambuc {
370433d6423SLionel Sambuc /* Perform a transfer involving a single buffer.
371433d6423SLionel Sambuc */
372433d6423SLionel Sambuc iovec_t iov;
373433d6423SLionel Sambuc
374433d6423SLionel Sambuc iov.iov_addr = (vir_bytes) buf;
375433d6423SLionel Sambuc iov.iov_size = size;
376433d6423SLionel Sambuc
377433d6423SLionel Sambuc vir_xfer(minor, pos, &iov, 1, write, exp, res);
378433d6423SLionel Sambuc }
379433d6423SLionel Sambuc
alloc_buf_and_grant(u8_t ** ptr,cp_grant_id_t * grant,size_t size,int perms)380433d6423SLionel Sambuc static void alloc_buf_and_grant(u8_t **ptr, cp_grant_id_t *grant,
381433d6423SLionel Sambuc size_t size, int perms)
382433d6423SLionel Sambuc {
383433d6423SLionel Sambuc /* Allocate a buffer suitable for DMA (i.e. contiguous) and create a
384433d6423SLionel Sambuc * grant for it with the requested CPF_* grant permissions.
385433d6423SLionel Sambuc */
386433d6423SLionel Sambuc
387433d6423SLionel Sambuc *ptr = alloc_dma_memory(size);
388433d6423SLionel Sambuc
389433d6423SLionel Sambuc if ((*grant = cpf_grant_direct(driver_endpt, (vir_bytes) *ptr, size,
390433d6423SLionel Sambuc perms)) == GRANT_INVALID)
391433d6423SLionel Sambuc panic("unable to allocate grant");
392433d6423SLionel Sambuc }
393433d6423SLionel Sambuc
free_buf_and_grant(u8_t * ptr,cp_grant_id_t grant,size_t size)394433d6423SLionel Sambuc static void free_buf_and_grant(u8_t *ptr, cp_grant_id_t grant, size_t size)
395433d6423SLionel Sambuc {
396433d6423SLionel Sambuc /* Revoke a grant and free a buffer.
397433d6423SLionel Sambuc */
398433d6423SLionel Sambuc
399433d6423SLionel Sambuc cpf_revoke(grant);
400433d6423SLionel Sambuc
401433d6423SLionel Sambuc free_dma_memory(ptr, size);
402433d6423SLionel Sambuc }
403433d6423SLionel Sambuc
bad_read1(void)404433d6423SLionel Sambuc static void bad_read1(void)
405433d6423SLionel Sambuc {
406433d6423SLionel Sambuc /* Test various illegal read transfer requests, part 1.
407433d6423SLionel Sambuc */
408433d6423SLionel Sambuc message mt, m;
409433d6423SLionel Sambuc iovec_s_t iovt, iov;
410433d6423SLionel Sambuc cp_grant_id_t grant, grant2, grant3;
411433d6423SLionel Sambuc u8_t *buf_ptr;
412433d6423SLionel Sambuc vir_bytes buf_size;
413433d6423SLionel Sambuc result_t res;
414433d6423SLionel Sambuc
415433d6423SLionel Sambuc test_group("bad read requests, part one", TRUE);
416433d6423SLionel Sambuc
417433d6423SLionel Sambuc #define BUF_SIZE 4096
418433d6423SLionel Sambuc buf_size = BUF_SIZE;
419433d6423SLionel Sambuc
420433d6423SLionel Sambuc alloc_buf_and_grant(&buf_ptr, &grant2, buf_size, CPF_WRITE);
421433d6423SLionel Sambuc
422433d6423SLionel Sambuc if ((grant = cpf_grant_direct(driver_endpt, (vir_bytes) &iov,
423433d6423SLionel Sambuc sizeof(iov), CPF_READ)) == GRANT_INVALID)
424433d6423SLionel Sambuc panic("unable to allocate grant");
425433d6423SLionel Sambuc
426433d6423SLionel Sambuc /* Initialize the defaults for some of the tests.
427433d6423SLionel Sambuc * This is a legitimate request for the first block of the partition.
428433d6423SLionel Sambuc */
429433d6423SLionel Sambuc memset(&mt, 0, sizeof(mt));
430433d6423SLionel Sambuc mt.m_type = BDEV_GATHER;
431433d6423SLionel Sambuc mt.m_lbdev_lblockdriver_msg.minor = driver_minor;
432433d6423SLionel Sambuc mt.m_lbdev_lblockdriver_msg.pos = 0LL;
433433d6423SLionel Sambuc mt.m_lbdev_lblockdriver_msg.count = 1;
434433d6423SLionel Sambuc mt.m_lbdev_lblockdriver_msg.grant = grant;
435433d6423SLionel Sambuc mt.m_lbdev_lblockdriver_msg.id = lrand48();
436433d6423SLionel Sambuc
437433d6423SLionel Sambuc memset(&iovt, 0, sizeof(iovt));
438433d6423SLionel Sambuc iovt.iov_grant = grant2;
439433d6423SLionel Sambuc iovt.iov_size = buf_size;
440433d6423SLionel Sambuc
441433d6423SLionel Sambuc /* Test normal request. */
442433d6423SLionel Sambuc m = mt;
443433d6423SLionel Sambuc iov = iovt;
444433d6423SLionel Sambuc
445433d6423SLionel Sambuc sendrec_driver(&m, OK, &res);
446433d6423SLionel Sambuc
447433d6423SLionel Sambuc if (res.type == RESULT_OK &&
448433d6423SLionel Sambuc m.m_lblockdriver_lbdev_reply.status != (ssize_t) iov.iov_size) {
449433d6423SLionel Sambuc res.type = RESULT_TRUNC;
450433d6423SLionel Sambuc res.value = m.m_lblockdriver_lbdev_reply.status;
451433d6423SLionel Sambuc }
452433d6423SLionel Sambuc
453433d6423SLionel Sambuc got_result(&res, "normal request");
454433d6423SLionel Sambuc
455433d6423SLionel Sambuc /* Test zero iovec elements. */
456433d6423SLionel Sambuc m = mt;
457433d6423SLionel Sambuc iov = iovt;
458433d6423SLionel Sambuc
459433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.count = 0;
460433d6423SLionel Sambuc
461433d6423SLionel Sambuc sendrec_driver(&m, EINVAL, &res);
462433d6423SLionel Sambuc
463433d6423SLionel Sambuc got_result(&res, "zero iovec elements");
464433d6423SLionel Sambuc
465433d6423SLionel Sambuc /* Test bad iovec grant. */
466433d6423SLionel Sambuc m = mt;
467433d6423SLionel Sambuc
468433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.grant = GRANT_INVALID;
469433d6423SLionel Sambuc
470433d6423SLionel Sambuc sendrec_driver(&m, EINVAL, &res);
471433d6423SLionel Sambuc
472433d6423SLionel Sambuc got_result(&res, "bad iovec grant");
473433d6423SLionel Sambuc
474433d6423SLionel Sambuc /* Test revoked iovec grant. */
475433d6423SLionel Sambuc m = mt;
476433d6423SLionel Sambuc iov = iovt;
477433d6423SLionel Sambuc
478433d6423SLionel Sambuc if ((grant3 = cpf_grant_direct(driver_endpt, (vir_bytes) &iov,
479433d6423SLionel Sambuc sizeof(iov), CPF_READ)) == GRANT_INVALID)
480433d6423SLionel Sambuc panic("unable to allocate grant");
481433d6423SLionel Sambuc
482433d6423SLionel Sambuc cpf_revoke(grant3);
483433d6423SLionel Sambuc
484433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.grant = grant3;
485433d6423SLionel Sambuc
486433d6423SLionel Sambuc sendrec_driver(&m, EINVAL, &res);
487433d6423SLionel Sambuc
488433d6423SLionel Sambuc accept_result(&res, RESULT_BADSTATUS, EPERM);
489433d6423SLionel Sambuc
490433d6423SLionel Sambuc got_result(&res, "revoked iovec grant");
491433d6423SLionel Sambuc
492433d6423SLionel Sambuc /* Test normal request (final check). */
493433d6423SLionel Sambuc m = mt;
494433d6423SLionel Sambuc iov = iovt;
495433d6423SLionel Sambuc
496433d6423SLionel Sambuc sendrec_driver(&m, OK, &res);
497433d6423SLionel Sambuc
498433d6423SLionel Sambuc if (res.type == RESULT_OK &&
499433d6423SLionel Sambuc m.m_lblockdriver_lbdev_reply.status != (ssize_t) iov.iov_size) {
500433d6423SLionel Sambuc res.type = RESULT_TRUNC;
501433d6423SLionel Sambuc res.value = m.m_lblockdriver_lbdev_reply.status;
502433d6423SLionel Sambuc }
503433d6423SLionel Sambuc
504433d6423SLionel Sambuc got_result(&res, "normal request");
505433d6423SLionel Sambuc
506433d6423SLionel Sambuc /* Clean up. */
507433d6423SLionel Sambuc free_buf_and_grant(buf_ptr, grant2, buf_size);
508433d6423SLionel Sambuc
509433d6423SLionel Sambuc cpf_revoke(grant);
510433d6423SLionel Sambuc }
511433d6423SLionel Sambuc
get_sum(u8_t * ptr,size_t size)512433d6423SLionel Sambuc static u32_t get_sum(u8_t *ptr, size_t size)
513433d6423SLionel Sambuc {
514433d6423SLionel Sambuc /* Compute a checksum over the given buffer.
515433d6423SLionel Sambuc */
516433d6423SLionel Sambuc u32_t sum;
517433d6423SLionel Sambuc
518433d6423SLionel Sambuc for (sum = 0; size > 0; size--, ptr++)
519433d6423SLionel Sambuc sum = sum ^ (sum << 5) ^ *ptr;
520433d6423SLionel Sambuc
521433d6423SLionel Sambuc return sum;
522433d6423SLionel Sambuc }
523433d6423SLionel Sambuc
fill_rand(u8_t * ptr,size_t size)524433d6423SLionel Sambuc static u32_t fill_rand(u8_t *ptr, size_t size)
525433d6423SLionel Sambuc {
526433d6423SLionel Sambuc /* Fill the given buffer with random data. Return a checksum over the
527433d6423SLionel Sambuc * resulting data.
528433d6423SLionel Sambuc */
529433d6423SLionel Sambuc size_t i;
530433d6423SLionel Sambuc
531433d6423SLionel Sambuc for (i = 0; i < size; i++)
532433d6423SLionel Sambuc ptr[i] = lrand48() % 256;
533433d6423SLionel Sambuc
534433d6423SLionel Sambuc return get_sum(ptr, size);
535433d6423SLionel Sambuc }
536433d6423SLionel Sambuc
test_sum(u8_t * ptr,size_t size,u32_t sum,int should_match,result_t * res)537433d6423SLionel Sambuc static void test_sum(u8_t *ptr, size_t size, u32_t sum, int should_match,
538433d6423SLionel Sambuc result_t *res)
539433d6423SLionel Sambuc {
540433d6423SLionel Sambuc /* If the test succeeded so far, check whether the given buffer does
541433d6423SLionel Sambuc * or does not match the given checksum, and adjust the test result
542433d6423SLionel Sambuc * accordingly.
543433d6423SLionel Sambuc */
544433d6423SLionel Sambuc u32_t sum2;
545433d6423SLionel Sambuc
546433d6423SLionel Sambuc if (res->type != RESULT_OK)
547433d6423SLionel Sambuc return;
548433d6423SLionel Sambuc
549433d6423SLionel Sambuc sum2 = get_sum(ptr, size);
550433d6423SLionel Sambuc
551433d6423SLionel Sambuc if ((sum == sum2) != should_match) {
552433d6423SLionel Sambuc res->type = should_match ? RESULT_CORRUPT : RESULT_MISSING;
553433d6423SLionel Sambuc res->value = 0; /* not much that's useful here */
554433d6423SLionel Sambuc }
555433d6423SLionel Sambuc }
556433d6423SLionel Sambuc
bad_read2(void)557433d6423SLionel Sambuc static void bad_read2(void)
558433d6423SLionel Sambuc {
559433d6423SLionel Sambuc /* Test various illegal read transfer requests, part 2.
560433d6423SLionel Sambuc *
561433d6423SLionel Sambuc * Consider allowing this test to be run twice, with different buffer
562433d6423SLionel Sambuc * sizes. It appears that we can make at_wini misbehave by making the
563433d6423SLionel Sambuc * size exceed the per-operation size (128KB ?). On the other hand, we
564433d6423SLionel Sambuc * then need to start checking partition sizes, possibly.
565433d6423SLionel Sambuc */
566433d6423SLionel Sambuc u8_t *buf_ptr, *buf2_ptr, *buf3_ptr, c1, c2;
567433d6423SLionel Sambuc size_t buf_size, buf2_size, buf3_size;
568433d6423SLionel Sambuc cp_grant_id_t buf_grant, buf2_grant, buf3_grant, grant;
569433d6423SLionel Sambuc u32_t buf_sum, buf2_sum, buf3_sum;
570433d6423SLionel Sambuc iovec_s_t iov[3], iovt[3];
571433d6423SLionel Sambuc result_t res;
572433d6423SLionel Sambuc
573433d6423SLionel Sambuc test_group("bad read requests, part two", TRUE);
574433d6423SLionel Sambuc
575433d6423SLionel Sambuc buf_size = buf2_size = buf3_size = BUF_SIZE;
576433d6423SLionel Sambuc
577433d6423SLionel Sambuc alloc_buf_and_grant(&buf_ptr, &buf_grant, buf_size, CPF_WRITE);
578433d6423SLionel Sambuc alloc_buf_and_grant(&buf2_ptr, &buf2_grant, buf2_size, CPF_WRITE);
579433d6423SLionel Sambuc alloc_buf_and_grant(&buf3_ptr, &buf3_grant, buf3_size, CPF_WRITE);
580433d6423SLionel Sambuc
581433d6423SLionel Sambuc iovt[0].iov_grant = buf_grant;
582433d6423SLionel Sambuc iovt[0].iov_size = buf_size;
583433d6423SLionel Sambuc iovt[1].iov_grant = buf2_grant;
584433d6423SLionel Sambuc iovt[1].iov_size = buf2_size;
585433d6423SLionel Sambuc iovt[2].iov_grant = buf3_grant;
586433d6423SLionel Sambuc iovt[2].iov_size = buf3_size;
587433d6423SLionel Sambuc
588433d6423SLionel Sambuc /* Test normal vector request. */
589433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
590433d6423SLionel Sambuc
591433d6423SLionel Sambuc buf_sum = fill_rand(buf_ptr, buf_size);
592433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
593433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
594433d6423SLionel Sambuc
595433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, FALSE,
596433d6423SLionel Sambuc buf_size + buf2_size + buf3_size, &res);
597433d6423SLionel Sambuc
598433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, FALSE, &res);
599433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, FALSE, &res);
600433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, FALSE, &res);
601433d6423SLionel Sambuc
602433d6423SLionel Sambuc got_result(&res, "normal vector request");
603433d6423SLionel Sambuc
604433d6423SLionel Sambuc /* Test zero sized iovec element. */
605433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
606433d6423SLionel Sambuc iov[1].iov_size = 0;
607433d6423SLionel Sambuc
608433d6423SLionel Sambuc buf_sum = fill_rand(buf_ptr, buf_size);
609433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
610433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
611433d6423SLionel Sambuc
612433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, FALSE, EINVAL, &res);
613433d6423SLionel Sambuc
614433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res);
615433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
616433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
617433d6423SLionel Sambuc
618433d6423SLionel Sambuc got_result(&res, "zero size in iovec element");
619433d6423SLionel Sambuc
620433d6423SLionel Sambuc /* Test negative sized iovec element. */
621433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
622433d6423SLionel Sambuc iov[1].iov_size = (vir_bytes) LONG_MAX + 1;
623433d6423SLionel Sambuc
624433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, FALSE, EINVAL, &res);
625433d6423SLionel Sambuc
626433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res);
627433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
628433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
629433d6423SLionel Sambuc
630433d6423SLionel Sambuc got_result(&res, "negative size in iovec element");
631433d6423SLionel Sambuc
632433d6423SLionel Sambuc /* Test iovec with negative total size. */
633433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
634433d6423SLionel Sambuc iov[0].iov_size = LONG_MAX / 2 - 1;
635433d6423SLionel Sambuc iov[1].iov_size = LONG_MAX / 2 - 1;
636433d6423SLionel Sambuc
637433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, FALSE, EINVAL, &res);
638433d6423SLionel Sambuc
639433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res);
640433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
641433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
642433d6423SLionel Sambuc
643433d6423SLionel Sambuc got_result(&res, "negative total size");
644433d6423SLionel Sambuc
645433d6423SLionel Sambuc /* Test iovec with wrapping total size. */
646433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
647433d6423SLionel Sambuc iov[0].iov_size = LONG_MAX - 1;
648433d6423SLionel Sambuc iov[1].iov_size = LONG_MAX - 1;
649433d6423SLionel Sambuc
650433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, FALSE, EINVAL, &res);
651433d6423SLionel Sambuc
652433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res);
653433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
654433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
655433d6423SLionel Sambuc
656433d6423SLionel Sambuc got_result(&res, "wrapping total size");
657433d6423SLionel Sambuc
658433d6423SLionel Sambuc /* Test word-unaligned iovec element size. */
659433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
660433d6423SLionel Sambuc iov[1].iov_size--;
661433d6423SLionel Sambuc
662433d6423SLionel Sambuc buf_sum = fill_rand(buf_ptr, buf_size);
663433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
664433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
665433d6423SLionel Sambuc c1 = buf2_ptr[buf2_size - 1];
666433d6423SLionel Sambuc
667433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, FALSE, BUF_SIZE * 3 - 1,
668433d6423SLionel Sambuc &res);
669433d6423SLionel Sambuc
670433d6423SLionel Sambuc if (accept_result(&res, RESULT_BADSTATUS, EINVAL)) {
671433d6423SLionel Sambuc /* Do not test the first buffer, as it may contain a partial
672433d6423SLionel Sambuc * result.
673433d6423SLionel Sambuc */
674433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
675433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
676433d6423SLionel Sambuc } else {
677433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, FALSE, &res);
678433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, FALSE, &res);
679433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, FALSE, &res);
680433d6423SLionel Sambuc if (c1 != buf2_ptr[buf2_size - 1])
681433d6423SLionel Sambuc set_result(&res, RESULT_CORRUPT, 0);
682433d6423SLionel Sambuc }
683433d6423SLionel Sambuc
684433d6423SLionel Sambuc got_result(&res, "word-unaligned size in iovec element");
685433d6423SLionel Sambuc
686433d6423SLionel Sambuc /* Test invalid grant in iovec element. */
687433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
688433d6423SLionel Sambuc iov[1].iov_grant = GRANT_INVALID;
689433d6423SLionel Sambuc
690433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
691433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
692433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
693433d6423SLionel Sambuc
694433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, FALSE, EINVAL, &res);
695433d6423SLionel Sambuc
696433d6423SLionel Sambuc /* Do not test the first buffer, as it may contain a partial result. */
697433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
698433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
699433d6423SLionel Sambuc
700433d6423SLionel Sambuc got_result(&res, "invalid grant in iovec element");
701433d6423SLionel Sambuc
702433d6423SLionel Sambuc /* Test revoked grant in iovec element. */
703433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
704433d6423SLionel Sambuc if ((grant = cpf_grant_direct(driver_endpt, (vir_bytes) buf2_ptr,
705433d6423SLionel Sambuc buf2_size, CPF_WRITE)) == GRANT_INVALID)
706433d6423SLionel Sambuc panic("unable to allocate grant");
707433d6423SLionel Sambuc
708433d6423SLionel Sambuc cpf_revoke(grant);
709433d6423SLionel Sambuc
710433d6423SLionel Sambuc iov[1].iov_grant = grant;
711433d6423SLionel Sambuc
712433d6423SLionel Sambuc buf_sum = fill_rand(buf_ptr, buf_size);
713433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
714433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
715433d6423SLionel Sambuc
716433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, FALSE, EINVAL, &res);
717433d6423SLionel Sambuc
718433d6423SLionel Sambuc accept_result(&res, RESULT_BADSTATUS, EPERM);
719433d6423SLionel Sambuc
720433d6423SLionel Sambuc /* Do not test the first buffer, as it may contain a partial result. */
721433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
722433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
723433d6423SLionel Sambuc
724433d6423SLionel Sambuc got_result(&res, "revoked grant in iovec element");
725433d6423SLionel Sambuc
726433d6423SLionel Sambuc /* Test read-only grant in iovec element. */
727433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
728433d6423SLionel Sambuc if ((grant = cpf_grant_direct(driver_endpt, (vir_bytes) buf2_ptr,
729433d6423SLionel Sambuc buf2_size, CPF_READ)) == GRANT_INVALID)
730433d6423SLionel Sambuc panic("unable to allocate grant");
731433d6423SLionel Sambuc
732433d6423SLionel Sambuc iov[1].iov_grant = grant;
733433d6423SLionel Sambuc
734433d6423SLionel Sambuc buf_sum = fill_rand(buf_ptr, buf_size);
735433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
736433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
737433d6423SLionel Sambuc
738433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, FALSE, EINVAL, &res);
739433d6423SLionel Sambuc
740433d6423SLionel Sambuc accept_result(&res, RESULT_BADSTATUS, EPERM);
741433d6423SLionel Sambuc
742433d6423SLionel Sambuc /* Do not test the first buffer, as it may contain a partial result. */
743433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
744433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
745433d6423SLionel Sambuc
746433d6423SLionel Sambuc got_result(&res, "read-only grant in iovec element");
747433d6423SLionel Sambuc
748433d6423SLionel Sambuc cpf_revoke(grant);
749433d6423SLionel Sambuc
750433d6423SLionel Sambuc /* Test word-unaligned iovec element buffer. */
751433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
752433d6423SLionel Sambuc if ((grant = cpf_grant_direct(driver_endpt, (vir_bytes) (buf2_ptr + 1),
753433d6423SLionel Sambuc buf2_size - 2, CPF_WRITE)) == GRANT_INVALID)
754433d6423SLionel Sambuc panic("unable to allocate grant");
755433d6423SLionel Sambuc
756433d6423SLionel Sambuc iov[1].iov_grant = grant;
757433d6423SLionel Sambuc iov[1].iov_size = buf2_size - 2;
758433d6423SLionel Sambuc
759433d6423SLionel Sambuc buf_sum = fill_rand(buf_ptr, buf_size);
760433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
761433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
762433d6423SLionel Sambuc c1 = buf2_ptr[0];
763433d6423SLionel Sambuc c2 = buf2_ptr[buf2_size - 1];
764433d6423SLionel Sambuc
765433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, FALSE, BUF_SIZE * 3 - 2, &res);
766433d6423SLionel Sambuc
767433d6423SLionel Sambuc if (accept_result(&res, RESULT_BADSTATUS, EINVAL)) {
768433d6423SLionel Sambuc /* Do not test the first buffer, as it may contain a partial
769433d6423SLionel Sambuc * result.
770433d6423SLionel Sambuc */
771433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
772433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
773433d6423SLionel Sambuc } else {
774433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, FALSE, &res);
775433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, FALSE, &res);
776433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, FALSE, &res);
777433d6423SLionel Sambuc if (c1 != buf2_ptr[0] || c2 != buf2_ptr[buf2_size - 1])
778433d6423SLionel Sambuc set_result(&res, RESULT_CORRUPT, 0);
779433d6423SLionel Sambuc }
780433d6423SLionel Sambuc
781433d6423SLionel Sambuc got_result(&res, "word-unaligned buffer in iovec element");
782433d6423SLionel Sambuc
783433d6423SLionel Sambuc cpf_revoke(grant);
784433d6423SLionel Sambuc
785433d6423SLionel Sambuc /* Test word-unaligned position. */
786433d6423SLionel Sambuc /* Only perform this test if the minimum read size is not 1, in which
787433d6423SLionel Sambuc * case it is safe to assume that the driver expects no position
788433d6423SLionel Sambuc * alignment either. These tests are indeed not exhaustive yet. For now
789433d6423SLionel Sambuc * we assume that if no alignment is required at all, the driver does
790433d6423SLionel Sambuc * not implement special logic to achieve this, so we don't need to
791433d6423SLionel Sambuc * test all possible positions and sizes either (yes, laziness..).
792433d6423SLionel Sambuc */
793433d6423SLionel Sambuc if (min_read > 1) {
794433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
795433d6423SLionel Sambuc
796433d6423SLionel Sambuc buf_sum = fill_rand(buf_ptr, buf_size);
797433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
798433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
799433d6423SLionel Sambuc
800433d6423SLionel Sambuc raw_xfer(driver_minor, 1ULL, iov, 3, FALSE, EINVAL, &res);
801433d6423SLionel Sambuc
802433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res);
803433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
804433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
805433d6423SLionel Sambuc
806433d6423SLionel Sambuc got_result(&res, "word-unaligned position");
807433d6423SLionel Sambuc }
808433d6423SLionel Sambuc
809433d6423SLionel Sambuc /* Test normal vector request (final check). */
810433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
811433d6423SLionel Sambuc
812433d6423SLionel Sambuc buf_sum = fill_rand(buf_ptr, buf_size);
813433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
814433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
815433d6423SLionel Sambuc
816433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, FALSE,
817433d6423SLionel Sambuc buf_size + buf2_size + buf3_size, &res);
818433d6423SLionel Sambuc
819433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, FALSE, &res);
820433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, FALSE, &res);
821433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, FALSE, &res);
822433d6423SLionel Sambuc
823433d6423SLionel Sambuc got_result(&res, "normal vector request");
824433d6423SLionel Sambuc
825433d6423SLionel Sambuc /* Clean up. */
826433d6423SLionel Sambuc free_buf_and_grant(buf3_ptr, buf3_grant, buf3_size);
827433d6423SLionel Sambuc free_buf_and_grant(buf2_ptr, buf2_grant, buf2_size);
828433d6423SLionel Sambuc free_buf_and_grant(buf_ptr, buf_grant, buf_size);
829433d6423SLionel Sambuc }
830433d6423SLionel Sambuc
bad_write(void)831433d6423SLionel Sambuc static void bad_write(void)
832433d6423SLionel Sambuc {
833433d6423SLionel Sambuc /* Test various illegal write transfer requests, if writing is allowed.
834433d6423SLionel Sambuc * If handled correctly, these requests will not actually write data.
835433d6423SLionel Sambuc * This part of the test set is in need of further expansion.
836433d6423SLionel Sambuc */
837433d6423SLionel Sambuc u8_t *buf_ptr, *buf2_ptr, *buf3_ptr;
838433d6423SLionel Sambuc size_t buf_size, buf2_size, buf3_size, sector_unalign;
839433d6423SLionel Sambuc cp_grant_id_t buf_grant, buf2_grant, buf3_grant;
840433d6423SLionel Sambuc cp_grant_id_t grant;
841433d6423SLionel Sambuc u32_t buf_sum, buf2_sum, buf3_sum;
842433d6423SLionel Sambuc iovec_s_t iov[3], iovt[3];
843433d6423SLionel Sambuc result_t res;
844433d6423SLionel Sambuc
845433d6423SLionel Sambuc test_group("bad write requests", may_write);
846433d6423SLionel Sambuc
847433d6423SLionel Sambuc if (!may_write)
848433d6423SLionel Sambuc return;
849433d6423SLionel Sambuc
850433d6423SLionel Sambuc buf_size = buf2_size = buf3_size = BUF_SIZE;
851433d6423SLionel Sambuc
852433d6423SLionel Sambuc alloc_buf_and_grant(&buf_ptr, &buf_grant, buf_size, CPF_READ);
853433d6423SLionel Sambuc alloc_buf_and_grant(&buf2_ptr, &buf2_grant, buf2_size, CPF_READ);
854433d6423SLionel Sambuc alloc_buf_and_grant(&buf3_ptr, &buf3_grant, buf3_size, CPF_READ);
855433d6423SLionel Sambuc
856433d6423SLionel Sambuc iovt[0].iov_grant = buf_grant;
857433d6423SLionel Sambuc iovt[0].iov_size = buf_size;
858433d6423SLionel Sambuc iovt[1].iov_grant = buf2_grant;
859433d6423SLionel Sambuc iovt[1].iov_size = buf2_size;
860433d6423SLionel Sambuc iovt[2].iov_grant = buf3_grant;
861433d6423SLionel Sambuc iovt[2].iov_size = buf3_size;
862433d6423SLionel Sambuc
863433d6423SLionel Sambuc /* Only perform write alignment tests if writes require alignment. */
864433d6423SLionel Sambuc if (min_write == 0)
865433d6423SLionel Sambuc min_write = sector_size;
866433d6423SLionel Sambuc
867433d6423SLionel Sambuc if (min_write > 1) {
868433d6423SLionel Sambuc /* If min_write is larger than 2, use 2 as sector-unaligned
869433d6423SLionel Sambuc * size, as word-unaligned values (e.g., 1) may be filtered out
870433d6423SLionel Sambuc * on another code path.
871433d6423SLionel Sambuc */
872433d6423SLionel Sambuc sector_unalign = (min_write > 2) ? 2 : 1;
873433d6423SLionel Sambuc
874433d6423SLionel Sambuc /* Test sector-unaligned write position. */
875433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
876433d6423SLionel Sambuc
877433d6423SLionel Sambuc buf_sum = fill_rand(buf_ptr, buf_size);
878433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
879433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
880433d6423SLionel Sambuc
881433d6423SLionel Sambuc raw_xfer(driver_minor, (u64_t)sector_unalign, iov, 3, TRUE,
882433d6423SLionel Sambuc EINVAL, &res);
883433d6423SLionel Sambuc
884433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res);
885433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
886433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
887433d6423SLionel Sambuc
888433d6423SLionel Sambuc got_result(&res, "sector-unaligned write position");
889433d6423SLionel Sambuc
890433d6423SLionel Sambuc /* Test sector-unaligned write size. */
891433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
892433d6423SLionel Sambuc iov[1].iov_size -= sector_unalign;
893433d6423SLionel Sambuc
894433d6423SLionel Sambuc buf_sum = fill_rand(buf_ptr, buf_size);
895433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
896433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
897433d6423SLionel Sambuc
898433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, TRUE, EINVAL, &res);
899433d6423SLionel Sambuc
900433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res);
901433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
902433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
903433d6423SLionel Sambuc
904433d6423SLionel Sambuc got_result(&res, "sector-unaligned write size");
905433d6423SLionel Sambuc }
906433d6423SLionel Sambuc
907433d6423SLionel Sambuc /* Test write-only grant in iovec element. */
908433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iovt));
909433d6423SLionel Sambuc if ((grant = cpf_grant_direct(driver_endpt, (vir_bytes) buf2_ptr,
910433d6423SLionel Sambuc buf2_size, CPF_WRITE)) == GRANT_INVALID)
911433d6423SLionel Sambuc panic("unable to allocate grant");
912433d6423SLionel Sambuc
913433d6423SLionel Sambuc iov[1].iov_grant = grant;
914433d6423SLionel Sambuc
915433d6423SLionel Sambuc buf_sum = fill_rand(buf_ptr, buf_size);
916433d6423SLionel Sambuc buf2_sum = fill_rand(buf2_ptr, buf2_size);
917433d6423SLionel Sambuc buf3_sum = fill_rand(buf3_ptr, buf3_size);
918433d6423SLionel Sambuc
919433d6423SLionel Sambuc raw_xfer(driver_minor, 0ULL, iov, 3, TRUE, EINVAL, &res);
920433d6423SLionel Sambuc
921433d6423SLionel Sambuc accept_result(&res, RESULT_BADSTATUS, EPERM);
922433d6423SLionel Sambuc
923433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, buf_sum, TRUE, &res);
924433d6423SLionel Sambuc test_sum(buf2_ptr, buf2_size, buf2_sum, TRUE, &res);
925433d6423SLionel Sambuc test_sum(buf3_ptr, buf3_size, buf3_sum, TRUE, &res);
926433d6423SLionel Sambuc
927433d6423SLionel Sambuc got_result(&res, "write-only grant in iovec element");
928433d6423SLionel Sambuc
929433d6423SLionel Sambuc cpf_revoke(grant);
930433d6423SLionel Sambuc
931433d6423SLionel Sambuc /* Clean up. */
932433d6423SLionel Sambuc free_buf_and_grant(buf3_ptr, buf3_grant, buf3_size);
933433d6423SLionel Sambuc free_buf_and_grant(buf2_ptr, buf2_grant, buf2_size);
934433d6423SLionel Sambuc free_buf_and_grant(buf_ptr, buf_grant, buf_size);
935433d6423SLionel Sambuc }
936433d6423SLionel Sambuc
vector_and_large_sub(size_t small_size)937433d6423SLionel Sambuc static void vector_and_large_sub(size_t small_size)
938433d6423SLionel Sambuc {
939433d6423SLionel Sambuc /* Check whether large vectored requests, and large single requests,
940433d6423SLionel Sambuc * succeed.
941433d6423SLionel Sambuc */
942433d6423SLionel Sambuc size_t large_size, buf_size, buf2_size;
943433d6423SLionel Sambuc u8_t *buf_ptr, *buf2_ptr;
944433d6423SLionel Sambuc iovec_t iovec[NR_IOREQS];
945433d6423SLionel Sambuc u64_t base_pos;
946433d6423SLionel Sambuc result_t res;
947433d6423SLionel Sambuc int i;
948433d6423SLionel Sambuc
949433d6423SLionel Sambuc base_pos = (u64_t)sector_size;
950433d6423SLionel Sambuc
951433d6423SLionel Sambuc large_size = small_size * NR_IOREQS;
952433d6423SLionel Sambuc
953433d6423SLionel Sambuc buf_size = large_size + sizeof(u32_t) * 2;
954433d6423SLionel Sambuc buf2_size = large_size + sizeof(u32_t) * (NR_IOREQS + 1);
955433d6423SLionel Sambuc
956433d6423SLionel Sambuc buf_ptr = alloc_dma_memory(buf_size);
957433d6423SLionel Sambuc buf2_ptr = alloc_dma_memory(buf2_size);
958433d6423SLionel Sambuc
959433d6423SLionel Sambuc /* The first buffer has one large chunk with dword-sized guards on each
960433d6423SLionel Sambuc * side. LPTR(n) points to the start of the nth small data chunk within
961433d6423SLionel Sambuc * the large chunk. The second buffer contains several small chunks. It
962433d6423SLionel Sambuc * has dword-sized guards before each chunk and after the last chunk.
963433d6423SLionel Sambuc * SPTR(n) points to the start of the nth small chunk.
964433d6423SLionel Sambuc */
965433d6423SLionel Sambuc #define SPTR(n) (buf2_ptr + sizeof(u32_t) + (n) * (sizeof(u32_t) + small_size))
966433d6423SLionel Sambuc #define LPTR(n) (buf_ptr + sizeof(u32_t) + small_size * (n))
967433d6423SLionel Sambuc
968433d6423SLionel Sambuc /* Write one large chunk, if writing is allowed. */
969433d6423SLionel Sambuc if (may_write) {
970433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size); /* don't need the checksum */
971433d6423SLionel Sambuc
972433d6423SLionel Sambuc iovec[0].iov_addr = (vir_bytes) (buf_ptr + sizeof(u32_t));
973433d6423SLionel Sambuc iovec[0].iov_size = large_size;
974433d6423SLionel Sambuc
975433d6423SLionel Sambuc vir_xfer(driver_minor, base_pos, iovec, 1, TRUE, large_size,
976433d6423SLionel Sambuc &res);
977433d6423SLionel Sambuc
978433d6423SLionel Sambuc got_result(&res, "large write");
979433d6423SLionel Sambuc }
980433d6423SLionel Sambuc
981433d6423SLionel Sambuc /* Read back in many small chunks. If writing is not allowed, do not
982433d6423SLionel Sambuc * check checksums.
983433d6423SLionel Sambuc */
984433d6423SLionel Sambuc for (i = 0; i < NR_IOREQS; i++) {
985433d6423SLionel Sambuc * (((u32_t *) SPTR(i)) - 1) = 0xDEADBEEFL + i;
986433d6423SLionel Sambuc iovec[i].iov_addr = (vir_bytes) SPTR(i);
987433d6423SLionel Sambuc iovec[i].iov_size = small_size;
988433d6423SLionel Sambuc }
989433d6423SLionel Sambuc * (((u32_t *) SPTR(i)) - 1) = 0xFEEDFACEL;
990433d6423SLionel Sambuc
991433d6423SLionel Sambuc vir_xfer(driver_minor, base_pos, iovec, NR_IOREQS, FALSE, large_size,
992433d6423SLionel Sambuc &res);
993433d6423SLionel Sambuc
994433d6423SLionel Sambuc if (res.type == RESULT_OK) {
995433d6423SLionel Sambuc for (i = 0; i < NR_IOREQS; i++) {
996433d6423SLionel Sambuc if (* (((u32_t *) SPTR(i)) - 1) != 0xDEADBEEFL + i)
997433d6423SLionel Sambuc set_result(&res, RESULT_OVERFLOW, 0);
998433d6423SLionel Sambuc }
999433d6423SLionel Sambuc if (* (((u32_t *) SPTR(i)) - 1) != 0xFEEDFACEL)
1000433d6423SLionel Sambuc set_result(&res, RESULT_OVERFLOW, 0);
1001433d6423SLionel Sambuc }
1002433d6423SLionel Sambuc
1003433d6423SLionel Sambuc if (res.type == RESULT_OK && may_write) {
1004433d6423SLionel Sambuc for (i = 0; i < NR_IOREQS; i++) {
1005433d6423SLionel Sambuc test_sum(SPTR(i), small_size,
1006433d6423SLionel Sambuc get_sum(LPTR(i), small_size), TRUE, &res);
1007433d6423SLionel Sambuc }
1008433d6423SLionel Sambuc }
1009433d6423SLionel Sambuc
1010433d6423SLionel Sambuc got_result(&res, "vectored read");
1011433d6423SLionel Sambuc
1012433d6423SLionel Sambuc /* Write new data in many small chunks, if writing is allowed. */
1013433d6423SLionel Sambuc if (may_write) {
1014433d6423SLionel Sambuc fill_rand(buf2_ptr, buf2_size); /* don't need the checksum */
1015433d6423SLionel Sambuc
1016433d6423SLionel Sambuc for (i = 0; i < NR_IOREQS; i++) {
1017433d6423SLionel Sambuc iovec[i].iov_addr = (vir_bytes) SPTR(i);
1018433d6423SLionel Sambuc iovec[i].iov_size = small_size;
1019433d6423SLionel Sambuc }
1020433d6423SLionel Sambuc
1021433d6423SLionel Sambuc vir_xfer(driver_minor, base_pos, iovec, NR_IOREQS, TRUE,
1022433d6423SLionel Sambuc large_size, &res);
1023433d6423SLionel Sambuc
1024433d6423SLionel Sambuc got_result(&res, "vectored write");
1025433d6423SLionel Sambuc }
1026433d6423SLionel Sambuc
1027433d6423SLionel Sambuc /* Read back in one large chunk. If writing is allowed, the checksums
1028433d6423SLionel Sambuc * must match the last write; otherwise, they must match the last read.
1029433d6423SLionel Sambuc * In both cases, the expected content is in the second buffer.
1030433d6423SLionel Sambuc */
1031433d6423SLionel Sambuc
1032433d6423SLionel Sambuc * (u32_t *) buf_ptr = 0xCAFEBABEL;
1033433d6423SLionel Sambuc * (u32_t *) (buf_ptr + sizeof(u32_t) + large_size) = 0xDECAFBADL;
1034433d6423SLionel Sambuc
1035433d6423SLionel Sambuc iovec[0].iov_addr = (vir_bytes) (buf_ptr + sizeof(u32_t));
1036433d6423SLionel Sambuc iovec[0].iov_size = large_size;
1037433d6423SLionel Sambuc
1038433d6423SLionel Sambuc vir_xfer(driver_minor, base_pos, iovec, 1, FALSE, large_size, &res);
1039433d6423SLionel Sambuc
1040433d6423SLionel Sambuc if (res.type == RESULT_OK) {
1041433d6423SLionel Sambuc if (* (u32_t *) buf_ptr != 0xCAFEBABEL)
1042433d6423SLionel Sambuc set_result(&res, RESULT_OVERFLOW, 0);
1043433d6423SLionel Sambuc if (* (u32_t *) (buf_ptr + sizeof(u32_t) + large_size) !=
1044433d6423SLionel Sambuc 0xDECAFBADL)
1045433d6423SLionel Sambuc set_result(&res, RESULT_OVERFLOW, 0);
1046433d6423SLionel Sambuc }
1047433d6423SLionel Sambuc
1048433d6423SLionel Sambuc if (res.type == RESULT_OK) {
1049433d6423SLionel Sambuc for (i = 0; i < NR_IOREQS; i++) {
1050433d6423SLionel Sambuc test_sum(SPTR(i), small_size,
1051433d6423SLionel Sambuc get_sum(LPTR(i), small_size), TRUE, &res);
1052433d6423SLionel Sambuc }
1053433d6423SLionel Sambuc }
1054433d6423SLionel Sambuc
1055433d6423SLionel Sambuc got_result(&res, "large read");
1056433d6423SLionel Sambuc
1057433d6423SLionel Sambuc #undef LPTR
1058433d6423SLionel Sambuc #undef SPTR
1059433d6423SLionel Sambuc
1060433d6423SLionel Sambuc /* Clean up. */
1061433d6423SLionel Sambuc free_dma_memory(buf2_ptr, buf2_size);
1062433d6423SLionel Sambuc free_dma_memory(buf_ptr, buf_size);
1063433d6423SLionel Sambuc }
1064433d6423SLionel Sambuc
vector_and_large(void)1065433d6423SLionel Sambuc static void vector_and_large(void)
1066433d6423SLionel Sambuc {
1067433d6423SLionel Sambuc /* Check whether large vectored requests, and large single requests,
1068433d6423SLionel Sambuc * succeed. These are request patterns commonly used by MFS and the
1069433d6423SLionel Sambuc * filter driver, respectively. We try the same test twice: once with
1070433d6423SLionel Sambuc * a common block size, and once to push against the max request size.
1071433d6423SLionel Sambuc */
1072433d6423SLionel Sambuc size_t max_block;
1073433d6423SLionel Sambuc
1074433d6423SLionel Sambuc /* Make sure that the maximum size does not exceed the target device
1075433d6423SLionel Sambuc * size, minus the margins we need for testing here and there.
1076433d6423SLionel Sambuc */
1077433d6423SLionel Sambuc if (max_size > part.size - sector_size * 4)
1078433d6423SLionel Sambuc max_size = part.size - sector_size * 4;
1079433d6423SLionel Sambuc
1080433d6423SLionel Sambuc /* Compute the largest sector multiple which, when multiplied by
1081433d6423SLionel Sambuc * NR_IOREQS, is no more than the maximum transfer size. Note that if
1082433d6423SLionel Sambuc * max_size is not a multiple of sector_size, we're not going up to the
1083433d6423SLionel Sambuc * limit entirely this way.
1084433d6423SLionel Sambuc */
1085433d6423SLionel Sambuc max_block = max_size / NR_IOREQS;
1086433d6423SLionel Sambuc max_block -= max_block % sector_size;
1087433d6423SLionel Sambuc
1088433d6423SLionel Sambuc #define COMMON_BLOCK_SIZE 4096
1089433d6423SLionel Sambuc
1090433d6423SLionel Sambuc test_group("vector and large, common block", TRUE);
1091433d6423SLionel Sambuc
1092433d6423SLionel Sambuc vector_and_large_sub(COMMON_BLOCK_SIZE);
1093433d6423SLionel Sambuc
1094433d6423SLionel Sambuc if (max_block != COMMON_BLOCK_SIZE) {
1095433d6423SLionel Sambuc test_group("vector and large, large block", TRUE);
1096433d6423SLionel Sambuc
1097433d6423SLionel Sambuc vector_and_large_sub(max_block);
1098433d6423SLionel Sambuc }
1099433d6423SLionel Sambuc }
1100433d6423SLionel Sambuc
open_device(dev_t minor)1101433d6423SLionel Sambuc static void open_device(dev_t minor)
1102433d6423SLionel Sambuc {
1103433d6423SLionel Sambuc /* Open a partition or subpartition. Remember that it has been opened,
1104433d6423SLionel Sambuc * so that we can reopen it later in the event of a driver crash.
1105433d6423SLionel Sambuc */
1106433d6423SLionel Sambuc message m;
1107433d6423SLionel Sambuc result_t res;
1108433d6423SLionel Sambuc
1109433d6423SLionel Sambuc memset(&m, 0, sizeof(m));
1110433d6423SLionel Sambuc m.m_type = BDEV_OPEN;
1111433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.minor = minor;
1112433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.access = may_write ? (BDEV_R_BIT | BDEV_W_BIT) : BDEV_R_BIT;
1113433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.id = lrand48();
1114433d6423SLionel Sambuc
1115433d6423SLionel Sambuc sendrec_driver(&m, OK, &res);
1116433d6423SLionel Sambuc
1117433d6423SLionel Sambuc /* We assume that this call is supposed to succeed. We pretend it
1118433d6423SLionel Sambuc * always succeeds, so that close_device() won't get confused later.
1119433d6423SLionel Sambuc */
1120433d6423SLionel Sambuc assert(nr_opened < NR_OPENED);
1121433d6423SLionel Sambuc opened[nr_opened++] = minor;
1122433d6423SLionel Sambuc
1123433d6423SLionel Sambuc got_result(&res, minor == driver_minor ? "opening the main partition" :
1124433d6423SLionel Sambuc "opening a subpartition");
1125433d6423SLionel Sambuc }
1126433d6423SLionel Sambuc
close_device(dev_t minor)1127433d6423SLionel Sambuc static void close_device(dev_t minor)
1128433d6423SLionel Sambuc {
1129433d6423SLionel Sambuc /* Close a partition or subpartition. Remove it from the list of opened
1130433d6423SLionel Sambuc * devices.
1131433d6423SLionel Sambuc */
1132433d6423SLionel Sambuc message m;
1133433d6423SLionel Sambuc result_t res;
1134433d6423SLionel Sambuc int i;
1135433d6423SLionel Sambuc
1136433d6423SLionel Sambuc memset(&m, 0, sizeof(m));
1137433d6423SLionel Sambuc m.m_type = BDEV_CLOSE;
1138433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.minor = minor;
1139433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.id = lrand48();
1140433d6423SLionel Sambuc
1141433d6423SLionel Sambuc sendrec_driver(&m, OK, &res);
1142433d6423SLionel Sambuc
1143433d6423SLionel Sambuc assert(nr_opened > 0);
1144433d6423SLionel Sambuc for (i = 0; i < nr_opened; i++) {
1145433d6423SLionel Sambuc if (opened[i] == minor) {
1146433d6423SLionel Sambuc opened[i] = opened[--nr_opened];
1147433d6423SLionel Sambuc break;
1148433d6423SLionel Sambuc }
1149433d6423SLionel Sambuc }
1150433d6423SLionel Sambuc
1151433d6423SLionel Sambuc got_result(&res, minor == driver_minor ? "closing the main partition" :
1152433d6423SLionel Sambuc "closing a subpartition");
1153433d6423SLionel Sambuc }
1154433d6423SLionel Sambuc
vir_ioctl(dev_t minor,unsigned long req,void * ptr,ssize_t exp,result_t * res)115563ce03dbSDavid van Moolenbroek static int vir_ioctl(dev_t minor, unsigned long req, void *ptr, ssize_t exp,
1156433d6423SLionel Sambuc result_t *res)
1157433d6423SLionel Sambuc {
1158433d6423SLionel Sambuc /* Perform an I/O control request, using a local buffer.
1159433d6423SLionel Sambuc */
1160433d6423SLionel Sambuc cp_grant_id_t grant;
1161433d6423SLionel Sambuc message m;
1162433d6423SLionel Sambuc int r, perm;
1163433d6423SLionel Sambuc
1164433d6423SLionel Sambuc assert(!_MINIX_IOCTL_BIG(req)); /* not supported */
1165433d6423SLionel Sambuc
1166433d6423SLionel Sambuc perm = 0;
1167433d6423SLionel Sambuc if (_MINIX_IOCTL_IOR(req)) perm |= CPF_WRITE;
1168433d6423SLionel Sambuc if (_MINIX_IOCTL_IOW(req)) perm |= CPF_READ;
1169433d6423SLionel Sambuc
1170433d6423SLionel Sambuc if ((grant = cpf_grant_direct(driver_endpt, (vir_bytes) ptr,
1171433d6423SLionel Sambuc _MINIX_IOCTL_SIZE(req), perm)) == GRANT_INVALID)
1172433d6423SLionel Sambuc panic("unable to allocate grant");
1173433d6423SLionel Sambuc
1174433d6423SLionel Sambuc memset(&m, 0, sizeof(m));
1175433d6423SLionel Sambuc m.m_type = BDEV_IOCTL;
1176433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.minor = minor;
1177433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.request = req;
1178433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.grant = grant;
1179433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.user = NONE;
1180433d6423SLionel Sambuc m.m_lbdev_lblockdriver_msg.id = lrand48();
1181433d6423SLionel Sambuc
1182433d6423SLionel Sambuc r = sendrec_driver(&m, exp, res);
1183433d6423SLionel Sambuc
1184*10b7016bSDavid van Moolenbroek if (cpf_revoke(grant) == -1)
1185433d6423SLionel Sambuc panic("unable to revoke grant");
1186433d6423SLionel Sambuc
1187433d6423SLionel Sambuc return r;
1188433d6423SLionel Sambuc }
1189433d6423SLionel Sambuc
misc_ioctl(void)1190433d6423SLionel Sambuc static void misc_ioctl(void)
1191433d6423SLionel Sambuc {
1192433d6423SLionel Sambuc /* Test some ioctls.
1193433d6423SLionel Sambuc */
1194433d6423SLionel Sambuc result_t res;
1195433d6423SLionel Sambuc int openct;
1196433d6423SLionel Sambuc
1197433d6423SLionel Sambuc test_group("test miscellaneous ioctls", TRUE);
1198433d6423SLionel Sambuc
1199433d6423SLionel Sambuc /* Retrieve the main partition's base and size. Save for later. */
1200433d6423SLionel Sambuc vir_ioctl(driver_minor, DIOCGETP, &part, OK, &res);
1201433d6423SLionel Sambuc
1202433d6423SLionel Sambuc got_result(&res, "ioctl to get partition");
1203433d6423SLionel Sambuc
1204433d6423SLionel Sambuc /* The other tests do not check whether there is sufficient room. */
1205433d6423SLionel Sambuc if (res.type == RESULT_OK && part.size < (u64_t)max_size * 2)
1206433d6423SLionel Sambuc output("WARNING: small partition, some tests may fail\n");
1207433d6423SLionel Sambuc
1208433d6423SLionel Sambuc /* Test retrieving global driver open count. */
1209433d6423SLionel Sambuc openct = 0x0badcafe;
1210433d6423SLionel Sambuc
1211433d6423SLionel Sambuc vir_ioctl(driver_minor, DIOCOPENCT, &openct, OK, &res);
1212433d6423SLionel Sambuc
1213433d6423SLionel Sambuc /* We assume that we're the only client to the driver right now. */
1214433d6423SLionel Sambuc if (res.type == RESULT_OK && openct != 1) {
1215433d6423SLionel Sambuc res.type = RESULT_BADVALUE;
1216433d6423SLionel Sambuc res.value = openct;
1217433d6423SLionel Sambuc }
1218433d6423SLionel Sambuc
1219433d6423SLionel Sambuc got_result(&res, "ioctl to get open count");
1220433d6423SLionel Sambuc
1221433d6423SLionel Sambuc /* Test increasing and re-retrieving open count. */
1222433d6423SLionel Sambuc open_device(driver_minor);
1223433d6423SLionel Sambuc
1224433d6423SLionel Sambuc openct = 0x0badcafe;
1225433d6423SLionel Sambuc
1226433d6423SLionel Sambuc vir_ioctl(driver_minor, DIOCOPENCT, &openct, OK, &res);
1227433d6423SLionel Sambuc
1228433d6423SLionel Sambuc if (res.type == RESULT_OK && openct != 2) {
1229433d6423SLionel Sambuc res.type = RESULT_BADVALUE;
1230433d6423SLionel Sambuc res.value = openct;
1231433d6423SLionel Sambuc }
1232433d6423SLionel Sambuc
1233433d6423SLionel Sambuc got_result(&res, "increased open count after opening");
1234433d6423SLionel Sambuc
1235433d6423SLionel Sambuc /* Test decreasing and re-retrieving open count. */
1236433d6423SLionel Sambuc close_device(driver_minor);
1237433d6423SLionel Sambuc
1238433d6423SLionel Sambuc openct = 0x0badcafe;
1239433d6423SLionel Sambuc
1240433d6423SLionel Sambuc vir_ioctl(driver_minor, DIOCOPENCT, &openct, OK, &res);
1241433d6423SLionel Sambuc
1242433d6423SLionel Sambuc if (res.type == RESULT_OK && openct != 1) {
1243433d6423SLionel Sambuc res.type = RESULT_BADVALUE;
1244433d6423SLionel Sambuc res.value = openct;
1245433d6423SLionel Sambuc }
1246433d6423SLionel Sambuc
1247433d6423SLionel Sambuc got_result(&res, "decreased open count after closing");
1248433d6423SLionel Sambuc }
1249433d6423SLionel Sambuc
read_limits(dev_t sub0_minor,dev_t sub1_minor,size_t sub_size)1250433d6423SLionel Sambuc static void read_limits(dev_t sub0_minor, dev_t sub1_minor, size_t sub_size)
1251433d6423SLionel Sambuc {
1252433d6423SLionel Sambuc /* Test reads up to, across, and beyond partition limits.
1253433d6423SLionel Sambuc */
1254433d6423SLionel Sambuc u8_t *buf_ptr;
1255433d6423SLionel Sambuc size_t buf_size;
1256433d6423SLionel Sambuc u32_t sum, sum2, sum3;
1257433d6423SLionel Sambuc result_t res;
1258433d6423SLionel Sambuc
1259433d6423SLionel Sambuc test_group("read around subpartition limits", TRUE);
1260433d6423SLionel Sambuc
1261433d6423SLionel Sambuc buf_size = sector_size * 3;
1262433d6423SLionel Sambuc buf_ptr = alloc_dma_memory(buf_size);
1263433d6423SLionel Sambuc
1264433d6423SLionel Sambuc /* Read one sector up to the partition limit. */
1265433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1266433d6423SLionel Sambuc
1267433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size - sector_size, buf_ptr,
1268433d6423SLionel Sambuc sector_size, FALSE, sector_size, &res);
1269433d6423SLionel Sambuc
1270433d6423SLionel Sambuc sum = get_sum(buf_ptr, sector_size);
1271433d6423SLionel Sambuc
1272433d6423SLionel Sambuc got_result(&res, "one sector read up to partition end");
1273433d6423SLionel Sambuc
1274433d6423SLionel Sambuc /* Read three sectors up to the partition limit. */
1275433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1276433d6423SLionel Sambuc
1277433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size - buf_size, buf_ptr, buf_size,
1278433d6423SLionel Sambuc FALSE, buf_size, &res);
1279433d6423SLionel Sambuc
1280433d6423SLionel Sambuc test_sum(buf_ptr + sector_size * 2, sector_size, sum, TRUE, &res);
1281433d6423SLionel Sambuc
1282433d6423SLionel Sambuc sum2 = get_sum(buf_ptr + sector_size, sector_size * 2);
1283433d6423SLionel Sambuc
1284433d6423SLionel Sambuc got_result(&res, "multisector read up to partition end");
1285433d6423SLionel Sambuc
1286433d6423SLionel Sambuc /* Read three sectors, two up to and one beyond the partition end. */
1287433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1288433d6423SLionel Sambuc sum3 = get_sum(buf_ptr + sector_size * 2, sector_size);
1289433d6423SLionel Sambuc
1290433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size - sector_size * 2, buf_ptr,
1291433d6423SLionel Sambuc buf_size, FALSE, sector_size * 2, &res);
1292433d6423SLionel Sambuc
1293433d6423SLionel Sambuc test_sum(buf_ptr, sector_size * 2, sum2, TRUE, &res);
1294433d6423SLionel Sambuc test_sum(buf_ptr + sector_size * 2, sector_size, sum3, TRUE, &res);
1295433d6423SLionel Sambuc
1296433d6423SLionel Sambuc got_result(&res, "read somewhat across partition end");
1297433d6423SLionel Sambuc
1298433d6423SLionel Sambuc /* Read three sectors, one up to and two beyond the partition end. */
1299433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1300433d6423SLionel Sambuc sum2 = get_sum(buf_ptr + sector_size, sector_size * 2);
1301433d6423SLionel Sambuc
1302433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size - sector_size, buf_ptr,
1303433d6423SLionel Sambuc buf_size, FALSE, sector_size, &res);
1304433d6423SLionel Sambuc
1305433d6423SLionel Sambuc test_sum(buf_ptr, sector_size, sum, TRUE, &res);
1306433d6423SLionel Sambuc test_sum(buf_ptr + sector_size, sector_size * 2, sum2, TRUE, &res);
1307433d6423SLionel Sambuc
1308433d6423SLionel Sambuc got_result(&res, "read mostly across partition end");
1309433d6423SLionel Sambuc
1310433d6423SLionel Sambuc /* Read one sector starting at the partition end. */
1311433d6423SLionel Sambuc sum = fill_rand(buf_ptr, buf_size);
1312433d6423SLionel Sambuc sum2 = get_sum(buf_ptr, sector_size);
1313433d6423SLionel Sambuc
1314433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size, buf_ptr, sector_size, FALSE,
1315433d6423SLionel Sambuc 0, &res);
1316433d6423SLionel Sambuc
1317433d6423SLionel Sambuc test_sum(buf_ptr, sector_size, sum2, TRUE, &res);
1318433d6423SLionel Sambuc
1319433d6423SLionel Sambuc got_result(&res, "one sector read at partition end");
1320433d6423SLionel Sambuc
1321433d6423SLionel Sambuc /* Read three sectors starting at the partition end. */
1322433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size, buf_ptr, buf_size, FALSE, 0,
1323433d6423SLionel Sambuc &res);
1324433d6423SLionel Sambuc
1325433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, sum, TRUE, &res);
1326433d6423SLionel Sambuc
1327433d6423SLionel Sambuc got_result(&res, "multisector read at partition end");
1328433d6423SLionel Sambuc
1329433d6423SLionel Sambuc /* Read one sector beyond the partition end. */
1330433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size + sector_size, buf_ptr,
1331433d6423SLionel Sambuc buf_size, FALSE, 0, &res);
1332433d6423SLionel Sambuc
1333433d6423SLionel Sambuc test_sum(buf_ptr, sector_size, sum2, TRUE, &res);
1334433d6423SLionel Sambuc
1335433d6423SLionel Sambuc got_result(&res, "single sector read beyond partition end");
1336433d6423SLionel Sambuc
1337433d6423SLionel Sambuc /* Read three sectors way beyond the partition end. */
1338433d6423SLionel Sambuc simple_xfer(sub0_minor, 0x1000000000000000ULL, buf_ptr, buf_size,
1339433d6423SLionel Sambuc FALSE, 0, &res);
1340433d6423SLionel Sambuc
1341433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, sum, TRUE, &res);
1342433d6423SLionel Sambuc
1343433d6423SLionel Sambuc /* Test negative offsets. This request should return EOF or fail; we
1344433d6423SLionel Sambuc * assume that it return EOF here (because that is what the AHCI driver
1345433d6423SLionel Sambuc * does, to avoid producing errors for requests close to the 2^64 byte
1346433d6423SLionel Sambuc * position limit [yes, this will indeed never happen anyway]). This is
1347433d6423SLionel Sambuc * more or less a bad requests test, but we cannot do it without
1348433d6423SLionel Sambuc * setting up subpartitions first.
1349433d6423SLionel Sambuc */
1350433d6423SLionel Sambuc simple_xfer(sub1_minor, 0xffffffffffffffffULL - sector_size + 1,
1351433d6423SLionel Sambuc buf_ptr, sector_size, FALSE, 0, &res);
1352433d6423SLionel Sambuc
1353433d6423SLionel Sambuc test_sum(buf_ptr, sector_size, sum2, TRUE, &res);
1354433d6423SLionel Sambuc
1355433d6423SLionel Sambuc got_result(&res, "read with negative offset");
1356433d6423SLionel Sambuc
1357433d6423SLionel Sambuc /* Clean up. */
1358433d6423SLionel Sambuc free_dma_memory(buf_ptr, buf_size);
1359433d6423SLionel Sambuc }
1360433d6423SLionel Sambuc
write_limits(dev_t sub0_minor,dev_t sub1_minor,size_t sub_size)1361433d6423SLionel Sambuc static void write_limits(dev_t sub0_minor, dev_t sub1_minor, size_t sub_size)
1362433d6423SLionel Sambuc {
1363433d6423SLionel Sambuc /* Test writes up to, across, and beyond partition limits. Use the
1364433d6423SLionel Sambuc * first given subpartition to test, and the second to make sure there
1365433d6423SLionel Sambuc * are no overruns. The given size is the size of each of the
1366433d6423SLionel Sambuc * subpartitions. Note that the necessity to check the results using
1367433d6423SLionel Sambuc * readback, makes this more or less a superset of the read test.
1368433d6423SLionel Sambuc */
1369433d6423SLionel Sambuc u8_t *buf_ptr;
1370433d6423SLionel Sambuc size_t buf_size;
1371433d6423SLionel Sambuc u32_t sum, sum2, sum3, sub1_sum;
1372433d6423SLionel Sambuc result_t res;
1373433d6423SLionel Sambuc
1374433d6423SLionel Sambuc test_group("write around subpartition limits", may_write);
1375433d6423SLionel Sambuc
1376433d6423SLionel Sambuc if (!may_write)
1377433d6423SLionel Sambuc return;
1378433d6423SLionel Sambuc
1379433d6423SLionel Sambuc buf_size = sector_size * 3;
1380433d6423SLionel Sambuc buf_ptr = alloc_dma_memory(buf_size);
1381433d6423SLionel Sambuc
1382433d6423SLionel Sambuc /* Write to the start of the second subpartition, so that we can
1383433d6423SLionel Sambuc * reliably check whether the contents have changed later.
1384433d6423SLionel Sambuc */
1385433d6423SLionel Sambuc sub1_sum = fill_rand(buf_ptr, buf_size);
1386433d6423SLionel Sambuc
1387433d6423SLionel Sambuc simple_xfer(sub1_minor, 0ULL, buf_ptr, buf_size, TRUE, buf_size, &res);
1388433d6423SLionel Sambuc
1389433d6423SLionel Sambuc got_result(&res, "write to second subpartition");
1390433d6423SLionel Sambuc
1391433d6423SLionel Sambuc /* Write one sector, up to the partition limit. */
1392433d6423SLionel Sambuc sum = fill_rand(buf_ptr, sector_size);
1393433d6423SLionel Sambuc
1394433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size - sector_size, buf_ptr,
1395433d6423SLionel Sambuc sector_size, TRUE, sector_size, &res);
1396433d6423SLionel Sambuc
1397433d6423SLionel Sambuc got_result(&res, "write up to partition end");
1398433d6423SLionel Sambuc
1399433d6423SLionel Sambuc /* Read back to make sure the results have persisted. */
1400433d6423SLionel Sambuc fill_rand(buf_ptr, sector_size * 2);
1401433d6423SLionel Sambuc
1402433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size - sector_size * 2, buf_ptr,
1403433d6423SLionel Sambuc sector_size * 2, FALSE, sector_size * 2, &res);
1404433d6423SLionel Sambuc
1405433d6423SLionel Sambuc test_sum(buf_ptr + sector_size, sector_size, sum, TRUE, &res);
1406433d6423SLionel Sambuc
1407433d6423SLionel Sambuc got_result(&res, "read up to partition end");
1408433d6423SLionel Sambuc
1409433d6423SLionel Sambuc /* Write three sectors, two up to and one beyond the partition end. */
1410433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1411433d6423SLionel Sambuc sum = get_sum(buf_ptr + sector_size, sector_size);
1412433d6423SLionel Sambuc sum3 = get_sum(buf_ptr, sector_size);
1413433d6423SLionel Sambuc
1414433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size - sector_size * 2, buf_ptr,
1415433d6423SLionel Sambuc buf_size, TRUE, sector_size * 2, &res);
1416433d6423SLionel Sambuc
1417433d6423SLionel Sambuc got_result(&res, "write somewhat across partition end");
1418433d6423SLionel Sambuc
1419433d6423SLionel Sambuc /* Read three sectors, one up to and two beyond the partition end. */
1420433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1421433d6423SLionel Sambuc sum2 = get_sum(buf_ptr + sector_size, sector_size * 2);
1422433d6423SLionel Sambuc
1423433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size - sector_size, buf_ptr,
1424433d6423SLionel Sambuc buf_size, FALSE, sector_size, &res);
1425433d6423SLionel Sambuc
1426433d6423SLionel Sambuc test_sum(buf_ptr, sector_size, sum, TRUE, &res);
1427433d6423SLionel Sambuc test_sum(buf_ptr + sector_size, sector_size * 2, sum2, TRUE, &res);
1428433d6423SLionel Sambuc
1429433d6423SLionel Sambuc got_result(&res, "read mostly across partition end");
1430433d6423SLionel Sambuc
1431433d6423SLionel Sambuc /* Repeat this but with write and read start positions swapped. */
1432433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1433433d6423SLionel Sambuc sum = get_sum(buf_ptr, sector_size);
1434433d6423SLionel Sambuc
1435433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size - sector_size, buf_ptr,
1436433d6423SLionel Sambuc buf_size, TRUE, sector_size, &res);
1437433d6423SLionel Sambuc
1438433d6423SLionel Sambuc got_result(&res, "write mostly across partition end");
1439433d6423SLionel Sambuc
1440433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1441433d6423SLionel Sambuc sum2 = get_sum(buf_ptr + sector_size * 2, sector_size);
1442433d6423SLionel Sambuc
1443433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size - sector_size * 2, buf_ptr,
1444433d6423SLionel Sambuc buf_size, FALSE, sector_size * 2, &res);
1445433d6423SLionel Sambuc
1446433d6423SLionel Sambuc test_sum(buf_ptr, sector_size, sum3, TRUE, &res);
1447433d6423SLionel Sambuc test_sum(buf_ptr + sector_size, sector_size, sum, TRUE, &res);
1448433d6423SLionel Sambuc test_sum(buf_ptr + sector_size * 2, sector_size, sum2, TRUE, &res);
1449433d6423SLionel Sambuc
1450433d6423SLionel Sambuc got_result(&res, "read somewhat across partition end");
1451433d6423SLionel Sambuc
1452433d6423SLionel Sambuc /* Write one sector at the end of the partition. */
1453433d6423SLionel Sambuc fill_rand(buf_ptr, sector_size);
1454433d6423SLionel Sambuc
1455433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size, buf_ptr, sector_size, TRUE, 0,
1456433d6423SLionel Sambuc &res);
1457433d6423SLionel Sambuc
1458433d6423SLionel Sambuc got_result(&res, "write at partition end");
1459433d6423SLionel Sambuc
1460433d6423SLionel Sambuc /* Write one sector beyond the end of the partition. */
1461433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size + sector_size, buf_ptr,
1462433d6423SLionel Sambuc sector_size, TRUE, 0, &res);
1463433d6423SLionel Sambuc
1464433d6423SLionel Sambuc got_result(&res, "write beyond partition end");
1465433d6423SLionel Sambuc
1466433d6423SLionel Sambuc /* Read from the start of the second subpartition, and see if it
1467433d6423SLionel Sambuc * matches what we wrote into it earlier.
1468433d6423SLionel Sambuc */
1469433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1470433d6423SLionel Sambuc
1471433d6423SLionel Sambuc simple_xfer(sub1_minor, 0ULL, buf_ptr, buf_size, FALSE, buf_size,
1472433d6423SLionel Sambuc &res);
1473433d6423SLionel Sambuc
1474433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, sub1_sum, TRUE, &res);
1475433d6423SLionel Sambuc
1476433d6423SLionel Sambuc got_result(&res, "read from second subpartition");
1477433d6423SLionel Sambuc
1478433d6423SLionel Sambuc /* Test offset wrapping, but this time for writes. */
1479433d6423SLionel Sambuc fill_rand(buf_ptr, sector_size);
1480433d6423SLionel Sambuc
1481433d6423SLionel Sambuc simple_xfer(sub1_minor, 0xffffffffffffffffULL - sector_size + 1,
1482433d6423SLionel Sambuc buf_ptr, sector_size, TRUE, 0, &res);
1483433d6423SLionel Sambuc
1484433d6423SLionel Sambuc got_result(&res, "write with negative offset");
1485433d6423SLionel Sambuc
1486433d6423SLionel Sambuc /* If the last request erroneously succeeded, it would have overwritten
1487433d6423SLionel Sambuc * the last sector of the first subpartition.
1488433d6423SLionel Sambuc */
1489433d6423SLionel Sambuc simple_xfer(sub0_minor, (u64_t)sub_size - sector_size, buf_ptr,
1490433d6423SLionel Sambuc sector_size, FALSE, sector_size, &res);
1491433d6423SLionel Sambuc
1492433d6423SLionel Sambuc test_sum(buf_ptr, sector_size, sum, TRUE, &res);
1493433d6423SLionel Sambuc
1494433d6423SLionel Sambuc got_result(&res, "read up to partition end");
1495433d6423SLionel Sambuc
1496433d6423SLionel Sambuc /* Clean up. */
1497433d6423SLionel Sambuc free_dma_memory(buf_ptr, buf_size);
1498433d6423SLionel Sambuc }
1499433d6423SLionel Sambuc
vir_limits(dev_t sub0_minor,dev_t sub1_minor,int part_secs)1500433d6423SLionel Sambuc static void vir_limits(dev_t sub0_minor, dev_t sub1_minor, int part_secs)
1501433d6423SLionel Sambuc {
1502433d6423SLionel Sambuc /* Create virtual, temporary subpartitions through the DIOCSETP ioctl,
1503433d6423SLionel Sambuc * and perform tests on the resulting subpartitions.
1504433d6423SLionel Sambuc */
1505433d6423SLionel Sambuc struct part_geom subpart, subpart2;
1506433d6423SLionel Sambuc size_t sub_size;
1507433d6423SLionel Sambuc result_t res;
1508433d6423SLionel Sambuc
1509433d6423SLionel Sambuc test_group("virtual subpartition limits", TRUE);
1510433d6423SLionel Sambuc
1511433d6423SLionel Sambuc /* Open the subpartitions. This is somewhat dodgy; we rely on the
1512433d6423SLionel Sambuc * driver allowing this even if no subpartitions exist. We cannot do
1513433d6423SLionel Sambuc * this test without doing a DIOCSETP on an open subdevice, though.
1514433d6423SLionel Sambuc */
1515433d6423SLionel Sambuc open_device(sub0_minor);
1516433d6423SLionel Sambuc open_device(sub1_minor);
1517433d6423SLionel Sambuc
1518433d6423SLionel Sambuc sub_size = sector_size * part_secs;
1519433d6423SLionel Sambuc
1520433d6423SLionel Sambuc /* Set, and check, the size of the first subpartition. */
1521433d6423SLionel Sambuc subpart = part;
1522433d6423SLionel Sambuc subpart.size = (u64_t)sub_size;
1523433d6423SLionel Sambuc
1524433d6423SLionel Sambuc vir_ioctl(sub0_minor, DIOCSETP, &subpart, OK, &res);
1525433d6423SLionel Sambuc
1526433d6423SLionel Sambuc got_result(&res, "ioctl to set first subpartition");
1527433d6423SLionel Sambuc
1528433d6423SLionel Sambuc vir_ioctl(sub0_minor, DIOCGETP, &subpart2, OK, &res);
1529433d6423SLionel Sambuc
1530433d6423SLionel Sambuc if (res.type == RESULT_OK && (subpart.base != subpart2.base ||
1531433d6423SLionel Sambuc subpart.size != subpart2.size)) {
1532433d6423SLionel Sambuc res.type = RESULT_BADVALUE;
1533433d6423SLionel Sambuc res.value = 0;
1534433d6423SLionel Sambuc }
1535433d6423SLionel Sambuc
1536433d6423SLionel Sambuc got_result(&res, "ioctl to get first subpartition");
1537433d6423SLionel Sambuc
1538433d6423SLionel Sambuc /* Set, and check, the base and size of the second subpartition. */
1539433d6423SLionel Sambuc subpart = part;
1540433d6423SLionel Sambuc subpart.base += sub_size;
1541433d6423SLionel Sambuc subpart.size = (u64_t)sub_size;
1542433d6423SLionel Sambuc
1543433d6423SLionel Sambuc vir_ioctl(sub1_minor, DIOCSETP, &subpart, OK, &res);
1544433d6423SLionel Sambuc
1545433d6423SLionel Sambuc got_result(&res, "ioctl to set second subpartition");
1546433d6423SLionel Sambuc
1547433d6423SLionel Sambuc vir_ioctl(sub1_minor, DIOCGETP, &subpart2, OK, &res);
1548433d6423SLionel Sambuc
1549433d6423SLionel Sambuc if (res.type == RESULT_OK && (subpart.base != subpart2.base ||
1550433d6423SLionel Sambuc subpart.size != subpart2.size)) {
1551433d6423SLionel Sambuc res.type = RESULT_BADVALUE;
1552433d6423SLionel Sambuc res.value = 0;
1553433d6423SLionel Sambuc }
1554433d6423SLionel Sambuc
1555433d6423SLionel Sambuc got_result(&res, "ioctl to get second subpartition");
1556433d6423SLionel Sambuc
1557433d6423SLionel Sambuc /* Perform the actual I/O tests. */
1558433d6423SLionel Sambuc read_limits(sub0_minor, sub1_minor, sub_size);
1559433d6423SLionel Sambuc
1560433d6423SLionel Sambuc write_limits(sub0_minor, sub1_minor, sub_size);
1561433d6423SLionel Sambuc
1562433d6423SLionel Sambuc /* Clean up. */
1563433d6423SLionel Sambuc close_device(sub1_minor);
1564433d6423SLionel Sambuc close_device(sub0_minor);
1565433d6423SLionel Sambuc }
1566433d6423SLionel Sambuc
real_limits(dev_t sub0_minor,dev_t sub1_minor,int part_secs)1567433d6423SLionel Sambuc static void real_limits(dev_t sub0_minor, dev_t sub1_minor, int part_secs)
1568433d6423SLionel Sambuc {
1569433d6423SLionel Sambuc /* Create our own subpartitions by writing a partition table, and
1570433d6423SLionel Sambuc * perform tests on the resulting real subpartitions.
1571433d6423SLionel Sambuc */
1572433d6423SLionel Sambuc u8_t *buf_ptr;
1573433d6423SLionel Sambuc size_t buf_size, sub_size;
1574433d6423SLionel Sambuc struct part_geom subpart;
1575433d6423SLionel Sambuc struct part_entry *entry;
1576433d6423SLionel Sambuc result_t res;
1577433d6423SLionel Sambuc
1578433d6423SLionel Sambuc test_group("real subpartition limits", may_write);
1579433d6423SLionel Sambuc
1580433d6423SLionel Sambuc if (!may_write)
1581433d6423SLionel Sambuc return;
1582433d6423SLionel Sambuc
1583433d6423SLionel Sambuc sub_size = sector_size * part_secs;
1584433d6423SLionel Sambuc
1585433d6423SLionel Sambuc /* Technically, we should be using 512 instead of sector_size in
1586433d6423SLionel Sambuc * various places, because even on CD-ROMs, the partition tables are
1587433d6423SLionel Sambuc * 512 bytes and the sector counts are based on 512-byte sectors in it.
1588433d6423SLionel Sambuc * We ignore this subtlety because CD-ROMs are assumed to be read-only
1589433d6423SLionel Sambuc * anyway.
1590433d6423SLionel Sambuc */
1591433d6423SLionel Sambuc buf_size = sector_size;
1592433d6423SLionel Sambuc buf_ptr = alloc_dma_memory(buf_size);
1593433d6423SLionel Sambuc
1594433d6423SLionel Sambuc memset(buf_ptr, 0, buf_size);
1595433d6423SLionel Sambuc
1596433d6423SLionel Sambuc /* Write an invalid partition table. */
1597433d6423SLionel Sambuc simple_xfer(driver_minor, 0ULL, buf_ptr, buf_size, TRUE, buf_size,
1598433d6423SLionel Sambuc &res);
1599433d6423SLionel Sambuc
1600433d6423SLionel Sambuc got_result(&res, "write of invalid partition table");
1601433d6423SLionel Sambuc
1602433d6423SLionel Sambuc /* Get the disk driver to reread the partition table. This should
1603433d6423SLionel Sambuc * happen (at least) when the device is fully closed and then reopened.
1604433d6423SLionel Sambuc * The ioctl test already made sure that we're the only client.
1605433d6423SLionel Sambuc */
1606433d6423SLionel Sambuc close_device(driver_minor);
1607433d6423SLionel Sambuc open_device(driver_minor);
1608433d6423SLionel Sambuc
1609433d6423SLionel Sambuc /* See if our changes are visible. We expect the subpartitions to have
1610433d6423SLionel Sambuc * a size of zero now, indicating that they're not there. For actual
1611433d6423SLionel Sambuc * subpartitions (as opposed to normal partitions), this requires the
1612433d6423SLionel Sambuc * driver to zero them out, because the partition code does not do so.
1613433d6423SLionel Sambuc */
1614433d6423SLionel Sambuc open_device(sub0_minor);
1615433d6423SLionel Sambuc open_device(sub1_minor);
1616433d6423SLionel Sambuc
1617433d6423SLionel Sambuc vir_ioctl(sub0_minor, DIOCGETP, &subpart, 0, &res);
1618433d6423SLionel Sambuc
1619433d6423SLionel Sambuc if (res.type == RESULT_OK && subpart.size != 0) {
1620433d6423SLionel Sambuc res.type = RESULT_BADVALUE;
1621433d6423SLionel Sambuc res.value = ex64lo(subpart.size);
1622433d6423SLionel Sambuc }
1623433d6423SLionel Sambuc
1624433d6423SLionel Sambuc got_result(&res, "ioctl to get first subpartition");
1625433d6423SLionel Sambuc
1626433d6423SLionel Sambuc vir_ioctl(sub1_minor, DIOCGETP, &subpart, 0, &res);
1627433d6423SLionel Sambuc
1628433d6423SLionel Sambuc if (res.type == RESULT_OK && subpart.size != 0) {
1629433d6423SLionel Sambuc res.type = RESULT_BADVALUE;
1630433d6423SLionel Sambuc res.value = ex64lo(subpart.size);
1631433d6423SLionel Sambuc }
1632433d6423SLionel Sambuc
1633433d6423SLionel Sambuc got_result(&res, "ioctl to get second subpartition");
1634433d6423SLionel Sambuc
1635433d6423SLionel Sambuc close_device(sub1_minor);
1636433d6423SLionel Sambuc close_device(sub0_minor);
1637433d6423SLionel Sambuc
1638433d6423SLionel Sambuc /* Now write a valid partition table. */
1639433d6423SLionel Sambuc memset(buf_ptr, 0, buf_size);
1640433d6423SLionel Sambuc
1641433d6423SLionel Sambuc entry = (struct part_entry *) &buf_ptr[PART_TABLE_OFF];
1642433d6423SLionel Sambuc
1643433d6423SLionel Sambuc entry[0].sysind = MINIX_PART;
1644433d6423SLionel Sambuc entry[0].lowsec = part.base / sector_size + 1;
1645433d6423SLionel Sambuc entry[0].size = part_secs;
1646433d6423SLionel Sambuc entry[1].sysind = MINIX_PART;
1647433d6423SLionel Sambuc entry[1].lowsec = entry[0].lowsec + entry[0].size;
1648433d6423SLionel Sambuc entry[1].size = part_secs;
1649433d6423SLionel Sambuc
1650433d6423SLionel Sambuc buf_ptr[510] = 0x55;
1651433d6423SLionel Sambuc buf_ptr[511] = 0xAA;
1652433d6423SLionel Sambuc
1653433d6423SLionel Sambuc simple_xfer(driver_minor, 0ULL, buf_ptr, buf_size, TRUE, buf_size,
1654433d6423SLionel Sambuc &res);
1655433d6423SLionel Sambuc
1656433d6423SLionel Sambuc got_result(&res, "write of valid partition table");
1657433d6423SLionel Sambuc
1658433d6423SLionel Sambuc /* Same as above. */
1659433d6423SLionel Sambuc close_device(driver_minor);
1660433d6423SLionel Sambuc open_device(driver_minor);
1661433d6423SLionel Sambuc
1662433d6423SLionel Sambuc /* Again, see if our changes are visible. This time the proper base and
1663433d6423SLionel Sambuc * size should be there.
1664433d6423SLionel Sambuc */
1665433d6423SLionel Sambuc open_device(sub0_minor);
1666433d6423SLionel Sambuc open_device(sub1_minor);
1667433d6423SLionel Sambuc
1668433d6423SLionel Sambuc vir_ioctl(sub0_minor, DIOCGETP, &subpart, 0, &res);
1669433d6423SLionel Sambuc
1670433d6423SLionel Sambuc if (res.type == RESULT_OK &&
1671433d6423SLionel Sambuc (subpart.base != part.base + sector_size ||
1672433d6423SLionel Sambuc subpart.size != (u64_t)part_secs * sector_size)) {
1673433d6423SLionel Sambuc
1674433d6423SLionel Sambuc res.type = RESULT_BADVALUE;
1675433d6423SLionel Sambuc res.value = 0;
1676433d6423SLionel Sambuc }
1677433d6423SLionel Sambuc
1678433d6423SLionel Sambuc got_result(&res, "ioctl to get first subpartition");
1679433d6423SLionel Sambuc
1680433d6423SLionel Sambuc vir_ioctl(sub1_minor, DIOCGETP, &subpart, 0, &res);
1681433d6423SLionel Sambuc
1682433d6423SLionel Sambuc if (res.type == RESULT_OK &&
1683433d6423SLionel Sambuc (subpart.base != part.base + (1 + part_secs) * sector_size ||
1684433d6423SLionel Sambuc subpart.size != (u64_t)part_secs * sector_size)) {
1685433d6423SLionel Sambuc
1686433d6423SLionel Sambuc res.type = RESULT_BADVALUE;
1687433d6423SLionel Sambuc res.value = 0;
1688433d6423SLionel Sambuc }
1689433d6423SLionel Sambuc
1690433d6423SLionel Sambuc got_result(&res, "ioctl to get second subpartition");
1691433d6423SLionel Sambuc
1692433d6423SLionel Sambuc /* Now perform the actual I/O tests. */
1693433d6423SLionel Sambuc read_limits(sub0_minor, sub1_minor, sub_size);
1694433d6423SLionel Sambuc
1695433d6423SLionel Sambuc write_limits(sub0_minor, sub1_minor, sub_size);
1696433d6423SLionel Sambuc
1697433d6423SLionel Sambuc /* Clean up. */
1698433d6423SLionel Sambuc close_device(sub0_minor);
1699433d6423SLionel Sambuc close_device(sub1_minor);
1700433d6423SLionel Sambuc
1701433d6423SLionel Sambuc free_dma_memory(buf_ptr, buf_size);
1702433d6423SLionel Sambuc }
1703433d6423SLionel Sambuc
part_limits(void)1704433d6423SLionel Sambuc static void part_limits(void)
1705433d6423SLionel Sambuc {
1706433d6423SLionel Sambuc /* Test reads and writes up to, across, and beyond partition limits.
1707433d6423SLionel Sambuc * As a side effect, test reading and writing partition sizes and
1708433d6423SLionel Sambuc * rereading partition tables.
1709433d6423SLionel Sambuc */
1710433d6423SLionel Sambuc dev_t par, sub0_minor, sub1_minor;
1711433d6423SLionel Sambuc
1712433d6423SLionel Sambuc /* First determine the first two subpartitions of the partition that we
1713433d6423SLionel Sambuc * are operating on. If we are already operating on a subpartition, we
1714433d6423SLionel Sambuc * cannot conduct this test.
1715433d6423SLionel Sambuc */
1716433d6423SLionel Sambuc if (driver_minor >= MINOR_d0p0s0) {
1717433d6423SLionel Sambuc output("WARNING: operating on subpartition, "
1718433d6423SLionel Sambuc "skipping partition tests\n");
1719433d6423SLionel Sambuc return;
1720433d6423SLionel Sambuc }
1721433d6423SLionel Sambuc par = driver_minor % DEV_PER_DRIVE;
1722433d6423SLionel Sambuc if (par > 0) /* adapted from libdriver's drvlib code */
1723433d6423SLionel Sambuc sub0_minor = MINOR_d0p0s0 + ((driver_minor / DEV_PER_DRIVE) *
1724433d6423SLionel Sambuc NR_PARTITIONS + par - 1) * NR_PARTITIONS;
1725433d6423SLionel Sambuc else
1726433d6423SLionel Sambuc sub0_minor = driver_minor + 1;
1727433d6423SLionel Sambuc sub1_minor = sub0_minor + 1;
1728433d6423SLionel Sambuc
1729433d6423SLionel Sambuc #define PART_SECS 9 /* sectors in each partition. must be >= 4. */
1730433d6423SLionel Sambuc
1731433d6423SLionel Sambuc /* First try the test with temporarily specified subpartitions. */
1732433d6423SLionel Sambuc vir_limits(sub0_minor, sub1_minor, PART_SECS);
1733433d6423SLionel Sambuc
1734433d6423SLionel Sambuc /* Then, if we're allowed to write, try the test with real, persisted
1735433d6423SLionel Sambuc * subpartitions.
1736433d6423SLionel Sambuc */
1737433d6423SLionel Sambuc real_limits(sub0_minor, sub1_minor, PART_SECS - 1);
1738433d6423SLionel Sambuc
1739433d6423SLionel Sambuc }
1740433d6423SLionel Sambuc
unaligned_size_io(u64_t base_pos,u8_t * buf_ptr,size_t buf_size,u8_t * sec_ptr[2],int sectors,int pattern,u32_t ssum[5])1741433d6423SLionel Sambuc static void unaligned_size_io(u64_t base_pos, u8_t *buf_ptr, size_t buf_size,
1742433d6423SLionel Sambuc u8_t *sec_ptr[2], int sectors, int pattern, u32_t ssum[5])
1743433d6423SLionel Sambuc {
1744433d6423SLionel Sambuc /* Perform a single small-element I/O read, write, readback test.
1745433d6423SLionel Sambuc * The number of sectors and the pattern varies with each call.
1746433d6423SLionel Sambuc * The ssum array has to be updated to reflect the five sectors'
1747433d6423SLionel Sambuc * checksums on disk, if writing is enabled. Note that for
1748433d6423SLionel Sambuc */
1749433d6423SLionel Sambuc iovec_t iov[3], iovt[3];
1750433d6423SLionel Sambuc u32_t rsum[3];
1751433d6423SLionel Sambuc result_t res;
1752433d6423SLionel Sambuc size_t total_size;
1753433d6423SLionel Sambuc int i, nr_req;
1754433d6423SLionel Sambuc
1755433d6423SLionel Sambuc base_pos += sector_size;
1756433d6423SLionel Sambuc total_size = sector_size * sectors;
1757433d6423SLionel Sambuc
1758433d6423SLionel Sambuc /* If the limit is two elements per sector, we cannot test three
1759433d6423SLionel Sambuc * elements in a single sector.
1760433d6423SLionel Sambuc */
1761433d6423SLionel Sambuc if (sector_size / element_size == 2 && sectors == 1 && pattern == 2)
1762433d6423SLionel Sambuc return;
1763433d6423SLionel Sambuc
1764433d6423SLionel Sambuc /* Set up the buffers and I/O vector. We use different buffers for the
1765433d6423SLionel Sambuc * elements to minimize the chance that something "accidentally" goes
1766433d6423SLionel Sambuc * right, but that means we have to do memory copying to do checksum
1767433d6423SLionel Sambuc * computation.
1768433d6423SLionel Sambuc */
1769433d6423SLionel Sambuc fill_rand(sec_ptr[0], sector_size);
1770433d6423SLionel Sambuc rsum[0] =
1771433d6423SLionel Sambuc get_sum(sec_ptr[0] + element_size, sector_size - element_size);
1772433d6423SLionel Sambuc
1773433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1774433d6423SLionel Sambuc
1775433d6423SLionel Sambuc switch (pattern) {
1776433d6423SLionel Sambuc case 0:
1777433d6423SLionel Sambuc /* First pattern: a small element on the left. */
1778433d6423SLionel Sambuc iovt[0].iov_addr = (vir_bytes) sec_ptr[0];
1779433d6423SLionel Sambuc iovt[0].iov_size = element_size;
1780433d6423SLionel Sambuc
1781433d6423SLionel Sambuc iovt[1].iov_addr = (vir_bytes) buf_ptr;
1782433d6423SLionel Sambuc iovt[1].iov_size = total_size - element_size;
1783433d6423SLionel Sambuc rsum[1] = get_sum(buf_ptr + iovt[1].iov_size, element_size);
1784433d6423SLionel Sambuc
1785433d6423SLionel Sambuc nr_req = 2;
1786433d6423SLionel Sambuc break;
1787433d6423SLionel Sambuc case 1:
1788433d6423SLionel Sambuc /* Second pattern: a small element on the right. */
1789433d6423SLionel Sambuc iovt[0].iov_addr = (vir_bytes) buf_ptr;
1790433d6423SLionel Sambuc iovt[0].iov_size = total_size - element_size;
1791433d6423SLionel Sambuc rsum[1] = get_sum(buf_ptr + iovt[0].iov_size, element_size);
1792433d6423SLionel Sambuc
1793433d6423SLionel Sambuc iovt[1].iov_addr = (vir_bytes) sec_ptr[0];
1794433d6423SLionel Sambuc iovt[1].iov_size = element_size;
1795433d6423SLionel Sambuc
1796433d6423SLionel Sambuc nr_req = 2;
1797433d6423SLionel Sambuc break;
1798433d6423SLionel Sambuc case 2:
1799433d6423SLionel Sambuc /* Third pattern: a small element on each side. */
1800433d6423SLionel Sambuc iovt[0].iov_addr = (vir_bytes) sec_ptr[0];
1801433d6423SLionel Sambuc iovt[0].iov_size = element_size;
1802433d6423SLionel Sambuc
1803433d6423SLionel Sambuc iovt[1].iov_addr = (vir_bytes) buf_ptr;
1804433d6423SLionel Sambuc iovt[1].iov_size = total_size - element_size * 2;
1805433d6423SLionel Sambuc rsum[1] = get_sum(buf_ptr + iovt[1].iov_size,
1806433d6423SLionel Sambuc element_size * 2);
1807433d6423SLionel Sambuc
1808433d6423SLionel Sambuc fill_rand(sec_ptr[1], sector_size);
1809433d6423SLionel Sambuc iovt[2].iov_addr = (vir_bytes) sec_ptr[1];
1810433d6423SLionel Sambuc iovt[2].iov_size = element_size;
1811433d6423SLionel Sambuc rsum[2] = get_sum(sec_ptr[1] + element_size,
1812433d6423SLionel Sambuc sector_size - element_size);
1813433d6423SLionel Sambuc
1814433d6423SLionel Sambuc nr_req = 3;
1815433d6423SLionel Sambuc break;
1816433d6423SLionel Sambuc default:
1817433d6423SLionel Sambuc assert(0);
1818433d6423SLionel Sambuc }
1819433d6423SLionel Sambuc
1820433d6423SLionel Sambuc /* Perform a read with small elements, and test whether the result is
1821433d6423SLionel Sambuc * as expected.
1822433d6423SLionel Sambuc */
1823433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iov));
1824433d6423SLionel Sambuc vir_xfer(driver_minor, base_pos, iov, nr_req, FALSE, total_size, &res);
1825433d6423SLionel Sambuc
1826433d6423SLionel Sambuc test_sum(sec_ptr[0] + element_size, sector_size - element_size,
1827433d6423SLionel Sambuc rsum[0], TRUE, &res);
1828433d6423SLionel Sambuc
1829433d6423SLionel Sambuc switch (pattern) {
1830433d6423SLionel Sambuc case 0:
1831433d6423SLionel Sambuc test_sum(buf_ptr + iovt[1].iov_size, element_size, rsum[1],
1832433d6423SLionel Sambuc TRUE, &res);
1833433d6423SLionel Sambuc memmove(buf_ptr + element_size, buf_ptr, iovt[1].iov_size);
1834433d6423SLionel Sambuc memcpy(buf_ptr, sec_ptr[0], element_size);
1835433d6423SLionel Sambuc break;
1836433d6423SLionel Sambuc case 1:
1837433d6423SLionel Sambuc test_sum(buf_ptr + iovt[0].iov_size, element_size, rsum[1],
1838433d6423SLionel Sambuc TRUE, &res);
1839433d6423SLionel Sambuc memcpy(buf_ptr + iovt[0].iov_size, sec_ptr[0], element_size);
1840433d6423SLionel Sambuc break;
1841433d6423SLionel Sambuc case 2:
1842433d6423SLionel Sambuc test_sum(buf_ptr + iovt[1].iov_size, element_size * 2, rsum[1],
1843433d6423SLionel Sambuc TRUE, &res);
1844433d6423SLionel Sambuc test_sum(sec_ptr[1] + element_size, sector_size - element_size,
1845433d6423SLionel Sambuc rsum[2], TRUE, &res);
1846433d6423SLionel Sambuc memmove(buf_ptr + element_size, buf_ptr, iovt[1].iov_size);
1847433d6423SLionel Sambuc memcpy(buf_ptr, sec_ptr[0], element_size);
1848433d6423SLionel Sambuc memcpy(buf_ptr + element_size + iovt[1].iov_size, sec_ptr[1],
1849433d6423SLionel Sambuc element_size);
1850433d6423SLionel Sambuc
1851433d6423SLionel Sambuc break;
1852433d6423SLionel Sambuc }
1853433d6423SLionel Sambuc
1854433d6423SLionel Sambuc for (i = 0; i < sectors; i++)
1855433d6423SLionel Sambuc test_sum(buf_ptr + sector_size * i, sector_size, ssum[1 + i],
1856433d6423SLionel Sambuc TRUE, &res);
1857433d6423SLionel Sambuc
1858433d6423SLionel Sambuc got_result(&res, "read with small elements");
1859433d6423SLionel Sambuc
1860433d6423SLionel Sambuc /* In read-only mode, we have nothing more to do. */
1861433d6423SLionel Sambuc if (!may_write)
1862433d6423SLionel Sambuc return;
1863433d6423SLionel Sambuc
1864433d6423SLionel Sambuc /* Use the same I/O vector to perform a write with small elements.
1865433d6423SLionel Sambuc * This will cause the checksums of the target sectors to change,
1866433d6423SLionel Sambuc * so we need to update those for both verification and later usage.
1867433d6423SLionel Sambuc */
1868433d6423SLionel Sambuc for (i = 0; i < sectors; i++)
1869433d6423SLionel Sambuc ssum[1 + i] =
1870433d6423SLionel Sambuc fill_rand(buf_ptr + sector_size * i, sector_size);
1871433d6423SLionel Sambuc
1872433d6423SLionel Sambuc switch (pattern) {
1873433d6423SLionel Sambuc case 0:
1874433d6423SLionel Sambuc memcpy(sec_ptr[0], buf_ptr, element_size);
1875433d6423SLionel Sambuc memmove(buf_ptr, buf_ptr + element_size, iovt[1].iov_size);
1876433d6423SLionel Sambuc fill_rand(buf_ptr + iovt[1].iov_size, element_size);
1877433d6423SLionel Sambuc break;
1878433d6423SLionel Sambuc case 1:
1879433d6423SLionel Sambuc memcpy(sec_ptr[0], buf_ptr + iovt[0].iov_size, element_size);
1880433d6423SLionel Sambuc fill_rand(buf_ptr + iovt[0].iov_size, element_size);
1881433d6423SLionel Sambuc break;
1882433d6423SLionel Sambuc case 2:
1883433d6423SLionel Sambuc memcpy(sec_ptr[0], buf_ptr, element_size);
1884433d6423SLionel Sambuc memcpy(sec_ptr[1], buf_ptr + element_size + iovt[1].iov_size,
1885433d6423SLionel Sambuc element_size);
1886433d6423SLionel Sambuc memmove(buf_ptr, buf_ptr + element_size, iovt[1].iov_size);
1887433d6423SLionel Sambuc fill_rand(buf_ptr + iovt[1].iov_size, element_size * 2);
1888433d6423SLionel Sambuc break;
1889433d6423SLionel Sambuc }
1890433d6423SLionel Sambuc
1891433d6423SLionel Sambuc memcpy(iov, iovt, sizeof(iov));
1892433d6423SLionel Sambuc
1893433d6423SLionel Sambuc vir_xfer(driver_minor, base_pos, iov, nr_req, TRUE, total_size, &res);
1894433d6423SLionel Sambuc
1895433d6423SLionel Sambuc got_result(&res, "write with small elements");
1896433d6423SLionel Sambuc
1897433d6423SLionel Sambuc /* Now perform normal readback verification. */
1898433d6423SLionel Sambuc fill_rand(buf_ptr, sector_size * 3);
1899433d6423SLionel Sambuc
1900433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf_ptr, sector_size * 3, FALSE,
1901433d6423SLionel Sambuc sector_size * 3, &res);
1902433d6423SLionel Sambuc
1903433d6423SLionel Sambuc for (i = 0; i < 3; i++)
1904433d6423SLionel Sambuc test_sum(buf_ptr + sector_size * i, sector_size, ssum[1 + i],
1905433d6423SLionel Sambuc TRUE, &res);
1906433d6423SLionel Sambuc
1907433d6423SLionel Sambuc got_result(&res, "readback verification");
1908433d6423SLionel Sambuc }
1909433d6423SLionel Sambuc
unaligned_size(void)1910433d6423SLionel Sambuc static void unaligned_size(void)
1911433d6423SLionel Sambuc {
1912433d6423SLionel Sambuc /* Test sector-unaligned sizes in I/O vector elements. The total size
1913433d6423SLionel Sambuc * of the request, however, has to add up to the sector size.
1914433d6423SLionel Sambuc */
1915433d6423SLionel Sambuc u8_t *buf_ptr, *sec_ptr[2];
1916433d6423SLionel Sambuc size_t buf_size;
1917433d6423SLionel Sambuc u32_t sum = 0L, ssum[5];
1918433d6423SLionel Sambuc u64_t base_pos;
1919433d6423SLionel Sambuc result_t res;
1920433d6423SLionel Sambuc int i;
1921433d6423SLionel Sambuc
1922433d6423SLionel Sambuc test_group("sector-unaligned elements", sector_size != element_size);
1923433d6423SLionel Sambuc
1924433d6423SLionel Sambuc /* We can only do this test if the driver allows small elements. */
1925433d6423SLionel Sambuc if (sector_size == element_size)
1926433d6423SLionel Sambuc return;
1927433d6423SLionel Sambuc
1928433d6423SLionel Sambuc /* Crashing on bad user input, terrible! */
1929433d6423SLionel Sambuc assert(sector_size % element_size == 0);
1930433d6423SLionel Sambuc
1931433d6423SLionel Sambuc /* Establish a baseline by writing and reading back five sectors; or
1932433d6423SLionel Sambuc * by reading only, if writing is disabled.
1933433d6423SLionel Sambuc */
1934433d6423SLionel Sambuc buf_size = sector_size * 5;
1935433d6423SLionel Sambuc
1936433d6423SLionel Sambuc base_pos = (u64_t)sector_size * 2;
1937433d6423SLionel Sambuc
1938433d6423SLionel Sambuc buf_ptr = alloc_dma_memory(buf_size);
1939433d6423SLionel Sambuc sec_ptr[0] = alloc_dma_memory(sector_size);
1940433d6423SLionel Sambuc sec_ptr[1] = alloc_dma_memory(sector_size);
1941433d6423SLionel Sambuc
1942433d6423SLionel Sambuc if (may_write) {
1943433d6423SLionel Sambuc sum = fill_rand(buf_ptr, buf_size);
1944433d6423SLionel Sambuc
1945433d6423SLionel Sambuc for (i = 0; i < 5; i++)
1946433d6423SLionel Sambuc ssum[i] = get_sum(buf_ptr + sector_size * i,
1947433d6423SLionel Sambuc sector_size);
1948433d6423SLionel Sambuc
1949433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf_ptr, buf_size, TRUE,
1950433d6423SLionel Sambuc buf_size, &res);
1951433d6423SLionel Sambuc
1952433d6423SLionel Sambuc got_result(&res, "write several sectors");
1953433d6423SLionel Sambuc }
1954433d6423SLionel Sambuc
1955433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1956433d6423SLionel Sambuc
1957433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf_ptr, buf_size, FALSE, buf_size,
1958433d6423SLionel Sambuc &res);
1959433d6423SLionel Sambuc
1960433d6423SLionel Sambuc if (may_write) {
1961433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, sum, TRUE, &res);
1962433d6423SLionel Sambuc }
1963433d6423SLionel Sambuc else {
1964433d6423SLionel Sambuc for (i = 0; i < 5; i++)
1965433d6423SLionel Sambuc ssum[i] = get_sum(buf_ptr + sector_size * i,
1966433d6423SLionel Sambuc sector_size);
1967433d6423SLionel Sambuc }
1968433d6423SLionel Sambuc
1969433d6423SLionel Sambuc got_result(&res, "read several sectors");
1970433d6423SLionel Sambuc
1971433d6423SLionel Sambuc /* We do nine subtests. The first three involve only the second sector;
1972433d6423SLionel Sambuc * the second three involve the second and third sectors, and the third
1973433d6423SLionel Sambuc * three involve all of the middle sectors. Each triplet tests small
1974433d6423SLionel Sambuc * elements at the left, at the right, and at both the left and the
1975433d6423SLionel Sambuc * right of the area. For each operation, we first do an unaligned
1976433d6423SLionel Sambuc * read, and if writing is enabled, an unaligned write and an aligned
1977433d6423SLionel Sambuc * read.
1978433d6423SLionel Sambuc */
1979433d6423SLionel Sambuc for (i = 0; i < 9; i++) {
1980433d6423SLionel Sambuc unaligned_size_io(base_pos, buf_ptr, buf_size, sec_ptr,
1981433d6423SLionel Sambuc i / 3 + 1, i % 3, ssum);
1982433d6423SLionel Sambuc }
1983433d6423SLionel Sambuc
1984433d6423SLionel Sambuc /* If writing was enabled, make sure that the first and fifth sector
1985433d6423SLionel Sambuc * have remained untouched.
1986433d6423SLionel Sambuc */
1987433d6423SLionel Sambuc if (may_write) {
1988433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
1989433d6423SLionel Sambuc
1990433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf_ptr, buf_size, FALSE,
1991433d6423SLionel Sambuc buf_size, &res);
1992433d6423SLionel Sambuc
1993433d6423SLionel Sambuc test_sum(buf_ptr, sector_size, ssum[0], TRUE, &res);
1994433d6423SLionel Sambuc test_sum(buf_ptr + sector_size * 4, sector_size, ssum[4], TRUE,
1995433d6423SLionel Sambuc &res);
1996433d6423SLionel Sambuc
1997433d6423SLionel Sambuc got_result(&res, "check first and last sectors");
1998433d6423SLionel Sambuc }
1999433d6423SLionel Sambuc
2000433d6423SLionel Sambuc /* Clean up. */
2001433d6423SLionel Sambuc free_dma_memory(sec_ptr[1], sector_size);
2002433d6423SLionel Sambuc free_dma_memory(sec_ptr[0], sector_size);
2003433d6423SLionel Sambuc free_dma_memory(buf_ptr, buf_size);
2004433d6423SLionel Sambuc }
2005433d6423SLionel Sambuc
unaligned_pos1(void)2006433d6423SLionel Sambuc static void unaligned_pos1(void)
2007433d6423SLionel Sambuc {
2008433d6423SLionel Sambuc /* Test sector-unaligned positions and total sizes for requests. This
2009433d6423SLionel Sambuc * is a read-only test for now. Write support should be added later.
2010433d6423SLionel Sambuc * In the current context, the term "lead" means an unwanted first part
2011433d6423SLionel Sambuc * of a sector, and "trail" means an unwanted last part of a sector.
2012433d6423SLionel Sambuc */
2013433d6423SLionel Sambuc u8_t *buf_ptr, *buf2_ptr;
2014433d6423SLionel Sambuc size_t buf_size, buf2_size, size;
2015433d6423SLionel Sambuc u32_t sum, sum2;
2016433d6423SLionel Sambuc u64_t base_pos;
2017433d6423SLionel Sambuc result_t res;
2018433d6423SLionel Sambuc
2019433d6423SLionel Sambuc test_group("sector-unaligned positions, part one",
2020433d6423SLionel Sambuc min_read != sector_size);
2021433d6423SLionel Sambuc
2022433d6423SLionel Sambuc /* We can only do this test if the driver allows small read requests.
2023433d6423SLionel Sambuc */
2024433d6423SLionel Sambuc if (min_read == sector_size)
2025433d6423SLionel Sambuc return;
2026433d6423SLionel Sambuc
2027433d6423SLionel Sambuc assert(sector_size % min_read == 0);
2028433d6423SLionel Sambuc assert(min_read % element_size == 0);
2029433d6423SLionel Sambuc
2030433d6423SLionel Sambuc /* Establish a baseline by writing and reading back three sectors; or
2031433d6423SLionel Sambuc * by reading only, if writing is disabled.
2032433d6423SLionel Sambuc */
2033433d6423SLionel Sambuc buf_size = buf2_size = sector_size * 3;
2034433d6423SLionel Sambuc
2035433d6423SLionel Sambuc base_pos = (u64_t)sector_size * 3;
2036433d6423SLionel Sambuc
2037433d6423SLionel Sambuc buf_ptr = alloc_dma_memory(buf_size);
2038433d6423SLionel Sambuc buf2_ptr = alloc_dma_memory(buf2_size);
2039433d6423SLionel Sambuc
2040433d6423SLionel Sambuc if (may_write) {
2041433d6423SLionel Sambuc sum = fill_rand(buf_ptr, buf_size);
2042433d6423SLionel Sambuc
2043433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf_ptr, buf_size, TRUE,
2044433d6423SLionel Sambuc buf_size, &res);
2045433d6423SLionel Sambuc
2046433d6423SLionel Sambuc got_result(&res, "write several sectors");
2047433d6423SLionel Sambuc }
2048433d6423SLionel Sambuc
2049433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
2050433d6423SLionel Sambuc
2051433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf_ptr, buf_size, FALSE, buf_size,
2052433d6423SLionel Sambuc &res);
2053433d6423SLionel Sambuc
2054433d6423SLionel Sambuc if (may_write)
2055433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, sum, TRUE, &res);
2056433d6423SLionel Sambuc
2057433d6423SLionel Sambuc got_result(&res, "read several sectors");
2058433d6423SLionel Sambuc
2059433d6423SLionel Sambuc /* Start with a simple test that operates within a single sector,
2060433d6423SLionel Sambuc * first using a lead.
2061433d6423SLionel Sambuc */
2062433d6423SLionel Sambuc fill_rand(buf2_ptr, sector_size);
2063433d6423SLionel Sambuc sum = get_sum(buf2_ptr + min_read, sector_size - min_read);
2064433d6423SLionel Sambuc
2065433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos + sector_size - min_read,
2066433d6423SLionel Sambuc buf2_ptr, min_read, FALSE, min_read, &res);
2067433d6423SLionel Sambuc
2068433d6423SLionel Sambuc test_sum(buf2_ptr, min_read, get_sum(buf_ptr + sector_size - min_read,
2069433d6423SLionel Sambuc min_read), TRUE, &res);
2070433d6423SLionel Sambuc test_sum(buf2_ptr + min_read, sector_size - min_read, sum, TRUE,
2071433d6423SLionel Sambuc &res);
2072433d6423SLionel Sambuc
2073433d6423SLionel Sambuc got_result(&res, "single sector read with lead");
2074433d6423SLionel Sambuc
2075433d6423SLionel Sambuc /* Then a trail. */
2076433d6423SLionel Sambuc fill_rand(buf2_ptr, sector_size);
2077433d6423SLionel Sambuc sum = get_sum(buf2_ptr, sector_size - min_read);
2078433d6423SLionel Sambuc
2079433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf2_ptr + sector_size - min_read,
2080433d6423SLionel Sambuc min_read, FALSE, min_read, &res);
2081433d6423SLionel Sambuc
2082433d6423SLionel Sambuc test_sum(buf2_ptr + sector_size - min_read, min_read, get_sum(buf_ptr,
2083433d6423SLionel Sambuc min_read), TRUE, &res);
2084433d6423SLionel Sambuc test_sum(buf2_ptr, sector_size - min_read, sum, TRUE, &res);
2085433d6423SLionel Sambuc
2086433d6423SLionel Sambuc got_result(&res, "single sector read with trail");
2087433d6423SLionel Sambuc
2088433d6423SLionel Sambuc /* And then a lead and a trail, unless min_read is half the sector
2089433d6423SLionel Sambuc * size, in which case this will be another lead test.
2090433d6423SLionel Sambuc */
2091433d6423SLionel Sambuc fill_rand(buf2_ptr, sector_size);
2092433d6423SLionel Sambuc sum = get_sum(buf2_ptr, min_read);
2093433d6423SLionel Sambuc sum2 = get_sum(buf2_ptr + min_read * 2, sector_size - min_read * 2);
2094433d6423SLionel Sambuc
2095433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos + min_read, buf2_ptr + min_read,
2096433d6423SLionel Sambuc min_read, FALSE, min_read, &res);
2097433d6423SLionel Sambuc
2098433d6423SLionel Sambuc test_sum(buf2_ptr + min_read, min_read, get_sum(buf_ptr + min_read,
2099433d6423SLionel Sambuc min_read), TRUE, &res);
2100433d6423SLionel Sambuc test_sum(buf2_ptr, min_read, sum, TRUE, &res);
2101433d6423SLionel Sambuc test_sum(buf2_ptr + min_read * 2, sector_size - min_read * 2, sum2,
2102433d6423SLionel Sambuc TRUE, &res);
2103433d6423SLionel Sambuc
2104433d6423SLionel Sambuc got_result(&res, "single sector read with lead and trail");
2105433d6423SLionel Sambuc
2106433d6423SLionel Sambuc /* Now do the same but with three sectors, and still only one I/O
2107433d6423SLionel Sambuc * vector element. First up: lead.
2108433d6423SLionel Sambuc */
2109433d6423SLionel Sambuc size = min_read + sector_size * 2;
2110433d6423SLionel Sambuc
2111433d6423SLionel Sambuc fill_rand(buf2_ptr, buf2_size);
2112433d6423SLionel Sambuc sum = get_sum(buf2_ptr + size, buf2_size - size);
2113433d6423SLionel Sambuc
2114433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos + sector_size - min_read, buf2_ptr,
2115433d6423SLionel Sambuc size, FALSE, size, &res);
2116433d6423SLionel Sambuc
2117433d6423SLionel Sambuc test_sum(buf2_ptr, size, get_sum(buf_ptr + sector_size - min_read,
2118433d6423SLionel Sambuc size), TRUE, &res);
2119433d6423SLionel Sambuc test_sum(buf2_ptr + size, buf2_size - size, sum, TRUE, &res);
2120433d6423SLionel Sambuc
2121433d6423SLionel Sambuc got_result(&res, "multisector read with lead");
2122433d6423SLionel Sambuc
2123433d6423SLionel Sambuc /* Then trail. */
2124433d6423SLionel Sambuc fill_rand(buf2_ptr, buf2_size);
2125433d6423SLionel Sambuc sum = get_sum(buf2_ptr + size, buf2_size - size);
2126433d6423SLionel Sambuc
2127433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf2_ptr, size, FALSE, size, &res);
2128433d6423SLionel Sambuc
2129433d6423SLionel Sambuc test_sum(buf2_ptr, size, get_sum(buf_ptr, size), TRUE, &res);
2130433d6423SLionel Sambuc test_sum(buf2_ptr + size, buf2_size - size, sum, TRUE, &res);
2131433d6423SLionel Sambuc
2132433d6423SLionel Sambuc got_result(&res, "multisector read with trail");
2133433d6423SLionel Sambuc
2134433d6423SLionel Sambuc /* Then lead and trail. Use sector size as transfer unit to throw off
2135433d6423SLionel Sambuc * simplistic lead/trail detection.
2136433d6423SLionel Sambuc */
2137433d6423SLionel Sambuc fill_rand(buf2_ptr, buf2_size);
2138433d6423SLionel Sambuc sum = get_sum(buf2_ptr + sector_size, buf2_size - sector_size);
2139433d6423SLionel Sambuc
2140433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos + min_read, buf2_ptr, sector_size,
2141433d6423SLionel Sambuc FALSE, sector_size, &res);
2142433d6423SLionel Sambuc
2143433d6423SLionel Sambuc test_sum(buf2_ptr, sector_size, get_sum(buf_ptr + min_read,
2144433d6423SLionel Sambuc sector_size), TRUE, &res);
2145433d6423SLionel Sambuc test_sum(buf2_ptr + sector_size, buf2_size - sector_size, sum, TRUE,
2146433d6423SLionel Sambuc &res);
2147433d6423SLionel Sambuc
2148433d6423SLionel Sambuc got_result(&res, "multisector read with lead and trail");
2149433d6423SLionel Sambuc
2150433d6423SLionel Sambuc /* Clean up. */
2151433d6423SLionel Sambuc free_dma_memory(buf2_ptr, buf2_size);
2152433d6423SLionel Sambuc free_dma_memory(buf_ptr, buf_size);
2153433d6423SLionel Sambuc }
2154433d6423SLionel Sambuc
unaligned_pos2(void)2155433d6423SLionel Sambuc static void unaligned_pos2(void)
2156433d6423SLionel Sambuc {
2157433d6423SLionel Sambuc /* Test sector-unaligned positions and total sizes for requests, second
2158433d6423SLionel Sambuc * part. This one tests the use of multiple I/O vector elements, and
2159433d6423SLionel Sambuc * tries to push the limits of the driver by completely filling an I/O
2160433d6423SLionel Sambuc * vector and going up to the maximum request size.
2161433d6423SLionel Sambuc */
2162433d6423SLionel Sambuc u8_t *buf_ptr, *buf2_ptr;
2163433d6423SLionel Sambuc size_t buf_size, buf2_size, max_block;
2164433d6423SLionel Sambuc u32_t sum = 0L, sum2 = 0L, rsum[NR_IOREQS];
2165433d6423SLionel Sambuc u64_t base_pos;
2166433d6423SLionel Sambuc iovec_t iov[NR_IOREQS];
2167433d6423SLionel Sambuc result_t res;
2168433d6423SLionel Sambuc int i;
2169433d6423SLionel Sambuc
2170433d6423SLionel Sambuc test_group("sector-unaligned positions, part two",
2171433d6423SLionel Sambuc min_read != sector_size);
2172433d6423SLionel Sambuc
2173433d6423SLionel Sambuc /* We can only do this test if the driver allows small read requests.
2174433d6423SLionel Sambuc */
2175433d6423SLionel Sambuc if (min_read == sector_size)
2176433d6423SLionel Sambuc return;
2177433d6423SLionel Sambuc
2178433d6423SLionel Sambuc buf_size = buf2_size = max_size + sector_size;
2179433d6423SLionel Sambuc
2180433d6423SLionel Sambuc base_pos = (u64_t)sector_size * 3;
2181433d6423SLionel Sambuc
2182433d6423SLionel Sambuc buf_ptr = alloc_dma_memory(buf_size);
2183433d6423SLionel Sambuc buf2_ptr = alloc_dma_memory(buf2_size);
2184433d6423SLionel Sambuc
2185433d6423SLionel Sambuc /* First establish a baseline. We need two requests for this, as the
2186433d6423SLionel Sambuc * total area intentionally exceeds the max request size.
2187433d6423SLionel Sambuc */
2188433d6423SLionel Sambuc if (may_write) {
2189433d6423SLionel Sambuc sum = fill_rand(buf_ptr, max_size);
2190433d6423SLionel Sambuc
2191433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf_ptr, max_size, TRUE,
2192433d6423SLionel Sambuc max_size, &res);
2193433d6423SLionel Sambuc
2194433d6423SLionel Sambuc got_result(&res, "large baseline write");
2195433d6423SLionel Sambuc
2196433d6423SLionel Sambuc sum2 = fill_rand(buf_ptr + max_size, sector_size);
2197433d6423SLionel Sambuc
2198433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos + max_size,
2199433d6423SLionel Sambuc buf_ptr + max_size, sector_size, TRUE, sector_size,
2200433d6423SLionel Sambuc &res);
2201433d6423SLionel Sambuc
2202433d6423SLionel Sambuc got_result(&res, "small baseline write");
2203433d6423SLionel Sambuc }
2204433d6423SLionel Sambuc
2205433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
2206433d6423SLionel Sambuc
2207433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf_ptr, max_size, FALSE, max_size,
2208433d6423SLionel Sambuc &res);
2209433d6423SLionel Sambuc
2210433d6423SLionel Sambuc if (may_write)
2211433d6423SLionel Sambuc test_sum(buf_ptr, max_size, sum, TRUE, &res);
2212433d6423SLionel Sambuc
2213433d6423SLionel Sambuc got_result(&res, "large baseline read");
2214433d6423SLionel Sambuc
2215433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos + max_size, buf_ptr + max_size,
2216433d6423SLionel Sambuc sector_size, FALSE, sector_size, &res);
2217433d6423SLionel Sambuc
2218433d6423SLionel Sambuc if (may_write)
2219433d6423SLionel Sambuc test_sum(buf_ptr + max_size, sector_size, sum2, TRUE, &res);
2220433d6423SLionel Sambuc
2221433d6423SLionel Sambuc got_result(&res, "small baseline read");
2222433d6423SLionel Sambuc
2223433d6423SLionel Sambuc /* First construct a full vector with minimal sizes. The resulting area
2224433d6423SLionel Sambuc * may well fall within a single sector, if min_read is small enough.
2225433d6423SLionel Sambuc */
2226433d6423SLionel Sambuc fill_rand(buf2_ptr, buf2_size);
2227433d6423SLionel Sambuc
2228433d6423SLionel Sambuc for (i = 0; i < NR_IOREQS; i++) {
2229433d6423SLionel Sambuc iov[i].iov_addr = (vir_bytes) buf2_ptr + i * sector_size;
2230433d6423SLionel Sambuc iov[i].iov_size = min_read;
2231433d6423SLionel Sambuc
2232433d6423SLionel Sambuc rsum[i] = get_sum(buf2_ptr + i * sector_size + min_read,
2233433d6423SLionel Sambuc sector_size - min_read);
2234433d6423SLionel Sambuc }
2235433d6423SLionel Sambuc
2236433d6423SLionel Sambuc vir_xfer(driver_minor, base_pos + min_read, iov, NR_IOREQS, FALSE,
2237433d6423SLionel Sambuc min_read * NR_IOREQS, &res);
2238433d6423SLionel Sambuc
2239433d6423SLionel Sambuc for (i = 0; i < NR_IOREQS; i++) {
2240433d6423SLionel Sambuc test_sum(buf2_ptr + i * sector_size + min_read,
2241433d6423SLionel Sambuc sector_size - min_read, rsum[i], TRUE, &res);
2242433d6423SLionel Sambuc memmove(buf2_ptr + i * min_read, buf2_ptr + i * sector_size,
2243433d6423SLionel Sambuc min_read);
2244433d6423SLionel Sambuc }
2245433d6423SLionel Sambuc
2246433d6423SLionel Sambuc test_sum(buf2_ptr, min_read * NR_IOREQS, get_sum(buf_ptr + min_read,
2247433d6423SLionel Sambuc min_read * NR_IOREQS), TRUE, &res);
2248433d6423SLionel Sambuc
2249433d6423SLionel Sambuc got_result(&res, "small fully unaligned filled vector");
2250433d6423SLionel Sambuc
2251433d6423SLionel Sambuc /* Sneak in a maximum sized request with a single I/O vector element,
2252433d6423SLionel Sambuc * unaligned. If the driver splits up such large requests into smaller
2253433d6423SLionel Sambuc * chunks, this tests whether it does so correctly in the presence of
2254433d6423SLionel Sambuc * leads and trails.
2255433d6423SLionel Sambuc */
2256433d6423SLionel Sambuc fill_rand(buf2_ptr, buf2_size);
2257433d6423SLionel Sambuc
2258433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos + min_read, buf2_ptr, max_size,
2259433d6423SLionel Sambuc FALSE, max_size, &res);
2260433d6423SLionel Sambuc
2261433d6423SLionel Sambuc test_sum(buf2_ptr, max_size, get_sum(buf_ptr + min_read, max_size),
2262433d6423SLionel Sambuc TRUE, &res);
2263433d6423SLionel Sambuc
2264433d6423SLionel Sambuc got_result(&res, "large fully unaligned single element");
2265433d6423SLionel Sambuc
2266433d6423SLionel Sambuc /* Then try with a vector where each element is as large as possible.
2267433d6423SLionel Sambuc * We don't have room to do bounds integrity checking here (we could
2268433d6423SLionel Sambuc * make room, but this may be a lot of memory already).
2269433d6423SLionel Sambuc */
2270433d6423SLionel Sambuc /* Compute the largest sector multiple which, when multiplied by
2271433d6423SLionel Sambuc * NR_IOREQS, is no more than the maximum transfer size.
2272433d6423SLionel Sambuc */
2273433d6423SLionel Sambuc max_block = max_size / NR_IOREQS;
2274433d6423SLionel Sambuc max_block -= max_block % sector_size;
2275433d6423SLionel Sambuc
2276433d6423SLionel Sambuc fill_rand(buf2_ptr, buf2_size);
2277433d6423SLionel Sambuc
2278433d6423SLionel Sambuc for (i = 0; i < NR_IOREQS; i++) {
2279433d6423SLionel Sambuc iov[i].iov_addr = (vir_bytes) buf2_ptr + i * max_block;
2280433d6423SLionel Sambuc iov[i].iov_size = max_block;
2281433d6423SLionel Sambuc }
2282433d6423SLionel Sambuc
2283433d6423SLionel Sambuc vir_xfer(driver_minor, base_pos + min_read, iov, NR_IOREQS, FALSE,
2284433d6423SLionel Sambuc max_block * NR_IOREQS, &res);
2285433d6423SLionel Sambuc
2286433d6423SLionel Sambuc test_sum(buf2_ptr, max_block * NR_IOREQS, get_sum(buf_ptr + min_read,
2287433d6423SLionel Sambuc max_block * NR_IOREQS), TRUE, &res);
2288433d6423SLionel Sambuc
2289433d6423SLionel Sambuc got_result(&res, "large fully unaligned filled vector");
2290433d6423SLionel Sambuc
2291433d6423SLionel Sambuc /* Clean up. */
2292433d6423SLionel Sambuc free_dma_memory(buf2_ptr, buf2_size);
2293433d6423SLionel Sambuc free_dma_memory(buf_ptr, buf_size);
2294433d6423SLionel Sambuc }
2295433d6423SLionel Sambuc
sweep_area(u64_t base_pos)2296433d6423SLionel Sambuc static void sweep_area(u64_t base_pos)
2297433d6423SLionel Sambuc {
2298433d6423SLionel Sambuc /* Go over an eight-sector area from left (low address) to right (high
2299433d6423SLionel Sambuc * address), reading and optionally writing in three-sector chunks, and
2300433d6423SLionel Sambuc * advancing one sector at a time.
2301433d6423SLionel Sambuc */
2302433d6423SLionel Sambuc u8_t *buf_ptr;
2303433d6423SLionel Sambuc size_t buf_size;
2304433d6423SLionel Sambuc u32_t sum = 0L, ssum[8];
2305433d6423SLionel Sambuc result_t res;
2306433d6423SLionel Sambuc int i, j;
2307433d6423SLionel Sambuc
2308433d6423SLionel Sambuc buf_size = sector_size * 8;
2309433d6423SLionel Sambuc buf_ptr = alloc_dma_memory(buf_size);
2310433d6423SLionel Sambuc
2311433d6423SLionel Sambuc /* First (write to, if allowed, and) read from the entire area in one
2312433d6423SLionel Sambuc * go, so that we know the (initial) contents of the area.
2313433d6423SLionel Sambuc */
2314433d6423SLionel Sambuc if (may_write) {
2315433d6423SLionel Sambuc sum = fill_rand(buf_ptr, buf_size);
2316433d6423SLionel Sambuc
2317433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf_ptr, buf_size, TRUE,
2318433d6423SLionel Sambuc buf_size, &res);
2319433d6423SLionel Sambuc
2320433d6423SLionel Sambuc got_result(&res, "write to full area");
2321433d6423SLionel Sambuc }
2322433d6423SLionel Sambuc
2323433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
2324433d6423SLionel Sambuc
2325433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf_ptr, buf_size, FALSE, buf_size,
2326433d6423SLionel Sambuc &res);
2327433d6423SLionel Sambuc
2328433d6423SLionel Sambuc if (may_write)
2329433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, sum, TRUE, &res);
2330433d6423SLionel Sambuc
2331433d6423SLionel Sambuc for (i = 0; i < 8; i++)
2332433d6423SLionel Sambuc ssum[i] = get_sum(buf_ptr + sector_size * i, sector_size);
2333433d6423SLionel Sambuc
2334433d6423SLionel Sambuc got_result(&res, "read from full area");
2335433d6423SLionel Sambuc
2336433d6423SLionel Sambuc /* For each of the six three-sector subareas, first read from the
2337433d6423SLionel Sambuc * subarea, check its checksum, and then (if allowed) write new content
2338433d6423SLionel Sambuc * to it.
2339433d6423SLionel Sambuc */
2340433d6423SLionel Sambuc for (i = 0; i < 6; i++) {
2341433d6423SLionel Sambuc fill_rand(buf_ptr, sector_size * 3);
2342433d6423SLionel Sambuc
2343433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos + sector_size * i, buf_ptr,
2344433d6423SLionel Sambuc sector_size * 3, FALSE, sector_size * 3, &res);
2345433d6423SLionel Sambuc
2346433d6423SLionel Sambuc for (j = 0; j < 3; j++)
2347433d6423SLionel Sambuc test_sum(buf_ptr + sector_size * j, sector_size,
2348433d6423SLionel Sambuc ssum[i + j], TRUE, &res);
2349433d6423SLionel Sambuc
2350433d6423SLionel Sambuc got_result(&res, "read from subarea");
2351433d6423SLionel Sambuc
2352433d6423SLionel Sambuc if (!may_write)
2353433d6423SLionel Sambuc continue;
2354433d6423SLionel Sambuc
2355433d6423SLionel Sambuc fill_rand(buf_ptr, sector_size * 3);
2356433d6423SLionel Sambuc
2357433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos + sector_size * i, buf_ptr,
2358433d6423SLionel Sambuc sector_size * 3, TRUE, sector_size * 3, &res);
2359433d6423SLionel Sambuc
2360433d6423SLionel Sambuc for (j = 0; j < 3; j++)
2361433d6423SLionel Sambuc ssum[i + j] = get_sum(buf_ptr + sector_size * j,
2362433d6423SLionel Sambuc sector_size);
2363433d6423SLionel Sambuc
2364433d6423SLionel Sambuc got_result(&res, "write to subarea");
2365433d6423SLionel Sambuc }
2366433d6423SLionel Sambuc
2367433d6423SLionel Sambuc /* Finally, if writing was enabled, do one final readback. */
2368433d6423SLionel Sambuc if (may_write) {
2369433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
2370433d6423SLionel Sambuc
2371433d6423SLionel Sambuc simple_xfer(driver_minor, base_pos, buf_ptr, buf_size, FALSE,
2372433d6423SLionel Sambuc buf_size, &res);
2373433d6423SLionel Sambuc
2374433d6423SLionel Sambuc for (i = 0; i < 8; i++)
2375433d6423SLionel Sambuc test_sum(buf_ptr + sector_size * i, sector_size,
2376433d6423SLionel Sambuc ssum[i], TRUE, &res);
2377433d6423SLionel Sambuc
2378433d6423SLionel Sambuc got_result(&res, "readback from full area");
2379433d6423SLionel Sambuc }
2380433d6423SLionel Sambuc
2381433d6423SLionel Sambuc /* Clean up. */
2382433d6423SLionel Sambuc free_dma_memory(buf_ptr, buf_size);
2383433d6423SLionel Sambuc }
2384433d6423SLionel Sambuc
sweep_and_check(u64_t pos,int check_integ)2385433d6423SLionel Sambuc static void sweep_and_check(u64_t pos, int check_integ)
2386433d6423SLionel Sambuc {
2387433d6423SLionel Sambuc /* Perform an area sweep at the given position. If asked for, get an
2388433d6423SLionel Sambuc * integrity checksum over the beginning of the disk (first writing
2389433d6423SLionel Sambuc * known data into it if that is allowed) before doing the sweep, and
2390433d6423SLionel Sambuc * test the integrity checksum against the disk contents afterwards.
2391433d6423SLionel Sambuc */
2392433d6423SLionel Sambuc u8_t *buf_ptr;
2393433d6423SLionel Sambuc size_t buf_size;
2394433d6423SLionel Sambuc u32_t sum = 0L;
2395433d6423SLionel Sambuc result_t res;
2396433d6423SLionel Sambuc
2397433d6423SLionel Sambuc if (check_integ) {
2398433d6423SLionel Sambuc buf_size = sector_size * 3;
2399433d6423SLionel Sambuc buf_ptr = alloc_dma_memory(buf_size);
2400433d6423SLionel Sambuc
2401433d6423SLionel Sambuc if (may_write) {
2402433d6423SLionel Sambuc sum = fill_rand(buf_ptr, buf_size);
2403433d6423SLionel Sambuc
2404433d6423SLionel Sambuc simple_xfer(driver_minor, 0ULL, buf_ptr, buf_size,
2405433d6423SLionel Sambuc TRUE, buf_size, &res);
2406433d6423SLionel Sambuc
2407433d6423SLionel Sambuc got_result(&res, "write integrity zone");
2408433d6423SLionel Sambuc }
2409433d6423SLionel Sambuc
2410433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
2411433d6423SLionel Sambuc
2412433d6423SLionel Sambuc simple_xfer(driver_minor, 0ULL, buf_ptr, buf_size, FALSE,
2413433d6423SLionel Sambuc buf_size, &res);
2414433d6423SLionel Sambuc
2415433d6423SLionel Sambuc if (may_write)
2416433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, sum, TRUE, &res);
2417433d6423SLionel Sambuc else
2418433d6423SLionel Sambuc sum = get_sum(buf_ptr, buf_size);
2419433d6423SLionel Sambuc
2420433d6423SLionel Sambuc got_result(&res, "read integrity zone");
2421433d6423SLionel Sambuc }
2422433d6423SLionel Sambuc
2423433d6423SLionel Sambuc sweep_area(pos);
2424433d6423SLionel Sambuc
2425433d6423SLionel Sambuc if (check_integ) {
2426433d6423SLionel Sambuc fill_rand(buf_ptr, buf_size);
2427433d6423SLionel Sambuc
2428433d6423SLionel Sambuc simple_xfer(driver_minor, 0ULL, buf_ptr, buf_size, FALSE,
2429433d6423SLionel Sambuc buf_size, &res);
2430433d6423SLionel Sambuc
2431433d6423SLionel Sambuc test_sum(buf_ptr, buf_size, sum, TRUE, &res);
2432433d6423SLionel Sambuc
2433433d6423SLionel Sambuc got_result(&res, "check integrity zone");
2434433d6423SLionel Sambuc
2435433d6423SLionel Sambuc free_dma_memory(buf_ptr, buf_size);
2436433d6423SLionel Sambuc }
2437433d6423SLionel Sambuc }
2438433d6423SLionel Sambuc
basic_sweep(void)2439433d6423SLionel Sambuc static void basic_sweep(void)
2440433d6423SLionel Sambuc {
2441433d6423SLionel Sambuc /* Perform a basic area sweep.
2442433d6423SLionel Sambuc */
2443433d6423SLionel Sambuc
2444433d6423SLionel Sambuc test_group("basic area sweep", TRUE);
2445433d6423SLionel Sambuc
2446433d6423SLionel Sambuc sweep_area((u64_t)sector_size);
2447433d6423SLionel Sambuc }
2448433d6423SLionel Sambuc
high_disk_pos(void)2449433d6423SLionel Sambuc static void high_disk_pos(void)
2450433d6423SLionel Sambuc {
2451433d6423SLionel Sambuc /* Test 64-bit absolute disk positions. This means that after adding
2452433d6423SLionel Sambuc * partition base to the given position, the driver will be dealing
2453433d6423SLionel Sambuc * with a position above 32 bit. We want to test the transition area
2454433d6423SLionel Sambuc * only; if the entire partition base is above 32 bit, we have already
2455433d6423SLionel Sambuc * effectively performed this test many times over. In other words, for
2456433d6423SLionel Sambuc * this test, the partition must start below 4GB and end above 4GB,
2457433d6423SLionel Sambuc * with at least four sectors on each side.
2458433d6423SLionel Sambuc */
2459433d6423SLionel Sambuc u64_t base_pos;
2460433d6423SLionel Sambuc
2461433d6423SLionel Sambuc base_pos = 0x100000000ULL | (sector_size * 4);
2462433d6423SLionel Sambuc base_pos -= base_pos % sector_size;
2463433d6423SLionel Sambuc
2464433d6423SLionel Sambuc /* The partition end must exceed 32 bits. */
2465433d6423SLionel Sambuc if (part.base + part.size < base_pos) {
2466433d6423SLionel Sambuc test_group("high disk positions", FALSE);
2467433d6423SLionel Sambuc
2468433d6423SLionel Sambuc return;
2469433d6423SLionel Sambuc }
2470433d6423SLionel Sambuc
2471433d6423SLionel Sambuc base_pos -= sector_size * 8;
2472433d6423SLionel Sambuc
2473433d6423SLionel Sambuc /* The partition start must not. */
2474433d6423SLionel Sambuc if (base_pos < part.base) {
2475433d6423SLionel Sambuc test_group("high disk positions", FALSE);
2476433d6423SLionel Sambuc return;
2477433d6423SLionel Sambuc }
2478433d6423SLionel Sambuc
2479433d6423SLionel Sambuc test_group("high disk positions", TRUE);
2480433d6423SLionel Sambuc
2481433d6423SLionel Sambuc base_pos -= part.base;
2482433d6423SLionel Sambuc
2483433d6423SLionel Sambuc sweep_and_check(base_pos, part.base == 0ULL);
2484433d6423SLionel Sambuc }
2485433d6423SLionel Sambuc
high_part_pos(void)2486433d6423SLionel Sambuc static void high_part_pos(void)
2487433d6423SLionel Sambuc {
2488433d6423SLionel Sambuc /* Test 64-bit partition-relative disk positions. In other words, use
2489433d6423SLionel Sambuc * within the current partition a position that exceeds a 32-bit value.
2490433d6423SLionel Sambuc * This requires the partition to be more than 4GB in size; we need an
2491433d6423SLionel Sambuc * additional 4 sectors, to be exact.
2492433d6423SLionel Sambuc */
2493433d6423SLionel Sambuc u64_t base_pos;
2494433d6423SLionel Sambuc
2495433d6423SLionel Sambuc /* If the partition starts at the beginning of the disk, this test is
2496433d6423SLionel Sambuc * no different from the high disk position test.
2497433d6423SLionel Sambuc */
2498433d6423SLionel Sambuc if (part.base == 0ULL) {
2499433d6423SLionel Sambuc /* don't complain: the test is simply superfluous now */
2500433d6423SLionel Sambuc return;
2501433d6423SLionel Sambuc }
2502433d6423SLionel Sambuc
2503433d6423SLionel Sambuc base_pos = 0x100000000ULL | (sector_size * 4);
2504433d6423SLionel Sambuc base_pos -= base_pos % sector_size;
2505433d6423SLionel Sambuc
2506433d6423SLionel Sambuc if (part.size < base_pos) {
2507433d6423SLionel Sambuc test_group("high partition positions", FALSE);
2508433d6423SLionel Sambuc
2509433d6423SLionel Sambuc return;
2510433d6423SLionel Sambuc }
2511433d6423SLionel Sambuc
2512433d6423SLionel Sambuc test_group("high partition positions", TRUE);
2513433d6423SLionel Sambuc
2514433d6423SLionel Sambuc base_pos -= sector_size * 8;
2515433d6423SLionel Sambuc
2516433d6423SLionel Sambuc sweep_and_check(base_pos, TRUE);
2517433d6423SLionel Sambuc }
2518433d6423SLionel Sambuc
high_lba_pos1(void)2519433d6423SLionel Sambuc static void high_lba_pos1(void)
2520433d6423SLionel Sambuc {
2521433d6423SLionel Sambuc /* Test 48-bit LBA positions, as opposed to *24-bit*. Drivers that only
2522433d6423SLionel Sambuc * support 48-bit LBA ATA transfers, will treat the lower and upper 24
2523433d6423SLionel Sambuc * bits differently. This is again relative to the disk start, not the
2524433d6423SLionel Sambuc * partition start. For 512-byte sectors, the lowest position exceeding
2525433d6423SLionel Sambuc * 24 bit is at 8GB. As usual, we need four sectors more, and fewer, on
2526433d6423SLionel Sambuc * the other side. The partition that we're operating on, must cover
2527433d6423SLionel Sambuc * this area.
2528433d6423SLionel Sambuc */
2529433d6423SLionel Sambuc u64_t base_pos;
2530433d6423SLionel Sambuc
2531433d6423SLionel Sambuc base_pos = (1ULL << 24) * sector_size;
2532433d6423SLionel Sambuc
2533433d6423SLionel Sambuc /* The partition end must exceed the 24-bit sector point. */
2534433d6423SLionel Sambuc if (part.base + part.size < base_pos) {
2535433d6423SLionel Sambuc test_group("high LBA positions, part one", FALSE);
2536433d6423SLionel Sambuc
2537433d6423SLionel Sambuc return;
2538433d6423SLionel Sambuc }
2539433d6423SLionel Sambuc
2540433d6423SLionel Sambuc base_pos -= sector_size * 8;
2541433d6423SLionel Sambuc
2542433d6423SLionel Sambuc /* The partition start must not. */
2543433d6423SLionel Sambuc if (base_pos < part.base) {
2544433d6423SLionel Sambuc test_group("high LBA positions, part one", FALSE);
2545433d6423SLionel Sambuc
2546433d6423SLionel Sambuc return;
2547433d6423SLionel Sambuc }
2548433d6423SLionel Sambuc
2549433d6423SLionel Sambuc test_group("high LBA positions, part one", TRUE);
2550433d6423SLionel Sambuc
2551433d6423SLionel Sambuc base_pos -= part.base;
2552433d6423SLionel Sambuc
2553433d6423SLionel Sambuc sweep_and_check(base_pos, part.base == 0ULL);
2554433d6423SLionel Sambuc }
2555433d6423SLionel Sambuc
high_lba_pos2(void)2556433d6423SLionel Sambuc static void high_lba_pos2(void)
2557433d6423SLionel Sambuc {
2558433d6423SLionel Sambuc /* Test 48-bit LBA positions, as opposed to *28-bit*. That means sector
2559433d6423SLionel Sambuc * numbers in excess of 28-bit values; the old ATA upper limit. The
2560433d6423SLionel Sambuc * same considerations as above apply, except that we now need a 128+GB
2561433d6423SLionel Sambuc * partition.
2562433d6423SLionel Sambuc */
2563433d6423SLionel Sambuc u64_t base_pos;
2564433d6423SLionel Sambuc
2565433d6423SLionel Sambuc base_pos = (1ULL << 28) * sector_size;
2566433d6423SLionel Sambuc
2567433d6423SLionel Sambuc /* The partition end must exceed the 28-bit sector point. */
2568433d6423SLionel Sambuc if (part.base + part.size < base_pos) {
2569433d6423SLionel Sambuc test_group("high LBA positions, part two", FALSE);
2570433d6423SLionel Sambuc
2571433d6423SLionel Sambuc return;
2572433d6423SLionel Sambuc }
2573433d6423SLionel Sambuc
2574433d6423SLionel Sambuc base_pos -= sector_size * 8;
2575433d6423SLionel Sambuc
2576433d6423SLionel Sambuc /* The partition start must not. */
2577433d6423SLionel Sambuc if (base_pos < part.base) {
2578433d6423SLionel Sambuc test_group("high LBA positions, part two", FALSE);
2579433d6423SLionel Sambuc
2580433d6423SLionel Sambuc return;
2581433d6423SLionel Sambuc }
2582433d6423SLionel Sambuc
2583433d6423SLionel Sambuc test_group("high LBA positions, part two", TRUE);
2584433d6423SLionel Sambuc
2585433d6423SLionel Sambuc base_pos -= part.base;
2586433d6423SLionel Sambuc
2587433d6423SLionel Sambuc sweep_and_check(base_pos, part.base == 0ULL);
2588433d6423SLionel Sambuc }
2589433d6423SLionel Sambuc
high_pos(void)2590433d6423SLionel Sambuc static void high_pos(void)
2591433d6423SLionel Sambuc {
2592433d6423SLionel Sambuc /* Check whether the driver deals well with 64-bit positions and
2593433d6423SLionel Sambuc * 48-bit LBA addresses. We test three cases: disk byte position beyond
2594433d6423SLionel Sambuc * what fits in 32 bit, in-partition byte position beyond what fits in
2595433d6423SLionel Sambuc * 32 bit, and disk sector position beyond what fits in 24 bit. With
2596433d6423SLionel Sambuc * the partition we've been given, we may not be able to test all of
2597433d6423SLionel Sambuc * them (or any, for that matter).
2598433d6423SLionel Sambuc */
2599433d6423SLionel Sambuc /* In certain rare cases, we might be able to perform integrity
2600433d6423SLionel Sambuc * checking on the area that would be affected if a 32-bit/24-bit
2601433d6423SLionel Sambuc * counter were to wrap. More specifically: we can do that if we can
2602433d6423SLionel Sambuc * access the start of the disk. This is why we should be given the
2603433d6423SLionel Sambuc * entire disk as test area if at all possible.
2604433d6423SLionel Sambuc */
2605433d6423SLionel Sambuc
2606433d6423SLionel Sambuc basic_sweep();
2607433d6423SLionel Sambuc
2608433d6423SLionel Sambuc high_disk_pos();
2609433d6423SLionel Sambuc
2610433d6423SLionel Sambuc high_part_pos();
2611433d6423SLionel Sambuc
2612433d6423SLionel Sambuc high_lba_pos1();
2613433d6423SLionel Sambuc
2614433d6423SLionel Sambuc high_lba_pos2();
2615433d6423SLionel Sambuc }
2616433d6423SLionel Sambuc
open_primary(void)2617433d6423SLionel Sambuc static void open_primary(void)
2618433d6423SLionel Sambuc {
2619433d6423SLionel Sambuc /* Open the primary device. This call has its own test group.
2620433d6423SLionel Sambuc */
2621433d6423SLionel Sambuc
2622433d6423SLionel Sambuc test_group("device open", TRUE);
2623433d6423SLionel Sambuc
2624433d6423SLionel Sambuc open_device(driver_minor);
2625433d6423SLionel Sambuc }
2626433d6423SLionel Sambuc
close_primary(void)2627433d6423SLionel Sambuc static void close_primary(void)
2628433d6423SLionel Sambuc {
2629433d6423SLionel Sambuc /* Close the primary device. This call has its own test group.
2630433d6423SLionel Sambuc */
2631433d6423SLionel Sambuc
2632433d6423SLionel Sambuc test_group("device close", TRUE);
2633433d6423SLionel Sambuc
2634433d6423SLionel Sambuc close_device(driver_minor);
2635433d6423SLionel Sambuc
2636433d6423SLionel Sambuc assert(nr_opened == 0);
2637433d6423SLionel Sambuc }
2638433d6423SLionel Sambuc
do_tests(void)2639433d6423SLionel Sambuc static void do_tests(void)
2640433d6423SLionel Sambuc {
2641433d6423SLionel Sambuc /* Perform all the tests.
2642433d6423SLionel Sambuc */
2643433d6423SLionel Sambuc
2644433d6423SLionel Sambuc open_primary();
2645433d6423SLionel Sambuc
2646433d6423SLionel Sambuc misc_ioctl();
2647433d6423SLionel Sambuc
2648433d6423SLionel Sambuc bad_read1();
2649433d6423SLionel Sambuc
2650433d6423SLionel Sambuc bad_read2();
2651433d6423SLionel Sambuc
2652433d6423SLionel Sambuc /* It is assumed that the driver implementation uses shared
2653433d6423SLionel Sambuc * code paths for read and write for the basic checks, so we do
2654433d6423SLionel Sambuc * not repeat those for writes.
2655433d6423SLionel Sambuc */
2656433d6423SLionel Sambuc bad_write();
2657433d6423SLionel Sambuc
2658433d6423SLionel Sambuc vector_and_large();
2659433d6423SLionel Sambuc
2660433d6423SLionel Sambuc part_limits();
2661433d6423SLionel Sambuc
2662433d6423SLionel Sambuc unaligned_size();
2663433d6423SLionel Sambuc
2664433d6423SLionel Sambuc unaligned_pos1();
2665433d6423SLionel Sambuc
2666433d6423SLionel Sambuc unaligned_pos2();
2667433d6423SLionel Sambuc
2668433d6423SLionel Sambuc high_pos();
2669433d6423SLionel Sambuc
2670433d6423SLionel Sambuc close_primary();
2671433d6423SLionel Sambuc }
2672433d6423SLionel Sambuc
sef_cb_init_fresh(int UNUSED (type),sef_init_info_t * UNUSED (info))2673433d6423SLionel Sambuc static int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
2674433d6423SLionel Sambuc {
2675433d6423SLionel Sambuc /* Initialize.
2676433d6423SLionel Sambuc */
2677433d6423SLionel Sambuc
2678433d6423SLionel Sambuc if (env_argc > 1)
2679433d6423SLionel Sambuc optset_parse(optset_table, env_argv[1]);
2680433d6423SLionel Sambuc
2681433d6423SLionel Sambuc if (driver_label[0] == '\0')
2682433d6423SLionel Sambuc panic("no driver label given");
2683433d6423SLionel Sambuc
2684433d6423SLionel Sambuc if (ds_retrieve_label_endpt(driver_label, &driver_endpt))
2685433d6423SLionel Sambuc panic("unable to resolve driver label");
2686433d6423SLionel Sambuc
2687433d6423SLionel Sambuc if (driver_minor > 255)
2688433d6423SLionel Sambuc panic("invalid or no driver minor given");
2689433d6423SLionel Sambuc
2690d91f738bSDavid van Moolenbroek srand48(getticks());
2691433d6423SLionel Sambuc
2692433d6423SLionel Sambuc output("BLOCKTEST: driver label '%s' (endpt %d), minor %d\n",
2693433d6423SLionel Sambuc driver_label, driver_endpt, driver_minor);
2694433d6423SLionel Sambuc
2695433d6423SLionel Sambuc do_tests();
2696433d6423SLionel Sambuc
2697433d6423SLionel Sambuc output("BLOCKTEST: summary: %d out of %d tests failed "
2698433d6423SLionel Sambuc "across %d group%s; %d driver deaths\n",
2699433d6423SLionel Sambuc failed_tests, total_tests, failed_groups,
2700433d6423SLionel Sambuc failed_groups == 1 ? "" : "s", driver_deaths);
2701433d6423SLionel Sambuc
2702433d6423SLionel Sambuc /* The returned code will determine the outcome of the RS call, and
2703433d6423SLionel Sambuc * thus the entire test. The actual error code does not matter.
2704433d6423SLionel Sambuc */
2705433d6423SLionel Sambuc return (failed_tests) ? EINVAL : OK;
2706433d6423SLionel Sambuc }
2707433d6423SLionel Sambuc
sef_local_startup(void)2708433d6423SLionel Sambuc static void sef_local_startup(void)
2709433d6423SLionel Sambuc {
2710433d6423SLionel Sambuc /* Initialize the SEF framework.
2711433d6423SLionel Sambuc */
2712433d6423SLionel Sambuc
2713433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init_fresh);
2714433d6423SLionel Sambuc
2715433d6423SLionel Sambuc sef_startup();
2716433d6423SLionel Sambuc }
2717433d6423SLionel Sambuc
main(int argc,char ** argv)2718433d6423SLionel Sambuc int main(int argc, char **argv)
2719433d6423SLionel Sambuc {
2720433d6423SLionel Sambuc /* Driver task.
2721433d6423SLionel Sambuc */
2722433d6423SLionel Sambuc
2723433d6423SLionel Sambuc env_setargs(argc, argv);
2724433d6423SLionel Sambuc sef_local_startup();
2725433d6423SLionel Sambuc
2726433d6423SLionel Sambuc return 0;
2727433d6423SLionel Sambuc }
2728