1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2025 Oxide Computer Company
14 */
15
16 /*
17 * Test various aspects of creating and removing devices. This operates on the
18 * smbussim1/0 port where there are no devices by default. In particular we
19 * want to verify a few different properties:
20 *
21 * - Invalid nvlists and missing nvlist fields are caught
22 * - The device name and compatible array are correctly populated
23 * - Address allocation across ports is sensible, meaning that something on the
24 * top-level port stops allocations on downstream ports and vice-versa
25 *
26 * Unlike the i2cadm tests, we care about the specific kernel ioctl return
27 * values.
28 */
29
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <err.h>
33 #include <sys/debug.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <sys/mman.h>
39 #include <sys/nvpair.h>
40 #include <sys/sysmacros.h>
41 #include <libdevinfo.h>
42
43 #include <sys/i2c/ioctl.h>
44 #include "i2c_ioctl_util.h"
45
46 static const char *bad_names[] = {
47 "",
48 "thisisalongstringthatshouldbetoolongbuthasvalidchars",
49 "0nonum",
50 "42",
51 "help#",
52 "!at24c32",
53 "at24%c32",
54 "at@24xc32",
55 "three rings",
56 "elven(kings)",
57 "ゼルダの伝説"
58 };
59
60 static bool
test_add(int fd,const void * arg,size_t len,i2c_errno_t err,const char * desc)61 test_add(int fd, const void *arg, size_t len, i2c_errno_t err, const char *desc)
62 {
63 bool ret = true;
64 ui2c_dev_add_t add = {
65 .uda_error = {
66 /*
67 * We use token values here to make sure that they're
68 * always set by the target.
69 */
70 INT32_MIN,
71 INT32_MIN
72 },
73 .uda_nvl = (uintptr_t)arg,
74 .uda_nvl_len = len
75 };
76
77 if (ioctl(fd, UI2C_IOCTL_DEVICE_ADD, &add) != 0) {
78 warnx("TEST FAILED: %s: add ioctl failed unexpectedly with "
79 "errno %s", desc, strerrorname_np(errno));
80 return (false);
81 }
82
83 if (add.uda_error.i2c_error != err) {
84 warnx("TEST FAILED: %s: ioctl failed with I2C error 0x%x, "
85 "expected 0x%x", desc, add.uda_error.i2c_error, err);
86 ret = false;
87 }
88
89 if (add.uda_error.i2c_ctrl != I2C_CTRL_E_OK) {
90 warnx("TEST FAILED: %s: ioctl has unexpected controller "
91 "error 0x%x", desc, add.uda_error.i2c_ctrl);
92 ret = false;
93 }
94
95 if (ret) {
96 if (err == I2C_CORE_E_OK) {
97 (void) printf("TEST PASSED: %s correctly created "
98 "device\n", desc);
99 } else {
100 (void) printf("TEST PASSED: %s correctly failed with "
101 "0x%x\n", desc, err);
102 }
103 }
104
105 return (ret);
106 }
107
108 static bool
test_add_nvlist(int fd,nvlist_t * nvl,i2c_errno_t err,const char * desc)109 test_add_nvlist(int fd, nvlist_t *nvl, i2c_errno_t err, const char *desc)
110 {
111 size_t len;
112 char *data = fnvlist_pack(nvl, &len);
113 bool ret = test_add(fd, data, len, err, desc);
114 fnvlist_pack_free(data, len);
115 return (ret);
116 }
117
118 static bool
test_bad_nvlists(int fd)119 test_bad_nvlists(int fd)
120 {
121 bool ret = true;
122 const char *str = "I promise I'm an nvlist_t";
123
124 if (!test_add(fd, NULL, 4 * 1024 * 1024, I2C_IOCTL_E_NVL_TOO_BIG,
125 "nvlist_t too large to copy in")) {
126 ret = false;
127 }
128
129 size_t pgsz = (size_t)sysconf(_SC_PAGESIZE);
130 void *addr = mmap(NULL, pgsz, PROT_NONE, MAP_PRIVATE | MAP_ANON,
131 -1, 0);
132 VERIFY3P(addr, !=, NULL);
133 if (!test_add(fd, addr, pgsz, I2C_IOCTL_E_BAD_USER_DATA, "unreadable "
134 "user data")) {
135 ret = false;
136 }
137 VERIFY0(munmap(addr, pgsz));
138
139 if (!test_add(fd, str, strlen(str) + 1, I2C_IOCTL_E_NVL_INVALID,
140 "unparseable nvlist_t")) {
141 ret = false;
142 }
143
144 /*
145 * Go through and test all of the missing keys cases.
146 */
147 nvlist_t *nvl = fnvlist_alloc();
148 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_NVL_KEY_MISSING, "missing "
149 "keys (all)")) {
150 ret = false;
151 }
152
153 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, 0x00);
154 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
155 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_NVL_KEY_MISSING, "missing "
156 "keys (name)")) {
157 ret = false;
158 }
159 nvlist_free(nvl);
160
161 nvl = fnvlist_alloc();
162 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, 0x00);
163 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, "foobar");
164 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_NVL_KEY_MISSING, "missing "
165 "keys (type)")) {
166 ret = false;
167 }
168 nvlist_free(nvl);
169
170 nvl = fnvlist_alloc();
171 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
172 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, "foobar");
173 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_NVL_KEY_MISSING, "missing "
174 "keys (type)")) {
175 ret = false;
176 }
177 nvlist_free(nvl);
178
179 nvl = fnvlist_alloc();
180 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, 0x00);
181 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
182 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_NAME, 0x42);
183 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_NVL_KEY_BAD_TYPE, "bad key "
184 "type (name)")) {
185 ret = false;
186 }
187 nvlist_free(nvl);
188
189 nvl = fnvlist_alloc();
190 fnvlist_add_uint32(nvl, UI2C_IOCTL_NVL_ADDR, 0x00);
191 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
192 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, "foobar");
193 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_NVL_KEY_BAD_TYPE, "bad key "
194 "type (addr)")) {
195 ret = false;
196 }
197 nvlist_free(nvl);
198
199 nvl = fnvlist_alloc();
200 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, 0x00);
201 fnvlist_add_int64(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
202 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, "foobar");
203 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_NVL_KEY_BAD_TYPE, "bad key "
204 "type (type)")) {
205 ret = false;
206 }
207 nvlist_free(nvl);
208
209 nvl = fnvlist_alloc();
210 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, 0x00);
211 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
212 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, "foobar");
213 fnvlist_add_byte_array(nvl, UI2C_IOCTL_NVL_COMPAT, (uchar_t *)str,
214 strlen(str));
215 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_NVL_KEY_BAD_TYPE, "bad key "
216 "type (compat)")) {
217 ret = false;
218 }
219 nvlist_free(nvl);
220
221 for (size_t i = 0; i < nbad_addrs; i++) {
222 char desc[128];
223
224 (void) snprintf(desc, sizeof (desc), "bad address %zu "
225 "(0x%x,0x%x)", i, bad_addrs[i].ba_type,
226 bad_addrs[i].ba_addr);
227 nvl = fnvlist_alloc();
228 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE,
229 bad_addrs[i].ba_type);
230 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR,
231 bad_addrs[i].ba_addr);
232 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, "foobar");
233 if (!test_add_nvlist(fd, nvl, bad_addrs[i].ba_error, desc)) {
234 ret = false;
235 }
236 fnvlist_free(nvl);
237 }
238
239 for (size_t i = 0; i < ARRAY_SIZE(bad_names); i++) {
240 char desc[128];
241
242 (void) snprintf(desc, sizeof (desc), "bad names %zu", i);
243 nvl = fnvlist_alloc();
244 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
245 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, 0x42);
246 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, bad_names[i]);
247 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_BAD_DEV_NAME, desc)) {
248 ret = false;
249 }
250 fnvlist_free(nvl);
251 }
252
253 for (size_t i = 0; i < ARRAY_SIZE(bad_names); i++) {
254 char desc[128];
255
256 (void) snprintf(desc, sizeof (desc), "bad compat %zu", i);
257 nvl = fnvlist_alloc();
258 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
259 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, 0x42);
260 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, "foobar");
261 fnvlist_add_string_array(nvl, UI2C_IOCTL_NVL_COMPAT,
262 (char * const *)&bad_names[i], 1);
263 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_BAD_DEV_NAME, desc)) {
264 ret = false;
265 }
266 fnvlist_free(nvl);
267 }
268
269 char *compat[42];
270 for (size_t i = 0; i < ARRAY_SIZE(compat); i++) {
271 compat[i] = "at24c32";
272 }
273
274 nvl = fnvlist_alloc();
275 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
276 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, 0x42);
277 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, "foobar");
278 fnvlist_add_string_array(nvl, UI2C_IOCTL_NVL_COMPAT, compat,
279 ARRAY_SIZE(compat));
280 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_COMPAT_LEN_RANGE,
281 "compat[] too long")) {
282 ret = false;
283 }
284 fnvlist_free(nvl);
285
286 nvl = fnvlist_alloc();
287 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
288 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, 0x42);
289 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, "foobar");
290 fnvlist_add_string(nvl, "magicite", "materia");
291
292 if (!test_add_nvlist(fd, nvl, I2C_IOCTL_E_NVL_KEY_UNKNOWN,
293 "extra keys")) {
294 ret = false;
295 }
296 fnvlist_free(nvl);
297
298 return (ret);
299 }
300
301 static bool
test_add_device(int fd,const char * name,uint8_t addr,i2c_errno_t err,const char * desc)302 test_add_device(int fd, const char *name, uint8_t addr, i2c_errno_t err,
303 const char *desc)
304 {
305 nvlist_t *nvl = fnvlist_alloc();
306 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
307 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, addr);
308 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, name);
309 bool ret = test_add_nvlist(fd, nvl, err, desc);
310 fnvlist_free(nvl);
311 return (ret);
312 }
313
314 static bool
test_address_conflicts(int fd)315 test_address_conflicts(int fd)
316 {
317 bool ret = true;
318
319 if (!test_add_device(fd, "pca9548", 0x70, I2C_CORE_E_OK, "create "
320 "pca9548")) {
321 ret = false;
322 }
323
324 if (!test_add_device(fd, "fake-device", 0x70, I2C_CORE_E_ADDR_IN_USE,
325 "address in use fails (0x70)")) {
326 ret = false;
327 }
328
329 int pfd0 = i2c_ioctl_test_get_fd(I2C_D_PORT, "smbussim1/0/0x70/mux/0",
330 O_RDWR);
331 int pfd4 = i2c_ioctl_test_get_fd(I2C_D_PORT, "smbussim1/0/0x70/mux/4",
332 O_RDWR);
333
334 /*
335 * Verify that an address used downstream on the mux cannot be used
336 * upstream of it.
337 */
338 if (!test_add_device(pfd0, "fake-device", 0x42, I2C_CORE_E_OK, "create "
339 "fake device (ox42) on mux port 0")) {
340 ret = false;
341 }
342
343 if (!test_add_device(pfd4, "fake-device", 0x42, I2C_CORE_E_OK, "create "
344 "fake device (ox42) on mux port 4")) {
345 ret = false;
346 }
347
348 if (!test_add_device(fd, "fake-device", 0x42, I2C_CORE_E_ADDR_IN_USE,
349 "cannot create device on upstream port used on downstream ports")) {
350 ret = false;
351 }
352
353 /*
354 * Verify that an address used on the top-level port cannot be used
355 * downstream of it.
356 */
357 if (test_add_device(fd, "fake-device", 0x23, I2C_CORE_E_OK, "create "
358 "fake device (0x23)")) {
359 if (!test_add_device(pfd0, "fake-device", 0x23,
360 I2C_CORE_E_ADDR_IN_USE, "cannot allocate address on "
361 "downstream port when used upstream (1)")) {
362 ret = false;
363 }
364
365 if (!test_add_device(pfd4, "fake-device", 0x23,
366 I2C_CORE_E_ADDR_IN_USE, "cannot allocate address on "
367 "downstream port when used upstream (2)")) {
368 ret = false;
369 }
370 } else {
371 ret = false;
372 }
373
374 VERIFY0(close(pfd4));
375 VERIFY0(close(pfd0));
376 return (ret);
377 }
378
379 typedef struct {
380 bool tcc_ret;
381 bool tcc_compat0;
382 bool tcc_compat1;
383 char **tcc_compat;
384 } test_compat_cb_t;
385
386 static int
test_compat_walk_cb(di_node_t di,void * arg)387 test_compat_walk_cb(di_node_t di, void *arg)
388 {
389 test_compat_cb_t *cb = arg;
390 const char *name = di_node_name(di);
391 int exp;
392
393 if (strcmp(name, "fake-compat-0") == 0) {
394 cb->tcc_compat0 = true;
395 exp = 1;
396 } else if (strcmp(name, "fake-compat-1") == 0) {
397 cb->tcc_compat1 = true;
398 exp = 32;
399 } else {
400 return (DI_WALK_CONTINUE);
401 }
402
403 char *compat;
404 int nents = di_prop_lookup_strings(DDI_DEV_T_ANY, di, "compatible",
405 &compat);
406 if (nents == exp) {
407 bool valid = true;
408 for (int i = 0; i < exp; i++) {
409 if (strcmp(compat, cb->tcc_compat[i]) != 0) {
410 valid = false;
411 warnx("TEST FAILED: %s has incorrect "
412 "compatible[%d] entry: expected %s, found "
413 "%s", name, i, compat, cb->tcc_compat[i]);
414 }
415
416 compat += strlen(compat) + 1;
417 }
418
419 if (valid) {
420 (void) printf("TEST PASSED: devi %s has correct "
421 "comaptible[%d]\n", name, nents);
422 }
423 } else {
424 warnx("TEST FAILED: node %s has wrong compatible[] count: "
425 "found %d, expected %d", name, nents, exp);
426 cb->tcc_ret = false;
427 }
428
429 return (DI_WALK_PRUNECHILD);
430 }
431
432 static bool
test_compat(int fd)433 test_compat(int fd)
434 {
435 bool ret = true;
436 char *compat[32];
437
438 for (size_t i = 0; i < ARRAY_SIZE(compat); i++) {
439 if (asprintf(&compat[i], "bad,compat%zu", i) < 0) {
440 err(EXIT_FAILURE, "INTERNAL TEST FAILURE: failed to "
441 "construct compat entry %zu", i);
442 }
443 }
444
445 nvlist_t *nvl = fnvlist_alloc();
446 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
447 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, 0x30);
448 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, "fake-compat-0");
449 fnvlist_add_string_array(nvl, UI2C_IOCTL_NVL_COMPAT, compat,
450 1);
451 if (!test_add_nvlist(fd, nvl, I2C_CORE_E_OK, "1-entry compat[]")) {
452 ret = false;
453 }
454 fnvlist_free(nvl);
455
456 nvl = fnvlist_alloc();
457 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_TYPE, I2C_ADDR_7BIT);
458 fnvlist_add_uint16(nvl, UI2C_IOCTL_NVL_ADDR, 0x31);
459 fnvlist_add_string(nvl, UI2C_IOCTL_NVL_NAME, "fake-compat-1");
460 fnvlist_add_string_array(nvl, UI2C_IOCTL_NVL_COMPAT, compat,
461 ARRAY_SIZE(compat));
462 if (!test_add_nvlist(fd, nvl, I2C_CORE_E_OK, "32-entry compat[]")) {
463 ret = false;
464 }
465 fnvlist_free(nvl);
466
467 test_compat_cb_t cb = {
468 .tcc_ret = true,
469 .tcc_compat0 = false,
470 .tcc_compat1 = false,
471 .tcc_compat = compat
472 };
473
474 di_node_t root = di_init(i2c_sim_dipath, DINFOCPYALL);
475 (void) di_walk_node(root, DI_WALK_CLDFIRST, &cb, test_compat_walk_cb);
476 di_fini(root);
477
478 if (!cb.tcc_ret) {
479 ret = false;
480 }
481
482 if (!cb.tcc_compat0) {
483 warnx("TEST FAILED: failed to find devi fake-compat-0");
484 ret = false;
485 }
486
487 if (!cb.tcc_compat1) {
488 warnx("TEST FAILED: failed to find devi fake-compat-1");
489 ret = false;
490 }
491
492 for (size_t i = 0; i < ARRAY_SIZE(compat); i++) {
493 free(compat[i]);
494 }
495
496 return (ret);
497 }
498
499 static bool
test_rm(int fd,uint16_t family,uint16_t addr,i2c_errno_t err,const char * desc)500 test_rm(int fd, uint16_t family, uint16_t addr, i2c_errno_t err,
501 const char *desc)
502 {
503 bool ret = true;
504 ui2c_dev_rem_t rm = {
505 .udr_error = {
506 /* Token errors to ensure this is set by copyout. */
507 INT32_MAX,
508 INT32_MAX
509 },
510 .udr_addr = { family, addr }
511 };
512
513 if (ioctl(fd, UI2C_IOCTL_DEVICE_REMOVE, &rm) != 0) {
514 warnx("TEST FAILED: %s: removal ioctl failed unexpectedly with "
515 "errno %s", desc, strerrorname_np(errno));
516 return (false);
517 }
518
519 if (rm.udr_error.i2c_error != err) {
520 warnx("TEST FAILED: %s: ioctl failed with I2C error 0x%x, "
521 "expected 0x%x", desc, rm.udr_error.i2c_error, err);
522 ret = false;
523 }
524
525 if (rm.udr_error.i2c_ctrl != I2C_CTRL_E_OK) {
526 warnx("TEST FAILED: %s: ioctl has unexpected controller "
527 "error 0x%x", desc, rm.udr_error.i2c_ctrl);
528 ret = false;
529 }
530
531 if (ret) {
532 if (err == I2C_CORE_E_OK) {
533 (void) printf("TEST PASSED: %s correctly removed "
534 "device\n", desc);
535 } else {
536 (void) printf("TEST PASSED: %s correctly failed with "
537 "0x%x\n", desc, err);
538 }
539 }
540
541 return (ret);
542 }
543
544 static bool
test_teardown(int fd)545 test_teardown(int fd)
546 {
547 bool ret = true;
548
549 for (size_t i = 0; i < nbad_addrs; i++) {
550 char desc[128];
551
552 (void) snprintf(desc, sizeof (desc), "remove bad address %zu",
553 i);
554 if (!test_rm(fd, bad_addrs[i].ba_type, bad_addrs[i].ba_addr,
555 bad_addrs[i].ba_error, desc)) {
556 ret = false;
557 }
558 }
559
560 if (!test_rm(fd, I2C_ADDR_7BIT, 0x70, I2C_IOCTL_E_NEXUS,
561 "cannot tear down mux with devices under it")) {
562 ret = false;
563 }
564
565 if (!test_rm(fd, I2C_ADDR_7BIT, 0x30, I2C_CORE_E_OK, "tear down device "
566 "unrelated to mux (0x30)")) {
567 ret = false;
568 }
569
570 if (!test_rm(fd, I2C_ADDR_7BIT, 0x31, I2C_CORE_E_OK, "tear down device "
571 "unrelated to mux (0x31)")) {
572 ret = false;
573 }
574
575 int pfd0 = i2c_ioctl_test_get_fd(I2C_D_PORT, "smbussim1/0/0x70/mux/0",
576 O_RDWR);
577 if (!test_rm(pfd0, I2C_ADDR_7BIT, 0x42, I2C_CORE_E_OK, "tear down "
578 "device under mux (0/0x42)")) {
579 ret = false;
580 }
581
582 if (!test_rm(pfd0, I2C_ADDR_7BIT, 0x42, I2C_CORE_E_UNKNOWN_ADDR,
583 "cannot remove 0/0x42 a second time on same port")) {
584 ret = false;
585 }
586 VERIFY0(close(pfd0));
587
588 int pfd2 = i2c_ioctl_test_get_fd(I2C_D_PORT, "smbussim1/0/0x70/mux/2",
589 O_RDWR);
590 if (!test_rm(pfd2, I2C_ADDR_7BIT, 0x42, I2C_CORE_E_UNKNOWN_ADDR,
591 "cannot remove non-existent 2/0x42")) {
592 ret = false;
593 }
594 VERIFY0(close(pfd2));
595
596 int pdf4 = i2c_ioctl_test_get_fd(I2C_D_PORT, "smbussim1/0/0x70/mux/4",
597 O_RDWR);
598 if (!test_rm(pdf4, I2C_ADDR_7BIT, 0x42, I2C_CORE_E_OK, "tear down "
599 "device under mux (4/0x42)")) {
600 ret = false;
601 }
602
603 if (!test_rm(pdf4, I2C_ADDR_7BIT, 0x42, I2C_CORE_E_UNKNOWN_ADDR,
604 "cannot remove 4/0x42 a second time on same port")) {
605 ret = false;
606 }
607 VERIFY0(close(pdf4));
608
609 if (!test_rm(fd, I2C_ADDR_7BIT, 0x70, I2C_CORE_E_OK, "tear down empty "
610 "mux")) {
611 ret = false;
612 }
613
614 if (!test_rm(fd, I2C_ADDR_7BIT, 0x23, I2C_CORE_E_OK, "tear down device "
615 "(0x23)")) {
616 ret = false;
617 }
618 return (ret);
619 }
620
621 int
main(void)622 main(void)
623 {
624 int ret = EXIT_SUCCESS;
625 int fd = i2c_ioctl_test_get_fd(I2C_D_PORT, "smbussim1/0", O_RDWR);
626
627 if (!test_bad_nvlists(fd)) {
628 ret = EXIT_FAILURE;
629 }
630
631 if (!test_address_conflicts(fd)) {
632 ret = EXIT_FAILURE;
633 }
634
635 if (!test_compat(fd)) {
636 ret = EXIT_FAILURE;
637 }
638
639 if (!test_teardown(fd)) {
640 ret = EXIT_FAILURE;
641 }
642
643 VERIFY0(close(fd));
644 if (ret == EXIT_SUCCESS) {
645 (void) printf("All tests passed successfully\n");
646 }
647 return (ret);
648 }
649