17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5d155f3feSshidokht * Common Development and Distribution License (the "License"). 6d155f3feSshidokht * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 2244d788f4Sgap * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <stdio.h> 297c478bd9Sstevel@tonic-gate #include <string.h> 307c478bd9Sstevel@tonic-gate #include <stdlib.h> 317c478bd9Sstevel@tonic-gate #include <unistd.h> 327c478bd9Sstevel@tonic-gate #include <sys/param.h> 337c478bd9Sstevel@tonic-gate #include <errno.h> 347c478bd9Sstevel@tonic-gate #include <sys/types.h> 357c478bd9Sstevel@tonic-gate #include <dirent.h> 367c478bd9Sstevel@tonic-gate #include <libdevinfo.h> 377c478bd9Sstevel@tonic-gate #include <fcntl.h> 387c478bd9Sstevel@tonic-gate #include <sys/types.h> 397c478bd9Sstevel@tonic-gate #include <sys/stat.h> 407c478bd9Sstevel@tonic-gate #include <sys/pci.h> 417c478bd9Sstevel@tonic-gate #include <sys/biosdisk.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate /* 457c478bd9Sstevel@tonic-gate * structure used for searching device tree for a node matching 467c478bd9Sstevel@tonic-gate * pci bus/dev/fn 477c478bd9Sstevel@tonic-gate */ 487c478bd9Sstevel@tonic-gate typedef struct pcibdf { 497c478bd9Sstevel@tonic-gate int busnum; 507c478bd9Sstevel@tonic-gate int devnum; 517c478bd9Sstevel@tonic-gate int funcnum; 527c478bd9Sstevel@tonic-gate di_node_t di_node; 537c478bd9Sstevel@tonic-gate } pcibdf_t; 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* 567c478bd9Sstevel@tonic-gate * structure used for searching device tree for a node matching 577c478bd9Sstevel@tonic-gate * USB serial number. 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate typedef struct { 607c478bd9Sstevel@tonic-gate uint64_t serialno; 617c478bd9Sstevel@tonic-gate di_node_t node; 627c478bd9Sstevel@tonic-gate } usbser_t; 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate /* 657c478bd9Sstevel@tonic-gate * structure for holding the mapping info 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate typedef struct { 687c478bd9Sstevel@tonic-gate int disklist_index; /* index to disk_list of the mapped path */ 697c478bd9Sstevel@tonic-gate int matchcount; /* number of matches per this device number */ 707c478bd9Sstevel@tonic-gate } mapinfo_t; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate #define DEVFS_PREFIX "/devices" 737c478bd9Sstevel@tonic-gate #define DISKS_LIST_INCR 20 /* increment for resizing disk_list */ 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate #define BIOSPROPNAME_TMPL "biosdev-0x%x" 767c478bd9Sstevel@tonic-gate #define BIOSPROPNAME_TMPL_LEN 13 777c478bd9Sstevel@tonic-gate #define BIOSDEV_NUM 8 787c478bd9Sstevel@tonic-gate #define STARTING_DRVNUM 0x80 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * array to hold mappings. Element at index X corresponds to BIOS device 827c478bd9Sstevel@tonic-gate * number 0x80 + X 837c478bd9Sstevel@tonic-gate */ 847c478bd9Sstevel@tonic-gate static mapinfo_t mapinfo[BIOSDEV_NUM]; 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate /* 877c478bd9Sstevel@tonic-gate * Cache copy of kernel device tree snapshot root handle, includes devices 887c478bd9Sstevel@tonic-gate * that are detached 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate static di_node_t root_node = DI_NODE_NIL; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * kernel device tree snapshot with currently attached devices. Detached 947c478bd9Sstevel@tonic-gate * devices are not included. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate static di_node_t root_allnode = DI_NODE_NIL; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * handle to retrieve prom properties 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static di_prom_handle_t prom_hdl = DI_PROM_HANDLE_NIL; 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate static char **disk_list = NULL; /* array of physical device pathnames */ 1057c478bd9Sstevel@tonic-gate static int disk_list_len = 0; /* length of disk_list */ 1067c478bd9Sstevel@tonic-gate static int disk_list_valid = 0; /* number of valid entries in disk_list */ 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate static int debug = 0; /* used for enabling debug output */ 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* Local function prototypes */ 1127c478bd9Sstevel@tonic-gate static void new_disk_list_entry(di_node_t node); 113d155f3feSshidokht static int i_disktype(di_node_t node, di_minor_t minor, void *arg); 1147c478bd9Sstevel@tonic-gate static void build_disk_list(); 115d155f3feSshidokht static int search_disklist_match_path(char *path); 1167c478bd9Sstevel@tonic-gate static void free_disks(); 117d155f3feSshidokht static void cleanup_and_exit(int); 118d155f3feSshidokht 1197c478bd9Sstevel@tonic-gate static int match_edd(biosdev_data_t *bd); 1207c478bd9Sstevel@tonic-gate static int match_first_block(biosdev_data_t *bd); 121d155f3feSshidokht 122d155f3feSshidokht static di_node_t search_tree_match_pcibdf(di_node_t node, int bus, int dev, 123d155f3feSshidokht int fn); 124d155f3feSshidokht static int i_match_pcibdf(di_node_t node, void *arg); 125d155f3feSshidokht 126d155f3feSshidokht static di_node_t search_tree_match_usbserialno(di_node_t node, 127d155f3feSshidokht uint64_t serialno); 128d155f3feSshidokht static int i_match_usbserialno(di_node_t node, void *arg); 129d155f3feSshidokht 130d155f3feSshidokht static di_node_t search_children_match_busaddr(di_node_t node, 131d155f3feSshidokht char *matchbusaddr); 132d155f3feSshidokht 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate static void 1367c478bd9Sstevel@tonic-gate new_disk_list_entry(di_node_t node) 1377c478bd9Sstevel@tonic-gate { 1387c478bd9Sstevel@tonic-gate size_t newsize; 1397c478bd9Sstevel@tonic-gate char **newlist; 1407c478bd9Sstevel@tonic-gate int newlen; 1417c478bd9Sstevel@tonic-gate char *devfspath; 1427c478bd9Sstevel@tonic-gate 1437c478bd9Sstevel@tonic-gate if (disk_list_valid >= disk_list_len) { 1447c478bd9Sstevel@tonic-gate /* valid should never really be larger than len */ 1457c478bd9Sstevel@tonic-gate /* if they are equal we need to init or realloc */ 1467c478bd9Sstevel@tonic-gate newlen = disk_list_len + DISKS_LIST_INCR; 1477c478bd9Sstevel@tonic-gate newsize = newlen * sizeof (*disk_list); 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate newlist = (char **)realloc(disk_list, newsize); 1507c478bd9Sstevel@tonic-gate if (newlist == NULL) { 1517c478bd9Sstevel@tonic-gate (void) printf("realloc failed to resize disk table\n"); 1527c478bd9Sstevel@tonic-gate cleanup_and_exit(1); 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate disk_list = newlist; 1557c478bd9Sstevel@tonic-gate disk_list_len = newlen; 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate devfspath = di_devfs_path(node); 1597c478bd9Sstevel@tonic-gate disk_list[disk_list_valid] = devfspath; 1607c478bd9Sstevel@tonic-gate if (debug) 1617c478bd9Sstevel@tonic-gate (void) printf("adding %s\n", devfspath); 1627c478bd9Sstevel@tonic-gate disk_list_valid++; 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* ARGSUSED */ 1667c478bd9Sstevel@tonic-gate static int 167d155f3feSshidokht i_disktype(di_node_t node, di_minor_t minor, void *arg) 1687c478bd9Sstevel@tonic-gate { 1697c478bd9Sstevel@tonic-gate char *minortype; 1707c478bd9Sstevel@tonic-gate 1717c478bd9Sstevel@tonic-gate if (di_minor_spectype(minor) == S_IFCHR) { 1727c478bd9Sstevel@tonic-gate minortype = di_minor_nodetype(minor); 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate /* exclude CD's */ 1757c478bd9Sstevel@tonic-gate if (strncmp(minortype, DDI_NT_CD, sizeof (DDI_NT_CD) - 1) != 0) 1767c478bd9Sstevel@tonic-gate /* only take p0 raw device */ 1777c478bd9Sstevel@tonic-gate if (strcmp(di_minor_name(minor), "q,raw") == 0) 1787c478bd9Sstevel@tonic-gate new_disk_list_entry(node); 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate static void 1847c478bd9Sstevel@tonic-gate build_disk_list() 1857c478bd9Sstevel@tonic-gate { 1867c478bd9Sstevel@tonic-gate int ret; 1877c478bd9Sstevel@tonic-gate ret = di_walk_minor(root_node, DDI_NT_BLOCK, 0, NULL, 188d155f3feSshidokht i_disktype); 1897c478bd9Sstevel@tonic-gate if (ret != 0) { 1907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "di_walk_minor failed errno %d\n", 1917c478bd9Sstevel@tonic-gate errno); 1927c478bd9Sstevel@tonic-gate cleanup_and_exit(1); 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate } 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate static void 1977c478bd9Sstevel@tonic-gate free_disks() 1987c478bd9Sstevel@tonic-gate { 1997c478bd9Sstevel@tonic-gate int i; 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate if (disk_list) { 2027c478bd9Sstevel@tonic-gate for (i = 0; i < disk_list_valid; i++) 2037c478bd9Sstevel@tonic-gate di_devfs_path_free(disk_list[i]); 2047c478bd9Sstevel@tonic-gate 2057c478bd9Sstevel@tonic-gate free(disk_list); 2067c478bd9Sstevel@tonic-gate } 2077c478bd9Sstevel@tonic-gate } 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate static int 210d155f3feSshidokht i_match_pcibdf(di_node_t node, void *arg) 2117c478bd9Sstevel@tonic-gate { 2127c478bd9Sstevel@tonic-gate pcibdf_t *pbp; 2137c478bd9Sstevel@tonic-gate int len; 2147c478bd9Sstevel@tonic-gate uint32_t regval; 2157c478bd9Sstevel@tonic-gate uint32_t busnum, funcnum, devicenum; 2167c478bd9Sstevel@tonic-gate char *devtype; 2177c478bd9Sstevel@tonic-gate uint32_t *regbuf = NULL; 2187c478bd9Sstevel@tonic-gate di_node_t parentnode; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate pbp = (pcibdf_t *)arg; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate parentnode = di_parent_node(node); 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate len = di_prop_lookup_strings(DDI_DEV_T_ANY, parentnode, 2257c478bd9Sstevel@tonic-gate "device_type", (char **)&devtype); 2267c478bd9Sstevel@tonic-gate 22770025d76Sjohnny if ((len <= 0) || 22870025d76Sjohnny ((strcmp(devtype, "pci") != 0) && (strcmp(devtype, "pciex") != 0))) 2297c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate len = di_prop_lookup_ints(DDI_DEV_T_ANY, node, "reg", 2327c478bd9Sstevel@tonic-gate (int **)®buf); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if (len <= 0) { 2357c478bd9Sstevel@tonic-gate /* Try PROM property */ 2367c478bd9Sstevel@tonic-gate len = di_prom_prop_lookup_ints(prom_hdl, node, "reg", 2377c478bd9Sstevel@tonic-gate (int **)®buf); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate 2417c478bd9Sstevel@tonic-gate if (len > 0) { 2427c478bd9Sstevel@tonic-gate regval = regbuf[0]; 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate busnum = PCI_REG_BUS_G(regval); 2457c478bd9Sstevel@tonic-gate devicenum = PCI_REG_DEV_G(regval); 2467c478bd9Sstevel@tonic-gate funcnum = PCI_REG_FUNC_G(regval); 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if ((busnum == pbp->busnum) && 2497c478bd9Sstevel@tonic-gate (devicenum == pbp->devnum) && 2507c478bd9Sstevel@tonic-gate (funcnum == pbp->funcnum)) { 2517c478bd9Sstevel@tonic-gate /* found it */ 2527c478bd9Sstevel@tonic-gate pbp->di_node = node; 2537c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate static di_node_t 261d155f3feSshidokht search_tree_match_pcibdf(di_node_t node, int bus, int dev, int fn) 2627c478bd9Sstevel@tonic-gate { 2637c478bd9Sstevel@tonic-gate pcibdf_t pb; 2647c478bd9Sstevel@tonic-gate pb.busnum = bus; 2657c478bd9Sstevel@tonic-gate pb.devnum = dev; 2667c478bd9Sstevel@tonic-gate pb.funcnum = fn; 2677c478bd9Sstevel@tonic-gate pb.di_node = DI_NODE_NIL; 2687c478bd9Sstevel@tonic-gate 269d155f3feSshidokht (void) di_walk_node(node, DI_WALK_CLDFIRST, &pb, i_match_pcibdf); 2707c478bd9Sstevel@tonic-gate return (pb.di_node); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate } 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate static int 275d155f3feSshidokht i_match_usbserialno(di_node_t node, void *arg) 2767c478bd9Sstevel@tonic-gate { 2777c478bd9Sstevel@tonic-gate int len; 2787c478bd9Sstevel@tonic-gate char *serialp; 2797c478bd9Sstevel@tonic-gate usbser_t *usbsp; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate usbsp = (usbser_t *)arg; 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate len = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, "usb-serialno", 2847c478bd9Sstevel@tonic-gate (uchar_t **)&serialp); 2857c478bd9Sstevel@tonic-gate 286d155f3feSshidokht if ((len > 0) && (strncmp((char *)&usbsp->serialno, serialp, 287d155f3feSshidokht sizeof (uint64_t)) == 0)) { 2887c478bd9Sstevel@tonic-gate usbsp->node = node; 2897c478bd9Sstevel@tonic-gate return (DI_WALK_TERMINATE); 2907c478bd9Sstevel@tonic-gate } 2917c478bd9Sstevel@tonic-gate return (DI_WALK_CONTINUE); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate static di_node_t 295d155f3feSshidokht search_tree_match_usbserialno(di_node_t node, uint64_t serialno) 2967c478bd9Sstevel@tonic-gate { 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate usbser_t usbs; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate usbs.serialno = serialno; 3017c478bd9Sstevel@tonic-gate usbs.node = DI_NODE_NIL; 3027c478bd9Sstevel@tonic-gate 303d155f3feSshidokht (void) di_walk_node(node, DI_WALK_CLDFIRST, &usbs, i_match_usbserialno); 3047c478bd9Sstevel@tonic-gate return (usbs.node); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 307d155f3feSshidokht /* 308d155f3feSshidokht * returns the index to the disklist to the disk with matching path 309d155f3feSshidokht */ 3107c478bd9Sstevel@tonic-gate static int 311d155f3feSshidokht search_disklist_match_path(char *path) 3127c478bd9Sstevel@tonic-gate { 3137c478bd9Sstevel@tonic-gate int i; 3147c478bd9Sstevel@tonic-gate for (i = 0; i < disk_list_valid; i++) 3157c478bd9Sstevel@tonic-gate if (strcmp(disk_list[i], path) == 0) { 3167c478bd9Sstevel@tonic-gate return (i); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate return (-1); 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate 321d155f3feSshidokht /* 322d155f3feSshidokht * Find first child of 'node' whose unit address is 'matchbusaddr' 323d155f3feSshidokht */ 324d155f3feSshidokht static di_node_t 325d155f3feSshidokht search_children_match_busaddr(di_node_t node, char *matchbusaddr) 326d155f3feSshidokht { 327d155f3feSshidokht di_node_t cnode; 328d155f3feSshidokht char *busaddr; 32944d788f4Sgap di_path_t pi = DI_PATH_NIL; 330d155f3feSshidokht 331d155f3feSshidokht if (matchbusaddr == NULL) 332d155f3feSshidokht return (DI_NODE_NIL); 333d155f3feSshidokht 334*602ca9eaScth while ((pi = di_path_phci_next_path(node, pi)) != DI_PATH_NIL) { 335*602ca9eaScth busaddr = di_path_bus_addr(pi); 336*602ca9eaScth if (busaddr == NULL) 337*602ca9eaScth continue; 338*602ca9eaScth if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0) 33944d788f4Sgap return (di_path_client_node(pi)); 340*602ca9eaScth } 341d155f3feSshidokht 342d155f3feSshidokht for (cnode = di_child_node(node); cnode != DI_NODE_NIL; 343d155f3feSshidokht cnode = di_sibling_node(cnode)) { 344d155f3feSshidokht busaddr = di_bus_addr(cnode); 345d155f3feSshidokht if (busaddr == NULL) 346d155f3feSshidokht continue; 347d155f3feSshidokht if (strncmp(busaddr, matchbusaddr, MAXNAMELEN) == 0) 348d155f3feSshidokht return (cnode); 349d155f3feSshidokht } 3507c478bd9Sstevel@tonic-gate 351*602ca9eaScth return (DI_NODE_NIL); 352*602ca9eaScth } 353*602ca9eaScth 3547c478bd9Sstevel@tonic-gate /* 3557c478bd9Sstevel@tonic-gate * Construct a physical device pathname from EDD and verify the 3567c478bd9Sstevel@tonic-gate * path exists. Return the index of in disk_list for the mapped 3577c478bd9Sstevel@tonic-gate * path on success, -1 on failure. 3587c478bd9Sstevel@tonic-gate */ 3597c478bd9Sstevel@tonic-gate static int 3607c478bd9Sstevel@tonic-gate match_edd(biosdev_data_t *bdata) 3617c478bd9Sstevel@tonic-gate { 362d155f3feSshidokht di_node_t node, cnode = DI_NODE_NIL; 363d155f3feSshidokht char *devfspath = NULL; 3647c478bd9Sstevel@tonic-gate fn48_t *bd; 3657c478bd9Sstevel@tonic-gate int index; 366d155f3feSshidokht char busaddrbuf[MAXNAMELEN]; 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate if (!bdata->edd_valid) { 3697c478bd9Sstevel@tonic-gate if (debug) 3707c478bd9Sstevel@tonic-gate (void) printf("edd not valid\n"); 3717c478bd9Sstevel@tonic-gate return (-1); 3727c478bd9Sstevel@tonic-gate } 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate bd = &bdata->fn48_dev_params; 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate if (bd->magic != 0xBEDD || bd->pathinfo_len == 0) { 3777c478bd9Sstevel@tonic-gate /* EDD extensions for devicepath not present */ 3787c478bd9Sstevel@tonic-gate if (debug) 3797c478bd9Sstevel@tonic-gate (void) printf("magic not valid %x pathinfolen %d\n", 3807c478bd9Sstevel@tonic-gate bd->magic, bd->pathinfo_len); 3817c478bd9Sstevel@tonic-gate return (-1); 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /* we handle only PCI scsi, ata or sata for now */ 3857c478bd9Sstevel@tonic-gate if (strncmp(bd->bustype, "PCI", 3) != 0) { 3867c478bd9Sstevel@tonic-gate if (debug) 3877c478bd9Sstevel@tonic-gate (void) printf("was not pci %s\n", bd->bustype); 3887c478bd9Sstevel@tonic-gate return (-1); 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate if (debug) 3917c478bd9Sstevel@tonic-gate (void) printf("match_edd bdf %d %d %d\n", 3927c478bd9Sstevel@tonic-gate bd->interfacepath.pci.bus, 3937c478bd9Sstevel@tonic-gate bd->interfacepath.pci.device, 3947c478bd9Sstevel@tonic-gate bd->interfacepath.pci.function); 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* look into devinfo tree and find a node with matching pci b/d/f */ 397d155f3feSshidokht node = search_tree_match_pcibdf(root_node, bd->interfacepath.pci.bus, 398d155f3feSshidokht bd->interfacepath.pci.device, bd->interfacepath.pci.function); 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate if (node == DI_NODE_NIL) { 4017c478bd9Sstevel@tonic-gate if (debug) 4027c478bd9Sstevel@tonic-gate (void) printf(" could not find a node in tree " 4037c478bd9Sstevel@tonic-gate "matching bdf\n"); 4047c478bd9Sstevel@tonic-gate return (-1); 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate 407801d74ddSshidokht if (debug) { 408801d74ddSshidokht int i; 409801d74ddSshidokht (void) printf("interface type "); 410801d74ddSshidokht for (i = 0; i < 8; i++) 411801d74ddSshidokht (void) printf("%c", bd->interface_type[i]); 412801d74ddSshidokht (void) printf(" pci channel %x target %x\n", 413801d74ddSshidokht bd->interfacepath.pci.channel, 414d155f3feSshidokht bd->devicepath.scsi.target); 415801d74ddSshidokht } 4167c478bd9Sstevel@tonic-gate 4177c478bd9Sstevel@tonic-gate if (strncmp(bd->interface_type, "SCSI", 4) == 0) { 4187c478bd9Sstevel@tonic-gate 419d155f3feSshidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%x,%x", 4207c478bd9Sstevel@tonic-gate bd->devicepath.scsi.target, bd->devicepath.scsi.lun_lo); 4217c478bd9Sstevel@tonic-gate 422d155f3feSshidokht cnode = search_children_match_busaddr(node, busaddrbuf); 4237c478bd9Sstevel@tonic-gate 424d155f3feSshidokht } else if ((strncmp(bd->interface_type, "ATAPI", 5) == 0) || 425d155f3feSshidokht (strncmp(bd->interface_type, "ATA", 3) == 0) || 426d155f3feSshidokht (strncmp(bd->interface_type, "SATA", 4) == 0)) { 427d155f3feSshidokht 428d155f3feSshidokht if (strncmp(di_node_name(node), "pci-ide", 7) == 0) { 429d155f3feSshidokht /* 430d155f3feSshidokht * Legacy using pci-ide 431d155f3feSshidokht * the child should be ide@<x>, where x is 432d155f3feSshidokht * the channel number 433d155f3feSshidokht */ 434d155f3feSshidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%d", 435d155f3feSshidokht bd->interfacepath.pci.channel); 436d155f3feSshidokht 437d155f3feSshidokht if ((cnode = search_children_match_busaddr(node, 438d155f3feSshidokht busaddrbuf)) != DI_NODE_NIL) { 439d155f3feSshidokht 440d155f3feSshidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0", 441d155f3feSshidokht bd->devicepath.ata.chan); 442d155f3feSshidokht cnode = search_children_match_busaddr(cnode, 443d155f3feSshidokht busaddrbuf); 444d155f3feSshidokht 445d155f3feSshidokht if (cnode == DI_NODE_NIL) 446d155f3feSshidokht if (debug) 447d155f3feSshidokht (void) printf("Interface %s " 448d155f3feSshidokht "using pci-ide no " 449d155f3feSshidokht "grandchild at %s\n", 450d155f3feSshidokht bd->interface_type, 451d155f3feSshidokht busaddrbuf); 452d155f3feSshidokht } else { 453d155f3feSshidokht if (debug) 454d155f3feSshidokht (void) printf("Interface %s using " 455d155f3feSshidokht "pci-ide, with no child at %s\n", 456d155f3feSshidokht bd->interface_type, busaddrbuf); 457d155f3feSshidokht } 458d155f3feSshidokht } else { 459d155f3feSshidokht if (strncmp(bd->interface_type, "SATA", 4) == 0) { 460d155f3feSshidokht /* 461d155f3feSshidokht * The current EDD (EDD-2) spec does not 462d155f3feSshidokht * address port number. This is work in 463d155f3feSshidokht * progress. 464d155f3feSshidokht * Interprete the first field of device path 465d155f3feSshidokht * as port number. Needs to be revisited 466d155f3feSshidokht * with port multiplier support. 467d155f3feSshidokht */ 468d155f3feSshidokht (void) snprintf(busaddrbuf, MAXNAMELEN, "%x,0", 4697c478bd9Sstevel@tonic-gate bd->devicepath.ata.chan); 4707c478bd9Sstevel@tonic-gate 471d155f3feSshidokht cnode = search_children_match_busaddr(node, 472d155f3feSshidokht busaddrbuf); 473d155f3feSshidokht } else { 474d155f3feSshidokht if (debug) 475d155f3feSshidokht (void) printf("Interface %s, not using" 476d155f3feSshidokht " pci-ide\n", bd->interface_type); 477d155f3feSshidokht } 478d155f3feSshidokht } 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate } else if (strncmp(bd->interface_type, "USB", 3) == 0) { 481d155f3feSshidokht cnode = search_tree_match_usbserialno(node, 482d155f3feSshidokht bd->devicepath.usb.usb_serial_id); 4837c478bd9Sstevel@tonic-gate } else { 4847c478bd9Sstevel@tonic-gate if (debug) 4857c478bd9Sstevel@tonic-gate (void) printf("sorry not supported interface %s\n", 4867c478bd9Sstevel@tonic-gate bd->interface_type); 4877c478bd9Sstevel@tonic-gate } 4887c478bd9Sstevel@tonic-gate 489d155f3feSshidokht if (cnode != DI_NODE_NIL) { 490d155f3feSshidokht devfspath = di_devfs_path(cnode); 491d155f3feSshidokht index = search_disklist_match_path(devfspath); 492d155f3feSshidokht di_devfs_path_free(devfspath); 493d155f3feSshidokht if (index >= 0) 4947c478bd9Sstevel@tonic-gate return (index); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate return (-1); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * For each disk in list of disks, compare the first block with the 5027c478bd9Sstevel@tonic-gate * one from bdd. On the first match, return the index of path in 5037c478bd9Sstevel@tonic-gate * disk_list. If none matched return -1. 5047c478bd9Sstevel@tonic-gate */ 5057c478bd9Sstevel@tonic-gate static int 5067c478bd9Sstevel@tonic-gate match_first_block(biosdev_data_t *bd) 5077c478bd9Sstevel@tonic-gate { 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate char diskpath[MAXPATHLEN]; 5107c478bd9Sstevel@tonic-gate int fd; 5117c478bd9Sstevel@tonic-gate char buf[512]; 5127c478bd9Sstevel@tonic-gate ssize_t num_read; 5137c478bd9Sstevel@tonic-gate int i; 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate if (!bd->first_block_valid) 5167c478bd9Sstevel@tonic-gate return (-1); 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate for (i = 0; i < disk_list_valid; i++) { 5197c478bd9Sstevel@tonic-gate (void) snprintf(diskpath, MAXPATHLEN, "%s/%s:q,raw", 5207c478bd9Sstevel@tonic-gate DEVFS_PREFIX, disk_list[i]); 5217c478bd9Sstevel@tonic-gate fd = open(diskpath, O_RDONLY); 5227c478bd9Sstevel@tonic-gate if (fd < 0) { 5237c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "opening %s failed errno %d\n", 5247c478bd9Sstevel@tonic-gate diskpath, errno); 5257c478bd9Sstevel@tonic-gate continue; 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate num_read = read(fd, buf, 512); 5287c478bd9Sstevel@tonic-gate if (num_read != 512) { 5297c478bd9Sstevel@tonic-gate (void) printf("read only %d bytes from %s\n", num_read, 5307c478bd9Sstevel@tonic-gate diskpath); 5317c478bd9Sstevel@tonic-gate continue; 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate if (memcmp(buf, bd->first_block, 512) == 0) { 5357c478bd9Sstevel@tonic-gate /* found it */ 5367c478bd9Sstevel@tonic-gate return (i); 5377c478bd9Sstevel@tonic-gate } 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate return (-1); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate static void 5447c478bd9Sstevel@tonic-gate cleanup_and_exit(int exitcode) 5457c478bd9Sstevel@tonic-gate { 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate free_disks(); 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate if (root_node != DI_NODE_NIL) 5507c478bd9Sstevel@tonic-gate di_fini(root_node); 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate if (root_allnode != DI_NODE_NIL) 5537c478bd9Sstevel@tonic-gate di_fini(root_allnode); 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate if (prom_hdl != DI_PROM_HANDLE_NIL) 5567c478bd9Sstevel@tonic-gate di_prom_fini(prom_hdl); 5577c478bd9Sstevel@tonic-gate exit(exitcode); 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate int 5637c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 5647c478bd9Sstevel@tonic-gate { 5657c478bd9Sstevel@tonic-gate biosdev_data_t *biosdata; 566801d74ddSshidokht int i, c, j; 5677c478bd9Sstevel@tonic-gate int matchedindex = -1; 5687c478bd9Sstevel@tonic-gate char biospropname[BIOSPROPNAME_TMPL_LEN]; 5697c478bd9Sstevel@tonic-gate int totalmatches = 0; 570801d74ddSshidokht biosdev_data_t *biosdataarray[BIOSDEV_NUM]; 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "d")) != -1) { 5747c478bd9Sstevel@tonic-gate switch (c) { 5757c478bd9Sstevel@tonic-gate case 'd': 5767c478bd9Sstevel@tonic-gate debug = 1; 5777c478bd9Sstevel@tonic-gate break; 5787c478bd9Sstevel@tonic-gate default: 5797c478bd9Sstevel@tonic-gate (void) printf("unknown option %c\n", c); 5807c478bd9Sstevel@tonic-gate exit(1); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate if ((prom_hdl = di_prom_init()) == DI_PROM_HANDLE_NIL) { 5857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "di_prom_init failed\n"); 5867c478bd9Sstevel@tonic-gate cleanup_and_exit(1); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate if ((root_node = di_init("/", DINFOCACHE)) == DI_NODE_NIL) { 5907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "di_init failed\n"); 5917c478bd9Sstevel@tonic-gate cleanup_and_exit(1); 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate if ((root_allnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 5957c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "di_init failed\n"); 5967c478bd9Sstevel@tonic-gate cleanup_and_exit(1); 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate (void) memset(mapinfo, 0, sizeof (mapinfo)); 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate /* get a list of all disks in the system */ 6027c478bd9Sstevel@tonic-gate build_disk_list(); 6037c478bd9Sstevel@tonic-gate 604801d74ddSshidokht /* Get property values that were created at boot up time */ 6057c478bd9Sstevel@tonic-gate for (i = 0; i < BIOSDEV_NUM; i++) { 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate (void) snprintf((char *)biospropname, BIOSPROPNAME_TMPL_LEN, 6087c478bd9Sstevel@tonic-gate BIOSPROPNAME_TMPL, i + STARTING_DRVNUM); 609801d74ddSshidokht if (di_prop_lookup_bytes(DDI_DEV_T_ANY, root_allnode, 610801d74ddSshidokht biospropname, (uchar_t **)&biosdataarray[i]) <= 0) 611801d74ddSshidokht biosdataarray[i] = NULL; 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate 614801d74ddSshidokht /* Try to match based on device/interface path info from BIOS */ 615801d74ddSshidokht for (i = 0; i < BIOSDEV_NUM; i++) { 616801d74ddSshidokht 617801d74ddSshidokht if ((biosdata = biosdataarray[i]) == NULL) 618801d74ddSshidokht continue; 6197c478bd9Sstevel@tonic-gate if (debug) 620801d74ddSshidokht (void) printf("matching edd 0x%x\n", 621801d74ddSshidokht i + STARTING_DRVNUM); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate matchedindex = match_edd(biosdata); 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate if (matchedindex != -1) { 626801d74ddSshidokht if (debug) { 627801d74ddSshidokht (void) printf("matched by edd\n"); 6287c478bd9Sstevel@tonic-gate (void) printf("0x%x %s\n", i + STARTING_DRVNUM, 6297c478bd9Sstevel@tonic-gate disk_list[matchedindex]); 630801d74ddSshidokht } 631801d74ddSshidokht 632801d74ddSshidokht mapinfo[i].disklist_index = matchedindex; 633801d74ddSshidokht mapinfo[i].matchcount++; 634801d74ddSshidokht 6357c478bd9Sstevel@tonic-gate for (j = 0; j < i; j++) { 6367c478bd9Sstevel@tonic-gate if (mapinfo[j].matchcount > 0 && 6377c478bd9Sstevel@tonic-gate mapinfo[j].disklist_index == matchedindex) { 6387c478bd9Sstevel@tonic-gate mapinfo[j].matchcount++; 6397c478bd9Sstevel@tonic-gate mapinfo[i].matchcount++; 6407c478bd9Sstevel@tonic-gate } 6417c478bd9Sstevel@tonic-gate } 6427c478bd9Sstevel@tonic-gate 643801d74ddSshidokht } else 644801d74ddSshidokht if (debug) 645801d74ddSshidokht (void) printf("No matches by edd\n"); 6467c478bd9Sstevel@tonic-gate } 6477c478bd9Sstevel@tonic-gate 648801d74ddSshidokht /* 649801d74ddSshidokht * Go through the list and ignore any found matches that are dups. 650801d74ddSshidokht * This is to workaround issues with BIOSes that do not implement 651801d74ddSshidokht * providing interface/device path info correctly. 652801d74ddSshidokht */ 653801d74ddSshidokht 654801d74ddSshidokht for (i = 0; i < BIOSDEV_NUM; i++) { 655801d74ddSshidokht if (mapinfo[i].matchcount > 1) { 656801d74ddSshidokht if (debug) 657801d74ddSshidokht (void) printf("Ignoring dup match_edd\n(count " 658801d74ddSshidokht "%d): 0x%x %s\n", mapinfo[i].matchcount, 659801d74ddSshidokht i + STARTING_DRVNUM, 660801d74ddSshidokht disk_list[mapinfo[i].disklist_index]); 661801d74ddSshidokht 662801d74ddSshidokht mapinfo[i].matchcount = 0; 663801d74ddSshidokht mapinfo[i].disklist_index = 0; 664801d74ddSshidokht } 665801d74ddSshidokht } 666801d74ddSshidokht 667801d74ddSshidokht 668801d74ddSshidokht /* 669801d74ddSshidokht * For each bios dev number that we do not have exactly one match 670801d74ddSshidokht * already, try to match based on first block 671801d74ddSshidokht */ 672801d74ddSshidokht for (i = 0; i < BIOSDEV_NUM; i++) { 673801d74ddSshidokht if (mapinfo[i].matchcount == 1) 674801d74ddSshidokht continue; 675801d74ddSshidokht 676801d74ddSshidokht if ((biosdata = biosdataarray[i]) == NULL) 677801d74ddSshidokht continue; 678801d74ddSshidokht 679801d74ddSshidokht if (debug) 680801d74ddSshidokht (void) printf("matching first block 0x%x\n", 681801d74ddSshidokht i + STARTING_DRVNUM); 682801d74ddSshidokht 683801d74ddSshidokht matchedindex = match_first_block(biosdata); 684801d74ddSshidokht if (matchedindex != -1) { 685801d74ddSshidokht if (debug) { 686801d74ddSshidokht (void) printf("matched by first block\n"); 687801d74ddSshidokht (void) printf("0x%x %s\n", i + STARTING_DRVNUM, 688801d74ddSshidokht disk_list[matchedindex]); 689801d74ddSshidokht } 690801d74ddSshidokht 691801d74ddSshidokht mapinfo[i].disklist_index = matchedindex; 692801d74ddSshidokht mapinfo[i].matchcount++; 693801d74ddSshidokht 694801d74ddSshidokht for (j = 0; j < i; j++) { 695801d74ddSshidokht if (mapinfo[j].matchcount > 0 && 696801d74ddSshidokht mapinfo[j].disklist_index == matchedindex) { 697801d74ddSshidokht mapinfo[j].matchcount++; 698801d74ddSshidokht mapinfo[i].matchcount++; 699801d74ddSshidokht } 700801d74ddSshidokht } 701801d74ddSshidokht } else 702801d74ddSshidokht if (debug) { 703801d74ddSshidokht (void) printf(" No matches by first block\n"); 704801d74ddSshidokht (void) fprintf(stderr, "Could not match 0x%x\n", 705801d74ddSshidokht i + STARTING_DRVNUM); 706801d74ddSshidokht } 707801d74ddSshidokht } 708801d74ddSshidokht 709801d74ddSshidokht 7107c478bd9Sstevel@tonic-gate for (i = 0; i < BIOSDEV_NUM; i++) { 7117c478bd9Sstevel@tonic-gate if (mapinfo[i].matchcount == 1) { 7127c478bd9Sstevel@tonic-gate (void) printf("0x%x %s\n", i + STARTING_DRVNUM, 7137c478bd9Sstevel@tonic-gate disk_list[mapinfo[i].disklist_index]); 7147c478bd9Sstevel@tonic-gate totalmatches++; 7157c478bd9Sstevel@tonic-gate } else if (debug && mapinfo[i].matchcount > 1) { 7167c478bd9Sstevel@tonic-gate (void) printf("0x%x %s matchcount %d\n", 7177c478bd9Sstevel@tonic-gate i + STARTING_DRVNUM, 7187c478bd9Sstevel@tonic-gate disk_list[mapinfo[i].disklist_index], 7197c478bd9Sstevel@tonic-gate mapinfo[i].matchcount); 7207c478bd9Sstevel@tonic-gate } 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate if (totalmatches == 0) { 7247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "biosdev: Could not match any!!\n"); 7257c478bd9Sstevel@tonic-gate cleanup_and_exit(1); 7267c478bd9Sstevel@tonic-gate } 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate cleanup_and_exit(0); 7297c478bd9Sstevel@tonic-gate /* NOTREACHED */ 7307c478bd9Sstevel@tonic-gate return (0); 7317c478bd9Sstevel@tonic-gate } 732