1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 1782 shidokht * Common Development and Distribution License (the "License"). 6 1782 shidokht * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 5763 gap * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 27 0 stevel 28 0 stevel #include <stdio.h> 29 0 stevel #include <string.h> 30 0 stevel #include <stdlib.h> 31 0 stevel #include <unistd.h> 32 0 stevel #include <sys/param.h> 33 0 stevel #include <errno.h> 34 0 stevel #include <sys/types.h> 35 0 stevel #include <dirent.h> 36 0 stevel #include <libdevinfo.h> 37 0 stevel #include <fcntl.h> 38 0 stevel #include <sys/types.h> 39 0 stevel #include <sys/stat.h> 40 0 stevel #include <sys/pci.h> 41 0 stevel #include <sys/biosdisk.h> 42 0 stevel 43 0 stevel 44 0 stevel /* 45 0 stevel * structure used for searching device tree for a node matching 46 0 stevel * pci bus/dev/fn 47 0 stevel */ 48 0 stevel typedef struct pcibdf { 49 0 stevel int busnum; 50 0 stevel int devnum; 51 0 stevel int funcnum; 52 0 stevel di_node_t di_node; 53 0 stevel } pcibdf_t; 54 0 stevel 55 0 stevel /* 56 0 stevel * structure used for searching device tree for a node matching 57 0 stevel * USB serial number. 58 0 stevel */ 59 0 stevel typedef struct { 60 0 stevel uint64_t serialno; 61 0 stevel di_node_t node; 62 0 stevel } usbser_t; 63 0 stevel 64 0 stevel /* 65 0 stevel * structure for holding the mapping info 66 0 stevel */ 67 0 stevel typedef struct { 68 0 stevel int disklist_index; /* index to disk_list of the mapped path */ 69 0 stevel int matchcount; /* number of matches per this device number */ 70 0 stevel } mapinfo_t; 71 0 stevel 72 0 stevel #define DEVFS_PREFIX "/devices" 73 0 stevel #define DISKS_LIST_INCR 20 /* increment for resizing disk_list */ 74 0 stevel 75 0 stevel #define BIOSPROPNAME_TMPL "biosdev-0x%x" 76 0 stevel #define BIOSPROPNAME_TMPL_LEN 13 77 0 stevel #define BIOSDEV_NUM 8 78 0 stevel #define STARTING_DRVNUM 0x80 79 0 stevel 80 0 stevel /* 81 0 stevel * array to hold mappings. Element at index X corresponds to BIOS device 82 0 stevel * number 0x80 + X 83 0 stevel */ 84 0 stevel static mapinfo_t mapinfo[BIOSDEV_NUM]; 85 0 stevel 86 0 stevel /* 87 0 stevel * Cache copy of kernel device tree snapshot root handle, includes devices 88 0 stevel * that are detached 89 0 stevel */ 90 0 stevel static di_node_t root_node = DI_NODE_NIL; 91 0 stevel 92 0 stevel /* 93 0 stevel * kernel device tree snapshot with currently attached devices. Detached 94 0 stevel * devices are not included. 95 0 stevel */ 96 0 stevel static di_node_t root_allnode = DI_NODE_NIL; 97 0 stevel 98 0 stevel /* 99 0 stevel * handle to retrieve prom properties 100 0 stevel */ 101 0 stevel 102 0 stevel static di_prom_handle_t prom_hdl = DI_PROM_HANDLE_NIL; 103 0 stevel 104 0 stevel static char **disk_list = NULL; /* array of physical device pathnames */ 105 0 stevel static int disk_list_len = 0; /* length of disk_list */ 106 0 stevel static int disk_list_valid = 0; /* number of valid entries in disk_list */ 107 0 stevel 108 0 stevel static int debug = 0; /* used for enabling debug output */ 109 0 stevel 110 0 stevel 111 0 stevel /* Local function prototypes */ 112 0 stevel static void new_disk_list_entry(di_node_t node); 113 1782 shidokht static int i_disktype(di_node_t node, di_minor_t minor, void *arg); 114 0 stevel static void build_disk_list(); 115 1782 shidokht static int search_disklist_match_path(char *path); 116 0 stevel static void free_disks(); 117 1782 shidokht static void cleanup_and_exit(int); 118 1782 shidokht 119 0 stevel static int match_edd(biosdev_data_t *bd); 120 0 stevel static int match_first_block(biosdev_data_t *bd); 121 1782 shidokht 122 1782 shidokht static di_node_t search_tree_match_pcibdf(di_node_t node, int bus, int dev, 123 1782 shidokht int fn); 124 1782 shidokht static int i_match_pcibdf(di_node_t node, void *arg); 125 1782 shidokht 126 1782 shidokht static di_node_t search_tree_match_usbserialno(di_node_t node, 127 1782 shidokht uint64_t serialno); 128 1782 shidokht static int i_match_usbserialno(di_node_t node, void *arg); 129 1782 shidokht 130 1782 shidokht static di_node_t search_children_match_busaddr(di_node_t node, 131 1782 shidokht char *matchbusaddr); 132 1782 shidokht 133 0 stevel 134 0 stevel 135 0 stevel static void 136 0 stevel new_disk_list_entry(di_node_t node) 137 0 stevel { 138 0 stevel size_t newsize; 139 0 stevel char **newlist; 140 0 stevel int newlen; 141 0 stevel char *devfspath; 142 0 stevel 143 0 stevel if (disk_list_valid >= disk_list_len) { 144 0 stevel /* valid should never really be larger than len */ 145 0 stevel /* if they are equal we need to init or realloc */ 146 0 stevel newlen = disk_list_len + DISKS_LIST_INCR; 147 0 stevel newsize = newlen * sizeof (*disk_list); 148 0 stevel 149 0 stevel newlist = (char **)realloc(disk_list, newsize); 150 0 stevel if (newlist == NULL) { 151 0 stevel (void) printf("realloc failed to resize disk table\n"); 152 0 stevel cleanup_and_exit(1); 153 0 stevel } 154 0 stevel disk_list = newlist; 155 0 stevel disk_list_len = newlen; 156 0 stevel } 157 0 stevel 158 0 stevel devfspath = di_devfs_path(node); 159 0 stevel disk_list[disk_list_valid] = devfspath; 160 0 stevel if (debug) 161 0 stevel (void) printf("adding %s\n", devfspath); 162 0 stevel disk_list_valid++; 163 0 stevel } 164 0 stevel 165 0 stevel /* ARGSUSED */ 166 0 stevel static int 167 1782 shidokht i_disktype(di_node_t node, di_minor_t minor, void *arg) 168 0 stevel { 169 0 stevel char *minortype; 170 0 stevel 171 0 stevel if (di_minor_spectype(minor) == S_IFCHR) { 172 0 stevel minortype = di_minor_nodetype(minor); 173 0 stevel 174 0 stevel /* exclude CD's */ 175 0 stevel if (strncmp(minortype, DDI_NT_CD, sizeof (DDI_NT_CD) - 1) != 0) 176 0 stevel /* only take p0 raw device */ 177 0 stevel if (strcmp(di_minor_name(minor), "q,raw") == 0) 178 0 stevel new_disk_list_entry(node); 179 0 stevel } 180 0 stevel return (DI_WALK_CONTINUE); 181 0 stevel } 182 0 stevel 183 0 stevel static void 184 0 stevel build_disk_list() 185 0 stevel { 186 0 stevel int ret; 187 0 stevel ret = di_walk_minor(root_node, DDI_NT_BLOCK, 0, NULL, 188 1782 shidokht i_disktype); 189 0 stevel if (ret != 0) { 190 0 stevel (void) fprintf(stderr, "di_walk_minor failed errno %d\n", 191 0 stevel errno); 192 0 stevel cleanup_and_exit(1); 193 0 stevel } 194 0 stevel } 195 0 stevel 196 0 stevel static void 197 0 stevel free_disks() 198 0 stevel { 199 0 stevel int i; 200 0 stevel 201 0 stevel if (disk_list) { 202 0 stevel for (i = 0; i < disk_list_valid; i++) 203 0 stevel di_devfs_path_free(disk_list[i]); 204 0 stevel 205 0 stevel free(disk_list); 206 0 stevel } 207 0 stevel } 208 0 stevel 209 0 stevel static int 210 1782 shidokht i_match_pcibdf(di_node_t node, void *arg) 211 0 stevel { 212 0 stevel pcibdf_t *pbp; 213 0 stevel int len; 214 0 stevel uint32_t regval; 215 0 stevel uint32_t busnum, funcnum, devicenum; 216 0 stevel char *devtype; 217 0 stevel uint32_t *regbuf = NULL; 218 0 stevel di_node_t parentnode; 219 0 stevel 220 0 stevel pbp = (pcibdf_t *)arg; 221 0 stevel 222 0 stevel parentnode = di_parent_node(node); 223 0 stevel 224 0 stevel len = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode, 225 0 stevel "device_type", (char **)&devtype); 226 0 stevel 227 881 johnny if ((len <= 0) || 228 881 johnny ((strcmp(devtype, "pci") != 0) && (strcmp(devtype, "pciex") != 0))) 229 0 stevel return (DI_WALK_CONTINUE); 230 0 stevel 231 0 stevel len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", 232 0 stevel (int **)®buf); 233 0 stevel 234 0 stevel if (len <= 0) { 235 0 stevel /* Try PROM property */ 236 0 stevel len = di_prom_prop_lookup_ints(prom_hdl, node, "reg", 237 0 stevel (int **)®buf); 238 0 stevel } 239 0 stevel 240 0 stevel 241 0 stevel if (len > 0) { 242 0 stevel regval = regbuf[0]; 243 0 stevel 244 0 stevel busnum = PCI_REG_BUS_G(regval); 245 0 stevel devicenum = PCI_REG_DEV_G(regval); 246 0 stevel funcnum = PCI_REG_FUNC_G(regval); 247 0 stevel 248 0 stevel if ((busnum == pbp->busnum) && 249 0 stevel (devicenum == pbp->devnum) && 250 0 stevel (funcnum == pbp->funcnum)) { 251 0 stevel /* found it */ 252 0 stevel pbp->di_node = node; 253 0 stevel return (DI_WALK_TERMINATE); 254 0 stevel } 255 0 stevel } 256 0 stevel 257 0 stevel return (DI_WALK_CONTINUE); 258 0 stevel } 259 0 stevel 260 0 stevel static di_node_t 261 1782 shidokht search_tree_match_pcibdf(di_node_t node, int bus, int dev, int fn) 262 0 stevel { 263 0 stevel pcibdf_t pb; 264 0 stevel pb.busnum = bus; 265 0 stevel pb.devnum = dev; 266 0 stevel pb.funcnum = fn; 267 0 stevel pb.di_node = DI_NODE_NIL; 268 0 stevel 269 1782 shidokht (void) di_walk_node(node, DI_WALK_CLDFIRST, &pb, i_match_pcibdf); 270 0 stevel return (pb.di_node); 271 0 stevel 272 0 stevel } 273 0 stevel 274 0 stevel static int 275 1782 shidokht i_match_usbserialno(di_node_t node, void *arg) 276 0 stevel { 277 0 stevel int len; 278 0 stevel char *serialp; 279 0 stevel usbser_t *usbsp; 280 0 stevel 281 0 stevel usbsp = (usbser_t *)arg; 282 0 stevel 283 0 stevel len = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, "usb-serialno", 284 1782 shidokht (uchar_t **)&serialp); 285 0 stevel 286 1782 shidokht if ((len > 0) && (strncmp((char *)&usbsp->serialno, serialp, 287 1782 shidokht sizeof (uint64_t)) == 0)) { 288 0 stevel usbsp->node = node; 289 0 stevel return (DI_WALK_TERMINATE); 290 0 stevel } 291 0 stevel return (DI_WALK_CONTINUE); 292 0 stevel } 293 0 stevel 294 0 stevel static di_node_t 295 1782 shidokht search_tree_match_usbserialno(di_node_t node, uint64_t serialno) 296 0 stevel { 297 0 stevel 298 0 stevel usbser_t usbs; 299 0 stevel 300 0 stevel usbs.serialno = serialno; 301 0 stevel usbs.node = DI_NODE_NIL; 302 0 stevel 303 1782 shidokht (void) di_walk_node(node, DI_WALK_CLDFIRST, &usbs, i_match_usbserialno); 304 0 stevel return (usbs.node); 305 0 stevel } 306 0 stevel 307 1782 shidokht /* 308 1782 shidokht * returns the index to the disklist to the disk with matching path 309 1782 shidokht */ 310 0 stevel static int 311 1782 shidokht search_disklist_match_path(char *path) 312 0 stevel { 313 0 stevel int i; 314 0 stevel for (i = 0; i < disk_list_valid; i++) 315 0 stevel if (strcmp(disk_list[i], path) == 0) { 316 0 stevel return (i); 317 0 stevel } 318 0 stevel return (-1); 319 0 stevel } 320 0 stevel 321 1782 shidokht /* 322 1782 shidokht * Find first child of 'node' whose unit address is 'matchbusaddr' 323 1782 shidokht */ 324 1782 shidokht static di_node_t 325 1782 shidokht search_children_match_busaddr(di_node_t node, char *matchbusaddr) 326 1782 shidokht { 327 1782 shidokht di_node_t cnode; 328 1782 shidokht char *busaddr; 329 5763 gap di_path_t pi = DI_PATH_NIL; 330 1782 shidokht 331 1782 shidokht if (matchbusaddr == NULL) 332 1782 shidokht return (DI_NODE_NIL); 333 1782 shidokht 334 6640 cth while ((pi = di_path_phci_next_path(node, pi)) != DI_PATH_NIL) { 335 6640 cth busaddr = di_path_bus_addr(pi); 336 6640 cth if (busaddr == NULL) 337 6640 cth continue; 338 6640 cth if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0) 339 5763 gap return (di_path_client_node(pi)); 340 6640 cth } 341 1782 shidokht 342 1782 shidokht for (cnode = di_child_node(node); cnode != DI_NODE_NIL; 343 1782 shidokht cnode = di_sibling_node(cnode)) { 344 1782 shidokht busaddr = di_bus_addr(cnode); 345 1782 shidokht if (busaddr == NULL) 346 1782 shidokht continue; 347 1782 shidokht if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0) 348 6640 cth return (cnode); 349 1782 shidokht } 350 6640 cth 351 6640 cth return (DI_NODE_NIL); 352 1782 shidokht } 353 0 stevel 354 0 stevel /* 355 0 stevel * Construct a physical device pathname from EDD and verify the 356 0 stevel * path exists. Return the index of in disk_list for the mapped 357 0 stevel * path on success, -1 on failure. 358 0 stevel */ 359 0 stevel static int 360 0 stevel match_edd(biosdev_data_t *bdata) 361 0 stevel { 362 1782 shidokht di_node_t node, cnode = DI_NODE_NIL; 363 1782 shidokht char *devfspath = NULL; 364 0 stevel fn48_t *bd; 365 0 stevel int index; 366 1782 shidokht char busaddrbuf[MAXNAMELEN]; 367 0 stevel 368 0 stevel if (!bdata->edd_valid) { 369 0 stevel if (debug) 370 0 stevel (void) printf("edd not valid\n"); 371 0 stevel return (-1); 372 0 stevel } 373 0 stevel 374 0 stevel bd = &bdata->fn48_dev_params; 375 0 stevel 376 0 stevel if (bd->magic != 0xBEDD || bd->pathinfo_len == 0) { 377 0 stevel /* EDD extensions for devicepath not present */ 378 0 stevel if (debug) 379 0 stevel (void) printf("magic not valid %x pathinfolen %d\n", 380 0 stevel bd->magic, bd->pathinfo_len); 381 0 stevel return (-1); 382 0 stevel } 383 0 stevel 384 0 stevel /* we handle only PCI scsi, ata or sata for now */ 385 0 stevel if (strncmp(bd->bustype, "PCI", 3) != 0) { 386 0 stevel if (debug) 387 0 stevel (void) printf("was not pci %s\n", bd->bustype); 388 0 stevel return (-1); 389 0 stevel } 390 0 stevel if (debug) 391 0 stevel (void) printf("match_edd bdf %d %d %d\n", 392 1782 shidokht bd->interfacepath.pci.bus, 393 1782 shidokht bd->interfacepath.pci.device, 394 1782 shidokht bd->interfacepath.pci.function); 395 0 stevel 396 0 stevel /* look into devinfo tree and find a node with matching pci b/d/f */ 397 1782 shidokht node = search_tree_match_pcibdf(root_node, bd->interfacepath.pci.bus, 398 1782 shidokht bd->interfacepath.pci.device, bd->interfacepath.pci.function); 399 0 stevel 400 0 stevel if (node == DI_NODE_NIL) { 401 0 stevel if (debug) 402 0 stevel (void) printf(" could not find a node in tree " 403 0 stevel "matching bdf\n"); 404 0 stevel return (-1); 405 0 stevel } 406 0 stevel 407 5287 shidokht if (debug) { 408 5287 shidokht int i; 409 5287 shidokht (void) printf("interface type "); 410 5287 shidokht for (i = 0; i < 8; i++) 411 5287 shidokht (void) printf("%c", bd->interface_type[i]); 412 5287 shidokht (void) printf(" pci channel %x target %x\n", 413 5287 shidokht bd->interfacepath.pci.channel, 414 1782 shidokht bd->devicepath.scsi.target); 415 5287 shidokht } 416 0 stevel 417 0 stevel if (strncmp(bd->interface_type, "SCSI", 4) == 0) { 418 0 stevel 419 1782 shidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%x,%x", 420 0 stevel bd->devicepath.scsi.target, bd->devicepath.scsi.lun_lo); 421 0 stevel 422 1782 shidokht cnode = search_children_match_busaddr(node, busaddrbuf); 423 0 stevel 424 1782 shidokht } else if ((strncmp(bd->interface_type, "ATAPI", 5) == 0) || 425 1782 shidokht (strncmp(bd->interface_type, "ATA", 3) == 0) || 426 1782 shidokht (strncmp(bd->interface_type, "SATA", 4) == 0)) { 427 0 stevel 428 1782 shidokht if (strncmp(di_node_name(node), "pci-ide", 7) == 0) { 429 1782 shidokht /* 430 1782 shidokht * Legacy using pci-ide 431 1782 shidokht * the child should be ide@<x>, where x is 432 1782 shidokht * the channel number 433 1782 shidokht */ 434 1782 shidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%d", 435 1782 shidokht bd->interfacepath.pci.channel); 436 0 stevel 437 1782 shidokht if ((cnode = search_children_match_busaddr(node, 438 1782 shidokht busaddrbuf)) != DI_NODE_NIL) { 439 0 stevel 440 1782 shidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0", 441 1782 shidokht bd->devicepath.ata.chan); 442 1782 shidokht cnode = search_children_match_busaddr(cnode, 443 1782 shidokht busaddrbuf); 444 0 stevel 445 1782 shidokht if (cnode == DI_NODE_NIL) 446 1782 shidokht if (debug) 447 1782 shidokht (void) printf("Interface %s " 448 1782 shidokht "using pci-ide no " 449 1782 shidokht "grandchild at %s\n", 450 1782 shidokht bd->interface_type, 451 1782 shidokht busaddrbuf); 452 1782 shidokht } else { 453 1782 shidokht if (debug) 454 1782 shidokht (void) printf("Interface %s using " 455 1782 shidokht "pci-ide, with no child at %s\n", 456 1782 shidokht bd->interface_type, busaddrbuf); 457 1782 shidokht } 458 1782 shidokht } else { 459 1782 shidokht if (strncmp(bd->interface_type, "SATA", 4) == 0) { 460 1782 shidokht /* 461 1782 shidokht * The current EDD (EDD-2) spec does not 462 1782 shidokht * address port number. This is work in 463 1782 shidokht * progress. 464 1782 shidokht * Interprete the first field of device path 465 1782 shidokht * as port number. Needs to be revisited 466 1782 shidokht * with port multiplier support. 467 1782 shidokht */ 468 1782 shidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0", 469 1782 shidokht bd->devicepath.ata.chan); 470 1782 shidokht 471 1782 shidokht cnode = search_children_match_busaddr(node, 472 1782 shidokht busaddrbuf); 473 1782 shidokht } else { 474 1782 shidokht if (debug) 475 1782 shidokht (void) printf("Interface %s, not using" 476 1782 shidokht " pci-ide\n", bd->interface_type); 477 1782 shidokht } 478 1782 shidokht } 479 0 stevel 480 0 stevel } else if (strncmp(bd->interface_type, "USB", 3) == 0) { 481 1782 shidokht cnode = search_tree_match_usbserialno(node, 482 1782 shidokht bd->devicepath.usb.usb_serial_id); 483 0 stevel } else { 484 0 stevel if (debug) 485 0 stevel (void) printf("sorry not supported interface %s\n", 486 1782 shidokht bd->interface_type); 487 0 stevel } 488 0 stevel 489 1782 shidokht if (cnode != DI_NODE_NIL) { 490 1782 shidokht devfspath = di_devfs_path(cnode); 491 1782 shidokht index = search_disklist_match_path(devfspath); 492 1782 shidokht di_devfs_path_free(devfspath); 493 1782 shidokht if (index >= 0) 494 1782 shidokht return (index); 495 0 stevel } 496 0 stevel 497 0 stevel return (-1); 498 0 stevel } 499 0 stevel 500 0 stevel /* 501 0 stevel * For each disk in list of disks, compare the first block with the 502 0 stevel * one from bdd. On the first match, return the index of path in 503 0 stevel * disk_list. If none matched return -1. 504 0 stevel */ 505 0 stevel static int 506 0 stevel match_first_block(biosdev_data_t *bd) 507 0 stevel { 508 0 stevel 509 0 stevel char diskpath[MAXPATHLEN]; 510 0 stevel int fd; 511 0 stevel char buf[512]; 512 0 stevel ssize_t num_read; 513 0 stevel int i; 514 0 stevel 515 0 stevel if (!bd->first_block_valid) 516 0 stevel return (-1); 517 0 stevel 518 0 stevel for (i = 0; i < disk_list_valid; i++) { 519 0 stevel (void) snprintf(diskpath, MAXPATHLEN, "%s/%s:q,raw", 520 0 stevel DEVFS_PREFIX, disk_list[i]); 521 0 stevel fd = open(diskpath, O_RDONLY); 522 0 stevel if (fd < 0) { 523 0 stevel (void) fprintf(stderr, "opening %s failed errno %d\n", 524 0 stevel diskpath, errno); 525 0 stevel continue; 526 0 stevel } 527 0 stevel num_read = read(fd, buf, 512); 528 0 stevel if (num_read != 512) { 529 0 stevel (void) printf("read only %d bytes from %s\n", num_read, 530 0 stevel diskpath); 531 0 stevel continue; 532 0 stevel } 533 0 stevel 534 0 stevel if (memcmp(buf, bd->first_block, 512) == 0) { 535 0 stevel /* found it */ 536 0 stevel return (i); 537 0 stevel } 538 0 stevel } 539 0 stevel return (-1); 540 0 stevel } 541 0 stevel 542 0 stevel 543 0 stevel static void 544 0 stevel cleanup_and_exit(int exitcode) 545 0 stevel { 546 0 stevel 547 0 stevel free_disks(); 548 0 stevel 549 0 stevel if (root_node != DI_NODE_NIL) 550 0 stevel di_fini(root_node); 551 0 stevel 552 0 stevel if (root_allnode != DI_NODE_NIL) 553 0 stevel di_fini(root_allnode); 554 0 stevel 555 0 stevel if (prom_hdl != DI_PROM_HANDLE_NIL) 556 0 stevel di_prom_fini(prom_hdl); 557 0 stevel exit(exitcode); 558 0 stevel 559 0 stevel } 560 0 stevel 561 0 stevel 562 0 stevel int 563 0 stevel main(int argc, char *argv[]) 564 0 stevel { 565 0 stevel biosdev_data_t *biosdata; 566 5287 shidokht int i, c, j; 567 0 stevel int matchedindex = -1; 568 0 stevel char biospropname[BIOSPROPNAME_TMPL_LEN]; 569 0 stevel int totalmatches = 0; 570 5287 shidokht biosdev_data_t *biosdataarray[BIOSDEV_NUM]; 571 0 stevel 572 0 stevel 573 0 stevel while ((c = getopt(argc, argv, "d")) != -1) { 574 0 stevel switch (c) { 575 0 stevel case 'd': 576 0 stevel debug = 1; 577 0 stevel break; 578 0 stevel default: 579 0 stevel (void) printf("unknown option %c\n", c); 580 0 stevel exit(1); 581 0 stevel } 582 0 stevel } 583 0 stevel 584 0 stevel if ((prom_hdl = di_prom_init()) == DI_PROM_HANDLE_NIL) { 585 0 stevel (void) fprintf(stderr, "di_prom_init failed\n"); 586 0 stevel cleanup_and_exit(1); 587 0 stevel } 588 0 stevel 589 0 stevel if ((root_node = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 590 0 stevel (void) fprintf(stderr, "di_init failed\n"); 591 0 stevel cleanup_and_exit(1); 592 0 stevel } 593 0 stevel 594 0 stevel if ((root_allnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 595 0 stevel (void) fprintf(stderr, "di_init failed\n"); 596 0 stevel cleanup_and_exit(1); 597 0 stevel } 598 0 stevel 599 0 stevel (void) memset(mapinfo, 0, sizeof (mapinfo)); 600 0 stevel 601 0 stevel /* get a list of all disks in the system */ 602 0 stevel build_disk_list(); 603 0 stevel 604 5287 shidokht /* Get property values that were created at boot up time */ 605 0 stevel for (i = 0; i < BIOSDEV_NUM; i++) { 606 0 stevel 607 0 stevel (void) snprintf((char *)biospropname, BIOSPROPNAME_TMPL_LEN, 608 0 stevel BIOSPROPNAME_TMPL, i + STARTING_DRVNUM); 609 5287 shidokht if (di_prop_lookup_bytes(DDI_DEV_T_ANY, root_allnode, 610 5287 shidokht biospropname, (uchar_t **)&biosdataarray[i]) <= 0) 611 5287 shidokht biosdataarray[i] = NULL; 612 5287 shidokht } 613 0 stevel 614 5287 shidokht /* Try to match based on device/interface path info from BIOS */ 615 5287 shidokht for (i = 0; i < BIOSDEV_NUM; i++) { 616 0 stevel 617 5287 shidokht if ((biosdata = biosdataarray[i]) == NULL) 618 0 stevel continue; 619 0 stevel if (debug) 620 5287 shidokht (void) printf("matching edd 0x%x\n", 621 5287 shidokht i + STARTING_DRVNUM); 622 0 stevel 623 0 stevel matchedindex = match_edd(biosdata); 624 0 stevel 625 5287 shidokht if (matchedindex != -1) { 626 5287 shidokht if (debug) { 627 5287 shidokht (void) printf("matched by edd\n"); 628 5287 shidokht (void) printf("0x%x %s\n", i + STARTING_DRVNUM, 629 5287 shidokht disk_list[matchedindex]); 630 5287 shidokht } 631 0 stevel 632 0 stevel mapinfo[i].disklist_index = matchedindex; 633 0 stevel mapinfo[i].matchcount++; 634 5287 shidokht 635 0 stevel for (j = 0; j < i; j++) { 636 0 stevel if (mapinfo[j].matchcount > 0 && 637 0 stevel mapinfo[j].disklist_index == matchedindex) { 638 0 stevel mapinfo[j].matchcount++; 639 0 stevel mapinfo[i].matchcount++; 640 0 stevel } 641 0 stevel } 642 0 stevel 643 5287 shidokht } else 644 5287 shidokht if (debug) 645 5287 shidokht (void) printf("No matches by edd\n"); 646 0 stevel } 647 5287 shidokht 648 5287 shidokht /* 649 5287 shidokht * Go through the list and ignore any found matches that are dups. 650 5287 shidokht * This is to workaround issues with BIOSes that do not implement 651 5287 shidokht * providing interface/device path info correctly. 652 5287 shidokht */ 653 5287 shidokht 654 5287 shidokht for (i = 0; i < BIOSDEV_NUM; i++) { 655 5287 shidokht if (mapinfo[i].matchcount > 1) { 656 5287 shidokht if (debug) 657 5287 shidokht (void) printf("Ignoring dup match_edd\n(count " 658 5287 shidokht "%d): 0x%x %s\n", mapinfo[i].matchcount, 659 5287 shidokht i + STARTING_DRVNUM, 660 5287 shidokht disk_list[mapinfo[i].disklist_index]); 661 5287 shidokht 662 5287 shidokht mapinfo[i].matchcount = 0; 663 5287 shidokht mapinfo[i].disklist_index = 0; 664 5287 shidokht } 665 5287 shidokht } 666 5287 shidokht 667 5287 shidokht 668 5287 shidokht /* 669 5287 shidokht * For each bios dev number that we do not have exactly one match 670 5287 shidokht * already, try to match based on first block 671 5287 shidokht */ 672 5287 shidokht for (i = 0; i < BIOSDEV_NUM; i++) { 673 5287 shidokht if (mapinfo[i].matchcount == 1) 674 5287 shidokht continue; 675 5287 shidokht 676 5287 shidokht if ((biosdata = biosdataarray[i]) == NULL) 677 5287 shidokht continue; 678 5287 shidokht 679 5287 shidokht if (debug) 680 5287 shidokht (void) printf("matching first block 0x%x\n", 681 5287 shidokht i + STARTING_DRVNUM); 682 5287 shidokht 683 5287 shidokht matchedindex = match_first_block(biosdata); 684 5287 shidokht if (matchedindex != -1) { 685 5287 shidokht if (debug) { 686 5287 shidokht (void) printf("matched by first block\n"); 687 5287 shidokht (void) printf("0x%x %s\n", i + STARTING_DRVNUM, 688 5287 shidokht disk_list[matchedindex]); 689 5287 shidokht } 690 5287 shidokht 691 5287 shidokht mapinfo[i].disklist_index = matchedindex; 692 5287 shidokht mapinfo[i].matchcount++; 693 5287 shidokht 694 5287 shidokht for (j = 0; j < i; j++) { 695 5287 shidokht if (mapinfo[j].matchcount > 0 && 696 5287 shidokht mapinfo[j].disklist_index == matchedindex) { 697 5287 shidokht mapinfo[j].matchcount++; 698 5287 shidokht mapinfo[i].matchcount++; 699 5287 shidokht } 700 5287 shidokht } 701 5287 shidokht } else 702 5287 shidokht if (debug) { 703 5287 shidokht (void) printf(" No matches by first block\n"); 704 5287 shidokht (void) fprintf(stderr, "Could not match 0x%x\n", 705 5287 shidokht i + STARTING_DRVNUM); 706 5287 shidokht } 707 5287 shidokht } 708 5287 shidokht 709 0 stevel 710 0 stevel for (i = 0; i < BIOSDEV_NUM; i++) { 711 0 stevel if (mapinfo[i].matchcount == 1) { 712 0 stevel (void) printf("0x%x %s\n", i + STARTING_DRVNUM, 713 0 stevel disk_list[mapinfo[i].disklist_index]); 714 0 stevel totalmatches++; 715 0 stevel } else if (debug && mapinfo[i].matchcount > 1) { 716 0 stevel (void) printf("0x%x %s matchcount %d\n", 717 0 stevel i + STARTING_DRVNUM, 718 0 stevel disk_list[mapinfo[i].disklist_index], 719 1782 shidokht mapinfo[i].matchcount); 720 0 stevel } 721 0 stevel } 722 0 stevel 723 0 stevel if (totalmatches == 0) { 724 0 stevel (void) fprintf(stderr, "biosdev: Could not match any!!\n"); 725 0 stevel cleanup_and_exit(1); 726 0 stevel } 727 0 stevel 728 0 stevel cleanup_and_exit(0); 729 0 stevel /* NOTREACHED */ 730 0 stevel return (0); 731 0 stevel } 732