linsysfs.c revision 293527
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 2006 IronPort Systems
31556Srgrimes * All rights reserved.
41556Srgrimes *
51556Srgrimes * Redistribution and use in source and binary forms, with or without
61556Srgrimes * modification, are permitted provided that the following conditions
71556Srgrimes * are met:
81556Srgrimes * 1. Redistributions of source code must retain the above copyright
91556Srgrimes *    notice, this list of conditions and the following disclaimer.
101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111556Srgrimes *    notice, this list of conditions and the following disclaimer in the
121556Srgrimes *    documentation and/or other materials provided with the distribution.
131556Srgrimes *
141556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
151556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
171556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
181556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
191556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
201556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
231556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241556Srgrimes * SUCH DAMAGE.
251556Srgrimes */
261556Srgrimes
271556Srgrimes#include <sys/cdefs.h>
281556Srgrimes__FBSDID("$FreeBSD: stable/10/sys/compat/linsysfs/linsysfs.c 293527 2016-01-09 16:08:22Z dchagin $");
291556Srgrimes
3090143Smarkm#include <sys/param.h>
311556Srgrimes#include <sys/queue.h>
3228052Ssteve#include <sys/blist.h>
3390143Smarkm#include <sys/conf.h>
3428052Ssteve#include <sys/exec.h>
3599110Sobrien#include <sys/filedesc.h>
3699110Sobrien#include <sys/kernel.h>
371556Srgrimes#include <sys/linker.h>
381556Srgrimes#include <sys/malloc.h>
391556Srgrimes#include <sys/mount.h>
401556Srgrimes#include <sys/mutex.h>
411556Srgrimes#include <sys/proc.h>
4228054Ssteve#include <sys/resourcevar.h>
4328054Ssteve#include <sys/sbuf.h>
441556Srgrimes#include <sys/smp.h>
451556Srgrimes#include <sys/socket.h>
461556Srgrimes#include <sys/vnode.h>
471556Srgrimes#include <sys/bus.h>
481556Srgrimes#include <sys/pciio.h>
491556Srgrimes
501556Srgrimes#include <dev/pci/pcivar.h>
511556Srgrimes#include <dev/pci/pcireg.h>
521556Srgrimes
53109504Sjmallett#include <net/if.h>
5490110Simp
551556Srgrimes#include <vm/vm.h>
561556Srgrimes#include <vm/pmap.h>
5769896Smckusick#include <vm/vm_map.h>
581556Srgrimes#include <vm/vm_param.h>
591556Srgrimes#include <vm/vm_object.h>
60130827Sgad#include <vm/swap_pager.h>
61130827Sgad
621556Srgrimes#include <machine/bus.h>
631556Srgrimes
641556Srgrimes#include <compat/linux/linux_ioctl.h>
65110411Ssobomax#include <compat/linux/linux_mib.h>
6690143Smarkm#include <compat/linux/linux_util.h>
67225868Strasz#include <fs/pseudofs/pseudofs.h>
68225868Strasz
69225868Straszstruct scsi_host_queue {
70225868Strasz	TAILQ_ENTRY(scsi_host_queue) scsi_host_next;
71225868Strasz	char *path;
7297958Sjmallett	char *name;
73225868Strasz};
74225868Strasz
75225868StraszTAILQ_HEAD(,scsi_host_queue) scsi_host_q;
76225868Strasz
77225868Straszstatic int host_number = 0;
7897850Sjmallett
79235851Skibstatic int
80225868Straszatoi(const char *str)
81225868Strasz{
82240645Szont	return (int)strtol(str, (char **)NULL, 10);
83225868Strasz}
84225868Strasz
85225868Strasz/*
86225868Strasz * Filler function for proc_name
87225868Strasz */
88225868Straszstatic int
89225868Straszlinsysfs_scsiname(PFS_FILL_ARGS)
90267904Spluknet{
91254943Swill	struct scsi_host_queue *scsi_host;
92225868Strasz	int index;
93267904Spluknet
94225868Strasz	if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
95225868Strasz		index = atoi(&pn->pn_parent->pn_name[4]);
96225868Strasz	} else {
97225868Strasz		sbuf_printf(sb, "unknown\n");
98225868Strasz		return (0);
99331471Sjhb	}
100225868Strasz	TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
101225868Strasz		if (index-- == 0) {
102225868Strasz			sbuf_printf(sb, "%s\n", scsi_host->name);
103225868Strasz			return (0);
104225868Strasz		}
105225868Strasz	}
106225868Strasz	sbuf_printf(sb, "unknown\n");
107225868Strasz	return (0);
108225868Strasz}
109225868Strasz
110225868Strasz/*
111225868Strasz * Filler function for device sym-link
112225868Strasz */
113225868Straszstatic int
114225868Straszlinsysfs_link_scsi_host(PFS_FILL_ARGS)
115225868Strasz{
116225868Strasz	struct scsi_host_queue *scsi_host;
117225868Strasz	int index;
118225868Strasz
119225868Strasz	if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) {
120225868Strasz		index = atoi(&pn->pn_parent->pn_name[4]);
121225868Strasz	} else {
122225868Strasz		sbuf_printf(sb, "unknown\n");
123225868Strasz		return (0);
124225868Strasz	}
125225868Strasz	TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) {
126225868Strasz		if (index-- == 0) {
127225868Strasz			sbuf_printf(sb, "../../../devices%s", scsi_host->path);
128225868Strasz			return(0);
129225868Strasz		}
130225868Strasz	}
131225868Strasz	sbuf_printf(sb, "unknown\n");
132225868Strasz	return (0);
133225868Strasz}
134225868Strasz
135225868Strasz#define PCI_DEV "pci"
136225868Straszstatic int
137225868Straszlinsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi, char *path,
138225868Strasz   char *prefix)
139225868Strasz{
140225868Strasz	struct scsi_host_queue *scsi_host;
141225868Strasz	struct pfs_node *sub_dir;
142225868Strasz	int i, nchildren;
143225868Strasz	device_t *children, parent;
144225868Strasz	devclass_t devclass;
145225868Strasz	const char *name = NULL;
14690143Smarkm	struct pci_devinfo *dinfo;
147225868Strasz	char *device, *host, *new_path = path;
148225868Strasz
149240645Szont	parent = device_get_parent(dev);
150225868Strasz	if (parent) {
151225868Strasz		devclass = device_get_devclass(parent);
152225868Strasz		if (devclass != NULL)
153225868Strasz			name = devclass_get_name(devclass);
154225868Strasz		if (name && strcmp(name, PCI_DEV) == 0) {
155225868Strasz			dinfo = device_get_ivars(dev);
156225868Strasz			if (dinfo) {
157225868Strasz				device = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
158225868Strasz				new_path = malloc(MAXPATHLEN, M_TEMP,
159225868Strasz				    M_WAITOK);
160225868Strasz				new_path[0] = '\000';
161225868Strasz				strcpy(new_path, path);
162225868Strasz				host = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
163225868Strasz				device[0] = '\000';
164225868Strasz				sprintf(device, "%s:%02x:%02x.%x",
165225868Strasz				    prefix,
166225868Strasz				    dinfo->cfg.bus,
167225868Strasz				    dinfo->cfg.slot,
168225868Strasz				    dinfo->cfg.func);
169225868Strasz				strcat(new_path, "/");
170225868Strasz				strcat(new_path, device);
171225868Strasz				dir = pfs_create_dir(dir, device,
172225868Strasz				    NULL, NULL, NULL, 0);
173225868Strasz
174225868Strasz				if (dinfo->cfg.baseclass == PCIC_STORAGE) {
175225868Strasz					/* DJA only make this if needed */
176225868Strasz					sprintf(host, "host%d", host_number++);
1771556Srgrimes					strcat(new_path, "/");
1781556Srgrimes					strcat(new_path, host);
1791556Srgrimes					pfs_create_dir(dir, host,
18090110Simp					    NULL, NULL, NULL, 0);
1811556Srgrimes					scsi_host = malloc(sizeof(
1821556Srgrimes					    struct scsi_host_queue),
1831556Srgrimes					    M_DEVBUF, M_NOWAIT);
18490143Smarkm					scsi_host->path = malloc(
1851556Srgrimes					    strlen(new_path) + 1,
1861556Srgrimes					    M_DEVBUF, M_NOWAIT);
1871556Srgrimes					scsi_host->path[0] = '\000';
1881556Srgrimes					bcopy(new_path, scsi_host->path,
1891556Srgrimes					    strlen(new_path) + 1);
1901556Srgrimes					scsi_host->name = "unknown";
1911556Srgrimes
1921556Srgrimes					sub_dir = pfs_create_dir(scsi, host,
1931556Srgrimes					    NULL, NULL, NULL, 0);
1941556Srgrimes					pfs_create_link(sub_dir, "device",
1951556Srgrimes					    &linsysfs_link_scsi_host,
1961556Srgrimes					    NULL, NULL, NULL, 0);
1971556Srgrimes					pfs_create_file(sub_dir, "proc_name",
1981556Srgrimes					    &linsysfs_scsiname,
1991556Srgrimes					    NULL, NULL, NULL, PFS_RD);
2001556Srgrimes					scsi_host->name
201109502Sjmallett					    = linux_driver_get_name_dev(dev);
2021556Srgrimes					TAILQ_INSERT_TAIL(&scsi_host_q,
20390143Smarkm					    scsi_host, scsi_host_next);
2041556Srgrimes				}
20598050Sjmallett				free(device, M_TEMP);
20690143Smarkm				free(host, M_TEMP);
20790143Smarkm			}
208109504Sjmallett		}
2091556Srgrimes	}
2101556Srgrimes
2111556Srgrimes	device_get_children(dev, &children, &nchildren);
21297944Sjmallett	for (i = 0; i < nchildren; i++) {
21398050Sjmallett		if (children[i])
21498050Sjmallett			linsysfs_run_bus(children[i], dir, scsi, new_path, prefix);
21598050Sjmallett	}
21697944Sjmallett	if (new_path != path)
21798050Sjmallett		free(new_path, M_TEMP);
21898050Sjmallett
21998050Sjmallett	return (1);
22098050Sjmallett}
22198050Sjmallett
22298050Sjmallett/*
22398050Sjmallett * Constructor
22498050Sjmallett */
225109504Sjmallettstatic int
2261556Srgrimeslinsysfs_init(PFS_INIT_ARGS)
227109502Sjmallett{
228109502Sjmallett	struct pfs_node *root;
229109502Sjmallett	struct pfs_node *dir;
230109502Sjmallett	struct pfs_node *pci;
231109502Sjmallett	struct pfs_node *scsi;
232109502Sjmallett	devclass_t devclass;
233109502Sjmallett	device_t dev;
234109502Sjmallett
235109502Sjmallett	TAILQ_INIT(&scsi_host_q);
236109502Sjmallett
2371556Srgrimes	root = pi->pi_root;
23897877Sjmallett
239109504Sjmallett	/* /sys/class/... */
240109504Sjmallett	scsi = pfs_create_dir(root, "class", NULL, NULL, NULL, 0);
241109504Sjmallett	scsi = pfs_create_dir(scsi, "scsi_host", NULL, NULL, NULL, 0);
242109504Sjmallett
243109504Sjmallett	/* /sys/device */
244109504Sjmallett	dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0);
24597848Sjmallett
24697848Sjmallett	/* /sys/device/pci0000:00 */
24797877Sjmallett	pci = pfs_create_dir(dir, "pci0000:00", NULL, NULL, NULL, 0);
24897848Sjmallett
249130999Sgad	devclass = devclass_find("root");
2501556Srgrimes	if (devclass == NULL) {
25190143Smarkm		return (0);
252130999Sgad	}
253104026Sjmallett
254104026Sjmallett	dev = devclass_get_device(devclass, 0);
255104026Sjmallett	linsysfs_run_bus(dev, pci, scsi, "/pci0000:00", "0000");
256104026Sjmallett	return (0);
2571556Srgrimes}
2581556Srgrimes
2591556Srgrimes/*
260109504Sjmallett * Destructor
2611556Srgrimes */
262156423Sgadstatic int
2631556Srgrimeslinsysfs_uninit(PFS_INIT_ARGS)
264156423Sgad{
2651556Srgrimes	struct scsi_host_queue *scsi_host, *scsi_host_tmp;
2661556Srgrimes
2671556Srgrimes	TAILQ_FOREACH_SAFE(scsi_host, &scsi_host_q, scsi_host_next,
2681556Srgrimes	    scsi_host_tmp) {
2691556Srgrimes		TAILQ_REMOVE(&scsi_host_q, scsi_host, scsi_host_next);
2701556Srgrimes		free(scsi_host->path, M_TEMP);
2711556Srgrimes		free(scsi_host, M_TEMP);
2721556Srgrimes	}
2731556Srgrimes
274156423Sgad	return (0);
275157559Sgad}
276157559Sgad
277157559SgadPSEUDOFS(linsysfs, 1, 0);
278157559Sgad#if defined(__amd64__)
279156423SgadMODULE_DEPEND(linsysfs, linux_common, 1, 1, 1);
280157559Sgad#else
281157559SgadMODULE_DEPEND(linsysfs, linux, 1, 1, 1);
282157559Sgad#endif
283157559Sgad