1 // SPDX-License-Identifier: GPL-2.0-only
10 #include <asm/papr-vpd.h>
14 #define DEVPATH "/dev/papr-vpd"
16 static int dev_papr_vpd_open_close(void)
18 const int devfd
= open(DEVPATH
, O_RDONLY
);
20 SKIP_IF_MSG(devfd
< 0 && errno
== ENOENT
,
21 DEVPATH
" not present");
24 FAIL_IF(close(devfd
) != 0);
29 static int dev_papr_vpd_get_handle_all(void)
31 const int devfd
= open(DEVPATH
, O_RDONLY
);
32 struct papr_location_code lc
= { .str
= "", };
36 SKIP_IF_MSG(devfd
< 0 && errno
== ENOENT
,
37 DEVPATH
" not present");
42 fd
= ioctl(devfd
, PAPR_VPD_IOC_CREATE_HANDLE
, &lc
);
46 FAIL_IF(close(devfd
) != 0);
48 size
= lseek(fd
, 0, SEEK_END
);
51 void *buf
= malloc((size_t)size
);
54 ssize_t consumed
= pread(fd
, buf
, size
, 0);
55 FAIL_IF(consumed
!= size
);
58 FAIL_IF(read(fd
, buf
, size
) != 0);
61 /* Verify that the buffer looks like VPD */
62 static const char needle
[] = "System VPD";
63 FAIL_IF(!memmem(buf
, size
, needle
, strlen(needle
)));
68 static int dev_papr_vpd_get_handle_byte_at_a_time(void)
70 const int devfd
= open(DEVPATH
, O_RDONLY
);
71 struct papr_location_code lc
= { .str
= "", };
74 SKIP_IF_MSG(devfd
< 0 && errno
== ENOENT
,
75 DEVPATH
" not present");
80 fd
= ioctl(devfd
, PAPR_VPD_IOC_CREATE_HANDLE
, &lc
);
84 FAIL_IF(close(devfd
) != 0);
92 res
= read(fd
, &c
, sizeof(c
));
93 FAIL_IF(res
> sizeof(c
));
101 FAIL_IF(consumed
!= lseek(fd
, 0, SEEK_END
));
109 static int dev_papr_vpd_unterm_loc_code(void)
111 const int devfd
= open(DEVPATH
, O_RDONLY
);
112 struct papr_location_code lc
= {};
115 SKIP_IF_MSG(devfd
< 0 && errno
== ENOENT
,
116 DEVPATH
" not present");
121 * Place a non-null byte in every element of loc_code; the
122 * driver should reject this input.
124 memset(lc
.str
, 'x', ARRAY_SIZE(lc
.str
));
127 fd
= ioctl(devfd
, PAPR_VPD_IOC_CREATE_HANDLE
, &lc
);
129 FAIL_IF(errno
!= EINVAL
);
131 FAIL_IF(close(devfd
) != 0);
135 static int dev_papr_vpd_null_handle(void)
137 const int devfd
= open(DEVPATH
, O_RDONLY
);
140 SKIP_IF_MSG(devfd
< 0 && errno
== ENOENT
,
141 DEVPATH
" not present");
146 rc
= ioctl(devfd
, PAPR_VPD_IOC_CREATE_HANDLE
, NULL
);
148 FAIL_IF(errno
!= EFAULT
);
150 FAIL_IF(close(devfd
) != 0);
154 static int papr_vpd_close_handle_without_reading(void)
156 const int devfd
= open(DEVPATH
, O_RDONLY
);
157 struct papr_location_code lc
= { .str
= "", };
160 SKIP_IF_MSG(devfd
< 0 && errno
== ENOENT
,
161 DEVPATH
" not present");
166 fd
= ioctl(devfd
, PAPR_VPD_IOC_CREATE_HANDLE
, &lc
);
170 /* close the handle without reading it */
171 FAIL_IF(close(fd
) != 0);
173 FAIL_IF(close(devfd
) != 0);
177 static int papr_vpd_reread(void)
179 const int devfd
= open(DEVPATH
, O_RDONLY
);
180 struct papr_location_code lc
= { .str
= "", };
183 SKIP_IF_MSG(devfd
< 0 && errno
== ENOENT
,
184 DEVPATH
" not present");
189 fd
= ioctl(devfd
, PAPR_VPD_IOC_CREATE_HANDLE
, &lc
);
193 FAIL_IF(close(devfd
) != 0);
195 const off_t size
= lseek(fd
, 0, SEEK_END
);
200 for (size_t i
= 0; i
< ARRAY_SIZE(bufs
); ++i
) {
201 bufs
[i
] = malloc(size
);
203 ssize_t consumed
= pread(fd
, bufs
[i
], size
, 0);
204 FAIL_IF(consumed
!= size
);
207 FAIL_IF(memcmp(bufs
[0], bufs
[1], size
));
209 FAIL_IF(close(fd
) != 0);
214 static int get_system_loc_code(struct papr_location_code
*lc
)
216 static const char system_id_path
[] = "/sys/firmware/devicetree/base/system-id";
217 static const char model_path
[] = "/sys/firmware/devicetree/base/model";
222 if (read_file_alloc(model_path
, &model
, NULL
))
225 if (read_file_alloc(system_id_path
, &system_id
, NULL
))
229 int sscanf_ret
= sscanf(model
, "IBM,%ms", &mtm
);
234 if (sscanf(system_id
, "IBM,%*c%*c%ms", &plant_and_seq
) != 1)
237 * Replace - with . to build location code.
239 char *sep
= strchr(mtm
, '-');
245 snprintf(lc
->str
, sizeof(lc
->str
),
246 "U%s.%s", mtm
, plant_and_seq
);
259 static int papr_vpd_system_loc_code(void)
261 struct papr_location_code lc
;
262 const int devfd
= open(DEVPATH
, O_RDONLY
);
266 SKIP_IF_MSG(devfd
< 0 && errno
== ENOENT
,
267 DEVPATH
" not present");
268 SKIP_IF_MSG(get_system_loc_code(&lc
),
269 "Cannot determine system location code");
274 fd
= ioctl(devfd
, PAPR_VPD_IOC_CREATE_HANDLE
, &lc
);
278 FAIL_IF(close(devfd
) != 0);
280 size
= lseek(fd
, 0, SEEK_END
);
283 void *buf
= malloc((size_t)size
);
286 ssize_t consumed
= pread(fd
, buf
, size
, 0);
287 FAIL_IF(consumed
!= size
);
290 FAIL_IF(read(fd
, buf
, size
) != 0);
293 /* Verify that the buffer looks like VPD */
294 static const char needle
[] = "System VPD";
295 FAIL_IF(!memmem(buf
, size
, needle
, strlen(needle
)));
301 int (*function
)(void);
302 const char *description
;
305 static const struct vpd_test vpd_tests
[] = {
307 .function
= dev_papr_vpd_open_close
,
308 .description
= "open/close " DEVPATH
,
311 .function
= dev_papr_vpd_unterm_loc_code
,
312 .description
= "ensure EINVAL on unterminated location code",
315 .function
= dev_papr_vpd_null_handle
,
316 .description
= "ensure EFAULT on bad handle addr",
319 .function
= dev_papr_vpd_get_handle_all
,
320 .description
= "get handle for all VPD"
323 .function
= papr_vpd_close_handle_without_reading
,
324 .description
= "close handle without consuming VPD"
327 .function
= dev_papr_vpd_get_handle_byte_at_a_time
,
328 .description
= "read all VPD one byte at a time"
331 .function
= papr_vpd_reread
,
332 .description
= "ensure re-read yields same results"
335 .function
= papr_vpd_system_loc_code
,
336 .description
= "get handle for system VPD"
344 for (size_t i
= 0; i
< ARRAY_SIZE(vpd_tests
); ++i
) {
345 const struct vpd_test
*t
= &vpd_tests
[i
];
347 if (test_harness(t
->function
, t
->description
))
351 return fails
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;