1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2006 IronPort Systems 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, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/ctype.h> 35 #include <sys/kernel.h> 36 #include <sys/malloc.h> 37 #include <sys/mount.h> 38 #include <sys/sbuf.h> 39 #include <sys/smp.h> 40 #include <sys/socket.h> 41 #include <sys/bus.h> 42 #include <sys/pciio.h> 43 44 #include <dev/pci/pcivar.h> 45 #include <dev/pci/pcireg.h> 46 47 #include <net/if.h> 48 #include <net/if_var.h> 49 #include <net/if_dl.h> 50 51 #include <compat/linux/linux.h> 52 #include <compat/linux/linux_common.h> 53 #include <compat/linux/linux_util.h> 54 #include <fs/pseudofs/pseudofs.h> 55 56 struct scsi_host_queue { 57 TAILQ_ENTRY(scsi_host_queue) scsi_host_next; 58 char *path; 59 char *name; 60 }; 61 62 TAILQ_HEAD(,scsi_host_queue) scsi_host_q; 63 64 static int host_number = 0; 65 66 static int 67 atoi(const char *str) 68 { 69 return (int)strtol(str, (char **)NULL, 10); 70 } 71 72 static int 73 linsysfs_ifnet_addr(PFS_FILL_ARGS) 74 { 75 struct epoch_tracker et; 76 struct l_sockaddr lsa; 77 struct ifnet *ifp; 78 int error; 79 80 CURVNET_SET(TD_TO_VNET(td)); 81 NET_EPOCH_ENTER(et); 82 ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name); 83 if (ifp != NULL && (error = linux_ifhwaddr(ifp, &lsa)) == 0) 84 error = sbuf_printf(sb, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", 85 lsa.sa_data[0], lsa.sa_data[1], lsa.sa_data[2], 86 lsa.sa_data[3], lsa.sa_data[4], lsa.sa_data[5]); 87 else 88 error = ENOENT; 89 NET_EPOCH_EXIT(et); 90 CURVNET_RESTORE(); 91 return (error == -1 ? ERANGE : error); 92 } 93 94 static int 95 linsysfs_ifnet_addrlen(PFS_FILL_ARGS) 96 { 97 98 sbuf_printf(sb, "%d\n", LINUX_IFHWADDRLEN); 99 return (0); 100 } 101 102 static int 103 linsysfs_ifnet_flags(PFS_FILL_ARGS) 104 { 105 struct epoch_tracker et; 106 struct ifnet *ifp; 107 int error; 108 109 CURVNET_SET(TD_TO_VNET(td)); 110 NET_EPOCH_ENTER(et); 111 ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name); 112 if (ifp != NULL) 113 error = sbuf_printf(sb, "0x%x\n", linux_ifflags(ifp)); 114 else 115 error = ENOENT; 116 NET_EPOCH_EXIT(et); 117 CURVNET_RESTORE(); 118 return (error == -1 ? ERANGE : error); 119 } 120 121 static int 122 linsysfs_ifnet_ifindex(PFS_FILL_ARGS) 123 { 124 struct epoch_tracker et; 125 struct ifnet *ifp; 126 int error; 127 128 CURVNET_SET(TD_TO_VNET(td)); 129 NET_EPOCH_ENTER(et); 130 ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name); 131 if (ifp != NULL) 132 error = sbuf_printf(sb, "%u\n", if_getindex(ifp)); 133 else 134 error = ENOENT; 135 NET_EPOCH_EXIT(et); 136 CURVNET_RESTORE(); 137 return (error == -1 ? ERANGE : error); 138 } 139 140 static int 141 linsysfs_ifnet_mtu(PFS_FILL_ARGS) 142 { 143 struct epoch_tracker et; 144 struct ifnet *ifp; 145 int error; 146 147 CURVNET_SET(TD_TO_VNET(td)); 148 NET_EPOCH_ENTER(et); 149 ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name); 150 if (ifp != NULL) 151 error = sbuf_printf(sb, "%u\n", if_getmtu(ifp)); 152 else 153 error = ENOENT; 154 NET_EPOCH_EXIT(et); 155 CURVNET_RESTORE(); 156 return (error == -1 ? ERANGE : error); 157 } 158 159 static int 160 linsysfs_ifnet_tx_queue_len(PFS_FILL_ARGS) 161 { 162 163 /* XXX */ 164 sbuf_printf(sb, "1000\n"); 165 return (0); 166 } 167 168 static int 169 linsysfs_ifnet_type(PFS_FILL_ARGS) 170 { 171 struct epoch_tracker et; 172 struct l_sockaddr lsa; 173 struct ifnet *ifp; 174 int error; 175 176 CURVNET_SET(TD_TO_VNET(td)); 177 NET_EPOCH_ENTER(et); 178 ifp = ifname_linux_to_ifp(td, pn->pn_parent->pn_name); 179 if (ifp != NULL && (error = linux_ifhwaddr(ifp, &lsa)) == 0) 180 error = sbuf_printf(sb, "%d\n", lsa.sa_family); 181 else 182 error = ENOENT; 183 NET_EPOCH_EXIT(et); 184 CURVNET_RESTORE(); 185 return (error == -1 ? ERANGE : error); 186 } 187 188 static void 189 linsysfs_listnics(struct pfs_node *dir) 190 { 191 struct pfs_node *nic; 192 struct pfs_node *lo; 193 194 nic = pfs_create_dir(dir, "eth0", NULL, NULL, NULL, 0); 195 196 pfs_create_file(nic, "address", &linsysfs_ifnet_addr, 197 NULL, NULL, NULL, PFS_RD); 198 199 pfs_create_file(nic, "addr_len", &linsysfs_ifnet_addrlen, 200 NULL, NULL, NULL, PFS_RD); 201 202 pfs_create_file(nic, "flags", &linsysfs_ifnet_flags, 203 NULL, NULL, NULL, PFS_RD); 204 205 pfs_create_file(nic, "ifindex", &linsysfs_ifnet_ifindex, 206 NULL, NULL, NULL, PFS_RD); 207 208 pfs_create_file(nic, "mtu", &linsysfs_ifnet_mtu, 209 NULL, NULL, NULL, PFS_RD); 210 211 pfs_create_file(nic, "tx_queue_len", &linsysfs_ifnet_tx_queue_len, 212 NULL, NULL, NULL, PFS_RD); 213 214 pfs_create_file(nic, "type", &linsysfs_ifnet_type, 215 NULL, NULL, NULL, PFS_RD); 216 217 lo = pfs_create_dir(dir, "lo", NULL, NULL, NULL, 0); 218 219 pfs_create_file(lo, "address", &linsysfs_ifnet_addr, 220 NULL, NULL, NULL, PFS_RD); 221 222 pfs_create_file(lo, "addr_len", &linsysfs_ifnet_addrlen, 223 NULL, NULL, NULL, PFS_RD); 224 225 pfs_create_file(lo, "flags", &linsysfs_ifnet_flags, 226 NULL, NULL, NULL, PFS_RD); 227 228 pfs_create_file(lo, "ifindex", &linsysfs_ifnet_ifindex, 229 NULL, NULL, NULL, PFS_RD); 230 231 pfs_create_file(lo, "mtu", &linsysfs_ifnet_mtu, 232 NULL, NULL, NULL, PFS_RD); 233 234 pfs_create_file(lo, "tx_queue_len", &linsysfs_ifnet_tx_queue_len, 235 NULL, NULL, NULL, PFS_RD); 236 237 pfs_create_file(lo, "type", &linsysfs_ifnet_type, 238 NULL, NULL, NULL, PFS_RD); 239 } 240 241 /* 242 * Filler function for proc_name 243 */ 244 static int 245 linsysfs_scsiname(PFS_FILL_ARGS) 246 { 247 struct scsi_host_queue *scsi_host; 248 int index; 249 250 if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) { 251 index = atoi(&pn->pn_parent->pn_name[4]); 252 } else { 253 sbuf_printf(sb, "unknown\n"); 254 return (0); 255 } 256 TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) { 257 if (index-- == 0) { 258 sbuf_printf(sb, "%s\n", scsi_host->name); 259 return (0); 260 } 261 } 262 sbuf_printf(sb, "unknown\n"); 263 return (0); 264 } 265 266 /* 267 * Filler function for device sym-link 268 */ 269 static int 270 linsysfs_link_scsi_host(PFS_FILL_ARGS) 271 { 272 struct scsi_host_queue *scsi_host; 273 int index; 274 275 if (strncmp(pn->pn_parent->pn_name, "host", 4) == 0) { 276 index = atoi(&pn->pn_parent->pn_name[4]); 277 } else { 278 sbuf_printf(sb, "unknown\n"); 279 return (0); 280 } 281 TAILQ_FOREACH(scsi_host, &scsi_host_q, scsi_host_next) { 282 if (index-- == 0) { 283 sbuf_printf(sb, "../../../devices%s", scsi_host->path); 284 return(0); 285 } 286 } 287 sbuf_printf(sb, "unknown\n"); 288 return (0); 289 } 290 291 static int 292 linsysfs_fill_data(PFS_FILL_ARGS) 293 { 294 sbuf_printf(sb, "%s", (char *)pn->pn_data); 295 return (0); 296 } 297 298 static int 299 linsysfs_fill_vendor(PFS_FILL_ARGS) 300 { 301 sbuf_printf(sb, "0x%04x\n", pci_get_vendor((device_t)pn->pn_data)); 302 return (0); 303 } 304 305 static int 306 linsysfs_fill_device(PFS_FILL_ARGS) 307 { 308 sbuf_printf(sb, "0x%04x\n", pci_get_device((device_t)pn->pn_data)); 309 return (0); 310 } 311 312 static int 313 linsysfs_fill_subvendor(PFS_FILL_ARGS) 314 { 315 sbuf_printf(sb, "0x%04x\n", pci_get_subvendor((device_t)pn->pn_data)); 316 return (0); 317 } 318 319 static int 320 linsysfs_fill_subdevice(PFS_FILL_ARGS) 321 { 322 sbuf_printf(sb, "0x%04x\n", pci_get_subdevice((device_t)pn->pn_data)); 323 return (0); 324 } 325 326 static int 327 linsysfs_fill_revid(PFS_FILL_ARGS) 328 { 329 sbuf_printf(sb, "0x%x\n", pci_get_revid((device_t)pn->pn_data)); 330 return (0); 331 } 332 333 static int 334 linsysfs_fill_config(PFS_FILL_ARGS) 335 { 336 uint8_t config[48]; 337 device_t dev; 338 uint32_t reg; 339 340 dev = (device_t)pn->pn_data; 341 bzero(config, sizeof(config)); 342 reg = pci_get_vendor(dev); 343 config[0] = reg; 344 config[1] = reg >> 8; 345 reg = pci_get_device(dev); 346 config[2] = reg; 347 config[3] = reg >> 8; 348 reg = pci_get_revid(dev); 349 config[8] = reg; 350 reg = pci_get_subvendor(dev); 351 config[44] = reg; 352 config[45] = reg >> 8; 353 reg = pci_get_subdevice(dev); 354 config[46] = reg; 355 config[47] = reg >> 8; 356 sbuf_bcat(sb, config, sizeof(config)); 357 return (0); 358 } 359 360 /* 361 * Filler function for PCI uevent file 362 */ 363 static int 364 linsysfs_fill_uevent_pci(PFS_FILL_ARGS) 365 { 366 device_t dev; 367 368 dev = (device_t)pn->pn_data; 369 sbuf_printf(sb, "DRIVER=%s\nPCI_CLASS=%X\nPCI_ID=%04X:%04X\n" 370 "PCI_SUBSYS_ID=%04X:%04X\nPCI_SLOT_NAME=%04d:%02x:%02x.%x\n", 371 linux_driver_get_name_dev(dev), pci_get_class(dev), 372 pci_get_vendor(dev), pci_get_device(dev), pci_get_subvendor(dev), 373 pci_get_subdevice(dev), pci_get_domain(dev), pci_get_bus(dev), 374 pci_get_slot(dev), pci_get_function(dev)); 375 return (0); 376 } 377 378 /* 379 * Filler function for drm uevent file 380 */ 381 static int 382 linsysfs_fill_uevent_drm(PFS_FILL_ARGS) 383 { 384 device_t dev; 385 int unit; 386 387 dev = (device_t)pn->pn_data; 388 unit = device_get_unit(dev); 389 sbuf_printf(sb, 390 "MAJOR=226\nMINOR=%d\nDEVNAME=dri/card%d\nDEVTYPE=dri_minor\n", 391 unit, unit); 392 return (0); 393 } 394 395 static char * 396 get_full_pfs_path(struct pfs_node *cur) 397 { 398 char *temp, *path; 399 400 temp = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 401 path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 402 path[0] = '\0'; 403 404 do { 405 snprintf(temp, MAXPATHLEN, "%s/%s", cur->pn_name, path); 406 strlcpy(path, temp, MAXPATHLEN); 407 cur = cur->pn_parent; 408 } while (cur->pn_parent != NULL); 409 410 path[strlen(path) - 1] = '\0'; /* remove extra slash */ 411 free(temp, M_TEMP); 412 return (path); 413 } 414 415 /* 416 * Filler function for symlink from drm char device to PCI device 417 */ 418 static int 419 linsysfs_fill_vgapci(PFS_FILL_ARGS) 420 { 421 char *path; 422 423 path = get_full_pfs_path((struct pfs_node*)pn->pn_data); 424 sbuf_printf(sb, "../../../%s", path); 425 free(path, M_TEMP); 426 return (0); 427 } 428 429 #undef PCI_DEV 430 #define PCI_DEV "pci" 431 #define DRMN_DEV "drmn" 432 static int 433 linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi, 434 struct pfs_node *chardev, struct pfs_node *drm, char *path, char *prefix) 435 { 436 struct scsi_host_queue *scsi_host; 437 struct pfs_node *sub_dir, *cur_file; 438 int i, nchildren, error; 439 device_t *children, parent; 440 devclass_t devclass; 441 const char *name = NULL; 442 struct pci_devinfo *dinfo; 443 char *device, *host, *new_path, *devname; 444 445 new_path = path; 446 devname = malloc(16, M_TEMP, M_WAITOK); 447 448 parent = device_get_parent(dev); 449 if (parent) { 450 devclass = device_get_devclass(parent); 451 if (devclass != NULL) 452 name = devclass_get_name(devclass); 453 if (name && strcmp(name, PCI_DEV) == 0) { 454 dinfo = device_get_ivars(dev); 455 if (dinfo) { 456 device = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 457 new_path = malloc(MAXPATHLEN, M_TEMP, 458 M_WAITOK); 459 new_path[0] = '\000'; 460 strcpy(new_path, path); 461 host = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 462 device[0] = '\000'; 463 sprintf(device, "%s:%02x:%02x.%x", 464 prefix, 465 dinfo->cfg.bus, 466 dinfo->cfg.slot, 467 dinfo->cfg.func); 468 strcat(new_path, "/"); 469 strcat(new_path, device); 470 dir = pfs_create_dir(dir, device, 471 NULL, NULL, NULL, 0); 472 cur_file = pfs_create_file(dir, "vendor", 473 &linsysfs_fill_vendor, NULL, NULL, NULL, 474 PFS_RD); 475 cur_file->pn_data = (void*)dev; 476 cur_file = pfs_create_file(dir, "device", 477 &linsysfs_fill_device, NULL, NULL, NULL, 478 PFS_RD); 479 cur_file->pn_data = (void*)dev; 480 cur_file = pfs_create_file(dir, 481 "subsystem_vendor", 482 &linsysfs_fill_subvendor, NULL, NULL, NULL, 483 PFS_RD); 484 cur_file->pn_data = (void*)dev; 485 cur_file = pfs_create_file(dir, 486 "subsystem_device", 487 &linsysfs_fill_subdevice, NULL, NULL, NULL, 488 PFS_RD); 489 cur_file->pn_data = (void*)dev; 490 cur_file = pfs_create_file(dir, "revision", 491 &linsysfs_fill_revid, NULL, NULL, NULL, 492 PFS_RD); 493 cur_file->pn_data = (void*)dev; 494 cur_file = pfs_create_file(dir, "config", 495 &linsysfs_fill_config, NULL, NULL, NULL, 496 PFS_RD); 497 cur_file->pn_data = (void*)dev; 498 cur_file = pfs_create_file(dir, "uevent", 499 &linsysfs_fill_uevent_pci, NULL, NULL, 500 NULL, PFS_RD); 501 cur_file->pn_data = (void*)dev; 502 cur_file = pfs_create_link(dir, "subsystem", 503 &linsysfs_fill_data, NULL, NULL, NULL, 0); 504 /* libdrm just checks that the link ends in "/pci" */ 505 cur_file->pn_data = "/sys/bus/pci"; 506 507 if (dinfo->cfg.baseclass == PCIC_STORAGE) { 508 /* DJA only make this if needed */ 509 sprintf(host, "host%d", host_number++); 510 strcat(new_path, "/"); 511 strcat(new_path, host); 512 pfs_create_dir(dir, host, 513 NULL, NULL, NULL, 0); 514 scsi_host = malloc(sizeof( 515 struct scsi_host_queue), 516 M_DEVBUF, M_NOWAIT); 517 scsi_host->path = malloc( 518 strlen(new_path) + 1, 519 M_DEVBUF, M_NOWAIT); 520 scsi_host->path[0] = '\000'; 521 bcopy(new_path, scsi_host->path, 522 strlen(new_path) + 1); 523 scsi_host->name = "unknown"; 524 525 sub_dir = pfs_create_dir(scsi, host, 526 NULL, NULL, NULL, 0); 527 pfs_create_link(sub_dir, "device", 528 &linsysfs_link_scsi_host, 529 NULL, NULL, NULL, 0); 530 pfs_create_file(sub_dir, "proc_name", 531 &linsysfs_scsiname, 532 NULL, NULL, NULL, PFS_RD); 533 scsi_host->name 534 = linux_driver_get_name_dev(dev); 535 TAILQ_INSERT_TAIL(&scsi_host_q, 536 scsi_host, scsi_host_next); 537 } 538 free(device, M_TEMP); 539 free(host, M_TEMP); 540 } 541 } 542 543 devclass = device_get_devclass(dev); 544 if (devclass != NULL) 545 name = devclass_get_name(devclass); 546 else 547 name = NULL; 548 if (name != NULL && strcmp(name, DRMN_DEV) == 0 && 549 device_get_unit(dev) >= 0) { 550 dinfo = device_get_ivars(parent); 551 if (dinfo != NULL && dinfo->cfg.baseclass == PCIC_DISPLAY) { 552 pfs_create_dir(dir, "drm", NULL, NULL, NULL, 0); 553 sprintf(devname, "226:%d", 554 device_get_unit(dev)); 555 sub_dir = pfs_create_dir(chardev, 556 devname, NULL, NULL, NULL, 0); 557 cur_file = pfs_create_link(sub_dir, 558 "device", &linsysfs_fill_vgapci, NULL, 559 NULL, NULL, PFS_RD); 560 cur_file->pn_data = (void*)dir; 561 cur_file = pfs_create_file(sub_dir, 562 "uevent", &linsysfs_fill_uevent_drm, NULL, 563 NULL, NULL, PFS_RD); 564 cur_file->pn_data = (void*)dev; 565 sprintf(devname, "card%d", 566 device_get_unit(dev)); 567 sub_dir = pfs_create_dir(drm, 568 devname, NULL, NULL, NULL, 0); 569 cur_file = pfs_create_link(sub_dir, 570 "device", &linsysfs_fill_vgapci, NULL, 571 NULL, NULL, PFS_RD); 572 cur_file->pn_data = (void*)dir; 573 } 574 } 575 } 576 577 error = device_get_children(dev, &children, &nchildren); 578 if (error == 0) { 579 for (i = 0; i < nchildren; i++) 580 if (children[i]) 581 linsysfs_run_bus(children[i], dir, scsi, 582 chardev, drm, new_path, prefix); 583 free(children, M_TEMP); 584 } 585 if (new_path != path) 586 free(new_path, M_TEMP); 587 free(devname, M_TEMP); 588 589 return (1); 590 } 591 592 /* 593 * Filler function for sys/devices/system/cpu/{online,possible,present} 594 */ 595 static int 596 linsysfs_cpuonline(PFS_FILL_ARGS) 597 { 598 599 sbuf_printf(sb, "%d-%d\n", CPU_FIRST(), mp_maxid); 600 return (0); 601 } 602 603 /* 604 * Filler function for sys/devices/system/cpu/cpuX/online 605 */ 606 static int 607 linsysfs_cpuxonline(PFS_FILL_ARGS) 608 { 609 610 sbuf_printf(sb, "1\n"); 611 return (0); 612 } 613 614 static void 615 linsysfs_listcpus(struct pfs_node *dir) 616 { 617 struct pfs_node *cpu; 618 char *name; 619 int i, count, len; 620 621 len = 1; 622 count = mp_maxcpus; 623 while (count > 10) { 624 count /= 10; 625 len++; 626 } 627 len += sizeof("cpu"); 628 name = malloc(len, M_TEMP, M_WAITOK); 629 630 for (i = 0; i < mp_ncpus; ++i) { 631 /* /sys/devices/system/cpu/cpuX */ 632 sprintf(name, "cpu%d", i); 633 cpu = pfs_create_dir(dir, name, NULL, NULL, NULL, 0); 634 635 pfs_create_file(cpu, "online", &linsysfs_cpuxonline, 636 NULL, NULL, NULL, PFS_RD); 637 } 638 free(name, M_TEMP); 639 } 640 641 /* 642 * Constructor 643 */ 644 static int 645 linsysfs_init(PFS_INIT_ARGS) 646 { 647 struct pfs_node *root; 648 struct pfs_node *class; 649 struct pfs_node *dir, *sys, *cpu; 650 struct pfs_node *drm; 651 struct pfs_node *pci; 652 struct pfs_node *scsi; 653 struct pfs_node *net; 654 struct pfs_node *devdir, *chardev; 655 struct pfs_node *kernel; 656 devclass_t devclass; 657 device_t dev; 658 659 TAILQ_INIT(&scsi_host_q); 660 661 root = pi->pi_root; 662 663 /* /sys/bus/... */ 664 dir = pfs_create_dir(root, "bus", NULL, NULL, NULL, 0); 665 666 /* /sys/class/... */ 667 class = pfs_create_dir(root, "class", NULL, NULL, NULL, 0); 668 scsi = pfs_create_dir(class, "scsi_host", NULL, NULL, NULL, 0); 669 drm = pfs_create_dir(class, "drm", NULL, NULL, NULL, 0); 670 pfs_create_dir(class, "power_supply", NULL, NULL, NULL, 0); 671 672 /* /sys/class/net/.. */ 673 net = pfs_create_dir(class, "net", NULL, NULL, NULL, 0); 674 675 /* /sys/dev/... */ 676 devdir = pfs_create_dir(root, "dev", NULL, NULL, NULL, 0); 677 chardev = pfs_create_dir(devdir, "char", NULL, NULL, NULL, 0); 678 679 /* /sys/devices/... */ 680 dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0); 681 pci = pfs_create_dir(dir, "pci0000:00", NULL, NULL, NULL, 0); 682 683 devclass = devclass_find("root"); 684 if (devclass == NULL) { 685 return (0); 686 } 687 688 dev = devclass_get_device(devclass, 0); 689 linsysfs_run_bus(dev, pci, scsi, chardev, drm, "/pci0000:00", "0000"); 690 691 /* /sys/devices/system */ 692 sys = pfs_create_dir(dir, "system", NULL, NULL, NULL, 0); 693 694 /* /sys/devices/system/cpu */ 695 cpu = pfs_create_dir(sys, "cpu", NULL, NULL, NULL, 0); 696 697 pfs_create_file(cpu, "online", &linsysfs_cpuonline, 698 NULL, NULL, NULL, PFS_RD); 699 pfs_create_file(cpu, "possible", &linsysfs_cpuonline, 700 NULL, NULL, NULL, PFS_RD); 701 pfs_create_file(cpu, "present", &linsysfs_cpuonline, 702 NULL, NULL, NULL, PFS_RD); 703 704 linsysfs_listcpus(cpu); 705 linsysfs_listnics(net); 706 707 /* /sys/kernel */ 708 kernel = pfs_create_dir(root, "kernel", NULL, NULL, NULL, 0); 709 /* /sys/kernel/debug, mountpoint for lindebugfs. */ 710 pfs_create_dir(kernel, "debug", NULL, NULL, NULL, 0); 711 712 /* /sys/subsystem/... */ 713 dir = pfs_create_dir(root, "subsystem", NULL, NULL, NULL, 0); 714 715 return (0); 716 } 717 718 /* 719 * Destructor 720 */ 721 static int 722 linsysfs_uninit(PFS_INIT_ARGS) 723 { 724 struct scsi_host_queue *scsi_host, *scsi_host_tmp; 725 726 TAILQ_FOREACH_SAFE(scsi_host, &scsi_host_q, scsi_host_next, 727 scsi_host_tmp) { 728 TAILQ_REMOVE(&scsi_host_q, scsi_host, scsi_host_next); 729 free(scsi_host->path, M_TEMP); 730 free(scsi_host, M_TEMP); 731 } 732 733 return (0); 734 } 735 736 PSEUDOFS(linsysfs, 1, VFCF_JAIL); 737 #if defined(__aarch64__) || defined(__amd64__) 738 MODULE_DEPEND(linsysfs, linux_common, 1, 1, 1); 739 #else 740 MODULE_DEPEND(linsysfs, linux, 1, 1, 1); 741 #endif 742