xref: /freebsd/sys/dev/sfxge/common/siena_vpd.c (revision f7c32ed617858bcd22f8d1b03199099d50125721)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2009-2016 Solarflare Communications Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice,
11  *    this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  *    this list of conditions and the following disclaimer in the documentation
14  *    and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * The views and conclusions contained in the software and documentation are
29  * those of the authors and should not be interpreted as representing official
30  * policies, either expressed or implied, of the FreeBSD Project.
31  */
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35 
36 #include "efx.h"
37 #include "efx_impl.h"
38 
39 #if EFSYS_OPT_VPD
40 
41 #if EFSYS_OPT_SIENA
42 
43 static	__checkReturn			efx_rc_t
44 siena_vpd_get_static(
45 	__in				efx_nic_t *enp,
46 	__in				uint32_t partn,
47 	__deref_out_bcount_opt(*sizep)	caddr_t *svpdp,
48 	__out				size_t *sizep)
49 {
50 	siena_mc_static_config_hdr_t *scfg;
51 	caddr_t svpd;
52 	size_t size;
53 	uint8_t cksum;
54 	unsigned int vpd_offset;
55 	unsigned int vpd_length;
56 	unsigned int hdr_length;
57 	unsigned int pos;
58 	unsigned int region;
59 	efx_rc_t rc;
60 
61 	EFSYS_ASSERT(partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0 ||
62 		    partn == MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1);
63 
64 	/* Allocate sufficient memory for the entire static cfg area */
65 	if ((rc = siena_nvram_partn_size(enp, partn, &size)) != 0)
66 		goto fail1;
67 
68 	if (size < SIENA_NVRAM_CHUNK) {
69 		rc = EINVAL;
70 		goto fail2;
71 	}
72 
73 	EFSYS_KMEM_ALLOC(enp->en_esip, size, scfg);
74 	if (scfg == NULL) {
75 		rc = ENOMEM;
76 		goto fail3;
77 	}
78 
79 	if ((rc = siena_nvram_partn_read(enp, partn, 0,
80 	    (caddr_t)scfg, SIENA_NVRAM_CHUNK)) != 0)
81 		goto fail4;
82 
83 	/* Verify the magic number */
84 	if (EFX_DWORD_FIELD(scfg->magic, EFX_DWORD_0) !=
85 	    SIENA_MC_STATIC_CONFIG_MAGIC) {
86 		rc = EINVAL;
87 		goto fail5;
88 	}
89 
90 	/* All future versions of the structure must be backwards compatible */
91 	EFX_STATIC_ASSERT(SIENA_MC_STATIC_CONFIG_VERSION == 0);
92 
93 	hdr_length = EFX_WORD_FIELD(scfg->length, EFX_WORD_0);
94 	vpd_offset = EFX_DWORD_FIELD(scfg->static_vpd_offset, EFX_DWORD_0);
95 	vpd_length = EFX_DWORD_FIELD(scfg->static_vpd_length, EFX_DWORD_0);
96 
97 	/* Verify the hdr doesn't overflow the sector size */
98 	if (hdr_length > size || vpd_offset > size || vpd_length > size ||
99 	    vpd_length + vpd_offset > size) {
100 		rc = EINVAL;
101 		goto fail6;
102 	}
103 
104 	/* Read the remainder of scfg + static vpd */
105 	region = vpd_offset + vpd_length;
106 	if (region > SIENA_NVRAM_CHUNK) {
107 		if ((rc = siena_nvram_partn_read(enp, partn, SIENA_NVRAM_CHUNK,
108 		    (caddr_t)scfg + SIENA_NVRAM_CHUNK,
109 		    region - SIENA_NVRAM_CHUNK)) != 0)
110 			goto fail7;
111 	}
112 
113 	/* Verify checksum */
114 	cksum = 0;
115 	for (pos = 0; pos < hdr_length; pos++)
116 		cksum += ((uint8_t *)scfg)[pos];
117 	if (cksum != 0) {
118 		rc = EINVAL;
119 		goto fail8;
120 	}
121 
122 	if (vpd_length == 0)
123 		svpd = NULL;
124 	else {
125 		/* Copy the vpd data out */
126 		EFSYS_KMEM_ALLOC(enp->en_esip, vpd_length, svpd);
127 		if (svpd == NULL) {
128 			rc = ENOMEM;
129 			goto fail9;
130 		}
131 		memcpy(svpd, (caddr_t)scfg + vpd_offset, vpd_length);
132 	}
133 
134 	EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
135 
136 	*svpdp = svpd;
137 	*sizep = vpd_length;
138 
139 	return (0);
140 
141 fail9:
142 	EFSYS_PROBE(fail9);
143 fail8:
144 	EFSYS_PROBE(fail8);
145 fail7:
146 	EFSYS_PROBE(fail7);
147 fail6:
148 	EFSYS_PROBE(fail6);
149 fail5:
150 	EFSYS_PROBE(fail5);
151 fail4:
152 	EFSYS_PROBE(fail4);
153 
154 	EFSYS_KMEM_FREE(enp->en_esip, size, scfg);
155 
156 fail3:
157 	EFSYS_PROBE(fail3);
158 fail2:
159 	EFSYS_PROBE(fail2);
160 fail1:
161 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
162 
163 	return (rc);
164 }
165 
166 	__checkReturn		efx_rc_t
167 siena_vpd_init(
168 	__in			efx_nic_t *enp)
169 {
170 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
171 	caddr_t svpd = NULL;
172 	unsigned int partn;
173 	size_t size = 0;
174 	efx_rc_t rc;
175 
176 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
177 
178 	partn = (emip->emi_port == 1)
179 		? MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT0
180 		: MC_CMD_NVRAM_TYPE_STATIC_CFG_PORT1;
181 
182 	/*
183 	 * We need the static VPD sector to present a unified static+dynamic
184 	 * VPD, that is, basically on every read, write, verify cycle. Since
185 	 * it should *never* change we can just cache it here.
186 	 */
187 	if ((rc = siena_vpd_get_static(enp, partn, &svpd, &size)) != 0)
188 		goto fail1;
189 
190 	if (svpd != NULL && size > 0) {
191 		if ((rc = efx_vpd_hunk_verify(svpd, size, NULL)) != 0)
192 			goto fail2;
193 	}
194 
195 	enp->en_u.siena.enu_svpd = svpd;
196 	enp->en_u.siena.enu_svpd_length = size;
197 
198 	return (0);
199 
200 fail2:
201 	EFSYS_PROBE(fail2);
202 
203 	EFSYS_KMEM_FREE(enp->en_esip, size, svpd);
204 fail1:
205 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
206 
207 	return (rc);
208 }
209 
210 	__checkReturn		efx_rc_t
211 siena_vpd_size(
212 	__in			efx_nic_t *enp,
213 	__out			size_t *sizep)
214 {
215 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
216 	uint32_t partn;
217 	efx_rc_t rc;
218 
219 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
220 
221 	/*
222 	 * This function returns the total size the user should allocate
223 	 * for all VPD operations. We've already cached the static vpd,
224 	 * so we just need to return an upper bound on the dynamic vpd.
225 	 * Since the dynamic_config structure can change under our feet,
226 	 * (as version numbers are inserted), just be safe and return the
227 	 * total size of the dynamic_config *sector*
228 	 */
229 	partn = (emip->emi_port == 1)
230 		? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
231 		: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
232 
233 	if ((rc = siena_nvram_partn_size(enp, partn, sizep)) != 0)
234 		goto fail1;
235 
236 	return (0);
237 
238 fail1:
239 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
240 
241 	return (rc);
242 }
243 
244 	__checkReturn		efx_rc_t
245 siena_vpd_read(
246 	__in			efx_nic_t *enp,
247 	__out_bcount(size)	caddr_t data,
248 	__in			size_t size)
249 {
250 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
251 	siena_mc_dynamic_config_hdr_t *dcfg = NULL;
252 	unsigned int vpd_length;
253 	unsigned int vpd_offset;
254 	unsigned int dcfg_partn;
255 	size_t dcfg_size;
256 	efx_rc_t rc;
257 
258 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
259 
260 	dcfg_partn = (emip->emi_port == 1)
261 		? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
262 		: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
263 
264 	if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
265 	    B_TRUE, &dcfg, &dcfg_size)) != 0)
266 		goto fail1;
267 
268 	vpd_length = EFX_DWORD_FIELD(dcfg->dynamic_vpd_length, EFX_DWORD_0);
269 	vpd_offset = EFX_DWORD_FIELD(dcfg->dynamic_vpd_offset, EFX_DWORD_0);
270 
271 	if (vpd_length > size) {
272 		rc = EFAULT;	/* Invalid dcfg: header bigger than sector */
273 		goto fail2;
274 	}
275 
276 	EFSYS_ASSERT3U(vpd_length, <=, size);
277 	memcpy(data, (caddr_t)dcfg + vpd_offset, vpd_length);
278 
279 	/* Pad data with all-1s, consistent with update operations */
280 	memset(data + vpd_length, 0xff, size - vpd_length);
281 
282 	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
283 
284 	return (0);
285 
286 fail2:
287 	EFSYS_PROBE(fail2);
288 
289 	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
290 fail1:
291 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
292 
293 	return (rc);
294 }
295 
296 	__checkReturn		efx_rc_t
297 siena_vpd_verify(
298 	__in			efx_nic_t *enp,
299 	__in_bcount(size)	caddr_t data,
300 	__in			size_t size)
301 {
302 	efx_vpd_tag_t stag;
303 	efx_vpd_tag_t dtag;
304 	efx_vpd_keyword_t skey;
305 	efx_vpd_keyword_t dkey;
306 	unsigned int scont;
307 	unsigned int dcont;
308 
309 	efx_rc_t rc;
310 
311 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
312 
313 	/*
314 	 * Strictly you could take the view that dynamic vpd is optional.
315 	 * Instead, to conform more closely to the read/verify/reinit()
316 	 * paradigm, we require dynamic vpd. siena_vpd_reinit() will
317 	 * reinitialize it as required.
318 	 */
319 	if ((rc = efx_vpd_hunk_verify(data, size, NULL)) != 0)
320 		goto fail1;
321 
322 	/*
323 	 * Verify that there is no duplication between the static and
324 	 * dynamic cfg sectors.
325 	 */
326 	if (enp->en_u.siena.enu_svpd_length == 0)
327 		goto done;
328 
329 	dcont = 0;
330 	_NOTE(CONSTANTCONDITION)
331 	while (1) {
332 		if ((rc = efx_vpd_hunk_next(data, size, &dtag,
333 		    &dkey, NULL, NULL, &dcont)) != 0)
334 			goto fail2;
335 		if (dcont == 0)
336 			break;
337 
338 		/*
339 		 * Skip the RV keyword. It should be present in both the static
340 		 * and dynamic cfg sectors.
341 		 */
342 		if (dtag == EFX_VPD_RO && dkey == EFX_VPD_KEYWORD('R', 'V'))
343 			continue;
344 
345 		scont = 0;
346 		_NOTE(CONSTANTCONDITION)
347 		while (1) {
348 			if ((rc = efx_vpd_hunk_next(
349 			    enp->en_u.siena.enu_svpd,
350 			    enp->en_u.siena.enu_svpd_length, &stag, &skey,
351 			    NULL, NULL, &scont)) != 0)
352 				goto fail3;
353 			if (scont == 0)
354 				break;
355 
356 			if (stag == dtag && skey == dkey) {
357 				rc = EEXIST;
358 				goto fail4;
359 			}
360 		}
361 	}
362 
363 done:
364 	return (0);
365 
366 fail4:
367 	EFSYS_PROBE(fail4);
368 fail3:
369 	EFSYS_PROBE(fail3);
370 fail2:
371 	EFSYS_PROBE(fail2);
372 fail1:
373 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
374 
375 	return (rc);
376 }
377 
378 	__checkReturn		efx_rc_t
379 siena_vpd_reinit(
380 	__in			efx_nic_t *enp,
381 	__in_bcount(size)	caddr_t data,
382 	__in			size_t size)
383 {
384 	boolean_t wantpid;
385 	efx_rc_t rc;
386 
387 	/*
388 	 * Only create a PID if the dynamic cfg doesn't have one
389 	 */
390 	if (enp->en_u.siena.enu_svpd_length == 0)
391 		wantpid = B_TRUE;
392 	else {
393 		unsigned int offset;
394 		uint8_t length;
395 
396 		rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
397 				    enp->en_u.siena.enu_svpd_length,
398 				    EFX_VPD_ID, 0, &offset, &length);
399 		if (rc == 0)
400 			wantpid = B_FALSE;
401 		else if (rc == ENOENT)
402 			wantpid = B_TRUE;
403 		else
404 			goto fail1;
405 	}
406 
407 	if ((rc = efx_vpd_hunk_reinit(data, size, wantpid)) != 0)
408 		goto fail2;
409 
410 	return (0);
411 
412 fail2:
413 	EFSYS_PROBE(fail2);
414 fail1:
415 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
416 
417 	return (rc);
418 }
419 
420 	__checkReturn		efx_rc_t
421 siena_vpd_get(
422 	__in			efx_nic_t *enp,
423 	__in_bcount(size)	caddr_t data,
424 	__in			size_t size,
425 	__inout			efx_vpd_value_t *evvp)
426 {
427 	unsigned int offset;
428 	uint8_t length;
429 	efx_rc_t rc;
430 
431 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
432 
433 	/* Attempt to satisfy the request from svpd first */
434 	if (enp->en_u.siena.enu_svpd_length > 0) {
435 		if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
436 		    enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
437 		    evvp->evv_keyword, &offset, &length)) == 0) {
438 			evvp->evv_length = length;
439 			memcpy(evvp->evv_value,
440 			    enp->en_u.siena.enu_svpd + offset, length);
441 			return (0);
442 		} else if (rc != ENOENT)
443 			goto fail1;
444 	}
445 
446 	/* And then from the provided data buffer */
447 	if ((rc = efx_vpd_hunk_get(data, size, evvp->evv_tag,
448 	    evvp->evv_keyword, &offset, &length)) != 0) {
449 		if (rc == ENOENT)
450 			return (rc);
451 
452 		goto fail2;
453 	}
454 
455 	evvp->evv_length = length;
456 	memcpy(evvp->evv_value, data + offset, length);
457 
458 	return (0);
459 
460 fail2:
461 	EFSYS_PROBE(fail2);
462 fail1:
463 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
464 
465 	return (rc);
466 }
467 
468 	__checkReturn		efx_rc_t
469 siena_vpd_set(
470 	__in			efx_nic_t *enp,
471 	__in_bcount(size)	caddr_t data,
472 	__in			size_t size,
473 	__in			efx_vpd_value_t *evvp)
474 {
475 	efx_rc_t rc;
476 
477 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
478 
479 	/* If the provided (tag,keyword) exists in svpd, then it is readonly */
480 	if (enp->en_u.siena.enu_svpd_length > 0) {
481 		unsigned int offset;
482 		uint8_t length;
483 
484 		if ((rc = efx_vpd_hunk_get(enp->en_u.siena.enu_svpd,
485 		    enp->en_u.siena.enu_svpd_length, evvp->evv_tag,
486 		    evvp->evv_keyword, &offset, &length)) == 0) {
487 			rc = EACCES;
488 			goto fail1;
489 		}
490 	}
491 
492 	if ((rc = efx_vpd_hunk_set(data, size, evvp)) != 0)
493 		goto fail2;
494 
495 	return (0);
496 
497 fail2:
498 	EFSYS_PROBE(fail2);
499 fail1:
500 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
501 
502 	return (rc);
503 }
504 
505 	__checkReturn		efx_rc_t
506 siena_vpd_next(
507 	__in			efx_nic_t *enp,
508 	__in_bcount(size)	caddr_t data,
509 	__in			size_t size,
510 	__out			efx_vpd_value_t *evvp,
511 	__inout			unsigned int *contp)
512 {
513 	_NOTE(ARGUNUSED(enp, data, size, evvp, contp))
514 
515 	return (ENOTSUP);
516 }
517 
518 	__checkReturn		efx_rc_t
519 siena_vpd_write(
520 	__in			efx_nic_t *enp,
521 	__in_bcount(size)	caddr_t data,
522 	__in			size_t size)
523 {
524 	efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip);
525 	siena_mc_dynamic_config_hdr_t *dcfg = NULL;
526 	unsigned int vpd_offset;
527 	unsigned int dcfg_partn;
528 	unsigned int hdr_length;
529 	unsigned int pos;
530 	uint8_t cksum;
531 	size_t partn_size, dcfg_size;
532 	size_t vpd_length;
533 	efx_rc_t rc;
534 
535 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
536 
537 	/* Determine total length of all tags */
538 	if ((rc = efx_vpd_hunk_length(data, size, &vpd_length)) != 0)
539 		goto fail1;
540 
541 	/* Lock dynamic config sector for write, and read structure only */
542 	dcfg_partn = (emip->emi_port == 1)
543 		? MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT0
544 		: MC_CMD_NVRAM_TYPE_DYNAMIC_CFG_PORT1;
545 
546 	if ((rc = siena_nvram_partn_size(enp, dcfg_partn, &partn_size)) != 0)
547 		goto fail2;
548 
549 	if ((rc = siena_nvram_partn_lock(enp, dcfg_partn)) != 0)
550 		goto fail3;
551 
552 	if ((rc = siena_nvram_get_dynamic_cfg(enp, dcfg_partn,
553 	    B_FALSE, &dcfg, &dcfg_size)) != 0)
554 		goto fail4;
555 
556 	hdr_length = EFX_WORD_FIELD(dcfg->length, EFX_WORD_0);
557 
558 	/* Allocated memory should have room for the new VPD */
559 	if (hdr_length + vpd_length > dcfg_size) {
560 		rc = ENOSPC;
561 		goto fail5;
562 	}
563 
564 	/* Copy in new vpd and update header */
565 	vpd_offset = dcfg_size - vpd_length;
566 	EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_offset, EFX_DWORD_0, vpd_offset);
567 	memcpy((caddr_t)dcfg + vpd_offset, data, vpd_length);
568 	EFX_POPULATE_DWORD_1(dcfg->dynamic_vpd_length, EFX_DWORD_0, vpd_length);
569 
570 	/* Update the checksum */
571 	cksum = 0;
572 	for (pos = 0; pos < hdr_length; pos++)
573 		cksum += ((uint8_t *)dcfg)[pos];
574 	dcfg->csum.eb_u8[0] -= cksum;
575 
576 	/* Erase and write the new sector */
577 	if ((rc = siena_nvram_partn_erase(enp, dcfg_partn, 0, partn_size)) != 0)
578 		goto fail6;
579 
580 	/* Write out the new structure to nvram */
581 	if ((rc = siena_nvram_partn_write(enp, dcfg_partn, 0, (caddr_t)dcfg,
582 	    vpd_offset + vpd_length)) != 0)
583 		goto fail7;
584 
585 	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
586 
587 	siena_nvram_partn_unlock(enp, dcfg_partn, NULL);
588 
589 	return (0);
590 
591 fail7:
592 	EFSYS_PROBE(fail7);
593 fail6:
594 	EFSYS_PROBE(fail6);
595 fail5:
596 	EFSYS_PROBE(fail5);
597 
598 	EFSYS_KMEM_FREE(enp->en_esip, dcfg_size, dcfg);
599 fail4:
600 	EFSYS_PROBE(fail4);
601 
602 	siena_nvram_partn_unlock(enp, dcfg_partn, NULL);
603 fail3:
604 	EFSYS_PROBE(fail3);
605 fail2:
606 	EFSYS_PROBE(fail2);
607 fail1:
608 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
609 
610 	return (rc);
611 }
612 
613 				void
614 siena_vpd_fini(
615 	__in			efx_nic_t *enp)
616 {
617 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_SIENA);
618 
619 	if (enp->en_u.siena.enu_svpd_length > 0) {
620 		EFSYS_KMEM_FREE(enp->en_esip, enp->en_u.siena.enu_svpd_length,
621 				enp->en_u.siena.enu_svpd);
622 
623 		enp->en_u.siena.enu_svpd = NULL;
624 		enp->en_u.siena.enu_svpd_length = 0;
625 	}
626 }
627 
628 #endif	/* EFSYS_OPT_SIENA */
629 
630 #endif	/* EFSYS_OPT_VPD */
631