Print this page
5513 KM_NORMALPRI should be documented in kmem_alloc(9f) and kmem_cache_create(9f) man pages
14465 Present KM_NOSLEEP_LAZY as documented interface
Change-Id: I002ec28ddf390650f1fcba1ca94f6abfdb241439
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/ufmtest.c
+++ new/usr/src/uts/common/io/ufmtest.c
1 1 /*
2 2 * This file and its contents are supplied under the terms of the
3 3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 4 * You may only use this file in accordance with the terms of version
5 5 * 1.0 of the CDDL.
6 6 *
7 7 * A full copy of the text of the CDDL should have accompanied this
8 8 * source. A copy of the CDDL is also available via the Internet at
9 9 * http://www.illumos.org/license/CDDL.
10 10 */
11 11
12 12 /*
13 13 * Copyright 2019 Joyent, Inc.
14 14 */
15 15
16 16 /*
17 17 * This is a test driver used for exercising the DDI UFM subsystem.
18 18 *
19 19 * Most of the test cases depend on the ufmtest driver being loaded.
20 20 * On SmartOS, this driver will need to be manually installed, as it is not
21 21 * part of the platform image.
22 22 */
23 23 #include <sys/ddi.h>
24 24 #include <sys/sunddi.h>
25 25 #include <sys/esunddi.h>
26 26 #include <sys/ddi_ufm.h>
27 27 #include <sys/conf.h>
28 28 #include <sys/debug.h>
29 29 #include <sys/file.h>
30 30 #include <sys/kmem.h>
31 31 #include <sys/stat.h>
32 32 #include <sys/zone.h>
33 33
34 34 #include "ufmtest.h"
35 35
36 36 typedef struct ufmtest {
37 37 dev_info_t *ufmt_devi;
38 38 nvlist_t *ufmt_nvl;
39 39 ddi_ufm_handle_t *ufmt_ufmh;
40 40 uint32_t ufmt_failflags;
41 41 } ufmtest_t;
42 42
43 43 static ufmtest_t ufmt = { 0 };
44 44
45 45 static int ufmtest_open(dev_t *, int, int, cred_t *);
46 46 static int ufmtest_close(dev_t, int, int, cred_t *);
47 47 static int ufmtest_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
48 48
49 49 static struct cb_ops ufmtest_cb_ops = {
50 50 .cb_open = ufmtest_open,
51 51 .cb_close = ufmtest_close,
52 52 .cb_strategy = nodev,
53 53 .cb_print = nodev,
54 54 .cb_dump = nodev,
55 55 .cb_read = nodev,
56 56 .cb_write = nodev,
57 57 .cb_ioctl = ufmtest_ioctl,
58 58 .cb_devmap = nodev,
59 59 .cb_mmap = nodev,
60 60 .cb_segmap = nodev,
61 61 .cb_chpoll = nochpoll,
62 62 .cb_prop_op = ddi_prop_op,
63 63 .cb_str = NULL,
64 64 .cb_flag = D_NEW | D_MP,
65 65 .cb_rev = CB_REV,
66 66 .cb_aread = nodev,
67 67 .cb_awrite = nodev
68 68 };
69 69
70 70 static int ufmtest_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
71 71 static int ufmtest_attach(dev_info_t *, ddi_attach_cmd_t);
72 72 static int ufmtest_detach(dev_info_t *, ddi_detach_cmd_t);
73 73
74 74 static struct dev_ops ufmtest_ops = {
75 75 .devo_rev = DEVO_REV,
76 76 .devo_refcnt = 0,
77 77 .devo_getinfo = ufmtest_info,
78 78 .devo_identify = nulldev,
79 79 .devo_probe = nulldev,
80 80 .devo_attach = ufmtest_attach,
81 81 .devo_detach = ufmtest_detach,
82 82 .devo_reset = nodev,
83 83 .devo_cb_ops = &ufmtest_cb_ops,
84 84 .devo_bus_ops = NULL,
85 85 .devo_power = NULL,
86 86 .devo_quiesce = ddi_quiesce_not_needed
87 87 };
88 88
89 89 static struct modldrv modldrv = {
90 90 .drv_modops = &mod_driverops,
91 91 .drv_linkinfo = "DDI UFM test driver",
92 92 .drv_dev_ops = &ufmtest_ops
93 93 };
94 94
95 95 static struct modlinkage modlinkage = {
96 96 .ml_rev = MODREV_1,
97 97 .ml_linkage = { (void *)&modldrv, NULL }
98 98 };
99 99
100 100 static int ufmtest_nimages(ddi_ufm_handle_t *, void *, uint_t *);
101 101 static int ufmtest_fill_image(ddi_ufm_handle_t *, void *, uint_t,
102 102 ddi_ufm_image_t *);
103 103 static int ufmtest_fill_slot(ddi_ufm_handle_t *, void *, uint_t, uint_t,
104 104 ddi_ufm_slot_t *);
105 105 static int ufmtest_getcaps(ddi_ufm_handle_t *, void *, ddi_ufm_cap_t *);
106 106
107 107 static ddi_ufm_ops_t ufmtest_ufm_ops = {
108 108 ufmtest_nimages,
109 109 ufmtest_fill_image,
110 110 ufmtest_fill_slot,
111 111 ufmtest_getcaps
112 112 };
113 113
114 114
115 115 int
116 116 _init(void)
117 117 {
118 118 return (mod_install(&modlinkage));
119 119 }
120 120
121 121 int
122 122 _fini(void)
123 123 {
124 124 return (mod_remove(&modlinkage));
125 125 }
126 126
127 127 int
128 128 _info(struct modinfo *modinfop)
129 129 {
130 130 return (mod_info(&modlinkage, modinfop));
131 131 }
132 132
133 133 static int
134 134 ufmtest_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
135 135 {
136 136 switch (infocmd) {
137 137 case DDI_INFO_DEVT2DEVINFO:
138 138 *result = ufmt.ufmt_devi;
139 139 return (DDI_SUCCESS);
140 140 case DDI_INFO_DEVT2INSTANCE:
141 141 *result = (void *)(uintptr_t)ddi_get_instance(dip);
142 142 return (DDI_SUCCESS);
143 143 }
144 144 return (DDI_FAILURE);
145 145 }
146 146
147 147 static int
148 148 ufmtest_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
149 149 {
150 150 if (cmd != DDI_ATTACH || ufmt.ufmt_devi != NULL)
151 151 return (DDI_FAILURE);
152 152
153 153 if (ddi_create_minor_node(devi, "ufmtest", S_IFCHR, 0, DDI_PSEUDO,
154 154 0) == DDI_FAILURE) {
155 155 ddi_remove_minor_node(devi, NULL);
156 156 return (DDI_FAILURE);
157 157 }
158 158
159 159 ufmt.ufmt_devi = devi;
160 160
161 161 if (ddi_ufm_init(ufmt.ufmt_devi, DDI_UFM_CURRENT_VERSION,
162 162 &ufmtest_ufm_ops, &ufmt.ufmt_ufmh, NULL) != 0) {
163 163 dev_err(ufmt.ufmt_devi, CE_WARN, "failed to initialize UFM "
164 164 "subsystem");
165 165 return (DDI_FAILURE);
166 166 }
167 167
168 168 return (DDI_SUCCESS);
169 169 }
170 170
171 171 static int
172 172 ufmtest_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
173 173 {
174 174 if (cmd != DDI_DETACH)
175 175 return (DDI_FAILURE);
176 176
177 177 if (devi != NULL)
178 178 ddi_remove_minor_node(devi, NULL);
179 179
180 180 ddi_ufm_fini(ufmt.ufmt_ufmh);
181 181 if (ufmt.ufmt_nvl != NULL) {
182 182 nvlist_free(ufmt.ufmt_nvl);
183 183 ufmt.ufmt_nvl = NULL;
184 184 }
185 185
186 186 return (DDI_SUCCESS);
187 187 }
188 188
189 189 static int
190 190 ufmtest_open(dev_t *devp, int flag, int otyp, cred_t *credp)
191 191 {
192 192 const int inv_flags = FWRITE | FEXCL | FNDELAY | FNONBLOCK;
193 193
194 194 if (otyp != OTYP_CHR)
195 195 return (EINVAL);
196 196
197 197 if (flag & inv_flags)
198 198 return (EINVAL);
199 199
200 200 if (drv_priv(credp) != 0)
201 201 return (EPERM);
202 202
203 203 if (getzoneid() != GLOBAL_ZONEID)
204 204 return (EPERM);
205 205
206 206 return (0);
207 207 }
208 208
209 209 static int
210 210 ufmtest_close(dev_t dev, int flag, int otyp, cred_t *credp)
211 211 {
212 212 return (0);
213 213 }
214 214
215 215 /*
216 216 * By default, this pseudo test driver contains no hardcoded UFM data to
217 217 * report. This ioctl takes a packed nvlist, representing a UFM report.
218 218 * This data is then used as a source for firmware information by this
219 219 * driver when it's UFM callback are called.
220 220 *
221 221 * External test programs can use this ioctl to effectively seed this
222 222 * driver with arbitrary firmware information which it will report up to the
223 223 * DDI UFM subsystem.
224 224 */
225 225 static int
226 226 ufmtest_do_setfw(intptr_t data, int mode)
227 227 {
228 228 int ret;
229 229 uint_t model;
230 230 ufmtest_ioc_setfw_t setfw;
231 231 char *nvlbuf = NULL;
232 232 #ifdef _MULTI_DATAMODEL
233 233 ufmtest_ioc_setfw32_t setfw32;
234 234 #endif
235 235 model = ddi_model_convert_from(mode);
236 236
237 237 switch (model) {
238 238 #ifdef _MULTI_DATAMODEL
239 239 case DDI_MODEL_ILP32:
240 240 if (ddi_copyin((void *)data, &setfw32,
241 241 sizeof (ufmtest_ioc_setfw32_t), mode) != 0)
242 242 return (EFAULT);
243 243 setfw.utsw_bufsz = setfw32.utsw_bufsz;
244 244 setfw.utsw_buf = (caddr_t)(uintptr_t)setfw32.utsw_buf;
245 245 break;
246 246 #endif /* _MULTI_DATAMODEL */
247 247 case DDI_MODEL_NONE:
248 248 default:
|
↓ open down ↓ |
248 lines elided |
↑ open up ↑ |
249 249 if (ddi_copyin((void *)data, &setfw,
250 250 sizeof (ufmtest_ioc_setfw_t), mode) != 0)
251 251 return (EFAULT);
252 252 }
253 253
254 254 if (ufmt.ufmt_nvl != NULL) {
255 255 nvlist_free(ufmt.ufmt_nvl);
256 256 ufmt.ufmt_nvl = NULL;
257 257 }
258 258
259 - nvlbuf = kmem_zalloc(setfw.utsw_bufsz, KM_NOSLEEP | KM_NORMALPRI);
259 + nvlbuf = kmem_zalloc(setfw.utsw_bufsz, KM_NOSLEEP_LAZY);
260 260 if (nvlbuf == NULL)
261 261 return (ENOMEM);
262 262
263 263 if (ddi_copyin(setfw.utsw_buf, nvlbuf, setfw.utsw_bufsz, mode) != 0) {
264 264 kmem_free(nvlbuf, setfw.utsw_bufsz);
265 265 return (EFAULT);
266 266 }
267 267
268 268 ret = nvlist_unpack(nvlbuf, setfw.utsw_bufsz, &ufmt.ufmt_nvl,
269 269 KM_NOSLEEP);
270 270 kmem_free(nvlbuf, setfw.utsw_bufsz);
271 271
272 272 if (ret != 0)
273 273 return (ret);
274 274
275 275 /*
276 276 * Notify the UFM subsystem that our firmware information has changed.
277 277 */
278 278 ddi_ufm_update(ufmt.ufmt_ufmh);
279 279
280 280 return (0);
281 281 }
282 282
283 283 static int
284 284 ufmtest_do_toggle_fails(intptr_t data, int mode)
285 285 {
286 286 ufmtest_ioc_fails_t fails;
287 287
288 288 if (ddi_copyin((void *)data, &fails, sizeof (ufmtest_ioc_fails_t),
289 289 mode) != 0)
290 290 return (EFAULT);
291 291
292 292 if (fails.utfa_flags > UFMTEST_MAX_FAILFLAGS)
293 293 return (EINVAL);
294 294
295 295 ufmt.ufmt_failflags = fails.utfa_flags;
296 296
297 297 return (0);
298 298 }
299 299
300 300 /* ARGSUSED */
301 301 static int
302 302 ufmtest_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *credp,
303 303 int *rvalp)
304 304 {
305 305 int ret = 0;
306 306
307 307 if (drv_priv(credp) != 0)
308 308 return (EPERM);
309 309
310 310 switch (cmd) {
311 311 case UFMTEST_IOC_SET_FW:
312 312 ret = ufmtest_do_setfw(data, mode);
313 313 break;
314 314 case UFMTEST_IOC_TOGGLE_FAILS:
315 315 ret = ufmtest_do_toggle_fails(data, mode);
316 316 break;
317 317 case UFMTEST_IOC_DO_UPDATE:
318 318 ddi_ufm_update(ufmt.ufmt_ufmh);
319 319 break;
320 320 default:
321 321 return (ENOTTY);
322 322 }
323 323 return (ret);
324 324 }
325 325
326 326 static int
327 327 ufmtest_nimages(ddi_ufm_handle_t *ufmh, void *arg, uint_t *nimgs)
328 328 {
329 329 nvlist_t **imgs;
330 330 uint_t ni;
331 331
332 332 if (ufmt.ufmt_failflags & UFMTEST_FAIL_NIMAGES ||
333 333 ufmt.ufmt_nvl == NULL)
334 334 return (EINVAL);
335 335
336 336 if (nvlist_lookup_nvlist_array(ufmt.ufmt_nvl, DDI_UFM_NV_IMAGES, &imgs,
337 337 &ni) != 0)
338 338 return (EINVAL);
339 339
340 340 *nimgs = ni;
341 341 return (0);
342 342 }
343 343
344 344 static int
345 345 ufmtest_fill_image(ddi_ufm_handle_t *ufmh, void *arg, uint_t imgno,
346 346 ddi_ufm_image_t *img)
347 347 {
348 348 nvlist_t **images, *misc, *miscdup = NULL, **slots;
349 349 char *desc;
350 350 uint_t ni, ns;
351 351
352 352 if (ufmt.ufmt_failflags & UFMTEST_FAIL_FILLIMAGE ||
353 353 ufmt.ufmt_nvl == NULL ||
354 354 nvlist_lookup_nvlist_array(ufmt.ufmt_nvl, DDI_UFM_NV_IMAGES,
355 355 &images, &ni) != 0)
356 356 goto err;
357 357
358 358 if (imgno >= ni)
359 359 goto err;
360 360
361 361 if (nvlist_lookup_string(images[imgno], DDI_UFM_NV_IMAGE_DESC,
362 362 &desc) != 0 ||
363 363 nvlist_lookup_nvlist_array(images[imgno], DDI_UFM_NV_IMAGE_SLOTS,
364 364 &slots, &ns) != 0)
365 365 goto err;
366 366
367 367 ddi_ufm_image_set_desc(img, desc);
368 368 ddi_ufm_image_set_nslots(img, ns);
369 369
370 370 if (nvlist_lookup_nvlist(images[imgno], DDI_UFM_NV_IMAGE_MISC, &misc)
371 371 == 0) {
372 372 if (nvlist_dup(misc, &miscdup, 0) != 0)
373 373 return (ENOMEM);
374 374
375 375 ddi_ufm_image_set_misc(img, miscdup);
376 376 }
377 377 return (0);
378 378 err:
379 379 return (EINVAL);
380 380 }
381 381
382 382 static int
383 383 ufmtest_fill_slot(ddi_ufm_handle_t *ufmh, void *arg, uint_t imgno,
384 384 uint_t slotno, ddi_ufm_slot_t *slot)
385 385 {
386 386 nvlist_t **images, *misc, *miscdup = NULL, **slots;
387 387 char *vers;
388 388 uint32_t attrs;
389 389 uint_t ni, ns;
390 390
391 391 if (ufmt.ufmt_failflags & UFMTEST_FAIL_FILLSLOT ||
392 392 ufmt.ufmt_nvl == NULL ||
393 393 nvlist_lookup_nvlist_array(ufmt.ufmt_nvl, DDI_UFM_NV_IMAGES,
394 394 &images, &ni) != 0)
395 395 goto err;
396 396
397 397 if (imgno >= ni)
398 398 goto err;
399 399
400 400 if (nvlist_lookup_nvlist_array(images[imgno], DDI_UFM_NV_IMAGE_SLOTS,
401 401 &slots, &ns) != 0)
402 402 goto err;
403 403
404 404 if (slotno >= ns)
405 405 goto err;
406 406
407 407 if (nvlist_lookup_uint32(slots[slotno], DDI_UFM_NV_SLOT_ATTR,
408 408 &attrs) != 0)
409 409 goto err;
410 410
411 411 ddi_ufm_slot_set_attrs(slot, attrs);
412 412 if (attrs & DDI_UFM_ATTR_EMPTY)
413 413 return (0);
414 414
415 415 if (nvlist_lookup_string(slots[slotno], DDI_UFM_NV_SLOT_VERSION,
416 416 &vers) != 0)
417 417 goto err;
418 418
419 419 ddi_ufm_slot_set_version(slot, vers);
420 420
421 421 if (nvlist_lookup_nvlist(slots[slotno], DDI_UFM_NV_SLOT_MISC, &misc) ==
422 422 0) {
423 423 if (nvlist_dup(misc, &miscdup, 0) != 0)
424 424 return (ENOMEM);
425 425
426 426 ddi_ufm_slot_set_misc(slot, miscdup);
427 427 }
428 428 return (0);
429 429 err:
430 430 return (EINVAL);
431 431 }
432 432
433 433 static int
434 434 ufmtest_getcaps(ddi_ufm_handle_t *ufmh, void *arg, ddi_ufm_cap_t *caps)
435 435 {
436 436 if (ufmt.ufmt_failflags & UFMTEST_FAIL_GETCAPS)
437 437 return (EINVAL);
438 438
439 439 *caps = DDI_UFM_CAP_REPORT;
440 440
441 441 return (0);
442 442 }
|
↓ open down ↓ |
173 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX