1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
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
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice unmodified, this list of conditions, and the following
12 *    disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include "opt_bus.h"	/* XXX trim includes */
33
34#include <sys/types.h>
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/malloc.h>
38#include <sys/module.h>
39#include <sys/linker.h>
40#include <sys/fcntl.h>
41#include <sys/conf.h>
42#include <sys/kernel.h>
43#include <sys/mman.h>
44#include <sys/proc.h>
45#include <sys/queue.h>
46#include <sys/rwlock.h>
47#include <sys/sglist.h>
48
49#include <vm/vm.h>
50#include <vm/pmap.h>
51#include <vm/vm_extern.h>
52#include <vm/vm_map.h>
53#include <vm/vm_object.h>
54#include <vm/vm_page.h>
55#include <vm/vm_pager.h>
56
57#include <sys/bus.h>
58#include <machine/bus.h>
59#include <sys/rman.h>
60#include <machine/resource.h>
61
62#include <sys/pciio.h>
63#include <dev/pci/pcireg.h>
64#include <dev/pci/pcivar.h>
65
66#include "pcib_if.h"
67#include "pci_if.h"
68
69#ifdef COMPAT_FREEBSD32
70struct pci_conf32 {
71	struct pcisel	pc_sel;		/* domain+bus+slot+function */
72	u_int8_t	pc_hdr;		/* PCI header type */
73	u_int16_t	pc_subvendor;	/* card vendor ID */
74	u_int16_t	pc_subdevice;	/* card device ID, assigned by
75					   card vendor */
76	u_int16_t	pc_vendor;	/* chip vendor ID */
77	u_int16_t	pc_device;	/* chip device ID, assigned by
78					   chip vendor */
79	u_int8_t	pc_class;	/* chip PCI class */
80	u_int8_t	pc_subclass;	/* chip PCI subclass */
81	u_int8_t	pc_progif;	/* chip PCI programming interface */
82	u_int8_t	pc_revid;	/* chip revision ID */
83	char		pd_name[PCI_MAXNAMELEN + 1];  /* device name */
84	u_int32_t	pd_unit;	/* device unit number */
85};
86
87struct pci_match_conf32 {
88	struct pcisel		pc_sel;		/* domain+bus+slot+function */
89	char			pd_name[PCI_MAXNAMELEN + 1];  /* device name */
90	u_int32_t		pd_unit;	/* Unit number */
91	u_int16_t		pc_vendor;	/* PCI Vendor ID */
92	u_int16_t		pc_device;	/* PCI Device ID */
93	u_int8_t		pc_class;	/* PCI class */
94	u_int32_t		flags;		/* Matching expression */
95};
96
97struct pci_conf_io32 {
98	u_int32_t		pat_buf_len;	/* pattern buffer length */
99	u_int32_t		num_patterns;	/* number of patterns */
100	u_int32_t		patterns;	/* struct pci_match_conf ptr */
101	u_int32_t		match_buf_len;	/* match buffer length */
102	u_int32_t		num_matches;	/* number of matches returned */
103	u_int32_t		matches;	/* struct pci_conf ptr */
104	u_int32_t		offset;		/* offset into device list */
105	u_int32_t		generation;	/* device list generation */
106	u_int32_t		status;		/* request status */
107};
108
109#define	PCIOCGETCONF32	_IOC_NEWTYPE(PCIOCGETCONF, struct pci_conf_io32)
110#endif
111
112/*
113 * This is the user interface to PCI configuration space.
114 */
115
116static d_open_t 	pci_open;
117static d_close_t	pci_close;
118static d_ioctl_t	pci_ioctl;
119
120struct cdevsw pcicdev = {
121	.d_version =	D_VERSION,
122	.d_flags =	D_NEEDGIANT,
123	.d_open =	pci_open,
124	.d_close =	pci_close,
125	.d_ioctl =	pci_ioctl,
126	.d_name =	"pci",
127};
128
129static int
130pci_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
131{
132	int error;
133
134	if (oflags & FWRITE) {
135		error = securelevel_gt(td->td_ucred, 0);
136		if (error)
137			return (error);
138	}
139
140	return (0);
141}
142
143static int
144pci_close(struct cdev *dev, int flag, int devtype, struct thread *td)
145{
146	return 0;
147}
148
149/*
150 * Match a single pci_conf structure against an array of pci_match_conf
151 * structures.  The first argument, 'matches', is an array of num_matches
152 * pci_match_conf structures.  match_buf is a pointer to the pci_conf
153 * structure that will be compared to every entry in the matches array.
154 * This function returns 1 on failure, 0 on success.
155 */
156static int
157pci_conf_match_native(struct pci_match_conf *matches, int num_matches,
158	       struct pci_conf *match_buf)
159{
160	int i;
161
162	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
163		return(1);
164
165	for (i = 0; i < num_matches; i++) {
166		/*
167		 * I'm not sure why someone would do this...but...
168		 */
169		if (matches[i].flags == PCI_GETCONF_NO_MATCH)
170			continue;
171
172		/*
173		 * Look at each of the match flags.  If it's set, do the
174		 * comparison.  If the comparison fails, we don't have a
175		 * match, go on to the next item if there is one.
176		 */
177		if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
178		 && (match_buf->pc_sel.pc_domain !=
179		 matches[i].pc_sel.pc_domain))
180			continue;
181
182		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
183		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
184			continue;
185
186		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
187		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
188			continue;
189
190		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
191		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
192			continue;
193
194		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0)
195		 && (match_buf->pc_vendor != matches[i].pc_vendor))
196			continue;
197
198		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
199		 && (match_buf->pc_device != matches[i].pc_device))
200			continue;
201
202		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
203		 && (match_buf->pc_class != matches[i].pc_class))
204			continue;
205
206		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
207		 && (match_buf->pd_unit != matches[i].pd_unit))
208			continue;
209
210		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
211		 && (strncmp(matches[i].pd_name, match_buf->pd_name,
212			     sizeof(match_buf->pd_name)) != 0))
213			continue;
214
215		return(0);
216	}
217
218	return(1);
219}
220
221#ifdef COMPAT_FREEBSD32
222static int
223pci_conf_match32(struct pci_match_conf32 *matches, int num_matches,
224	       struct pci_conf *match_buf)
225{
226	int i;
227
228	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
229		return(1);
230
231	for (i = 0; i < num_matches; i++) {
232		/*
233		 * I'm not sure why someone would do this...but...
234		 */
235		if (matches[i].flags == PCI_GETCONF_NO_MATCH)
236			continue;
237
238		/*
239		 * Look at each of the match flags.  If it's set, do the
240		 * comparison.  If the comparison fails, we don't have a
241		 * match, go on to the next item if there is one.
242		 */
243		if (((matches[i].flags & PCI_GETCONF_MATCH_DOMAIN) != 0)
244		 && (match_buf->pc_sel.pc_domain !=
245		 matches[i].pc_sel.pc_domain))
246			continue;
247
248		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS) != 0)
249		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
250			continue;
251
252		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV) != 0)
253		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
254			continue;
255
256		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC) != 0)
257		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
258			continue;
259
260		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR) != 0)
261		 && (match_buf->pc_vendor != matches[i].pc_vendor))
262			continue;
263
264		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE) != 0)
265		 && (match_buf->pc_device != matches[i].pc_device))
266			continue;
267
268		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS) != 0)
269		 && (match_buf->pc_class != matches[i].pc_class))
270			continue;
271
272		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT) != 0)
273		 && (match_buf->pd_unit != matches[i].pd_unit))
274			continue;
275
276		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME) != 0)
277		 && (strncmp(matches[i].pd_name, match_buf->pd_name,
278			     sizeof(match_buf->pd_name)) != 0))
279			continue;
280
281		return(0);
282	}
283
284	return(1);
285}
286#endif	/* COMPAT_FREEBSD32 */
287
288#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
289    defined(COMPAT_FREEBSD6)
290#define PRE7_COMPAT
291
292typedef enum {
293	PCI_GETCONF_NO_MATCH_OLD	= 0x00,
294	PCI_GETCONF_MATCH_BUS_OLD	= 0x01,
295	PCI_GETCONF_MATCH_DEV_OLD	= 0x02,
296	PCI_GETCONF_MATCH_FUNC_OLD	= 0x04,
297	PCI_GETCONF_MATCH_NAME_OLD	= 0x08,
298	PCI_GETCONF_MATCH_UNIT_OLD	= 0x10,
299	PCI_GETCONF_MATCH_VENDOR_OLD	= 0x20,
300	PCI_GETCONF_MATCH_DEVICE_OLD	= 0x40,
301	PCI_GETCONF_MATCH_CLASS_OLD	= 0x80
302} pci_getconf_flags_old;
303
304struct pcisel_old {
305	u_int8_t	pc_bus;		/* bus number */
306	u_int8_t	pc_dev;		/* device on this bus */
307	u_int8_t	pc_func;	/* function on this device */
308};
309
310struct pci_conf_old {
311	struct pcisel_old pc_sel;	/* bus+slot+function */
312	u_int8_t	pc_hdr;		/* PCI header type */
313	u_int16_t	pc_subvendor;	/* card vendor ID */
314	u_int16_t	pc_subdevice;	/* card device ID, assigned by
315					   card vendor */
316	u_int16_t	pc_vendor;	/* chip vendor ID */
317	u_int16_t	pc_device;	/* chip device ID, assigned by
318					   chip vendor */
319	u_int8_t	pc_class;	/* chip PCI class */
320	u_int8_t	pc_subclass;	/* chip PCI subclass */
321	u_int8_t	pc_progif;	/* chip PCI programming interface */
322	u_int8_t	pc_revid;	/* chip revision ID */
323	char		pd_name[PCI_MAXNAMELEN + 1];  /* device name */
324	u_long		pd_unit;	/* device unit number */
325};
326
327struct pci_match_conf_old {
328	struct pcisel_old	pc_sel;		/* bus+slot+function */
329	char			pd_name[PCI_MAXNAMELEN + 1];  /* device name */
330	u_long			pd_unit;	/* Unit number */
331	u_int16_t		pc_vendor;	/* PCI Vendor ID */
332	u_int16_t		pc_device;	/* PCI Device ID */
333	u_int8_t		pc_class;	/* PCI class */
334	pci_getconf_flags_old	flags;		/* Matching expression */
335};
336
337struct pci_io_old {
338	struct pcisel_old pi_sel;	/* device to operate on */
339	int		pi_reg;		/* configuration register to examine */
340	int		pi_width;	/* width (in bytes) of read or write */
341	u_int32_t	pi_data;	/* data to write or result of read */
342};
343
344#ifdef COMPAT_FREEBSD32
345struct pci_conf_old32 {
346	struct pcisel_old pc_sel;	/* bus+slot+function */
347	uint8_t		pc_hdr;		/* PCI header type */
348	uint16_t	pc_subvendor;	/* card vendor ID */
349	uint16_t	pc_subdevice;	/* card device ID, assigned by
350					   card vendor */
351	uint16_t	pc_vendor;	/* chip vendor ID */
352	uint16_t	pc_device;	/* chip device ID, assigned by
353					   chip vendor */
354	uint8_t		pc_class;	/* chip PCI class */
355	uint8_t		pc_subclass;	/* chip PCI subclass */
356	uint8_t		pc_progif;	/* chip PCI programming interface */
357	uint8_t		pc_revid;	/* chip revision ID */
358	char		pd_name[PCI_MAXNAMELEN + 1]; /* device name */
359	uint32_t	pd_unit;	/* device unit number (u_long) */
360};
361
362struct pci_match_conf_old32 {
363	struct pcisel_old pc_sel;	/* bus+slot+function */
364	char		pd_name[PCI_MAXNAMELEN + 1]; /* device name */
365	uint32_t	pd_unit;	/* Unit number (u_long) */
366	uint16_t	pc_vendor;	/* PCI Vendor ID */
367	uint16_t	pc_device;	/* PCI Device ID */
368	uint8_t		pc_class;	/* PCI class */
369	pci_getconf_flags_old flags;	/* Matching expression */
370};
371
372#define	PCIOCGETCONF_OLD32	_IOWR('p', 1, struct pci_conf_io32)
373#endif	/* COMPAT_FREEBSD32 */
374
375#define	PCIOCGETCONF_OLD	_IOWR('p', 1, struct pci_conf_io)
376#define	PCIOCREAD_OLD		_IOWR('p', 2, struct pci_io_old)
377#define	PCIOCWRITE_OLD		_IOWR('p', 3, struct pci_io_old)
378
379static int
380pci_conf_match_old(struct pci_match_conf_old *matches, int num_matches,
381    struct pci_conf *match_buf)
382{
383	int i;
384
385	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
386		return(1);
387
388	for (i = 0; i < num_matches; i++) {
389		if (match_buf->pc_sel.pc_domain != 0)
390			continue;
391
392		/*
393		 * I'm not sure why someone would do this...but...
394		 */
395		if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
396			continue;
397
398		/*
399		 * Look at each of the match flags.  If it's set, do the
400		 * comparison.  If the comparison fails, we don't have a
401		 * match, go on to the next item if there is one.
402		 */
403		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0)
404		 && (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
405			continue;
406
407		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0)
408		 && (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
409			continue;
410
411		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0)
412		 && (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
413			continue;
414
415		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0)
416		 && (match_buf->pc_vendor != matches[i].pc_vendor))
417			continue;
418
419		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0)
420		 && (match_buf->pc_device != matches[i].pc_device))
421			continue;
422
423		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0)
424		 && (match_buf->pc_class != matches[i].pc_class))
425			continue;
426
427		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0)
428		 && (match_buf->pd_unit != matches[i].pd_unit))
429			continue;
430
431		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0)
432		 && (strncmp(matches[i].pd_name, match_buf->pd_name,
433			     sizeof(match_buf->pd_name)) != 0))
434			continue;
435
436		return(0);
437	}
438
439	return(1);
440}
441
442#ifdef COMPAT_FREEBSD32
443static int
444pci_conf_match_old32(struct pci_match_conf_old32 *matches, int num_matches,
445    struct pci_conf *match_buf)
446{
447	int i;
448
449	if ((matches == NULL) || (match_buf == NULL) || (num_matches <= 0))
450		return(1);
451
452	for (i = 0; i < num_matches; i++) {
453		if (match_buf->pc_sel.pc_domain != 0)
454			continue;
455
456		/*
457		 * I'm not sure why someone would do this...but...
458		 */
459		if (matches[i].flags == PCI_GETCONF_NO_MATCH_OLD)
460			continue;
461
462		/*
463		 * Look at each of the match flags.  If it's set, do the
464		 * comparison.  If the comparison fails, we don't have a
465		 * match, go on to the next item if there is one.
466		 */
467		if (((matches[i].flags & PCI_GETCONF_MATCH_BUS_OLD) != 0) &&
468		    (match_buf->pc_sel.pc_bus != matches[i].pc_sel.pc_bus))
469			continue;
470
471		if (((matches[i].flags & PCI_GETCONF_MATCH_DEV_OLD) != 0) &&
472		    (match_buf->pc_sel.pc_dev != matches[i].pc_sel.pc_dev))
473			continue;
474
475		if (((matches[i].flags & PCI_GETCONF_MATCH_FUNC_OLD) != 0) &&
476		    (match_buf->pc_sel.pc_func != matches[i].pc_sel.pc_func))
477			continue;
478
479		if (((matches[i].flags & PCI_GETCONF_MATCH_VENDOR_OLD) != 0) &&
480		    (match_buf->pc_vendor != matches[i].pc_vendor))
481			continue;
482
483		if (((matches[i].flags & PCI_GETCONF_MATCH_DEVICE_OLD) != 0) &&
484		    (match_buf->pc_device != matches[i].pc_device))
485			continue;
486
487		if (((matches[i].flags & PCI_GETCONF_MATCH_CLASS_OLD) != 0) &&
488		    (match_buf->pc_class != matches[i].pc_class))
489			continue;
490
491		if (((matches[i].flags & PCI_GETCONF_MATCH_UNIT_OLD) != 0) &&
492		    ((u_int32_t)match_buf->pd_unit != matches[i].pd_unit))
493			continue;
494
495		if (((matches[i].flags & PCI_GETCONF_MATCH_NAME_OLD) != 0) &&
496		    (strncmp(matches[i].pd_name, match_buf->pd_name,
497		    sizeof(match_buf->pd_name)) != 0))
498			continue;
499
500		return (0);
501	}
502
503	return (1);
504}
505#endif	/* COMPAT_FREEBSD32 */
506#endif	/* !PRE7_COMPAT */
507
508union pci_conf_union {
509	struct pci_conf		pc;
510#ifdef COMPAT_FREEBSD32
511	struct pci_conf32	pc32;
512#endif
513#ifdef PRE7_COMPAT
514	struct pci_conf_old	pco;
515#ifdef COMPAT_FREEBSD32
516	struct pci_conf_old32	pco32;
517#endif
518#endif
519};
520
521static int
522pci_conf_match(u_long cmd, struct pci_match_conf *matches, int num_matches,
523    struct pci_conf *match_buf)
524{
525
526	switch (cmd) {
527	case PCIOCGETCONF:
528		return (pci_conf_match_native(
529		    (struct pci_match_conf *)matches, num_matches, match_buf));
530#ifdef COMPAT_FREEBSD32
531	case PCIOCGETCONF32:
532		return (pci_conf_match32((struct pci_match_conf32 *)matches,
533		    num_matches, match_buf));
534#endif
535#ifdef PRE7_COMPAT
536	case PCIOCGETCONF_OLD:
537		return (pci_conf_match_old(
538		    (struct pci_match_conf_old *)matches, num_matches,
539		    match_buf));
540#ifdef COMPAT_FREEBSD32
541	case PCIOCGETCONF_OLD32:
542		return (pci_conf_match_old32(
543		    (struct pci_match_conf_old32 *)matches, num_matches,
544		    match_buf));
545#endif
546#endif
547	default:
548		/* programmer error */
549		return (0);
550	}
551}
552
553/*
554 * Like PVE_NEXT but takes an explicit length since 'pve' is a user
555 * pointer that cannot be dereferenced.
556 */
557#define	PVE_NEXT_LEN(pve, datalen)					\
558	((struct pci_vpd_element *)((char *)(pve) +			\
559	    sizeof(struct pci_vpd_element) + (datalen)))
560
561static int
562pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
563{
564	struct pci_vpd_element vpd_element, *vpd_user;
565	struct pcicfg_vpd *vpd;
566	size_t len;
567	int error, i;
568
569	vpd = pci_fetch_vpd_list(dev);
570	if (vpd->vpd_reg == 0 || vpd->vpd_ident == NULL)
571		return (ENXIO);
572
573	/*
574	 * Calculate the amount of space needed in the data buffer.  An
575	 * identifier element is always present followed by the read-only
576	 * and read-write keywords.
577	 */
578	len = sizeof(struct pci_vpd_element) + strlen(vpd->vpd_ident);
579	for (i = 0; i < vpd->vpd_rocnt; i++)
580		len += sizeof(struct pci_vpd_element) + vpd->vpd_ros[i].len;
581	for (i = 0; i < vpd->vpd_wcnt; i++)
582		len += sizeof(struct pci_vpd_element) + vpd->vpd_w[i].len;
583
584	if (lvio->plvi_len == 0) {
585		lvio->plvi_len = len;
586		return (0);
587	}
588	if (lvio->plvi_len < len) {
589		lvio->plvi_len = len;
590		return (ENOMEM);
591	}
592
593	/*
594	 * Copyout the identifier string followed by each keyword and
595	 * value.
596	 */
597	vpd_user = lvio->plvi_data;
598	vpd_element.pve_keyword[0] = '\0';
599	vpd_element.pve_keyword[1] = '\0';
600	vpd_element.pve_flags = PVE_FLAG_IDENT;
601	vpd_element.pve_datalen = strlen(vpd->vpd_ident);
602	error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
603	if (error)
604		return (error);
605	error = copyout(vpd->vpd_ident, vpd_user->pve_data,
606	    strlen(vpd->vpd_ident));
607	if (error)
608		return (error);
609	vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
610	vpd_element.pve_flags = 0;
611	for (i = 0; i < vpd->vpd_rocnt; i++) {
612		vpd_element.pve_keyword[0] = vpd->vpd_ros[i].keyword[0];
613		vpd_element.pve_keyword[1] = vpd->vpd_ros[i].keyword[1];
614		vpd_element.pve_datalen = vpd->vpd_ros[i].len;
615		error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
616		if (error)
617			return (error);
618		error = copyout(vpd->vpd_ros[i].value, vpd_user->pve_data,
619		    vpd->vpd_ros[i].len);
620		if (error)
621			return (error);
622		vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
623	}
624	vpd_element.pve_flags = PVE_FLAG_RW;
625	for (i = 0; i < vpd->vpd_wcnt; i++) {
626		vpd_element.pve_keyword[0] = vpd->vpd_w[i].keyword[0];
627		vpd_element.pve_keyword[1] = vpd->vpd_w[i].keyword[1];
628		vpd_element.pve_datalen = vpd->vpd_w[i].len;
629		error = copyout(&vpd_element, vpd_user, sizeof(vpd_element));
630		if (error)
631			return (error);
632		error = copyout(vpd->vpd_w[i].value, vpd_user->pve_data,
633		    vpd->vpd_w[i].len);
634		if (error)
635			return (error);
636		vpd_user = PVE_NEXT_LEN(vpd_user, vpd_element.pve_datalen);
637	}
638	KASSERT((char *)vpd_user - (char *)lvio->plvi_data == len,
639	    ("length mismatch"));
640	lvio->plvi_len = len;
641	return (0);
642}
643
644static size_t
645pci_match_conf_size(u_long cmd)
646{
647
648	switch (cmd) {
649	case PCIOCGETCONF:
650		return (sizeof(struct pci_match_conf));
651#ifdef COMPAT_FREEBSD32
652	case PCIOCGETCONF32:
653		return (sizeof(struct pci_match_conf32));
654#endif
655#ifdef PRE7_COMPAT
656	case PCIOCGETCONF_OLD:
657		return (sizeof(struct pci_match_conf_old));
658#ifdef COMPAT_FREEBSD32
659	case PCIOCGETCONF_OLD32:
660		return (sizeof(struct pci_match_conf_old32));
661#endif
662#endif
663	default:
664		/* programmer error */
665		return (0);
666	}
667}
668
669static size_t
670pci_conf_size(u_long cmd)
671{
672
673	switch (cmd) {
674	case PCIOCGETCONF:
675		return (sizeof(struct pci_conf));
676#ifdef COMPAT_FREEBSD32
677	case PCIOCGETCONF32:
678		return (sizeof(struct pci_conf32));
679#endif
680#ifdef PRE7_COMPAT
681	case PCIOCGETCONF_OLD:
682		return (sizeof(struct pci_conf_old));
683#ifdef COMPAT_FREEBSD32
684	case PCIOCGETCONF_OLD32:
685		return (sizeof(struct pci_conf_old32));
686#endif
687#endif
688	default:
689		/* programmer error */
690		return (0);
691	}
692}
693
694static void
695pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd)
696{
697#if defined(COMPAT_FREEBSD32)
698	struct pci_conf_io32 *cio32;
699#endif
700
701	switch (cmd) {
702	case PCIOCGETCONF:
703#ifdef PRE7_COMPAT
704	case PCIOCGETCONF_OLD:
705#endif
706		*cio = *(struct pci_conf_io *)data;
707		return;
708
709#ifdef COMPAT_FREEBSD32
710	case PCIOCGETCONF32:
711#ifdef PRE7_COMPAT
712	case PCIOCGETCONF_OLD32:
713#endif
714               cio32 = (struct pci_conf_io32 *)data;
715               cio->pat_buf_len = cio32->pat_buf_len;
716               cio->num_patterns = cio32->num_patterns;
717               cio->patterns = (void *)(uintptr_t)cio32->patterns;
718               cio->match_buf_len = cio32->match_buf_len;
719               cio->num_matches = cio32->num_matches;
720               cio->matches = (void *)(uintptr_t)cio32->matches;
721               cio->offset = cio32->offset;
722               cio->generation = cio32->generation;
723               cio->status = cio32->status;
724               return;
725#endif
726
727	default:
728		/* programmer error */
729		return;
730	}
731}
732
733static void
734pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data,
735    u_long cmd)
736{
737	struct pci_conf_io *d_cio;
738#if defined(COMPAT_FREEBSD32)
739	struct pci_conf_io32 *cio32;
740#endif
741
742	switch (cmd) {
743	case PCIOCGETCONF:
744#ifdef PRE7_COMPAT
745	case PCIOCGETCONF_OLD:
746#endif
747		d_cio = (struct pci_conf_io *)data;
748		d_cio->status = cio->status;
749		d_cio->generation = cio->generation;
750		d_cio->offset = cio->offset;
751		d_cio->num_matches = cio->num_matches;
752		return;
753
754#ifdef COMPAT_FREEBSD32
755	case PCIOCGETCONF32:
756#ifdef PRE7_COMPAT
757	case PCIOCGETCONF_OLD32:
758#endif
759		cio32 = (struct pci_conf_io32 *)data;
760
761		cio32->status = cio->status;
762		cio32->generation = cio->generation;
763		cio32->offset = cio->offset;
764		cio32->num_matches = cio->num_matches;
765		return;
766#endif
767
768	default:
769		/* programmer error */
770		return;
771	}
772}
773
774static void
775pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup,
776    u_long cmd)
777{
778
779	memset(pcup, 0, sizeof(*pcup));
780
781	switch (cmd) {
782	case PCIOCGETCONF:
783		pcup->pc = *pcp;
784		return;
785
786#ifdef COMPAT_FREEBSD32
787	case PCIOCGETCONF32:
788		pcup->pc32.pc_sel = pcp->pc_sel;
789		pcup->pc32.pc_hdr = pcp->pc_hdr;
790		pcup->pc32.pc_subvendor = pcp->pc_subvendor;
791		pcup->pc32.pc_subdevice = pcp->pc_subdevice;
792		pcup->pc32.pc_vendor = pcp->pc_vendor;
793		pcup->pc32.pc_device = pcp->pc_device;
794		pcup->pc32.pc_class = pcp->pc_class;
795		pcup->pc32.pc_subclass = pcp->pc_subclass;
796		pcup->pc32.pc_progif = pcp->pc_progif;
797		pcup->pc32.pc_revid = pcp->pc_revid;
798		strlcpy(pcup->pc32.pd_name, pcp->pd_name,
799		    sizeof(pcup->pc32.pd_name));
800		pcup->pc32.pd_unit = (uint32_t)pcp->pd_unit;
801		return;
802#endif
803
804#ifdef PRE7_COMPAT
805#ifdef COMPAT_FREEBSD32
806	case PCIOCGETCONF_OLD32:
807		pcup->pco32.pc_sel.pc_bus = pcp->pc_sel.pc_bus;
808		pcup->pco32.pc_sel.pc_dev = pcp->pc_sel.pc_dev;
809		pcup->pco32.pc_sel.pc_func = pcp->pc_sel.pc_func;
810		pcup->pco32.pc_hdr = pcp->pc_hdr;
811		pcup->pco32.pc_subvendor = pcp->pc_subvendor;
812		pcup->pco32.pc_subdevice = pcp->pc_subdevice;
813		pcup->pco32.pc_vendor = pcp->pc_vendor;
814		pcup->pco32.pc_device = pcp->pc_device;
815		pcup->pco32.pc_class = pcp->pc_class;
816		pcup->pco32.pc_subclass = pcp->pc_subclass;
817		pcup->pco32.pc_progif = pcp->pc_progif;
818		pcup->pco32.pc_revid = pcp->pc_revid;
819		strlcpy(pcup->pco32.pd_name, pcp->pd_name,
820		    sizeof(pcup->pco32.pd_name));
821		pcup->pco32.pd_unit = (uint32_t)pcp->pd_unit;
822		return;
823
824#endif /* COMPAT_FREEBSD32 */
825	case PCIOCGETCONF_OLD:
826		pcup->pco.pc_sel.pc_bus = pcp->pc_sel.pc_bus;
827		pcup->pco.pc_sel.pc_dev = pcp->pc_sel.pc_dev;
828		pcup->pco.pc_sel.pc_func = pcp->pc_sel.pc_func;
829		pcup->pco.pc_hdr = pcp->pc_hdr;
830		pcup->pco.pc_subvendor = pcp->pc_subvendor;
831		pcup->pco.pc_subdevice = pcp->pc_subdevice;
832		pcup->pco.pc_vendor = pcp->pc_vendor;
833		pcup->pco.pc_device = pcp->pc_device;
834		pcup->pco.pc_class = pcp->pc_class;
835		pcup->pco.pc_subclass = pcp->pc_subclass;
836		pcup->pco.pc_progif = pcp->pc_progif;
837		pcup->pco.pc_revid = pcp->pc_revid;
838		strlcpy(pcup->pco.pd_name, pcp->pd_name,
839		    sizeof(pcup->pco.pd_name));
840		pcup->pco.pd_unit = pcp->pd_unit;
841		return;
842#endif /* PRE7_COMPAT */
843
844	default:
845		/* programmer error */
846		return;
847	}
848}
849
850static int
851pci_bar_mmap(device_t pcidev, struct pci_bar_mmap *pbm)
852{
853	vm_map_t map;
854	vm_object_t obj;
855	struct thread *td;
856	struct sglist *sg;
857	struct pci_map *pm;
858	vm_paddr_t membase;
859	vm_paddr_t pbase;
860	vm_size_t plen;
861	vm_offset_t addr;
862	vm_prot_t prot;
863	int error, flags;
864
865	td = curthread;
866	map = &td->td_proc->p_vmspace->vm_map;
867	if ((pbm->pbm_flags & ~(PCIIO_BAR_MMAP_FIXED | PCIIO_BAR_MMAP_EXCL |
868	    PCIIO_BAR_MMAP_RW | PCIIO_BAR_MMAP_ACTIVATE)) != 0 ||
869	    pbm->pbm_memattr != (vm_memattr_t)pbm->pbm_memattr ||
870	    !pmap_is_valid_memattr(map->pmap, pbm->pbm_memattr))
871		return (EINVAL);
872
873	/* Fetch the BAR physical base and length. */
874	pm = pci_find_bar(pcidev, pbm->pbm_reg);
875	if (pm == NULL)
876		return (EINVAL);
877	if (!pci_bar_enabled(pcidev, pm))
878		return (EBUSY); /* XXXKIB enable if _ACTIVATE */
879	if (!PCI_BAR_MEM(pm->pm_value))
880		return (EIO);
881	membase = pm->pm_value & PCIM_BAR_MEM_BASE;
882	pbase = trunc_page(membase);
883	plen = round_page(membase + ((pci_addr_t)1 << pm->pm_size)) -
884	    pbase;
885	prot = VM_PROT_READ | (((pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0) ?
886	    VM_PROT_WRITE : 0);
887
888	/* Create vm structures and mmap. */
889	sg = sglist_alloc(1, M_WAITOK);
890	error = sglist_append_phys(sg, pbase, plen);
891	if (error != 0)
892		goto out;
893	obj = vm_pager_allocate(OBJT_SG, sg, plen, prot, 0, td->td_ucred);
894	if (obj == NULL) {
895		error = EIO;
896		goto out;
897	}
898	obj->memattr = pbm->pbm_memattr;
899	flags = MAP_SHARED;
900	addr = 0;
901	if ((pbm->pbm_flags & PCIIO_BAR_MMAP_FIXED) != 0) {
902		addr = (uintptr_t)pbm->pbm_map_base;
903		flags |= MAP_FIXED;
904	}
905	if ((pbm->pbm_flags & PCIIO_BAR_MMAP_EXCL) != 0)
906		flags |= MAP_CHECK_EXCL;
907	error = vm_mmap_object(map, &addr, plen, prot, prot, flags, obj, 0,
908	    FALSE, td);
909	if (error != 0) {
910		vm_object_deallocate(obj);
911		goto out;
912	}
913	pbm->pbm_map_base = (void *)addr;
914	pbm->pbm_map_length = plen;
915	pbm->pbm_bar_off = membase - pbase;
916	pbm->pbm_bar_length = (pci_addr_t)1 << pm->pm_size;
917
918out:
919	sglist_free(sg);
920	return (error);
921}
922
923static int
924pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
925{
926	device_t pcidev;
927	const char *name;
928	struct devlist *devlist_head;
929	struct pci_conf_io *cio = NULL;
930	struct pci_devinfo *dinfo;
931	struct pci_io *io;
932	struct pci_bar_io *bio;
933	struct pci_list_vpd_io *lvio;
934	struct pci_match_conf *pattern_buf;
935	struct pci_map *pm;
936	struct pci_bar_mmap *pbm;
937	size_t confsz, iolen;
938	int error, ionum, i, num_patterns;
939	union pci_conf_union pcu;
940#ifdef PRE7_COMPAT
941	struct pci_io iodata;
942	struct pci_io_old *io_old;
943
944	io_old = NULL;
945#endif
946
947	if (!(flag & FWRITE)) {
948		switch (cmd) {
949		case PCIOCGETCONF:
950#ifdef COMPAT_FREEBSD32
951		case PCIOCGETCONF32:
952#endif
953#ifdef PRE7_COMPAT
954		case PCIOCGETCONF_OLD:
955#ifdef COMPAT_FREEBSD32
956		case PCIOCGETCONF_OLD32:
957#endif
958#endif
959		case PCIOCGETBAR:
960		case PCIOCLISTVPD:
961			break;
962		default:
963			return (EPERM);
964		}
965	}
966
967
968	switch (cmd) {
969	case PCIOCGETCONF:
970#ifdef COMPAT_FREEBSD32
971	case PCIOCGETCONF32:
972#endif
973#ifdef PRE7_COMPAT
974	case PCIOCGETCONF_OLD:
975#ifdef COMPAT_FREEBSD32
976	case PCIOCGETCONF_OLD32:
977#endif
978#endif
979		cio = malloc(sizeof(struct pci_conf_io), M_TEMP,
980		    M_WAITOK | M_ZERO);
981		pci_conf_io_init(cio, data, cmd);
982		pattern_buf = NULL;
983		num_patterns = 0;
984		dinfo = NULL;
985
986		cio->num_matches = 0;
987
988		/*
989		 * If the user specified an offset into the device list,
990		 * but the list has changed since they last called this
991		 * ioctl, tell them that the list has changed.  They will
992		 * have to get the list from the beginning.
993		 */
994		if ((cio->offset != 0)
995		 && (cio->generation != pci_generation)){
996			cio->status = PCI_GETCONF_LIST_CHANGED;
997			error = 0;
998			goto getconfexit;
999		}
1000
1001		/*
1002		 * Check to see whether the user has asked for an offset
1003		 * past the end of our list.
1004		 */
1005		if (cio->offset >= pci_numdevs) {
1006			cio->status = PCI_GETCONF_LAST_DEVICE;
1007			error = 0;
1008			goto getconfexit;
1009		}
1010
1011		/* get the head of the device queue */
1012		devlist_head = &pci_devq;
1013
1014		/*
1015		 * Determine how much room we have for pci_conf structures.
1016		 * Round the user's buffer size down to the nearest
1017		 * multiple of sizeof(struct pci_conf) in case the user
1018		 * didn't specify a multiple of that size.
1019		 */
1020		confsz = pci_conf_size(cmd);
1021		iolen = min(cio->match_buf_len - (cio->match_buf_len % confsz),
1022		    pci_numdevs * confsz);
1023
1024		/*
1025		 * Since we know that iolen is a multiple of the size of
1026		 * the pciconf union, it's okay to do this.
1027		 */
1028		ionum = iolen / confsz;
1029
1030		/*
1031		 * If this test is true, the user wants the pci_conf
1032		 * structures returned to match the supplied entries.
1033		 */
1034		if ((cio->num_patterns > 0) && (cio->num_patterns < pci_numdevs)
1035		 && (cio->pat_buf_len > 0)) {
1036			/*
1037			 * pat_buf_len needs to be:
1038			 * num_patterns * sizeof(struct pci_match_conf)
1039			 * While it is certainly possible the user just
1040			 * allocated a large buffer, but set the number of
1041			 * matches correctly, it is far more likely that
1042			 * their kernel doesn't match the userland utility
1043			 * they're using.  It's also possible that the user
1044			 * forgot to initialize some variables.  Yes, this
1045			 * may be overly picky, but I hazard to guess that
1046			 * it's far more likely to just catch folks that
1047			 * updated their kernel but not their userland.
1048			 */
1049			if (cio->num_patterns * pci_match_conf_size(cmd) !=
1050			    cio->pat_buf_len) {
1051				/* The user made a mistake, return an error. */
1052				cio->status = PCI_GETCONF_ERROR;
1053				error = EINVAL;
1054				goto getconfexit;
1055			}
1056
1057			/*
1058			 * Allocate a buffer to hold the patterns.
1059			 */
1060			pattern_buf = malloc(cio->pat_buf_len, M_TEMP,
1061			    M_WAITOK);
1062			error = copyin(cio->patterns, pattern_buf,
1063			    cio->pat_buf_len);
1064			if (error != 0) {
1065				error = EINVAL;
1066				goto getconfexit;
1067			}
1068			num_patterns = cio->num_patterns;
1069		} else if ((cio->num_patterns > 0)
1070			|| (cio->pat_buf_len > 0)) {
1071			/*
1072			 * The user made a mistake, spit out an error.
1073			 */
1074			cio->status = PCI_GETCONF_ERROR;
1075			error = EINVAL;
1076                       goto getconfexit;
1077		}
1078
1079		/*
1080		 * Go through the list of devices and copy out the devices
1081		 * that match the user's criteria.
1082		 */
1083		for (cio->num_matches = 0, i = 0,
1084				 dinfo = STAILQ_FIRST(devlist_head);
1085		     dinfo != NULL;
1086		     dinfo = STAILQ_NEXT(dinfo, pci_links), i++) {
1087
1088			if (i < cio->offset)
1089				continue;
1090
1091			/* Populate pd_name and pd_unit */
1092			name = NULL;
1093			if (dinfo->cfg.dev)
1094				name = device_get_name(dinfo->cfg.dev);
1095			if (name) {
1096				strncpy(dinfo->conf.pd_name, name,
1097					sizeof(dinfo->conf.pd_name));
1098				dinfo->conf.pd_name[PCI_MAXNAMELEN] = 0;
1099				dinfo->conf.pd_unit =
1100					device_get_unit(dinfo->cfg.dev);
1101			} else {
1102				dinfo->conf.pd_name[0] = '\0';
1103				dinfo->conf.pd_unit = 0;
1104			}
1105
1106			if (pattern_buf == NULL ||
1107			    pci_conf_match(cmd, pattern_buf, num_patterns,
1108			    &dinfo->conf) == 0) {
1109				/*
1110				 * If we've filled up the user's buffer,
1111				 * break out at this point.  Since we've
1112				 * got a match here, we'll pick right back
1113				 * up at the matching entry.  We can also
1114				 * tell the user that there are more matches
1115				 * left.
1116				 */
1117				if (cio->num_matches >= ionum) {
1118					error = 0;
1119					break;
1120				}
1121
1122				pci_conf_for_copyout(&dinfo->conf, &pcu, cmd);
1123				error = copyout(&pcu,
1124				    (caddr_t)cio->matches +
1125				    confsz * cio->num_matches, confsz);
1126				if (error)
1127					break;
1128				cio->num_matches++;
1129			}
1130		}
1131
1132		/*
1133		 * Set the pointer into the list, so if the user is getting
1134		 * n records at a time, where n < pci_numdevs,
1135		 */
1136		cio->offset = i;
1137
1138		/*
1139		 * Set the generation, the user will need this if they make
1140		 * another ioctl call with offset != 0.
1141		 */
1142		cio->generation = pci_generation;
1143
1144		/*
1145		 * If this is the last device, inform the user so he won't
1146		 * bother asking for more devices.  If dinfo isn't NULL, we
1147		 * know that there are more matches in the list because of
1148		 * the way the traversal is done.
1149		 */
1150		if (dinfo == NULL)
1151			cio->status = PCI_GETCONF_LAST_DEVICE;
1152		else
1153			cio->status = PCI_GETCONF_MORE_DEVS;
1154
1155getconfexit:
1156		pci_conf_io_update_data(cio, data, cmd);
1157		free(cio, M_TEMP);
1158		free(pattern_buf, M_TEMP);
1159
1160		break;
1161
1162#ifdef PRE7_COMPAT
1163	case PCIOCREAD_OLD:
1164	case PCIOCWRITE_OLD:
1165		io_old = (struct pci_io_old *)data;
1166		iodata.pi_sel.pc_domain = 0;
1167		iodata.pi_sel.pc_bus = io_old->pi_sel.pc_bus;
1168		iodata.pi_sel.pc_dev = io_old->pi_sel.pc_dev;
1169		iodata.pi_sel.pc_func = io_old->pi_sel.pc_func;
1170		iodata.pi_reg = io_old->pi_reg;
1171		iodata.pi_width = io_old->pi_width;
1172		iodata.pi_data = io_old->pi_data;
1173		data = (caddr_t)&iodata;
1174		/* FALLTHROUGH */
1175#endif
1176	case PCIOCREAD:
1177	case PCIOCWRITE:
1178		io = (struct pci_io *)data;
1179		switch(io->pi_width) {
1180		case 4:
1181		case 2:
1182		case 1:
1183			/* Make sure register is not negative and aligned. */
1184			if (io->pi_reg < 0 ||
1185			    io->pi_reg & (io->pi_width - 1)) {
1186				error = EINVAL;
1187				break;
1188			}
1189			/*
1190			 * Assume that the user-level bus number is
1191			 * in fact the physical PCI bus number.
1192			 * Look up the grandparent, i.e. the bridge device,
1193			 * so that we can issue configuration space cycles.
1194			 */
1195			pcidev = pci_find_dbsf(io->pi_sel.pc_domain,
1196			    io->pi_sel.pc_bus, io->pi_sel.pc_dev,
1197			    io->pi_sel.pc_func);
1198			if (pcidev) {
1199#ifdef PRE7_COMPAT
1200				if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
1201#else
1202				if (cmd == PCIOCWRITE)
1203#endif
1204					pci_write_config(pcidev,
1205							  io->pi_reg,
1206							  io->pi_data,
1207							  io->pi_width);
1208#ifdef PRE7_COMPAT
1209				else if (cmd == PCIOCREAD_OLD)
1210					io_old->pi_data =
1211						pci_read_config(pcidev,
1212							  io->pi_reg,
1213							  io->pi_width);
1214#endif
1215				else
1216					io->pi_data =
1217						pci_read_config(pcidev,
1218							  io->pi_reg,
1219							  io->pi_width);
1220				error = 0;
1221			} else {
1222#ifdef COMPAT_FREEBSD4
1223				if (cmd == PCIOCREAD_OLD) {
1224					io_old->pi_data = -1;
1225					error = 0;
1226				} else
1227#endif
1228					error = ENODEV;
1229			}
1230			break;
1231		default:
1232			error = EINVAL;
1233			break;
1234		}
1235		break;
1236
1237	case PCIOCGETBAR:
1238		bio = (struct pci_bar_io *)data;
1239
1240		/*
1241		 * Assume that the user-level bus number is
1242		 * in fact the physical PCI bus number.
1243		 */
1244		pcidev = pci_find_dbsf(bio->pbi_sel.pc_domain,
1245		    bio->pbi_sel.pc_bus, bio->pbi_sel.pc_dev,
1246		    bio->pbi_sel.pc_func);
1247		if (pcidev == NULL) {
1248			error = ENODEV;
1249			break;
1250		}
1251		pm = pci_find_bar(pcidev, bio->pbi_reg);
1252		if (pm == NULL) {
1253			error = EINVAL;
1254			break;
1255		}
1256		bio->pbi_base = pm->pm_value;
1257		bio->pbi_length = (pci_addr_t)1 << pm->pm_size;
1258		bio->pbi_enabled = pci_bar_enabled(pcidev, pm);
1259		error = 0;
1260		break;
1261	case PCIOCATTACHED:
1262		error = 0;
1263		io = (struct pci_io *)data;
1264		pcidev = pci_find_dbsf(io->pi_sel.pc_domain, io->pi_sel.pc_bus,
1265				       io->pi_sel.pc_dev, io->pi_sel.pc_func);
1266		if (pcidev != NULL)
1267			io->pi_data = device_is_attached(pcidev);
1268		else
1269			error = ENODEV;
1270		break;
1271	case PCIOCLISTVPD:
1272		lvio = (struct pci_list_vpd_io *)data;
1273
1274		/*
1275		 * Assume that the user-level bus number is
1276		 * in fact the physical PCI bus number.
1277		 */
1278		pcidev = pci_find_dbsf(lvio->plvi_sel.pc_domain,
1279		    lvio->plvi_sel.pc_bus, lvio->plvi_sel.pc_dev,
1280		    lvio->plvi_sel.pc_func);
1281		if (pcidev == NULL) {
1282			error = ENODEV;
1283			break;
1284		}
1285		error = pci_list_vpd(pcidev, lvio);
1286		break;
1287
1288	case PCIOCBARMMAP:
1289		pbm = (struct pci_bar_mmap *)data;
1290		if ((flag & FWRITE) == 0 &&
1291		    (pbm->pbm_flags & PCIIO_BAR_MMAP_RW) != 0)
1292			return (EPERM);
1293		pcidev = pci_find_dbsf(pbm->pbm_sel.pc_domain,
1294		    pbm->pbm_sel.pc_bus, pbm->pbm_sel.pc_dev,
1295		    pbm->pbm_sel.pc_func);
1296		error = pcidev == NULL ? ENODEV : pci_bar_mmap(pcidev, pbm);
1297		break;
1298
1299	default:
1300		error = ENOTTY;
1301		break;
1302	}
1303
1304	return (error);
1305}
1306