1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <strings.h> 26 #include <devid.h> 27 #include <pthread.h> 28 #include <inttypes.h> 29 #include <sys/dkio.h> 30 #include <sys/scsi/scsi_types.h> 31 #include <fm/topo_mod.h> 32 #include <fm/topo_list.h> 33 #include <fm/libdiskstatus.h> 34 #include <sys/fm/protocol.h> 35 #include "disk.h" 36 #include "disk_drivers.h" 37 38 static int disk_enum(topo_mod_t *, tnode_t *, const char *, 39 topo_instance_t, topo_instance_t, void *, void *); 40 41 static const topo_modops_t disk_ops = 42 { disk_enum, NULL }; 43 44 static const topo_modinfo_t disk_info = 45 {DISK, FM_FMRI_SCHEME_HC, DISK_VERSION, &disk_ops}; 46 47 static int 48 disk_declare_driver(topo_mod_t *mod, tnode_t *baynode, topo_list_t *dlistp, 49 char *driver) 50 { 51 int err; 52 53 if (strcmp("mpt_sas", driver) == 0) { 54 char *sas_address = NULL; 55 tnode_t *child = NULL; 56 57 if (disk_mptsas_find_disk(mod, baynode, &sas_address) != 0) 58 return (err); 59 60 err = disk_declare_addr(mod, baynode, dlistp, 61 sas_address, &child); 62 topo_mod_strfree(mod, sas_address); 63 64 return (err); 65 } 66 67 topo_mod_dprintf(mod, "unknown disk driver '%s'\n", driver); 68 return (-1); 69 } 70 71 /*ARGSUSED*/ 72 static int 73 disk_enum(topo_mod_t *mod, tnode_t *baynode, 74 const char *name, topo_instance_t min, topo_instance_t max, 75 void *arg, void *notused) 76 { 77 char *device, *driver; 78 int err; 79 nvlist_t *fmri; 80 topo_list_t *dlistp = topo_mod_getspecific(mod); 81 82 if (strcmp(name, DISK) != 0) { 83 topo_mod_dprintf(mod, "disk_enum: " 84 "only know how to enumerate %s components.\n", DISK); 85 return (-1); 86 } 87 88 /* set the parent fru */ 89 if (topo_node_resource(baynode, &fmri, &err) != 0) { 90 topo_mod_dprintf(mod, "disk_enum: " 91 "topo_node_resource error %s\n", topo_strerror(err)); 92 return (-1); 93 } 94 if (topo_node_fru_set(baynode, fmri, 0, &err) != 0) { 95 topo_mod_dprintf(mod, "disk_enum: " 96 "topo_node_fru error %s\n", topo_strerror(err)); 97 nvlist_free(fmri); 98 return (-1); 99 } 100 nvlist_free(fmri); 101 102 /* 103 * For internal storage, first check to see if we need to 104 * request more detail from an HBA driver. 105 */ 106 if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING, 107 TOPO_BINDING_DRIVER, &driver, &err) == 0) { 108 err = disk_declare_driver(mod, baynode, dlistp, driver); 109 110 topo_mod_strfree(mod, driver); 111 return (err); 112 } else if (err != ETOPO_PROP_NOENT) { 113 topo_mod_dprintf(mod, "disk_enum: " 114 "binding error %s\n", topo_strerror(err)); 115 return (-1); 116 } 117 118 /* 119 * For internal storage, get the path to the occupant from the 120 * binding group of the bay node 121 */ 122 if (topo_prop_get_string(baynode, TOPO_PGROUP_BINDING, 123 TOPO_BINDING_OCCUPANT, &device, &err) != 0) { 124 topo_mod_dprintf(mod, "disk_enum: " 125 "binding error %s\n", topo_strerror(err)); 126 return (-1); 127 } 128 129 130 /* locate and topo enumerate the disk with that path */ 131 err = disk_declare_path(mod, baynode, dlistp, device); 132 133 topo_mod_strfree(mod, device); 134 return (err); 135 } 136 137 /*ARGSUSED*/ 138 int 139 _topo_init(topo_mod_t *mod, topo_version_t version) 140 { 141 topo_list_t *dlistp; 142 143 /* 144 * Turn on module debugging output 145 */ 146 if (getenv("TOPODISKDEBUG") != NULL) 147 topo_mod_setdebug(mod); 148 topo_mod_dprintf(mod, "_topo_init: " 149 "initializing %s enumerator\n", DISK); 150 151 if (topo_mod_register(mod, &disk_info, TOPO_VERSION) != 0) { 152 topo_mod_dprintf(mod, "_topo_init: " 153 "%s registration failed: %s\n", DISK, topo_mod_errmsg(mod)); 154 return (-1); /* mod errno already set */ 155 } 156 157 if ((dlistp = topo_mod_zalloc(mod, sizeof (topo_list_t))) == NULL) { 158 topo_mod_dprintf(mod, "_topo_inti: failed to allocate " 159 "disk list"); 160 return (-1); 161 } 162 163 if (dev_list_gather(mod, dlistp) != 0) { 164 topo_mod_unregister(mod); 165 topo_mod_free(mod, dlistp, sizeof (topo_list_t)); 166 topo_mod_dprintf(mod, "_topo_init: " 167 "failed to locate disks"); 168 return (-1); 169 } 170 171 topo_mod_dprintf(mod, "_topo_init: " 172 "%s enumerator initialized\n", DISK); 173 174 topo_mod_setspecific(mod, dlistp); 175 176 return (0); 177 } 178 179 void 180 _topo_fini(topo_mod_t *mod) 181 { 182 topo_list_t *dlistp = topo_mod_getspecific(mod); 183 dev_list_free(mod, dlistp); 184 topo_mod_free(mod, dlistp, sizeof (topo_list_t)); 185 topo_mod_unregister(mod); 186 topo_mod_dprintf(mod, "_topo_fini: " 187 "%s enumerator uninitialized\n", DISK); 188 }